一段被破解程序中的shellcode分析
只是感兴趣,大牛路过.
默笙妹子发来一个被用SMC方式破解的一个软件,于是研究其SMC中的ShellCode.
//////////////////////////////////////////////////////////////////////////////////////////////////
执行流程:
1.首先得到kernel32的ImageBase为起始解析PE,得到导出表.
2.然后取出GetProcAddress函数地址,获取指定的API
3.Api hook破解该软件
分析代码:
00400380 60 pushad ; 保存寄存器环境 00400381 8B4424 44 mov eax, dword ptr [esp+0x44] 00400385 25 0000FFFF and eax, 0xFFFF0000 ; 不为序号导出 0040038A 66:8138 4D5A cmp word ptr [eax], 0x5A4D ; 判断MZ 0040038F 74 07 je short 00400398 ; 该判断成立即意味着已经得到kernel32的imageBase 00400391 2D 00100000 sub eax, 0x1000 ; 内存中4K对齐,挪动到kernel32 dll的头部 00400396 ^ EB F2 jmp short 0040038A ; 循环得到kernel32 imagebase 获得一个存放kernel32_ImageBase的指针: 00400398 50 push eax ; eax == kernel32_ImageBase 00400399 E8 C2000000 call 00400460 ; push 0x0040039E 0040039E 59 pop ecx 0040039F 58 pop eax 00400460: 00400460 E8 F5FFFFFF call 0040045A 00400465 0000 add byte ptr [eax], al 0040045A: 0040045A 58 pop eax 0040045B 870424 xchg dword ptr [esp], eax 0040045E 50 push eax 0040045F C3 retn 进函数时栈布局 $ ==> > 00400465 __CALL_RET_EIP -> EAX $+4 > 0040039E _CALL_RET_EIP -> $+8 > 7C800000 kernel32_ImageBase 出函数时栈布局 $ ==> > 0040039E _CALL_RET_EIP $+4 > 00400465 __CALL_RET_EIP $+8 > 7C800000 kernel32.7C800000 得出的结论即是,mov ecx,00400465(kernel32_ImageBase),其他忽略不谈 通过PE结构的固定偏移算出kernel32.dll的导出表,为后面顺利取出WINAPI做准备 004003A0 8BD8 mov ebx, eax ; ebx == kernel32_ImageBase(SAVE) 004003A2 8B48 3C mov ecx, dword ptr [eax+0x3C] ; ecx == e_lfanew(offset) 004003A5 03C8 add ecx, eax ; ecx == kernel32_Image_NT_Header 004003A7 8B51 78 mov edx, dword ptr [ecx+0x78] ; edx == Kernel32_Export_Table(offset) 004003AA 03D0 add edx, eax ; EDX == Kernel32_ExportTable_VA 同上冲定位函数,直接给出结果 mov ecx,00400465 004003AC 50 push eax 004003AD E8 AE000000 call 00400460 004003B2 59 pop ecx 004003B3 58 pop eax 004003B4 83C1 08 add ecx, 0x8 ; ecx == pNewEipAddr 004003B7 50 push eax ; kernel32_ImageBase 004003B8 51 push ecx ; ecx == pNewEipAddr 004003B9 E8 9C000000 call 0040045A 0040045A: 0040045A 58 pop eax 0040045B 870424 xchg dword ptr [esp], eax 0040045E 50 push eax 0040045F C3 retn 有意思的在于下面的一句,之前没注意看,此时才发现&pKernel32 + 8的位置是接下来运算的中的shellcode的一部分 004003B4 83C1 08 add ecx, 0x8 ; ecx == 0040046D(pKernel32) 004003B7 50 push eax ; kernel32_ImageBase 004003B8 51 push ecx ; ecx == pUnKnowAddr 004003B9 E8 9C000000 call 0040045A 0040046D 59 pop ecx 0040046E 58 pop eax ; eax == Kernel32_ImageBase 0040046F 8B4A 20 mov ecx, dword ptr [edx+0x20] ; ecx == Kernel32_ExprotTable_AddrOfNames(offset) 00400472 52 push edx ; edx == Kernel32_ExportTable_VA 00400473 03C1 add eax, ecx ; eax == Kernel32_ExprotTable_AddrOfNames 00400475 53 push ebx ; ebx == Kernel32_ImageBase(SAVE) 00400476 33DB xor ebx, ebx 00400478 EB 04 jmp short 0040047E 0040047A 83C0 04 add eax, 0x4 0040047D 43 inc ebx 0040047E 8B0C24 mov ecx, dword ptr [esp] ; ecx == Kernel32_ImageBase 00400481 8B10 mov edx, dword ptr [eax] ; api offset 00400483 03D1 add edx, ecx ; edx == API Addr 00400485 8BFA mov edi, edx ; Sava Api Addr 00400487 33C9 xor ecx, ecx 00400489 50 push eax ; Kernel32_ExprotTable_AddrOfNames(Save) 0040048A 33C0 xor eax, eax 0040048C 41 inc ecx ; 计数器(API Name Len) 0040048D AE scas byte ptr es:[edi] 0040048E ^ 75 FC jnz short 0040048C 00400490 49 dec ecx 00400491 E8 28FFFFFF call 004003BE 004003BE E8 97000000 call 0040045A 004003C3 47 inc edi ;看不懂正常,因为是字符串 004003C4 65:74 50 je short 00400417 004003C7 72 6F jb short 00400438 004003C9 6341 64 arpl word ptr [ecx+0x64], ax 004003CC 64:72 65 jb short 00400434 004003CF 73 73 jnb short 00400444 004003D1 0000 add byte ptr [eax], al 004003D3 56 push esi 004003D4 6972 74 75616C5>imul esi, dword ptr [edx+0x74], 0x506> 004003DB 72 6F jb short 0040044C 004003DD 74 65 je short 00400444 004003DF 637400 00 arpl word ptr [eax+eax], si 004003E3 4D dec ebp 004003E4 61 popad 004003E5 70 56 jo short 0040043D 004003E7 6965 77 4F66466>imul esp, dword ptr [ebp+0x77], 0x694> 004003EE 6C ins byte ptr es:[edi], dx 004003EF 65:0000 add byte ptr gs:[eax], al 004003F2 0043 72 add byte ptr [ebx+0x72], al 004003F5 65:61 popad 004003F7 74 65 je short 0040045E 004003F9 46 inc esi 004003FA 696C65 41 00000>imul ebp, dword ptr [ebp+0x41], 0x0 00400402 0056 69 add byte ptr [esi+0x69], dl 00400405 72 74 jb short 0040047B 00400407 75 61 jnz short 0040046A 00400409 6C ins byte ptr es:[edi], dx 0040040A 41 inc ecx 0040040B 6C ins byte ptr es:[edi], dx 0040040C 6C ins byte ptr es:[edi], dx 0040040D 6F outs dx, dword ptr es:[edi] 0040040E 6300 arpl word ptr [eax], ax 004003C3 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 GetProcAddress.. 004003D3 56 69 72 74 75 61 6C 50 72 6F 74 65 63 74 00 00 VirtualProtect.. 004003E3 4D 61 70 56 69 65 77 4F 66 46 69 6C 65 00 00 00 MapViewOfFile... 004003F3 43 72 65 61 74 65 46 69 6C 65 41 00 00 00 00 00 CreateFileA..... 00400403 56 69 72 74 75 61 6C 41 6C 6C 6F 63 00 00 00 00 VirtualAlloc.... 当前在获取GetProcAddress 0040047A 83C0 04 add eax, 0x4 ; 挪动指针,方便取新API 0040047D 43 inc ebx ; 计数器 0040047E 8B0C24 mov ecx, dword ptr [esp] ; ecx == Kernel32_ImageBase 00400481 8B10 mov edx, dword ptr [eax] ; api offset 00400483 03D1 add edx, ecx ; edx == API Addr 00400485 8BFA mov edi, edx ; Sava Api Addr 00400487 33C9 xor ecx, ecx 00400489 50 push eax ; Kernel32_ExprotTable_AddrOfNames(Save) 0040048A 33C0 xor eax, eax 0040048C 41 inc ecx ; 计数器(API Name Len) 0040048D AE scas byte ptr es:[edi] 0040048E ^ 75 FC jnz short 0040048C 00400490 49 dec ecx 00400491 E8 28FFFFFF call 004003BE 00400496 5E pop esi ; esi == "GetProcAddress" 00400497 58 pop eax ; eax == Kernel32_ExprotTable_AddrOfNames 00400498 8BFA mov edi, edx ; 当前遍历出的API 0040049A F3:A6 repe cmps byte ptr es:[edi], byte ptr>; 比较是否一致 0040049C ^ 75 DC jnz short 0040047A ; 不一致开始下一轮 0040049E 58 pop eax ; eax == Kernel32_ImageBase 0040049F 870424 xchg dword ptr [esp], eax ; 与Kernel32_Export_Table_VA交换 004004A2 90 nop 004004A3 83C0 1C add eax, 0x1C ; eax == Kernel32_ExportTable_AddrOfFunc(offset) 004004A6 8B00 mov eax, dword ptr [eax] ; eax == Kernel32_ExportTable_AddrOfFunc 004004A8 50 push eax 004004A9 8B4C24 04 mov ecx, dword ptr [esp+0x4] ; ecx == Kernel32_ImageBase 004004AD 8BFF mov edi, edi 004004AF 58 pop eax 004004B0 03C1 add eax, ecx ; eax == Kernel32_ExportTable_AddrOfFunc(VA) 004004B2 8B0498 mov eax, dword ptr [eax+ebx*4] ; 利用计数器查表得到API offset 004004B5 03C1 add eax, ecx ; 得到API 004004B7 50 push eax ; push api addr 004004B8 E8 A3FFFFFF call 00400460 ; 执行 004004C8 59 pop ecx 004004C9 58 pop eax 004004CA 83C1 10 add ecx, 0x10 ; 取自定义API名字表中的下一项(VirtualProtect) 004004CD 51 push ecx 004004CE 8BD0 mov edx, eax 004004D0 E8 8BFFFFFF call 00400460 004004D5 59 pop ecx 004004D6 58 pop eax 004004D7 50 push eax ; push lpProcName 004004D8 FF31 push dword ptr [ecx] ; hModule 004004DA FFD2 call edx ; edx == GetProcAddress 004004DC 50 push eax ; api(VirtualProtect) addr 004004DD E8 4EFEFFFF call 00400330 00400330 8BF8 mov edi, eax 00400332 50 push eax 00400333 54 push esp 00400334 6A 40 push 0x40 ; VirtualProtect 参数 PAGE_EXECUTE_READWRITE 00400336 68 00010000 push 0x100 ; VirtualProtect 参数 Size 0040033B E8 F3000000 call 00400433 00400436 0000 add byte ptr [eax], al 00400438 D4 1A aam 0x1A ; VirtualProtectEx addr 0040043A 807C95 B9 80 cmp byte ptr [ebp+edx*4-0x47], 0x80 ; MapViewOfFile addr 0040043F 7C 00 jl short 00400441 00400350 8B4424 08 mov eax, dword ptr [esp+0x8] 00400354 8901 mov dword ptr [ecx], eax ; 保存 kernel32_imagebase 00400356 8959 04 mov dword ptr [ecx+0x4], ebx ; 保存GetProcAddress 00400359 E8 D5000000 call 00400433 0040035E 59 pop ecx 0040035F C3 retn 00400580 59 pop ecx 00400581 58 pop eax 00400582 50 push eax ; push lpProcName(MapViewOffile) 00400583 FF31 push dword ptr [ecx] ; hModule 00400585 FF51 04 call dword ptr [ecx+0x4] ; kernel32.GetProcAddress 保存了前五字节,应是要进入HOOK: 004005B8 59 pop ecx 004005B9 58 pop eax 004005BA 83C1 14 add ecx, 0x14 004005BD 8B10 mov edx, dword ptr [eax] 004005BF 66:8B58 04 mov bx, word ptr [eax+0x4] 004005C3 8911 mov dword ptr [ecx], edx 004005C5 66:8959 04 mov word ptr [ecx+0x4], bx 004005C9 C3 retn HOOK操作: 00400606 59 pop ecx 00400607 58 pop eax 00400608 C600 68 mov byte ptr [eax], 0x68 0040060B 8948 01 mov dword ptr [eax+0x1], ecx 0040060E C640 05 C3 mov byte ptr [eax+0x5], 0xC3 00400612 C3 retn 恢复环境: 00400598 61 popad 00400599 830424 07 add dword ptr [esp], 0x7 0040059D C3 retn CreateFile挂后: 7C801A28 > 68 8F074000 push 0x40078F ; ASCII "PQ?" 7C801A2D C3 retn MapViewOffile挂后: 7C80B995 > 68 38064000 push 0x400638 7C80B99A C3 retn
Patch Code(只是简单跟了下,估计不全只简单跟了下hook createfile的部分,没测试过):
1. 004391c9: jmp PatchAddr PatchAddr: call PatchFun(00400810) 恢复原流程: mov ecx, esi jmp 004391CB 2. 0043B45E |. 8B07 mov eax, dword ptr [edi] 0043B460 |. 48 dec eax ; Switch (cases 1..C) 0043B461 |. 83F8 0B cmp eax, 0xB 0043B464 |. 0F87 95020000 ja 0043B6FF 0043B45E |. 33C0 xor eax, eax 0043B460 |. 40 inc eax ; Switch (cases 1..C) 0043B461 |. 83F8 0B cmp eax, 0xB 0043B464 |. 0F87 95020000 ja 0043B6FF 3. 00443830 . 6A FF push -0x1 00443830 . C3 retn 00443831 ? 90 nop
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。