笑解 API 函数 -- API 绝密档案系列之三 高处不胜寒
"怎么又笑了,防热涂的血" -- 摘自悍匪座山雕语录。
在这一篇中,我们首先简单介绍另一个函数 GetProcAddress, GetProcAddress 和 GetModuleHandle 函数是兄弟的关系,我个人认为这两个函数的命名非常容易让用户产生混乱,而且有些颠倒的感觉,似乎如下命名更好:
将 GetModuleHandle 改为
GetProcBaseAddress //GetModuleHandle 实质是获取进程加载的基地址
将 GetProcAddress 改为
GetFunctionAddress //GetProcAddress 实质是获取函数的调用地址
db "GetProcAddress",0
在内存中的映象为:
47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00
如果是Uncode在内存中的映象为:
47 00 65 00 74 00 50 00 72 00 6F 00 63 00 41 00 64 00 64 00 72 00 65 00 73 00 73 00
77E80CAB ; Exported entry 344. GetProcAddress
77E80CAB ; ======== S U B R O U T I N E ====================
77E80CAB ; FARPROC __stdcall GetProcAddress(HMODULE hModule,LPCSTR lpProcName)
77E80CAB public _GetProcAddress@8
77E80CAB _GetProcAddress@8 proc near
77E80CAB ProcNameString= dword ptr -8
77E80CAB hModule= dword ptr 8
77E80CAB lpProcName= dword ptr 0Ch
77E80CAB push ebp
77E80CAC mov ebp, esp
77E80CAE push ecx
77E80CAF push ecx
77E80CB0 push ebx
77E80CB1 push edi
77E80CB2 mov edi, [ebp+lpProcName] ; 获取指向函数名的指针(地址)
77E80CB5 mov ebx, 0FFFFh
77E80CBA cmp edi, ebx ; 如果lpProcName是字符串,这指向这个字符串的地址一定
77E80CBA ; 大于 0FFFFh
77E80CBC jbe short IfProcNameIsNull
77E80CBE lea eax, [ebp+ProcNameString]
77E80CC1 push edi ; SourceString
77E80CC2 push eax ; DestinationString
77E80CC3 call ds:__imp__RtlInitString@8 ; __declspec(dllimport) RtlInitString(x,x)
77E80CC9 lea eax, [ebp+lpProcName] ; 将 lpProcName 作为变量使用
77E80CCC push eax ; ProcedureAddress
77E80CCD lea eax, [ebp+ProcNameString]
77E80CD0 push 0 ; Ordinal
77E80CD2 push eax ; Name
77E80CD3 jmp short GetProcAddress
77E80CD5 IfProcNameIsNull:
77E80CD5 lea eax, [ebp+lpProcName]
77E80CD8 push eax ; ProcedureAddress
77E80CD9 push edi ; Ordinal
77E80CDA push 0 ; Name
77E80CDC GetProcAddress: ; flag
77E80CDC push 0
77E80CDE push [ebp+hModule] ; hModule
77E80CE1 call _BasepMapModuleHandle@8 ; BasepMapModuleHandle(x,x)
77E80CE6 push eax ; BaseAddress
77E80CE7 call _LdrGetProcedureAddress@16 ; LdrGetProcedureAddress(x,x,x,x)
77E80CEC test eax, eax
77E80CEE jl short IfFunAddrEquZero
77E80CF0 push 0 ; flag
77E80CF2 push [ebp+hModule] ; hModule
77E80CF5 call _BasepMapModuleHandle@8 ; BasepMapModuleHandle(x,x)
77E80CFA cmp [ebp+lpProcName], eax
77E80CFD jnz short IfFunAddrIsOk
77E80CFF cmp ebx, edi
77E80D01 sbb eax, eax
77E80D03 neg eax
77E80D05 add eax, STATUS_ORDINAL_NOT_FOUND
77E80D0A IfFunAddrEquZero:
77E80D0A push eax ; Status
77E80D0B call _BaseSetLastNTError@4 ; BaseSetLastNTError(x)
77E80D10 xor eax, eax
77E80D12 jmp short Exit
77E80D14 IfFunAddrIsOk: ; 变量参数lpProcName的内容为 ProcAddress
77E80D14 mov eax, [ebp+lpProcName] ; 变量参数lpProcName的内容为 ProcAddress
77E80D17 Exit:
77E80D17 pop edi
77E80D18 pop ebx
77E80D19 leave
77E80D1A retn 8
77E80D1A _GetProcAddress@8 endp
77E68210 ; ======== S U B R O U T I N E ====================
77E68210 ; int __stdcall BasepMapModuleHandle(HMODULE hModule,BOOLEAN flag)
77E68210 _BasepMapModuleHandle@8 proc near
77E68210 hModule= dword ptr 8
77E68210 flag = byte ptr 0Ch
77E68210 push ebp
77E68211 mov ebp, esp
77E68213 mov eax, [ebp+hModule]
77E68216 test eax, eax
77E68218 jz short loc_77E68229
77E6821A test al, 1
77E6821C jz short loc_77E68235
77E6821E ;if flag == 0
77E6821E ; ecx = 0
77E6821E ;else
77E6821E ; ecx = 0xFFFFFFFF
77E6821E mov cl, [ebp+flag]
77E68221 neg cl
77E68223 sbb ecx, ecx
77E68225 and eax, ecx
77E68227 jmp short loc_77E68235
77E68229 loc_77E68229:
77E68229 mov eax, large fs:18h
77E6822F mov eax, [eax+TEB.Peb]
77E68232 mov eax, [eax+PEB.ImageBaseAddress]
77E68235 loc_77E68235:
77E68235 pop ebp
77E68236 retn 8
77E68236 _BasepMapModuleHandle@8 endp
77E80CB2 mov edi, [ebp+lpProcName] ; 获取指向函数名的指针(地址)
77E80CB5 mov ebx, 0FFFFh
77E80CBA cmp edi, ebx ; 如果lpProcName是字符串,这指向这个字符串的地址一定
77E80CBA ; 大于 0FFFFh
77E80CBC jbe short IfProcNameIsNull
77E80CBE lea eax, [ebp+ProcNameString]
77E80CC1 push edi ; SourceString
77E80CC2 push eax ; DestinationString
77E80CC3 call ds:__imp__RtlInitString@8 ; __declspec(dllimport) RtlInitString(x,x)
;下面是为调用 LdrGetProcedureAddress(x,x,x,x) 而设置入口参数
77E80CC9 lea eax, [ebp+lpProcName] ; 将 lpProcName 作为变量使用
77E80CCC push eax ; ProcedureAddress
77E80CCD lea eax, [ebp+ProcNameString]
77E80CD0 push 0 ; Ordinal
77E80CD2 push eax ; Name
77E80CD3 jmp short GetProcAddress ; 跳到获取函数地址的具体调用
UNICODE_STRING struc ; (sizeof=0X8, standard type)
Length dw ?
MaximumLength dw ?
Buffer dd ? ;指向字符串的指针
UNICODE_STRING ends
STRING struc ; (sizeof=0X8)
Length dw ?
MaximumLength dw ?
Buffer dd ? ;指向字符串的指针
STRING ends
strings struc ; (sizeof=0X8, variable size)
top dd ?
Len dd ?
Text db 0 dup(?) ; string(C)
strings ends
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)