- UID
- 1874
注册时间2005-6-3
阅读权限30
最后登录1970-1-1
龙战于野
该用户从未签到
|
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 [Esc] 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:[ebp+eax*4+5C]
0040D5AB FF16 call dword ptr ds:[esi]
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:[ebx-4]
0040D745 95 xchg eax,ebp
0040D746 AC lods byte ptr ds:[esi]
0040D747 84C0 test al,al
0040D749 ^ 75 FB jnz short Server.0040D746
0040D74B 3806 cmp byte ptr ds:[esi],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:[esi]
0040D758 50 push eax
0040D759 55 push ebp ; 以后将不断硬中断于此(从kernel,ntdll返回主程序server领空)
0040D75A FF13 call dword ptr ds:[ebx]
0040D75C AB stos dword ptr es:[edi]
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 0040A030 ASCII "CreateThread"
再5次F9,
0012FFC0 0040A03D ASCII "OpenThread"
....
....
现在取消硬件读中断,用F8一步步来跟这个循环:
0040D759 55 push ebp
0040D75A FF13 call dword ptr ds:[ebx]
0040D75C AB stos dword ptr es:[edi]
0040D75D ^ EB E7 jmp short Server.0040D746 ; 往回跳
0040D746 AC lods byte ptr ds:[esi] ; 循环开始,[esi]循环指向不同的输入函数名
0040D747 84C0 test al,al
0040D749 ^ 75 FB jnz short Server.0040D746
0040D74B 3806 cmp byte ptr ds:[esi],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:[esi]
0040D758 50 push eax
0040D759 55 push ebp
0040D75A FF13 call dword ptr ds:[ebx]
0040D75C AB stos dword ptr es:[edi]
0040D75D ^ EB E7 jmp short Server.0040D746 ;往回跳到循环开始处
来到:
0040D736 46 inc esi
0040D737 AD lods dword ptr ds:[esi] ;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:[ebx-4]
0040D745 95 xchg eax,ebp
0040D746 AC lods byte ptr ds:[esi]
0040D747 84C0 test al,al
0040D749 ^ 75 FB jnz short Server.0040D746
0040D74B 3806 cmp byte ptr ds:[esi],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:[esi]
0040D758 50 push eax
0040D759 55 push ebp
0040D75A FF13 call dword ptr ds:[ebx]
0040D75C AB stos dword ptr es:[edi]
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:[408090] ; \GetModuleHandleA
004045E6 . A3 E4784000 mov dword ptr ds:[4078E4],eax
004045EB .^ E9 B4FFFFFF jmp Server.004045A4
004045F0 . 50 push eax
004045F1 . 50 push eax
004045F2 . FF35 94804000 push dword ptr ds:[408094] ; 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文件何偏移处。 |
|