hash算法搜索获得api函数地址的实现
Posted bokernb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hash算法搜索获得api函数地址的实现相关的知识,希望对你有一定的参考价值。
我们一般要获得一个函数的地址,通常采用的是明文,例如定义一个api函数字符串"MessageBoxA",然后在GetProcAddress函数中一个字节一个字节进行比较。这样弊端很多,例如如果我们定义一个杀毒软件比较敏感的api函数字符串,那么可能就会增加杀毒软件对我们的程序的判定值,而且定义这些字符串还有一个弊端是占用的字节数较大。我们想想如何我们的api函数字符串通过算法将它定义成一个4字节的值,然后在GetProcAddress中把AddressOfNames表中的每个地址指向的api字符串通过我们的算法压缩成4字节值后,与我们之前定义的4字节值进行判断,如果匹配成功则读取函数地址。
我们来看一种rol 3移位算法,这个算法是每次将目的地址循环向左移动3位,然后将低字节与源字符串的每个字节进行异或。算法很精巧方便。还有很多方便小巧的算法,例如ROR 13等算法,其实它和我们上面的基本一样,只不过它将函数名表的字符串通过我们的算法过程获得hash值后与我们之前定义的hash值进行匹配,匹配成功则获得对应函数的地址。
下面的代码通过hash搜索WinExec函数来运行Clac:
.386 .model flat, stdcall option casemap:none include windows.inc include user32.inc include kernel32.inc includelib user32.lib includelib kernel32.lib .const szCalc db ‘calc.exe‘, 0 .code _GetKrnl32 proc ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 获取kernel32.dll的地址,因为xp和win7不一样 ; 故采用比较名称的方式获取地址,具体见Kernel32基地址获得学习 ; http://blog.csdn.net/programmingring/article/details/11357393 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> assume fs:nothing mov eax, fs:[30h] mov eax, [eax + 0ch] mov eax, [eax + 1ch] ; 第一个LDR_MODULE ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 压入kernel32.dll的unicode字符串 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> push dword ptr 006ch push dword ptr 6c0064h push dword ptr 2e0032h push dword ptr 33006ch push dword ptr 65006eh push dword ptr 720065h push word ptr 006bh mov ebx, esp ; ebx指向字符串 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 开始比较 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> _Search: cmp eax, 0 jz _NotFound cmp eax, 0ffffffffh jz _NotFound lea esi, [eax + 1ch] ; esi指向UNICODE_STRING结构 xor ecx, ecx mov cx, 13 ; 比较的长度 mov esi, [esi + 4] ; 获得UNICODE_STRING结构的Buffer成员 mov edi, ebx ; edi指向kernel32unicode字符串 repz cmpsw or ecx, ecx ; ecx减完说明相等 jz _Found mov eax, [eax] ; 获取下一个LDR_MODULE jmp _Search _NotFound: mov eax, 0ffffffffh jmp _Over _Found: mov eax, [eax + 08h] ; 获得地址 _Over: add esp, 26 ret _GetKrnl32 endp _GetRolHash proc _lpApiString mov eax, _lpApiString push esi xor edx, edx xchg eax, esi ; esi = _lpApiString cld ; 递增 _Next: lodsb ; 从esi指向的地址中取一个字符 test al, al ; 比较是否为0 jz _Ret rol edx, 3 ; 左循环移位3位 xor dl, al ; 低字节和字符异或 jmp _Next _Ret: xchg eax, edx ; eax = 处理后的_lpApiString的hash pop esi ret _GetRolHash endp _GetApi proc _hDllHandle, _iHashApi push ebp mov eax, _hDllHandle mov ecx, _iHashApi mov ebx, eax mov edi, ecx mov eax, [ebx + 3ch] mov esi, [ebx + eax + 78h] ; Get Export RVA lea esi, [esi + ebx + IMAGE_EXPORT_DIRECTORY.NumberOfNames] lodsd xchg eax, edx ; edx = NumberOfNames lodsd push eax ; [esp] = AddressOfFunctions lodsd xchg eax, ebp ; ebp = AddressOfNames lodsd xchg eax, ebp ; ebp = AddressOfNameOrdinals, eax = AddressOfNames add eax, ebx xchg eax, esi ; esi = AddressOfNames _LoopScas: dec edx js _Ret lodsd ; eax = api名称的rva add eax, ebx ; eax = api名称的实际地址 push edx invoke _GetRolHash, eax ; 计算hash字符串 pop edx cmp eax, edi ; 比较和传入的hash参数是否相等 jz _GetAddr add ebp, 2 ; 递增,和esi相对应 jmp _LoopScas _GetAddr: movzx eax, word ptr [ebp + ebx] ; 取得序号值 shl eax, 2 ; 乘4 add eax, [esp] ; 在AddressOfFunctions取得相应序号值位置的值 mov eax, [ebx + eax] ; 取得函数地址 add eax, ebx _Ret: pop ecx pop ebp ret _GetApi endp _WinMain proc invoke _GetKrnl32 invoke _GetApi, eax, 016ef74bh ; "WinExec"的hash push SW_SHOW lea ebx, szCalc push ebx call eax ret _WinMain endp start: call _WinMain invoke ExitProcess, 0 end start
以上是关于hash算法搜索获得api函数地址的实现的主要内容,如果未能解决你的问题,请参考以下文章