用PEid检测为:
PECompact 2.x -> Jeremy Collake
用OD载入:
004010CC notepad.> B8 48E84000 mov eax,notepad.0040E848
004010D1 50 push eax
004010D2 64:FF35 00000000 push dword ptr fs:[0]
004010D9 64:8925 00000000 mov dword ptr fs:[0],esp
004010E0 33C0 xor eax,eax
一看到fs:[0],本能猜到壳用到了异常,决定先用ESP定律试试,F8单步到:
004010D9 64:8925 00000000 mov dword ptr fs:[0],esp
此时ESP=0013FFBC,下断:hr 0013FFBC,然后按Shift+F9,断下:
0040E877 83C4 04 add esp,4
0040E87A 55 push ebp
0040E87B 53 push ebx
0040E87C 51 push ecx
0040E87D 57 push edi
0040E87E 56 push esi
一步步单步跟进:
0040E89B 03CA add ecx,edx
0040E89D 8B01 mov eax,dword ptr ds:[ecx]
0040E89F FFD0 call eax ; kernel32.VirtualAlloc
记住这个,这个对分析PECompact加壳的原理有用!
0040E8E0 8B4B 0C mov ecx,dword ptr ds:[ebx+C]
0040E8E3 894E 14 mov dword ptr ds:[esi+14],ecx
0040E8E6 FFD7 call edi
//此处,我们可以跟进分析,也可以不跟进,往下看:
0040E8E6 FFD7 call edi
0040E8E8 8985 FA120010 mov dword ptr ss:[ebp+100012FA],eax
0040E8EE 8BF0 mov esi,eax
0040E8F0 8B4B 14 mov ecx,dword ptr ds:[ebx+14]
0040E8F3 5A pop edx
0040E8F4 EB 0C jmp short notepad.0040E902
0040E8F6 03CA add ecx,edx
0040E8F8 68 00800000 push 8000
0040E8FD 6A 00 push 0
0040E8FF 57 push edi
0040E900 FF11 call dword ptr ds:[ecx]
0040E902 8BC6 mov eax,esi
0040E904 5A pop edx
0040E905 5E pop esi
0040E906 5F pop edi
0040E907 59 pop ecx
0040E908 5B pop ebx
0040E909 5D pop ebp
0040E90A FFE0 jmp eax //此处就是跳到OEP了
我们还是跟进一下,看看壳是如何处理的吧!
0003094B 0053 57 add byte ptr ds:[ebx+57],dl
0003094E 56 push esi
0003094F 55 push ebp
00030950 E8 00000000 call 00030955
000309CC 6A 40 push 40
000309CE 68 00100000 push 1000
000309D3 51 push ecx
000309D4 6A 00 push 0
000309D6 FF95 291E0010 call dword ptr ss:[ebp+10001E29] ; kernel32.VirtualAlloc
00030AD8 68 00800000 push 8000
00030ADD 6A 00 push 0
00030ADF FFB5 191E0010 push dword ptr ss:[ebp+10001E19]
00030AE5 FF95 2D1E0010 call dword ptr ss:[ebp+10001E2D] ; kernel32.VirtualFree
//跟到些处,我们发现了与VirtualAlloc相对应的VirtualFree,也发现了大家常说的特征码:push 8000了,……#……
00030AEB 8B46 0C mov eax,dword ptr ds:[esi+C]
//载入基址00400000
00030AEE 03C7 add eax,edi
//eax=00400000+10CC,就是OEP了
00030AF0 5D pop ebp
00030AF1 5E pop esi
00030AF2 5F pop edi
00030AF3 5B pop ebx
00030AF4 C3 retn //恢复堆栈后,返回
0040E904 5A pop edx
0040E905 5E pop esi
0040E906 5F pop edi
0040E907 59 pop ecx
0040E908 5B pop ebx
0040E909 5D pop ebp
0040E90A - FFE0 jmp eax ; notepad.<模块入口点>
看看此时的寄存器值:
EAX 004010CC notepad.<模块入口点>
ECX 0013FFB0
EDX 7C9585EC ntdll.KiFastSystemCallRet
EBX 7FFD7000
ESP 0013FFC4
EBP 0013FFF0
ESI 00000000
EDI 00000000
EIP 0040E90A notepad.0040E90A
对比一下程序载入时的值:
EAX 00000000
ECX 0013FFB0
EDX 7C9585EC ntdll.KiFastSystemCallRet
EBX 7FFD8000
ESP 0013FFC4
EBP 0013FFF0
ESI 00000000
EDI 00000000
EIP 004010CC notepad.<模块入口点>
=================呵呵,明白了吧!
…………
=================不过,你明白了,我自己却还是糊涂着呢!^#^
还有一种快捷方式:
1、OD载入后,直接下断点:bp VirtualFree,然后按Shift+F9,就会断在第一次调用处:
000309D6 FF95 291E0010 call dword ptr ss:[ebp+10001E29] ; kernel32.VirtualAlloc
2、然后搜索特征码:Ctrl+F,搜索push 8000,就会来到第二次调用VirtualFree前:
00030AD8 68 00800000 push 8000
00030ADD 6A 00 push 0
00030ADF FFB5 191E0010 push dword ptr ss:[ebp+10001E19]
00030AE5 FF95 2D1E0010 call dword ptr ss:[ebp+10001E2D] ; kernel32.VirtualFree
现在我们明白了,就可以一次下断bp VirtualFree,连续按两次Shift+F9运行,然后按Alt+F9返回到程序领空,就可以到了最后一个关键点了,呵呵!
试试了一下:汇编及VB,只要一次Shift+F9或F9就能OK,跟进了一个进去看,也是两次调用VirtualFree,不知为什么只一次就OK!Delphi、Borland C++、VC++需要两次!