测试程序
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
int _tmain(int argc, _TCHAR* argv[])
{
_tprintf(L">> tmain\r\n");
do
{
_tprintf(L"loop here not need quit\r\n");
::Sleep(1000);
} while (1);
_tprintf(L"<< tmain\r\n");
return 0;
}
用VS2008, 编译成默认的Release版, 输出PE为: forTest.exe
加壳
用 UPXv3.25 对 forTest.exe 加壳, 改名为 forTestAfterUpx.exe
查壳
用 Exeinfo_v0032work_658sign 对加壳后的 forTestAfterUpx.exe 查壳
寻找OEP
用OD加载 forTestAfterUpx.exe单步寻找OEP, OEP的标志为 E8, E9打头的两行汇编.
未加壳的Vs2008程序, 用OD载入后, 直接停在E8,E9打头的2行汇编上.
单步往下走, 直到找到和未加壳程序相同的OEP
在往小地址跳的语句后面按下F4, 运行到往上跳的语句后面, 便于快速向下走.
004079CC .^\E2 D9 loopd short 004079A7
004079CE . 8DBE 00500000 lea edi, dword ptr [esi+5000] ; F4
004079D4 > 8B07 mov eax, dword ptr [edi]
004079D6 . 09C0 or eax, eax
004079D8 . 74 3C je short 00407A16 ; 解压完成后, 跳出
004079DA . 8B5F 04 mov ebx, dword ptr [edi+4]
004079DD . 8D8430 B47200>lea eax, dword ptr [eax+esi+72B4]
004079E4 . 01F3 add ebx, esi
004079E6 . 50 push eax
004079E7 . 83C7 08 add edi, 8
004079EA . FF96 F0720000 call dword ptr [esi+72F0]
004079F0 . 95 xchg eax, ebp
004079F1 > 8A07 mov al, byte ptr [edi]
004079F3 . 47 inc edi
004079F4 . 08C0 or al, al
004079F6 .^ 74 DC je short 004079D4
004079F8 . 89F9 mov ecx, edi
004079FA . 57 push edi
004079FB . 48 dec eax
004079FC . F2:AE repne scas byte ptr es:[edi]
004079FE . 55 push ebp
004079FF . FF96 F4720000 call dword ptr [esi+72F4]
00407A05 . 09C0 or eax, eax
00407A07 . 74 07 je short 00407A10
00407A09 . 8903 mov dword ptr [ebx], eax
00407A0B . 83C3 04 add ebx, 4
00407A0E .^ EB E1 jmp short 004079F1 ; 最后一轮解压循环
00407A10 > FF96 04730000 call dword ptr [esi+7304]
00407A16 > 8BAE F8720000 mov ebp, dword ptr [esi+72F8] ; 解压完成
00407A1C . 8DBE 00F0FFFF lea edi, dword ptr [esi-1000]
00407A22 . BB 00100000 mov ebx, 1000
00407A27 . 50 push eax
00407A28 . 54 push esp
00407A29 . 6A 04 push 4
00407A2B . 53 push ebx
00407A2C . 57 push edi
00407A2D . FFD5 call ebp
00407A2F . 8D87 07020000 lea eax, dword ptr [edi+207]
00407A35 . 8020 7F and byte ptr [eax], 7F
00407A38 . 8060 28 7F and byte ptr [eax+28], 7F
00407A3C . 58 pop eax
00407A3D . 50 push eax
00407A3E . 54 push esp
00407A3F . 50 push eax
00407A40 . 53 push ebx
00407A41 . 57 push edi
00407A42 . FFD5 call ebp
00407A44 . 58 pop eax
00407A45 . 61 popad ; 解压完成后的 POPAD
00407A46 . 8D4424 80 lea eax, dword ptr [esp-80]
00407A4A > 6A 00 push 0
00407A4C . 39C4 cmp esp, eax
00407A4E .^ 75 FA jnz short 00407A4A ; 调整堆栈呢
00407A50 . 83EC 80 sub esp, -80
00407A53 .- E9 8498FFFF jmp 004012DC ; 解压完成后, POPAD后的跨段跳转
可以看出, UPX解压完成的标志是POPAD, 加一句跨段跳转, 跑到OEP.
004012DC E8 77040000 call 00401758 ; E8E9两行是OEP~, 未加壳的原始程序EP也是E8E9, E8E9两行的OPCODE也和未加壳程序相同.
004012E1 ^ E9 9FFDFFFF jmp 00401085
004012E6 8BFF mov edi, edi
004012E8 55 push ebp
004012E9 8BEC mov ebp, esp
004012EB 81EC 28030000 sub esp, 328
比对在加壳程序解压后找到的OEP和未加壳程序OEP
对照未加壳程序的EP013D12DC > $ E8 77040000 call 013D1758
013D12E1 .^ E9 9FFDFFFF jmp 013D1085
013D12E6 > 8BFF mov edi, edi
013D12E8 /. 55 push ebp
013D12E9 |. 8BEC mov ebp, esp
013D12EB |. 81EC 28030000 sub esp, 328
经过对比, 程序基址 + 0x12DC, 就是OEP.