首先感谢shoooo,forgot,fly的指点。
本来的试练品是一个XX的XX服务端,体积有点大,无法上传,有需要的请留言.
可以用附件中的abest写的一个专门用来练习脱壳的小程序代替(因为不是二次加密所以IAT需要修复).
http://www.cracking.com.cn/dispbbs.asp?boardid=4&id=827&star=1#827
下面的过程是按脱服务端的过程写的.
已知:
1.这个是2次加密的,不会用SDK.
2.VC编译的
step0.抹掉TLS表
用lord-PE把数据目录(Directories)中TLS一项全部置0,然后save.
注意:不能把TLS CALLBACK ADDRESS 和TLS CALLBACK INDEX置0 !!!!(why?I Don't Know)
BTW:这个"秘密"是forgot广播的.
step1.
经过step0后,就不用设置让OD停在系统断点了(设置停在EP).而且TLS中的"飞刀"也不用管了.但是还需要一个"核武器"----advencedolly插件.加上这个插件,EXEC的anti可以全过.
但是,本次脱壳用hideOD就可以了,因为我们没有KEY,无法跑到后面,也不需要跑到后面.所以很多anti是没有用的.
step2.
步骤其实很简单,经过上面的准备后.用OD载入,忽略所有异常:
0BB8CE4E > E8 F7FEFFFF call 0BB8CD4A
0BB8CE53 05 07480000 add eax, 4807
0BB8CE58 FFE0 jmp eax
0BB8CE5A E8 EBFEFFFF call 0BB8CD4A
0BB8CE5F 05 9F6A0000 add eax, 6A9F
0BB8CE64 FFE0 jmp eax
0BB8CE66 E8 04000000 call 0BB8CE6F
0BB8CE6B FFFF ??? ; 未知命令
0BB8CE6D FFFF ??? ; 未知命令
0BB8CE6F 5E pop esi
0BB8CE70 C3 retn
然后
1.HE GetProcAddress
2.F9
3.HD GetProcAddress
4.alt+f9
现在我们到了填充IAT的地方了:
0BB8CBE7 55 push ebp
0BB8CBE8 8BEC mov ebp, esp
0BB8CBEA 83C4 F4 add esp, -0C
0BB8CBED 56 push esi
0BB8CBEE 57 push edi
0BB8CBEF 53 push ebx
0BB8CBF0 BE 00F0AD0A mov esi, 0AADF000
0BB8CBF5 B8 00004000 mov eax, 00400000
0BB8CBFA 8945 FC mov dword ptr ss:[ebp-4], eax
0BB8CBFD 89C2 mov edx, eax
0BB8CBFF 8B46 0C mov eax, dword ptr ds:[esi+C]
0BB8CC02 09C0 or eax, eax
0BB8CC04 0F84 8E000000 je 0BB8CC98
0BB8CC0A 01D0 add eax, edx
0BB8CC0C 89C3 mov ebx, eax
0BB8CC0E 50 push eax
0BB8CC0F FF15 B480AA0B call dword ptr ds:[<&kernel32.GetModu>; kernel32.GetModuleHandleA
0BB8CC15 09C0 or eax, eax
0BB8CC17 0F85 0F000000 jnz 0BB8CC2C
0BB8CC1D 53 push ebx
0BB8CC1E FF15 B880AA0B call dword ptr ds:[<&kernel32.LoadLib>; kernel32.LoadLibraryA
0BB8CC24 09C0 or eax, eax
0BB8CC26 0F84 64000000 je 0BB8CC90
0BB8CC2C 8945 F8 mov dword ptr ss:[ebp-8], eax
0BB8CC2F 6A 00 push 0
0BB8CC31 8F45 F4 pop dword ptr ss:[ebp-C]
0BB8CC34 8B06 mov eax, dword ptr ds:[esi]
0BB8CC36 09C0 or eax, eax
0BB8CC38 8B55 FC mov edx, dword ptr ss:[ebp-4]
0BB8CC3B 0F85 03000000 jnz 0BB8CC44
0BB8CC41 8B46 10 mov eax, dword ptr ds:[esi+10]
0BB8CC44 01D0 add eax, edx
0BB8CC46 0345 F4 add eax, dword ptr ss:[ebp-C]
0BB8CC49 8B18 mov ebx, dword ptr ds:[eax]
0BB8CC4B 8B7E 10 mov edi, dword ptr ds:[esi+10]
0BB8CC4E 01D7 add edi, edx
0BB8CC50 037D F4 add edi, dword ptr ss:[ebp-C]
0BB8CC53 09DB or ebx, ebx
0BB8CC55 0F84 E2000000 je 0BB8CD3D
0BB8CC5B F7C3 00000080 test ebx, 80000000
0BB8CC61 0F85 04000000 jnz 0BB8CC6B
0BB8CC67 8D5C13 02 lea ebx, dword ptr ds:[ebx+edx+2]
0BB8CC6B 81E3 FFFFFF7F and ebx, 7FFFFFFF
0BB8CC71 53 push ebx
0BB8CC72 FF75 F8 push dword ptr ss:[ebp-8]
0BB8CC75 FF15 BC80AA0B call dword ptr ds:[<&kernel32.GetProc>; kernel32.GetProcAddress
0BB8CC7B 09C0 or eax, eax ; WS2_32.send //我们现在停在这里
0BB8CC7D 0F84 0D000000 je 0BB8CC90
0BB8CC83 8907 mov dword ptr ds:[edi], eax
0BB8CC85 8345 F4 04 add dword ptr ss:[ebp-C], 4
0BB8CC89 ^ E9 A6FFFFFF jmp 0BB8CC34
0BB8CC8E 0000 add byte ptr ds:[eax], al
0BB8CC90 53 push ebx
0BB8CC91 89D8 mov eax, ebx
0BB8CC93 E8 07000000 call 0BB8CC9F
0BB8CC98 5B pop ebx //走到这里后IAT就填充完毕了,在这里F4
0BB8CC99 5F pop edi
0BB8CC9A 5E pop esi
0BB8CC9B 8BE5 mov esp, ebp
0BB8CC9D 5D pop ebp
0BB8CC9E C3 retn
观察上面代码发现,者个函数就是填充IAT的函数,退出这个函数后IAT就处理完了.所以在0BB8CC98 上F4走完这个函数.
BTW:论坛上看到过几位牛人讨论无KEY脱exec,再出来注册框之前,所有东西都解码完毕了.
我想一般的壳填充IAT都是最后一步,于是我就去看看代码段是否解码完了.果然全部代码都解出来了.
step3.修复stolen code
再次感谢shoooo,forgot的指点.
因为IAT已经填充完,而且没有加密.根据VC的启动代码都会call GetVersion,所以根据IAT反查出Call GetVersion的地址:
00529265 - E9 E4ED5E0A jmp 0AB1804E
0052926A 8BC2 mov eax, edx
0052926C 5A pop edx
0052926D - E9 8EDD5B0A jmp 0AAE7000
00529272 C1FC 56 sar esp, 56
00529275 BE 948B56E8 mov esi, E8568B94
0052927A 50 push eax
0052927B 64:8925 0000000>mov dword ptr fs:[0], esp
00529282 83EC 58 sub esp, 58
00529285 53 push ebx
00529286 56 push esi
00529287 57 push edi
00529288 8965 E8 mov dword ptr ss:[ebp-18], esp
0052928B FF15 34FDAD0A call dword ptr ds:[AADFD34] ; kernel32.GetVersion //See?See!
00529291 33D2 xor edx, edx
00529293 8AD4 mov dl, ah
根据VC的OEP的特称,可以断定00529265是OEP.
但是被stolen了5行
应该是
push ebp
mov ebp,esp
push -1
push imm32
push imm32
...........
关键就是这两个imm32是多少.如果有KEY可以让程序跑起来断在后在,通过堆栈的值来修复这两个数.但问题是,我们没有KEY,程序无法运行.
我请教了forgot,问这两个imm32有没有办法找出来.他说这是VC的机制,是个xxx表.由于我愚钝,似懂非懂.后来遇上了shoooo.shoooo说这就是VC封装的SEH.想弄清楚就自己写个
__try,__except来看看.
于是豁然开朗~
我大体说一下怎么找这两imm32(为什么这样找?自己写个__try,__except看看就明白了,还有就是看看Crt.c或者crt0.c的源码.)
先纪录两个地址:
00529265 - E9 E4ED5E0A jmp 0AB1804E
0052926A 8BC2 mov eax, edx
0052926C 5A pop edx
0052926D - E9 8EDD5B0A jmp 0AAE7000
00529272 C1FC 56 sar esp, 56
00529275 BE 948B56E8 mov esi, E8568B94
0052927A 50 push eax
0052927B 64:8925 0000000>mov dword ptr fs:[0], esp
00529282 83EC 58 sub esp, 58
00529285 53 push ebx
00529286 56 push esi
00529287 57 push edi
00529288 8965 E8 mov dword ptr ss:[ebp-18], esp
0052928B FF15 34FDAD0A call dword ptr ds:[AADFD34] ; kernel32.GetVersion
00529291 33D2 xor edx, edx
00529293 8AD4 mov dl, ah
00529295 8915 D0C7AD0A mov dword ptr ds:[AADC7D0], edx
0052929B 8BC8 mov ecx, eax
0052929D 81E1 FF000000 and ecx, 0FF
005292A3 890D CCC7AD0A mov dword ptr ds:[AADC7CC], ecx
005292A9 C1E1 08 shl ecx, 8
005292AC 03CA add ecx, edx
005292AE 890D C8C7AD0A mov dword ptr ds:[AADC7C8], ecx
005292B4 C1E8 10 shr eax, 10
005292B7 A3 C4C7AD0A mov dword ptr ds:[AADC7C4], eax
005292BC 6A 01 push 1
005292BE E8 7E560000 call 0052E941
005292C3 59 pop ecx
005292C4 85C0 test eax, eax
005292C6 75 08 jnz short 005292D0
005292C8 6A 1C push 1C
005292CA E8 C3000000 call 00529392
005292CF 59 pop ecx
005292D0 E8 DD1A0000 call 0052ADB2
005292D5 85C0 test eax, eax
005292D7 75 08 jnz short 005292E1
005292D9 6A 10 push 10
005292DB E8 B2000000 call 00529392
005292E0 59 pop ecx
005292E1 33F6 xor esi, esi
005292E3 8975 FC mov dword ptr ss:[ebp-4], esi
005292E6 E8 52850000 call 0053183D
005292EB FF15 0CFEAD0A call dword ptr ds:[AADFE0C] ; kernel32.GetCommandLineA
005292F1 A3 84E7AD0A mov dword ptr ds:[AADE784], eax
005292F6 E8 10840000 call 0053170B
005292FB A3 B4C7AD0A mov dword ptr ds:[AADC7B4], eax
00529300 E8 B9810000 call 005314BE
00529305 E8 FB800000 call 00531405
0052930A E8 41050000 call 00529850
0052930F 8975 D0 mov dword ptr ss:[ebp-30], esi
00529312 8D45 A4 lea eax, dword ptr ss:[ebp-5C]
00529315 50 push eax
00529316 FF15 08FEAD0A call dword ptr ds:[AADFE08] ; kernel32.GetStartupInfoA
0052931C E8 8C800000 call 005313AD
00529321 8945 9C mov dword ptr ss:[ebp-64], eax
00529324 F645 D0 01 test byte ptr ss:[ebp-30], 1
00529328 74 06 je short 00529330
0052932A 0FB745 D4 movzx eax, word ptr ss:[ebp-2C]
0052932E EB 03 jmp short 00529333
00529330 6A 0A push 0A
00529332 58 pop eax
00529333 50 push eax
00529334 FF75 9C push dword ptr ss:[ebp-64]
00529337 56 push esi
00529338 56 push esi
00529339 FF15 50FDAD0A call dword ptr ds:[AADFD50] ; kernel32.GetModuleHandleA
0052933F 50 push eax
00529340 E8 4E8AEDFF call 00401D93 ////这个就是Call WinMain
00529345 8945 A0 mov dword ptr ss:[ebp-60], eax
00529348 50 push eax
00529349 E8 2F050000 call 0052987D
0052934E 8B45 EC mov eax, dword ptr ss:[ebp-14] //这一行
00529351 8B08 mov ecx, dword ptr ds:[eax]
00529353 8B09 mov ecx, dword ptr ds:[ecx]
00529355 894D 98 mov dword ptr ss:[ebp-68], ecx
00529358 50 push eax
00529359 51 push ecx
0052935A E8 89400000 call 0052D3E8
0052935F 59 pop ecx
00529360 59 pop ecx
00529361 C3 retn
00529362 8B65 E8 mov esp, dword ptr ss:[ebp-18] //还有这一行
00529365 FF75 98 push dword ptr ss:[ebp-68]
00529368 E8 21050000 call 0052988E
0052936D 833D BCC7AD0A 0>cmp dword ptr ds:[AADC7BC], 1
00529374 75 05 jnz short 0052937B
00529376 E8 D2860000 call 00531A4D
0052937B FF7424 04 push dword ptr ss:[esp+4]
0052937F E8 02870000 call 00531A86
00529384 68 FF000000 push 0FF
00529389 FF15 CC566200 call dword ptr ds:[6256CC] ; GameServ.0052988E
0052938F 59 pop ecx
00529390 59 pop ecx
00529391 C3 retn
00529392 833D BCC7AD0A 0>cmp dword ptr ds:[AADC7BC], 1
00529399 75 05 jnz short 005293A0
0052939B E8 AD860000 call 00531A4D
005293A0 FF7424 04 push dword ptr ss:[esp+4]
005293A4 E8 DD860000 call 00531A86
005293A9 59 pop ecx
005293AA 68 FF000000 push 0FF
005293AF FF15 10FEAD0A call dword ptr ds:[AADFE10] ; kernel32.ExitProcess
005293B5 C3 retn
得到两个地址:
0052934E
00529362
然后到数据窗口转到data段,搜索2进制字串:
FF FF FF FF 4e 93 52 00 62 93 52 00
找一个:
00615E68 FF FF FF FF 4E 93 52 00 62 93 52 00 80 90 61 00 N?.b?.€?.
00615E78 DF 93 52 00 00 00 00 00 63 73 6D E0 01 00 00 00 ?R.....csm?...
00615E88 00 00 00 00 00 00 00 00 03 00 00 00 20 05 93 19 ........... ?
00615E98 00 00 00 00 00 00 00 00 48 3A 6D 6D 3A 73 73 00 ........H:mm:ss.
这个存放这个2进制字串的地址就是第一个imm32
于是我们知道了第一个imm32是00615E68
第二个就简单了,是 SEH_HANDLE函数的地址,这个有个明显的标记
在代码段搜索2进制字串:"VC20XC00"
找到一个:
00526CCC . 56 43 32 30 5>ascii "VC20XC00"
00526CD4 /$ 55 push ebp ; 结构异常处理程序
00526CD5 |. 8BEC mov ebp, esp
00526CD7 |. 83EC 08 sub esp, 8
00526CDA |. 53 push ebx
00526CDB |. 56 push esi
00526CDC |. 57 push edi
00526CDD |. 55 push ebp
00526CDE |. FC cld
于是第二个imm32就是00526CD4
现在我们就能修复stolen code了
修复后
004010C0 >/$ 55 push ebp
004010C1 |. 8BEC mov ebp, esp
004010C3 |. 6A FF push -1
004010C5 |. 68 40014200 push 00615E68
004010CA |. 68 A42C4000 push 00526CD4 ; SE 处理程序安装
004010CF |. 64:A1 0000000>mov eax, dword ptr fs:[0]
004010D5 |. 50 push eax
004010D6 |. 64:8925 00000>mov dword ptr fs:[0], esp
00529282 . 83EC 58 sub esp, 58
004010E0 |. 53 push ebx
004010E1 |. 56 push esi
004010E2 |. 57 push edi
004010E3 |. 8965 E8 mov dword ptr ss:[ebp-18], esp
004010E6 |. FF15 94514200 call dword ptr ds:[<&KERNEL32.GetVers>; kernel32.GetVersion
现在用lordPE,先correct ImageSize,然后dump full.(这个文件巨大有100多MB).
把dump.exe用PE-TOOL把最后3个区段砍掉(壳加上去的),然后用LordPE rebuildPE(注意不要rebuild ImportTable).
之后文件小多了,但是还是有10+MB
step4. 修复导入表
这步就不说了,因为IAT完好无损.
step5.
over.
谢谢你的阅读.
iSaiAh.nET
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!