1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
| ;找到导出表 找到导出表中 NumberOfNames字段(存放着导出函数的总个数)用这个个数构建一个循环 ;在 AddressOfNames 执行函数名称地址表 ;循环中将每一项定义的函数名与所要搜索的函数名进行比较 ;如果没找到任何一个函数名符合 表示文件中没有该指定名称的函数 ;如果找到相符合的函数名 那么就几下这个函数名在字符串地址表中的索引值,然后在AddressOfNameOrdinals指向的数组中使用同样的索引值 ;使用该索引值 在AddressOfFunctions字段指向的函数入口地址表中获取的RVA即函数入口地址RVA
.386 .model flat,stdcall option casemap:none include windows.inc
.data lpKernel32 dd 0 szUser32 db 'user32.dll',0 lpUser32 dd 0 szMessageBoxA db 'MessageBoxA',0 lpMessageBoxA dd 0 szLoadLibraryA db 'LoadLibraryA',0 lpLoadLibraryA dd 0 szExitProcess db 'ExitProcess',0 lpExitProcess dd 0 szGetProcAddress db 'GetProcAddress',0 lpGetProcAddress dd 0
hola db 'hola!'
.code
GetKernelBase proc uses esi edi dwKernel:dword
local kernelbase:dword mov edi, dwKernel and edi, 0ffff0000h ; 初始化页 .while TRUE .if word ptr [edi] == IMAGE_DOS_SIGNATURE ;等于MZ? mov esi, edi add esi, [esi+IMAGE_DOS_HEADER.e_lfanew] ; [esi+3ch] .if word ptr [esi] == IMAGE_NT_SIGNATURE ;等于PE? mov kernelbase, edi .break .endif .endif sub edi, 010000h ;暴力搜索内存 64kb 即每次减少64kb ;kernel32.dll的块对齐值是00001000h, 并且一般DLL以1M为边界,通过10000h (64k) 作为跨度 .break .if edi < 070000000h ;基地址小于70000000h退出 .endw mov eax, kernelbase ; 存到寄存器中再返回 ret GetKernelBase endp
;hMoudle 基地址 GetApi proc hModule:dword, szApiname:dword local apilen:dword ;local声明局部遍历 local apibase:dword
pushad ;计算api字符长度 mov esi, szApiname mov edx, esi countStr: cmp byte ptr [esi], 0 ;字符串末尾是否为0 jz countStrOver inc esi;还没结束继续 jmp countStr
countStrOver: inc esi sub esi, edx ;减去首地址得到长度 mov apilen, esi
;找到导出表地址 mov esi, hModule;拿到模块基地址 一般esi存放指针、地址 add esi, [esi+3ch]; +3ch定位到NT_HEADERS assume esi:ptr IMAGE_NT_HEADERS ; mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress;得到导出表RVA add esi, hModule;加上基地址 定位到地址
assume esi:ptr IMAGE_EXPORT_DIRECTORY; 让esi 指向 Kernel32.dll 的导出表
mov ebx, [esi].AddressOfNames; add ebx, hModule
xor edx, edx ;计数函数 先初始化 .repeat push esi mov edi, [ebx] add edi, hModule; 指向AddressOfNames指向的数组 mov esi, szApiname mov ecx, apilen cld ;设置方向标志 正向 repz cmpsb ;开始遍历查找 rep(重复)z(相等) ds:esi和es:edi 所指向的两个字节相等(zf=1) 就继续比较 如果不相等就停止循环
.if ZERO? ; 找到了 ZERO?是否置位 相当于 if(zf==1) pop esi ; 恢复esi esi指向导出表 jmp findOver .endif ;如果没找到 pop esi ; 恢复esi esi指向导出表 add ebx,4 ;下一个函数名称 每个函数地址占4个字节 inc edx; 计数函数加1
.until edx >= [esi].NumberOfNames ;遍历完后没有找到 退出 NumberOfNames函数名称总数量 jmp _Exit
findOver: sub ebx, hModule; 减去基地址 得到RVA sub ebx, [esi].AddressOfNames;得到匹配函数字符串首地址 相当于数组起始地址的偏移量
;除以2,用这个偏移量+AddressOfNameOrdinals指向的数组首地址找到索引 shr ebx,1 add ebx,[esi].AddressOfNameOrdinals;加上算出来的偏移量找到和AddressOfNames对应的那一项 add ebx,hModule
movzx eax,word ptr [ebx];取出AddressOfNameOrdinals那一项存放的索引 word movzx高位拓展0 shl eax,2;乘以4 索引值x4个字节+ add eax,[esi].AddressOfFunctions;AddressOfFunctions指向函数RVA地址表起始地址,加上这个偏移量取出AddressOfNameOrdinals给出索引的那一项 add eax,hModule
;API's Address = ( API's Ordinal * 4 ) + AddressOfFunctions' VA + Kernel32 imagebase
mov eax,[eax];得到函数的RVA add eax,hModule;加上kernel32基地址得到函数入口地址VA mov apibase,eax
_Exit: assume esi:nothing ;不再使用esi寄存器作为指针时 用assume esi:nothing取消定义 释放掉。 popad mov eax, apibase ret
GetApi endp
main proc
;得到kernel32基地址 invoke GetKernelBase, [esp] mov lpKernel32, eax ;获取API invoke GetApi, lpKernel32, addr szLoadLibraryA mov lpLoadLibraryA, eax invoke GetApi, lpKernel32, addr szGetProcAddress mov lpGetProcAddress, eax
invoke GetApi,lpKernel32,addr szExitProcess mov lpExitProcess,eax
;载入user32.dll push offset szUser32 call [lpLoadLibraryA] mov lpUser32,eax
;获取user32.dll中的MessageBoxA push offset szMessageBoxA push lpUser32 call [lpGetProcAddress] mov lpMessageBoxA,eax push MB_OK push offset hola push offset hola push NULL call [lpMessageBoxA]
push 0 call [lpExitProcess]
main endp end
|