转自:http://bbs.pediy.com/showthread.php?s=&threadid=21959
标 题: 【原创】笑解 API 函数 -- API 绝密档案系列之一
作 者: gzgzlxg
时 间: 2006-03-01,07:14
链 接: http://bbs.pediy.com/showthread.php?t=21959
看到 qduwg 老师凭"【翻译】3个脱壳相关的重要函数介绍" 也"骗"到一个精,不觉心痒,也弄几个函数来介绍一下,不过我不是翻译,而是著作。我 们就从 qduwg 老师介绍的几个函数入手。希望上面的话没有伤到 qduwg 老师的自尊心。我看到你对别人评价的反应,知道你很在意这些。
1. HMODULE GetModuleHandle(
LPCTSTR lpModuleName // address of module name to return handle
// for
);
GetModuleHandle 实际上分为两个函数
GetModuleHandleA--处理 Ansi 字符串
GetModuleHandleW--处理 Unicode 字符串
其实真正干活的函数是,GetModuleHandleW (指NT以后的系统),GetModuleHandleA 只不过将用户输入的 Ansi 字 符串转成 Unicode 字符串然后就直接调用 GetModuleHandleW,所以在 OD 中如果下断拦截这个函数,直接拦 截 GetModuleHandleW 就可以了,保险一个都跑不掉。我看一些新手写 Hook 程序时往往不厌其烦的将每个函数都“沟”一下,其实大可 不必,随着我的文章深入,你会发现一个基本原则--千条江河归大海,大部分的调用其实最后都是进入最底层的 ntoskrnl.exe、Hal.dll、 和其他几个内核程序。而我们平常打交道最多的 Kernel32.dll 和 ntdll.dll 其实只是对底层函数进行了包装(当然对于某些 ring3层的特定功能还是自己完成的),相当于一个接口,起一个中转和隔离的作用,将用户的函数调用进行预处理,比如检测用户参数的合法性,对用户参数 进行重新排序(底层函数的参数排列顺序有时和用户层不同,这样可以防止你轻易的弄明白底层在干什么),将用户的调用分离拆解为若干个更为细小的调用,因为 底层函数分类往往更细,这样比较灵活。
使用 GetModuleHandle 函数,在高级语言中可以直接写成:
hMod = GetModuleHandle(lpModuleName);
编译器会根据参数的性质自行决定调用那一个函数,但在汇编中却不能这样使用,你必须明确的指明你要使用那一个函数。另外在OD中下断点,你也必须明确的指 明对那一个函数下断,例如在OD中,进入CPU窗口,按Ctrl-G,然后输入GetModuleHandle,OD会告诉你 “未识的标识符”,你必须 清楚的告诉 OD 你到底要在那一个函数下断,是 A 还是 W。按前面的说法其实你只要下 GetModuleHandleW 就可以了(当然有时候在 A下断,比较容易知道程序是从那里调用的,如果程序使用的是A调用)。
俗话说,口说无凭。你怎么知道那两个还是最后变成了一个?
看雪老大也在qduwg的文章后说:
77E80B1A ; HMODULE __stdcall GetModuleHandleA(LPCSTR lpModuleName)
77E80B1A public GetModuleHandleA
77E80B1A GetModuleHandleA proc near ; CODE XREF: sub_77E684C2+2p
77E80B1A ; CreateRemoteThread+FBp ...
77E80B1A
77E80B1A lpModuleName= dword ptr 8
77E80B1A
77E80B1A push ebp
77E80B1B mov ebp, esp
77E80B1D cmp [ebp+lpModuleName], 0
77E80B21 jnz short loc_77E80B31 ; lpModuleName 是有效的则转移
77E80B23 mov eax, large fs:18h ; TEB.NT_TIB.Self
77E80B29 mov eax, [eax+30h] ; TEB.Peb
77E80B2C mov eax, [eax+8] ; PEB.ImageBaseAddress
77E80B2F jmp short loc_77E80B45
77E80B31
77E80B31 loc_77E80B31: ; CODE XREF: GetModuleHandleA+7j
77E80B31 push [ebp+lpModuleName]
77E80B34 call @AnsiStrToUnicodeStr ; 将Ansi字符串转成Unicode字符串
77E80B39 test eax, eax
77E80B3B jz short loc_77E80B45
77E80B3D push dword ptr [eax+4] ; lpModuleName
77E80B40 call GetModuleHandleW ; 这里开始同流合污了。
77E80B45
77E80B45 loc_77E80B45: ; CODE XREF: GetModuleHandleA+15j
77E80B45 ; GetModuleHandleA+21j
77E80B45 pop ebp
77E80B46 retn 4
77E80B46 GetModuleHandleA endp
kd> !teb //老盖的Debug命令一般都需要这个"哇"符号做前缀,读作"哇!!添一杯"
TEB at 7FFDE000
ExceptionList: 12f830 " 0x0
Stack Base: 130000 | 0x4
Stack Limit: 126000 | 0x8
SubSystemTib: 0 | 0xC 这里其实是 NT_TIB 的一个结构
FiberData: 1e00 | 0x10
ArbitraryUser: 0 | 0x14
Self: 7ffde000 / 0x18
EnvironmentPtr: 0 0x1C
ClientId: 4cc.4c8 0x20
Real ClientId: 4cc.4c8 0x24
RpcHandle: 0 0x28
Tls Storage: 0 0x2C
PEB Address: 7ffdf000 0x30 这里指向 PEB 表,即进程环境块
LastErrorValue: 0
LastStatusValue: 8000001a
Count Owned Locks:0
HardErrorsMode: 0
kd> !kdex2x86.strct peb //如果 kdex2x86 已经加载,可以直接输入 !strct peb
struct _PEB (sizeof=488)
+000 byte InheritedAddressSpace
+001 byte ReadImageFileExecOptions
+002 byte BeingDebugged //Debug运行标志
+003 byte SpareBool
+004 void *Mutant
+008 void *ImageBaseAddress //这里就是程序加载的基地址了
+00c struct _PEB_LDR_DATA *Ldr
+010 struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters
+014 void *SubSystemData
+018 void *ProcessHeap
+01c void *FastPebLock
+020 void *FastPebLockRoutine
+024 void *FastPebUnlockRoutine
+028 uint32 EnvironmentUpdateCount
+02c void *KernelCallbackTable
+030 uint32 SystemReserved[2]
+038 struct _PEB_FREE_BLOCK *FreeList
+03c uint32 TlsExpansionCounter
+040 void *TlsBitmap
+044 uint32 TlsBitmapBits[2]
+04c void *ReadOnlySharedMemoryBase
+050 void *ReadOnlySharedMemoryHeap
+054 void **ReadOnlyStaticServerData
+058 void *AnsiCodePageData
+05c void *OemCodePageData
+060 void *UnicodeCaseTableData
+064 uint32 NumberOfProcessors
+068 uint32 NtGlobalFlag
+070 union _LARGE_INTEGER CriticalSectionTimeout
+070 uint32 LowPart
+074 int32 HighPart
+070 struct __unnamed3 u
+070 uint32 LowPart
+074 int32 HighPart
+070 int64 QuadPart
+078 uint32 HeapSegmentReserve
+07c uint32 HeapSegmentCommit
+080 uint32 HeapDeCommitTotalFreeThreshold
+084 uint32 HeapDeCommitFreeBlockThreshold
+088 uint32 NumberOfHeaps
+08c uint32 MaximumNumberOfHeaps
+090 void **ProcessHeaps
+094 void *GdiSharedHandleTable
+098 void *ProcessStarterHelper
+09c uint32 GdiDCAttributeList
+0a0 void *LoaderLock
+0a4 uint32 OSMajorVersion
+0a8 uint32 OSMinorVersion
+0ac uint16 OSBuildNumber
+0ae uint16 OSCSDVersion
+0b0 uint32 OSPlatformId
+0b4 uint32 ImageSubsystem
+0b8 uint32 ImageSubsystemMajorVersion
+0bc uint32 ImageSubsystemMinorVersion
+0c0 uint32 ImageProcessAffinityMask
+0c4 uint32 GdiHandleBuffer[34]
+14c function *PostProcessInitRoutine
+150 void *TlsExpansionBitmap
+154 uint32 TlsExpansionBitmapBits[32]
+1d4 uint32 SessionId
+1d8 void *AppCompatInfo
+1dc struct _UNICODE_STRING CSDVersion
+1dc uint16 Length
+1de uint16 MaximumLength
+1e0 uint16 *Buffer
77E80B1A push ebp
77E80B1B mov ebp, esp
77E80B1D cmp [ebp+lpModuleName], 0
77E80B21 jnz short loc_77E80B31 ; lpModuleName 是有效的则转移
77E80B23 mov eax, large fs:18h ; TEB.NT_TIB.Self
77E80B29 mov eax, [eax+30h] ; TEB.Peb
77E80B2C mov eax, [eax+8] ; PEB.ImageBaseAddress
77E80B2F jmp short loc_77E80B45
77E80B23 mov eax, large fs:18h ; TEB.NT_TIB.Self
77E80B29 mov eax, [eax+30h] ; TEB.Peb
77E80B2C mov eax, [eax+8] ; PEB.ImageBaseAddress
77E80B1D cmp [ebp+lpModuleName], 0