转自:http://bbs.pediy.com/showthread.php?t=22313&highlight=%E7%AC%91%E8%A7%A3+API+%E5%87%BD%E6%95%B0
标 题: 【原创】笑解 API 函数 -- API 绝密档案系列之三
作 者: gzgzlxg将 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
77E80CD5 IfProcNameIsNull:
;下面是为调用 LdrGetProcedureAddress(x,x,x,x) 而设置入口参数
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 ; 检查 hModule 的合法性
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 ; 检查函数调用地址的合法性
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: ; Status
77E80D0A push eax
77E80D0B call _BaseSetLastNTError@4 ; BaseSetLastNTError(x)
77E80D10 xor eax, eax
77E80D12 jmp short Exit
77F8C0B8 ; NTSTATUS __stdcall LdrpSnapThunk(PVOID BaseAddress, "
ANSI_STRING *lpProcName, "
ULONG Ordinal, "
PVOID *ProceAddr, "
PVOID ExportTabAddr, "
int, "
BOOLEAN ShowNotFound, "
int Unknown)
77F8C0B8 _LdrpSnapThunk@32 proc near
77F8C0B8 var_24= dword ptr -24h
77F8C0B8 var_20= dword ptr -20h
77F8C0B8 var_18= dword ptr -18h
77F8C0B8 var_10= dword ptr -10h
77F8C0B8 ProcName= STRING ptr -8
77F8C0B8 BaseAddress= dword ptr 8
77F8C0B8 lpProcName= dword ptr 0Ch
77F8C0B8 Ordinal= dword ptr 10h
77F8C0B8 ProceAddr= dword ptr 14h
77F8C0B8 ExportTabAddr= dword ptr 18h
77F8C0B8 arg_14= dword ptr 1Ch
77F8C0B8 ShowNotFound= byte ptr 20h
77F8C0B8 Unknown= dword ptr 24h
77F8C0B8 push ebp
77F8C0B9 mov ebp, esp
77F8C0BB sub esp, 24h
77F8C0BE mov eax, [ebp+Ordinal]
......
......
77F8C157 RealGetFunctionAddress:
77F8C157 push edi ; AddressOfNameOrdinals
77F8C158 push eax ; AddressOfNames
77F8C159 push [ebp+BaseAddress] ; BaseAddress
77F8C15C push [esi+IMAGE_EXPORT_DIRECTORY.NumberOfNames] ; NumberOfNames
77F8C15F push [ebp+lpProcName] ; lpProcName
77F8C162 call _LdrpNameToOrdinal@20 ; LdrpNameToOrdinal(x,x,x,x,x)
77F8C167 loc_77F8C167:
77F8C167 movzx ecx, ax
77F8C16A cmp ecx, [esi+IMAGE_EXPORT_DIRECTORY.NumberOfFunctions]
77F8C16D jnb loc_77F8C248
77F8C173 mov eax, [esi+IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
77F8C176 mov edx, [ebp+BaseAddress]
77F8C179 add eax, edx ; Offset + BaseAddress
77F8C17B lea eax, [eax+ecx*4] ; Offset + Ordinal * 4
77F8C17E mov ecx, [eax] ; OffsetFunction
77F8C180 add ecx, edx ; FunctionAddress = OffsetFunction + BaseAddress
77F8C182 mov edx, [ebp+ProceAddr]
77F8C185 cmp ecx, esi
77F8C187 mov [edx], ecx
77F8C189 jbe loc_77F8C243
......
......
77F800D0 PEHead db 'PE',0,0 ; Signature
77F800D0 dw 14Ch ; FileHeader.Machine
77F800D0 dw 7 ; FileHeader.NumberOfSections
77F800D0 dd 41E648E0h ; FileHeader.TimeDateStamp
77F800D0 dd 0 ; FileHeader.PointerToSymbolTable
77F800D0 dd 0 ; FileHeader.NumberOfSymbols
77F800D0 dw 0E0h ; FileHeader.SizeOfOptionalHeader
77F800D0 dw 230Eh ; FileHeader.Characteristics
77F800D0 dw 10Bh ; OptionalHeader.Magic
......
......
77F800D0 dd offset ExportTableBase ; OptionalHeader.Export.VirtualAddress
77F800D0 dd 83D7h ; OptionalHeader.Export.Size
77F800D0 dd offset ImportTableBase ; OptionalHeader.Import.VirtualAddress
77F800D0 dd 0 ; OptionalHeader.Import.Size
77F800D0 dd offset ResourceTableBase ; OptionalHeader.Resource.VirtualAddress
77F800D0 dd 0DCA0h ; OptionalHeader.Resource.Size
......
......
77FBBE20 ExportTableBase
77FBBE20 dd 0 ; Characteristics ; "ntdll.dll"
77FBBE20 dd 41AFD201h ; TimeDateStamp
77FBBE20 dw 0 ; MajorVersion
77FBBE20 dw 0 ; MinorVersion
77FBBE20 dd offset aNtdll_dll_0 ; Name
77FBBE20 dd 1 ; Base
77FBBE20 dd 4A5h ; NumberOfFunctions
77FBBE20 dd 4A5h ; NumberOfNames
77FBBE20 dd offset AddrOfFunBase ; AddressOfFunctions
77FBBE20 dd offset AddrOfNamesBase ; AddressOfNames
77FBBE20 dd offset AddrOfNameOrdinalsBase ; AddressOfNameOrdinals
77FBBE48 AddrOfFunBase
77FBBE48 dd offset PropertyLengthAsVariant
77FBBE4C dd offset RtlConvertPropertyToVariant
77FBBE50 dd offset RtlConvertVariantToProperty
77FBBE54 dd offset @RtlUlongByteSwap@4
77FBBE58 dd offset @RtlUlonglongByteSwap@4
77FBBE5C dd offset @RtlUshortByteSwap@4
77FBBE60 dd offset _CsrAllocateCaptureBuffer@8
......
77FBD0DC AddrOfNamesBase
77FBD0DC dd offset aCsrallocatecapturebuff ; "CsrAllocateCaptureBuffer"
77FBD0E0 dd offset aCsrallocatemessagepoin ; "CsrAllocateMessagePointer"
77FBD0E4 dd offset aCsrcapturemessagebuffe ; "CsrCaptureMessageBuffer"
77FBD0E8 dd offset aCsrcapturemessagestrin ; "CsrCaptureMessageString"
77FBD0EC dd offset aCsrcapturetimeout ; "CsrCaptureTimeout"
77FBD0F0 dd offset aCsrclientcallserver ; "CsrClientCallServer"
77FBD0F4 dd offset aCsrclientconnecttoserv ; "CsrClientConnectToServer"
......
77FBE370 AddrOfNameOrdinalsBase
77FBE370 dw 6, 7, 8, 9, 0Ah, 0Bh, 0Ch, 0Dh
77FBE370 dw 0Eh, 0Fh, 10h, 11h, 12h, 13h, 14h, 15h
77FBE370 dw 16h, 17h, 18h, 19h, 1Ah, 1Bh, 1Ch, 1Dh
77FBE370 dw 1Eh, 1Fh, 20h, 21h, 22h, 23h, 24h, 25h
77FBE370 dw 26h, 27h, 28h, 29h, 2Ah, 2Bh, 2Ch, 2Dh
......
77F8C157 RealGetFunctionAddress:
77F8C157 push edi ; AddressOfNameOrdinals
77F8C158 push eax ; AddressOfNames
77F8C159 push [ebp+BaseAddress] ; BaseAddress
77F8C15C push [esi+IMAGE_EXPORT_DIRECTORY.NumberOfNames] ; NumberOfNames
77F8C15F push [ebp+lpProcName] ; lpProcName
77F8C162 call _LdrpNameToOrdinal@20 ; LdrpNameToOrdinal(x,x,x,x,x)
......
......
77F859A4 ; USHORT __stdcall LdrpNameToOrdinal(ANSI_STRING *lpProcName,
ULONG NumberOfNames, "
ULONG BaseAddress, "
ULONG AddressOfNames, "
ULONG AddressOfNameOrdinals)
77F859A4 _LdrpNameToOrdinal@20 proc near
77F859A4 Count = dword ptr -4
77F859A4 lpProcName= dword ptr 8
77F859A4 NumberOfNames= dword ptr 0Ch
77F859A4 BaseAddress= dword ptr 10h
77F859A4 AddressOfNames= dword ptr 14h
77F859A4 AddressOfNameOrdinals= dword ptr 18h
77F859A4
77F859A4 push ebp
77F859A5 mov ebp, esp
77F859A7 push ecx
77F859A8 mov eax, [ebp+NumberOfNames]
77F859AB and [ebp+Count], 0
77F859AF push ebx
77F859B0 push esi
77F859B1 lea ecx, [eax-1] ; ecx = NumberOfNames - 1
77F859B4 push edi
77F859B5 test ecx, ecx
77F859B7 jl short loc_77F85A0C ; 检测 ECX 是否为零
77F859B9
77F859B9 Loop1:
77F859B9 mov eax, [ebp+Count]
77F859BC mov edi, [ebp+lpProcName]
77F859BF lea esi, [eax+ecx] ; ecx = NumberOfName - 1
77F859BF ; esi = Count + ecx
77F859C2 mov eax, [ebp+AddressOfNames] ; eax = AddressOfNamesBase
77F859C5 sar esi, 1 ; 这段代码写的相当精彩,可歌可泣,可以非常快的查找函
77F859C5 ; 数所在位置,其先觉条件是函数名必须是严格的排序,包
77F859C5 ; 括大小写敏感。
77F859C5 ; 首先将函数的个数除以二,即从中间开始搜索。
77F859C5 ;
77F859C7 mov eax, [eax+esi*4] ; 在AddressOfNames偏移地址表中取函数名的偏移量
77F859CA add eax, [ebp+BaseAddress] ; 加上基地址得到函数名的地址
77F859CD
77F859CD Loop_If_dl_IsNotTerminalChar: ; 从函数名中取一个字符
77F859CD mov bl, [edi]
77F859CF mov dl, bl
77F859D1 cmp bl, [eax] ; 和函数名列表中的函数名在相应的位置上进行比较,特别
77F859D1 ; 需要注意,当两个字符进行比较时:
77F859D1 ; if bl >= [eax]
77F859D1 ; CF = 0 //这里将CF标志位置 0
77F859D1 ; else //bl < [eax]
77F859D1 ; CF = 1
77F859D1 ; end
77F859D1 ; 这里将 CF(进位标志) 置位,根据函数名排序的条件,即
77F859D1 ; 决定了是向前搜索,还是向后搜索:
77F859D1 ; jnz short IfCharNotEqu
77F859D1 ; 不影响标志位,这个标志位将在后面的代码中使用
77F859D3 jnz short IfCharNoEqu
77F859D5 test dl, dl
77F859D7 jz short If_dl_IsTerminalChar
77F859D9 mov bl, [edi+1] ; 取下一个字符
77F859DC mov dl, bl
77F859DE cmp bl, [eax+1] ; 和下一个函数名字符进行比较,这里和上面的比较相同,
77F859DE ; 通过设置 CF 标志位来决定搜索的方向。
77F859E1 jnz short IfCharNoEqu
77F859E3 inc edi ; 调整指针,指向下二个字符
77F859E4 inc edi
77F859E5 inc eax
77F859E6 inc eax
77F859E7 test dl, dl
77F859E9 jnz short Loop_If_dl_IsNotTerminalChar
77F859EB
77F859EB If_dl_IsTerminalChar:
77F859EB xor eax, eax
77F859ED jmp short loc_77F859F4
77F859EF
77F859EF IfCharNoEqu: ; 指令
77F859EF sbb eax, eax ; sbb eax, eax //带进位减
77F859EF ; 其结果只有两种可能
77F859EF ; if CF == 0
77F859EF ; eax = 0
77F859EF ; set CF = 0
77F859EF ; else //CF = 1
77F859EF ; eax = 0xFFFFFFFF
77F859EF ; set CF = 1
77F859EF ; end;
77F859F1 sbb eax, 0FFFFFFFFh ; 指令
77F859F1 ; sbb eax, 0FFFFFFFFh //带进位减
77F859F1 ; 其结果也是两种可能
77F859F1 ; if CF == 0
77F859F1 ; eax = 0
77F859F1 ; set SF = 0
77F859F1 ; else //CF = 1
77F859F1 ; eax = 0xFFFFFFFF
77F859F1 ; set SF = 1
77F859F1 ; end
77F859F1 ; 这里 SF 是符号标志位,即判断结果是正数还是负数。
77F859F4
77F859F4 loc_77F859F4: ; 指令
77F859F4 test eax, eax ; test eax, eax
77F859F4 ; 一般我们用来测试某一位是 1 还是 0,但这个操作同样影
77F859F4 ; 响符号标志位:
77F859F4 ; if eax >= 0
77F859F4 ; set SF = 0
77F859F4 ; else
77F859F4 ; set SF = 1
77F859F4 ; end
77F859F6 jge short ForewardSearch ; Jump if Greater or Equal (SF=0)
77F859F8
77F859F8 BackwardSearch:
77F859F8 lea ecx, [esi-1]
77F859FB jmp short NextSearch
77F859FD
77F859FD ForewardSearch:
77F859FD jle short SearchEnd
77F859FF lea eax, [esi+1]
77F85A02 mov [ebp+Count], eax
77F85A05
77F85A05 NextSearch:
77F85A05 cmp ecx, [ebp+Count]
77F85A08 jge short Loop1
77F85A0A jmp short SearchEnd
77F85A0C
77F85A0C loc_77F85A0C:
77F85A0C mov esi, [ebp+NumberOfNames]
77F85A0F
77F85A0F SearchEnd:
77F85A0F cmp ecx, [ebp+Count]
77F85A12 jge short GetOrdinal
77F85A14 or ax, 0FFFFh
77F85A18 jmp short Exit
77F85A1A
77F85A1A GetOrdinal:
77F85A1A mov eax, [ebp+AddressOfNameOrdinals]
77F85A1D mov ax, [eax+esi*2] ; 序号列表的单位是 WORD 所以 esi*2 即得到序号的偏移
77F85A1D ; 地址,加上基地址,即得到函数的序号。
77F85A21
77F85A21 Exit:
77F85A21 pop edi
77F85A22 pop esi
77F85A23 pop ebx
77F85A24 leave
77F85A25 retn 14h
77F85A25 _LdrpNameToOrdinal@20 endp
jg xxxx //Jump short if greater (ZF=0 and SF=OF)
ja xxxx //Jump short if above (CF=0 and ZF=0)
jl xxxx //Jump short if less (SF<>OF)
jb xxxx //Jump short if below (CF=1)
77F8C167 movzx ecx, ax
77F8C16A cmp ecx, [esi+IMAGE_EXPORT_DIRECTORY.NumberOfFunctions]
77F8C16D jnb loc_77F8C248
77F8C173 mov eax, [esi+IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
77F8C176 mov edx, [ebp+BaseAddress]
77F8C179 add eax, edx ; Offset + BaseAddress
77F8C17B lea eax, [eax+ecx*4] ; Offset + Ordinal * 4
77F8C17E mov ecx, [eax] ; OffsetFunction
77F8C180 add ecx, edx ; FunctionAddress = OffsetFunction + BaseAddress
77F8C182 mov edx, [ebp+ProceAddr]
77F8C185 cmp ecx, esi
77F8C187 mov [edx], ecx ;将函数调用地址从变参 ProceAddr 返回(最后还要将这个数送给EAX)