【原创】ESP定律搞定KEN QQServer2.0 QQ挂机程序脱壳
KEN QQServer.exe2.0 QQ挂机服务端程序今天QQ群上一个老弟传给我个据称是挂QQ的服务端程序,说不知是什么壳。我打肿脸充胖子,对于手动脱壳我完全是个生手。
同时冒着是木马/病毒的风险,硬接过来,还好,一切顺利。
server_.exe 为脱壳后
server__.exe 为脱壳后修复
参照pediy论坛《【原创】WinUpack 0.29 beta主程序脱壳》一文中cater提供的方法可以迅速找到OEP.
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&——————
后来我自己根据ESP定律脱壳的过程:
用PeID093查不出是什么壳Nothing *,用STUD_PEv2.101看PE结构:
Press to close this window!
No| Name | VSize | VOffset | RSize | ROffset | Charact. |
01| .Upack | 0000A000 | 00001000 | 000001CC | 00000020 | E0000060 |
02| .rsrc | 0000A000 | 0000B000 | 0000280D | 00000200 | E0000060 |
一个Upack段,再看PE文件头:
MZKERNEL32.DLL...LoadLibraryA...GetProcAddress.[[email protected]..
上google查了下,初步确定是Dwing的(Win)Upack壳,一个纯压缩壳,版本未知。当然也不排除伪造壳
特征的可能。对于未知壳,我也不知用什么自动脱壳工具好,只好手工脱壳了。
用OLLYDBG110加载Server.exe,来到:
00401030 S> $- E9 5BC50000 jmp Server.0040D590
00401035 .42 79 44 77 69 6E 67 40 00 ascii "ByDwing@",0
0040103E 00 db 00
0040103F 00 db 00
00401040 .50 45 00 ascii "PE",0
注意此时的堆栈寄存器ESP
EAX 00000000
ECX 00000101
EDX FFFFFFFF
EBX 7FFDF000
ESP 0012FFC4
EBP 0012FFF0
ESI 00000000
EDI 00000000
EIP 00401030 Server.<ModuleEntryPoint>
运用ESP定律(一开始也不知道管不管用,反正试试看),在ESP+4处0012FFC0设置硬件读中断HR,
F9,中断于:
0040D5A4 97 xchg eax,edi ; Server.0041482C
0040D5A5 51 push ecx
0040D5A6 58 pop eax
0040D5A7 8D5485 5C lea edx,dword ptr ss:
0040D5AB FF16 call dword ptr ds:
edi=0041482C (Server.0041482C)
eax=00401000 (Server.00401000), ASCII "MZKERNEL32.DLL"
再F9两次,来到:
0040D738 85C0 test eax,eax
0040D73A - 0F84 946EFFFF je Server.004045D4 ;其实,这里的长跳转地址Server.004045D4就是OEP了
0040D740 56 push esi
0040D741 97 xchg eax,edi ; Server.00404972,硬件读中断于此
0040D742 FF53 FC call dword ptr ds:
0040D745 95 xchg eax,ebp
0040D746 AC lods byte ptr ds:
0040D747 84C0 test al,al
0040D749 ^ 75 FB jnz short Server.0040D746
0040D74B 3806 cmp byte ptr ds:,al
0040D74D ^ 74 E7 je short Server.0040D736
0040D74F 8BC6 mov eax,esi
0040D751 79 05 jns short Server.0040D758
0040D753 46 inc esi
0040D754 33C0 xor eax,eax
0040D756 66:AD lods word ptr ds:
0040D758 50 push eax
0040D759 55 push ebp ; 以后将不断硬中断于此(从kernel,ntdll返回主程序server领空)
0040D75A FF13 call dword ptr ds:
0040D75C AB stos dword ptr es:
0040D75D ^ EB E7 jmp short Server.0040D746 ; 这里跳回,是个循环
EAX 00408030 Server.00408030
ECX 00000000
EDX 0040DF0C Server.0040DF0C
EBX 0040D7E1 <&KERNEL32.GetProcAddress>
ESP 0012FFC0
EBP 0040D810 Server.0040D810
ESI 0040A004 ASCII "KERNEL32.DLL"
EDI 00404972 Server.00404972
EIP 0040D741 Server.0040D741
又F9,来到:
77E80228 53 push ebx ; <&KERNEL32.GetProcAddress>
连续2次F9,重回Server领空:
0040D759 55 push ebp ; KERNEL32.77E60000
EAX 0040A011 ASCII "lstrcpyA"
ECX 0012FFE0
EDX 00130608
EBX 0040D7E1 <&KERNEL32.GetProcAddress>
ESP 0012FFC0
EBP 77E60000 KERNEL32.77E60000
ESI 0040A011 ASCII "lstrcpyA"
EDI 00408030 Server.00408030
EIP 0040D759 Server.0040D759
又F9连续5次,又回到了0040D759:
代码和上次一样,只是部分寄存器有变化
EAX 0040A01A ASCII "lstrlenA"
ECX 0012FFE0
EDX 77FCE748 ntdll.77FCE748
EBX 0040D7E1 <&KERNEL32.GetProcAddress>
ESP 0012FFC0
EBP 77E60000 KERNEL32.77E60000
ESI 0040A01A ASCII "lstrlenA"
EDI 00408034 Server.00408034
EIP 0040D759 Server.0040D759
重复5次F9,同样又中断于0040D759:
EAX 0040A023 ASCII "GetTickCount"
ECX 0012FFE0
EDX 77FCE748 ntdll.77FCE748
EBX 0040D7E1 <&KERNEL32.GetProcAddress>
ESP 0012FFC0
EBP 77E60000 KERNEL32.77E60000
ESI 0040A023 ASCII "GetTickCount"
EDI 00408038 Server.00408038
EIP 0040D759 Server.0040D759
看到了么,是解析不同的函数地址,看来这里是个循环,不信可以再F9试试:
5次F9后看堆栈,EIP还是在0040D759:
0012FFC0 0040A030ASCII "CreateThread"
再5次F9,
0012FFC0 0040A03DASCII "OpenThread"
....
....
现在取消硬件读中断,用F8一步步来跟这个循环:
0040D759 55 push ebp
0040D75A FF13 call dword ptr ds:
0040D75C AB stos dword ptr es:
0040D75D ^ EB E7 jmp short Server.0040D746 ; 往回跳
0040D746 AC lods byte ptr ds: ; 循环开始,循环指向不同的输入函数名
0040D747 84C0 test al,al
0040D749 ^ 75 FB jnz short Server.0040D746
0040D74B 3806 cmp byte ptr ds:,al
0040D74D ^ 74 E7 je short Server.0040D736 ; 循环体内只有这一处跳转跳出循环体,回车来到0040D736处查看代码
0040D74F 8BC6 mov eax,esi
0040D751 79 05 jns short Server.0040D758
0040D753 46 inc esi
0040D754 33C0 xor eax,eax
0040D756 66:AD lods word ptr ds:
0040D758 50 push eax
0040D759 55 push ebp
0040D75A FF13 call dword ptr ds:
0040D75C AB stos dword ptr es:
0040D75D ^ EB E7 jmp short Server.0040D746 ;往回跳到循环开始处
来到:
0040D736 46 inc esi
0040D737 AD lods dword ptr ds: ;Load doubleword at address DS:(E)SI into EAX
EAX 004080D8 Server.004080D8
ECX 0012FFE0
EDX 77FCE748 ntdll.77FCE748
EBX 0040D7E1 <&KERNEL32.GetProcAddress>
ESP 0012FFC4
EBP 77E60000 KERNEL32.77E60000
ESI 0040A19C ASCII "USER32.DLL"
0040D738 85C0 test eax,eax ; 注意EAX!=0,表示还有其他导入库的输入函数需要解析地址,现在是USER32.DLL了
0040D73A - 0F84 946EFFFF je Server.004045D4 ; 那么我们假定EAX=0,则说明所有的输入函数都已解析完毕,而且这是个长跳转"—",
; 因此我们直接在004045D4下断F2,--〉光明之巅。
0040D740 56 push esi
0040D741 97 xchg eax,edi
0040D742 FF53 FC call dword ptr ds:
0040D745 95 xchg eax,ebp
0040D746 AC lods byte ptr ds:
0040D747 84C0 test al,al
0040D749 ^ 75 FB jnz short Server.0040D746
0040D74B 3806 cmp byte ptr ds:,al
0040D74D ^ 74 E7 je short Server.0040D736
0040D74F 8BC6 mov eax,esi
0040D751 79 05 jns short Server.0040D758
0040D753 46 inc esi
0040D754 33C0 xor eax,eax
0040D756 66:AD lods word ptr ds:
0040D758 50 push eax
0040D759 55 push ebp
0040D75A FF13 call dword ptr ds:
0040D75C AB stos dword ptr es:
0040D75D ^ EB E7 jmp short Server.0040D746
在004045D4下断F2时,由于程序还没解压完毕,OD会提示在数据中设置断点,不管它,点确定。
F9运行,中断于:
004045D4 68 db 68 ;CHAR 'h'
004045D5 F0 db F0
004045D6 45 db 45 ;CHAR 'E'
004045D7 40 db 40 ;CHAR '@'
004045D8 00 db 00
004045D9 68 db 68 ;CHAR 'h'
004045DA 00 db 00
似乎不像哦,怎么回事?别急,在CPU窗口中鼠标右键--〉分析--〉分析代码:
004045D4 .68 F0454000 push Server.004045F0 ; 这里就是OEP了,用OD插件OLLYDUMP到Server_.exe。
004045D9 .68 00104000 push Server.00401000
004045DE .6A 00 push 0 ; /pModule = NULL
004045E0 .FF15 90804000 call dword ptr ds: ; \GetModuleHandleA
004045E6 .A3 E4784000 mov dword ptr ds:,eax
004045EB .^ E9 B4FFFFFF jmp Server.004045A4
004045F0 .50 push eax
004045F1 .50 push eax
004045F2 .FF35 94804000 push dword ptr ds: ;KERNEL32.ExitProcess
004045F8 .^ E9 93FFFFFF jmp Server.00404590
呵呵,代码出来了。
DUMP后,OD现在不要动,运行IMPORT REC v16Final,选Server.exe进程,OEP处输入000045D4,自动搜索IAT,
获取输入表,修复抓起文件,选前一步骤dump的Server_.exe文件,OKay,Server__.exe生成,完工。
运行Server__.exe无错误,正常运行。原Server.exe有10.2k,现在Server__.exe竟90k,WinUPack压缩率够大的呀。
反正脱壳后体积也不大,懒得优化了(其实是不大熟悉PE减肥:-))
[总结]
一般对于纯压缩壳,无异常SEH、anti和花指令等,用ESP定律很好用。
[问题]
我怎么才能知道这个Server.exe程序是用WinUpack哪个版本压缩的?在PE文件何偏移处。 对于纯压缩壳,无异常SEH、anti和花指令等,用ESP定律通杀
兄弟把原程序传上来就好了,我也可以看看学习 Originally posted by hyd009 at 2005-8-23 07:14 AM:
对于纯压缩壳,无异常SEH、anti和花指令等,用ESP定律通杀
兄弟把原程序传上来就好了,我也可以看看学习
感谢兄弟阅读本文. 不对啊,我这里的ESP是0013FFC4,再说,我根本就下不了断点,求解释
页:
[1]