【脱文标题】 PECompact 2.06加壳的记事本和主程序的脱壳和伪破解
【脱文作者】 weiyi75[Dfcg]
【作者邮箱】 [email]weiyi75@sohu.com[/email]
【作者主页】 Dfcg官方大本营
【使用工具】 Peid,Ollydbg,Loadpe,ImportREC,W32Dasm,Winhex
【破解平台】 Win2000/XP
【软件名称】 PECompact 2.06
【下载地址】 http://www.bitsum.com/files/pec2setup.zip
【软件简介】 PECompact是一个能压缩可执行文件的工具,通过压缩代码、数据、相关资源使压缩能达到100%,由于在运行时不需要恢复磁盘上压缩后的数据,所以与没有压缩的程序在运行时没有明显的速度差异,在某种程度上还有所改善。
【软件大小】 955K
【加壳方式】 PECompact 2.06
【破解声明】 我是一只小菜鸟,偶得一点心得,愿与大家分享:
--------------------------------------------------------------------------------
【破解内容】
PECompact两年没有更新了,最近推出了2.0X版,一个月内升级4个版本左右。观察程序界面和PECompact1.84大不一样,压缩选项也精简了很多。PECompact一直以压缩比高闻名,为了测试其性能,我用UPX1.24,Aspack2.12,PECompact2.06,FSG1.33都用最大压缩比压缩了Win98的记事本。
排名结果如下。
FSG 1.33 52k To 17.5K
PECompact 2.06 52k To 21k
UPX 1.24 52k To 26.5k
Aspack 2.12 52k To 32.5k
PECompact 2.06排第二名,压缩比还是很高的。
因为PECompact 2.06刚刚发行,Peid和FI都不认识,我们来识别它的特征。
先看看Win98的记事本。
这次PECompact 2.06增加了压缩壳没有的一个SEH异常,OD异常设置不忽略内存异常。
004010CC > B8 00E44000 mov eax, NOTEPAD.0040E400 //记事本入口点没有变,但代码段内容被替换了,F9运行。 SEH结构和Petite2.2一样的。
004010D1 50 push eax //填充ERR结构的Hander,当发生异常时系统会自动调用这里。
004010D2 64:FF35 0000000>push dword ptr fs:[0] //填充ERR结构的Prev
004010D9 64:8925 0000000>mov dword ptr fs:[0], esp //建立SEH链
004010E0 33C0 xor eax, eax
004010E2 8908 mov dword ptr ds:[eax], ecx //典型PECompact 2.0X最后一次内存异常
004010E4 50 push eax
004010E5 45 inc ebp
004010E6 43 inc ebx
004010E7 6F outs dx, dword ptr es:[edi]
004010E8 6D ins dword ptr es:[edi], dx
004010E9 70 61 jo short NOTEPAD.0040114C
004010EB 637432 00 arpl word ptr ds:[edx+esi], si
004010EF F6E1 mul cl
004010F1 100A adc byte ptr ds:[edx], cl
004010F3 B9 3A677351 mov ecx, 5173673A
004010F8 000F add byte ptr ds:[edi], cl
004010FA B7 45 mov bh, 45
...........................................................
堆栈友好提示
0012FFBC 0012FFE0 指针到下一个 SEH 记录
0012FFC0 0040E400 SE 句柄 //直接去SEH出口下断点,INT3或内存访问断点都可以。
0012FFC4 77E614C7 返回到 kernel32.77E614C7
0012FFC8 77F517E6 返回到 ntdll.77F517E6 来自 ntdll.77F78C4E
0012FFCC 77F51778 返回到 ntdll.77F51778 来自 ntdll.77F517B5
0040E400 B8 A9D340F0 mov eax, F040D3A9 //清除断点。
0040E405 8D88 7A100010 lea ecx, dword ptr ds:[eax+1000107A] //ECX=40E423是出口。
0040E40B 8941 01 mov dword ptr ds:[ecx+1], eax
0040E40E 8B5424 04 mov edx, dword ptr ss:[esp+4]
0040E412 8B52 0C mov edx, dword ptr ds:[edx+C]
0040E415 C602 E9 mov byte ptr ds:[edx], 0E9
0040E418 83C2 05 add edx, 5
0040E41B 2BCA sub ecx, edx
0040E41D 894A FC mov dword ptr ds:[edx-4], ecx
0040E420 33C0 xor eax, eax
0040E422 C3 retn //要进入系统领空了。
0040E423 B8 78563412 mov eax, 12345678 这里F2下断点,F9运行中断后取消断点。
0040E428 64:8F05 0000000>pop dword ptr fs:[0]
0040E42F 83C4 04 add esp, 4
0040E432 55 push ebp
0040E433 53 push ebx
0040E434 51 push ecx
0040E435 57 push edi
0040E436 56 push esi
0040E437 8D98 33100010 lea ebx, dword ptr ds:[eax+10001033]
0040E43D 8B53 18 mov edx, dword ptr ds:[ebx+18]
0040E440 8BE8 mov ebp, eax
0040E442 6A 40 push 40
0040E444 68 00100000 push 1000
0040E449 FF73 04 push dword ptr ds:[ebx+4]
0040E44C 6A 00 push 0
0040E44E 8B4B 10 mov ecx, dword ptr ds:[ebx+10]
0040E451 03CA add ecx, edx
0040E453 8B01 mov eax, dword ptr ds:[ecx]
0040E455 FFD0 call eax
0040E457 8BF8 mov edi, eax
0040E459 50 push eax
0040E45A 8B33 mov esi, dword ptr ds:[ebx]
0040E45C 8B53 18 mov edx, dword ptr ds:[ebx+18]
0040E45F 8B43 20 mov eax, dword ptr ds:[ebx+20]
0040E462 03C2 add eax, edx
0040E464 8B08 mov ecx, dword ptr ds:[eax]
0040E466 894B 20 mov dword ptr ds:[ebx+20], ecx
0040E469 8B43 1C mov eax, dword ptr ds:[ebx+1C]
0040E46C 03C2 add eax, edx
0040E46E 8B08 mov ecx, dword ptr ds:[eax]
0040E470 894B 1C mov dword ptr ds:[ebx+1C], ecx
0040E473 03F2 add esi, edx
0040E475 8B4B 0C mov ecx, dword ptr ds:[ebx+C] //中间一大段分配内存载入动态运行库和处理输入表的过程
0040E478 03CA add ecx, edx
0040E47A 8D43 1C lea eax, dword ptr ds:[ebx+1C]
0040E47D 50 push eax
0040E47E 8D85 29110010 lea eax, dword ptr ss:[ebp+10001129]
0040E484 FF73 04 push dword ptr ds:[ebx+4]
0040E487 8F00 pop dword ptr ds:[eax]
0040E489 50 push eax
0040E48A 57 push edi
0040E48B 56 push esi
0040E48C FFD1 call ecx
0040E48E 58 pop eax
0040E48F 0343 08 add eax, dword ptr ds:[ebx+8]
0040E492 8BF8 mov edi, eax
0040E494 8B53 18 mov edx, dword ptr ds:[ebx+18]
0040E497 8BF0 mov esi, eax
0040E499 8B46 FC mov eax, dword ptr ds:[esi-4]
0040E49C 83C0 04 add eax, 4
0040E49F 2BF0 sub esi, eax
0040E4A1 8956 08 mov dword ptr ds:[esi+8], edx
0040E4A4 8B4B 10 mov ecx, dword ptr ds:[ebx+10]
0040E4A7 894E 24 mov dword ptr ds:[esi+24], ecx
0040E4AA 8B4B 14 mov ecx, dword ptr ds:[ebx+14]
0040E4AD 51 push ecx
0040E4AE 894E 28 mov dword ptr ds:[esi+28], ecx
0040E4B1 FFD7 call edi
0040E4B3 8985 2D110010 mov dword ptr ss:[ebp+1000112D], eax EAX=4010CC=记事本的OEP
0040E4B9 8BF0 mov esi, eax
0040E4BB 59 pop ecx
0040E4BC 034B 18 add ecx, dword ptr ds:[ebx+18]
0040E4BF 68 00800000 push 8000
0040E4C4 6A 00 push 0
0040E4C6 57 push edi
0040E4C7 FF11 call dword ptr ds:[ecx]
0040E4C9 8BC6 mov eax, esi
0040E4CB 5E pop esi
0040E4CC 5F pop edi
0040E4CD 59 pop ecx
0040E4CE 5B pop ebx
0040E4CF 5D pop ebp
0040E4D0 FFE0 jmp eax //内存解压完毕,跳往OEP,准备运行了。
004010CC > 55 push ebp //达到这里,往下一看输入表没有加密,用OD的插件直接脱壳重建输入表方式选1
004010CD 8BEC mov ebp, esp
004010CF 83EC 44 sub esp, 44
004010D2 56 push esi
004010D3 FF15 E4634000 call dword ptr ds:[4063E4] ; kernel32.GetCommandLineA
004010D9 8BF0 mov esi, eax
004010DB 8A00 mov al, byte ptr ds:[eax]
004010DD 3C 22 cmp al, 22
004010DF 75 1B jnz short NOTEPAD.004010FC
004010E1 56 push esi
004010E2 FF15 F4644000 call dword ptr ds:[4064F4] ; user32.CharNextA
004010E8 8BF0 mov esi, eax
004010EA 8A00 mov al, byte ptr ds:[eax]
004010EC 84C0 test al, al
004010EE 74 04 je short NOTEPAD.004010F4
004010F0 3C 22 cmp al, 22
004010F2 ^ 75 ED jnz short NOTEPAD.004010E1
004010F4 803E 22 cmp byte ptr ds:[esi], 22
004010F7 75 15 jnz short NOTEPAD.0040110E
004010F9 46 inc esi
004010FA EB 12 jmp short NOTEPAD.0040110E
........................................................
运行脱壳程序,正常运行,记事本脱壳完毕。
继续努力脱掉它的主程序,先前有了一些经验了吧。
00401000 > B8 B4F14100 mov eax, pec2gui.0041F1B4 //外壳入口,F9运行。
00401005 50 push eax EAX=41F1B4,直接去哪里下断点吧。
00401006 64:FF35 0000000>push dword ptr fs:[0]
0040100D 64:8925 0000000>mov dword ptr fs:[0], esp
00401014 33C0 xor eax, eax
00401016 8908 mov dword ptr ds:[eax], ecx
00401018 50 push eax
00401019 45 inc ebp
0040101A 43 inc ebx
0040101B 6F outs dx, dword ptr es:[edi]
0040101C 6D ins dword ptr es:[edi], dx
0040101D 70 61 jo short pec2gui.00401080
0040101F 637432 00 arpl word ptr ds:[edx+esi], si
00401023 0068 01 add byte ptr ds:[eax+1], ch
00401026 24 BD and al, 0BD
00401028 40 inc eax
00401029 0064A1 00 add byte ptr ds:[ecx], ah
0040102D E0 50 loopdne short pec2gui.0040107F
0040102F 64:8925 780083E>mov dword ptr fs:[EC830078], esp
00401036 000C53 add byte ptr ds:[ebx+edx*2], cl
................................................................
堆栈友好提示
0012FFBC 0012FFE0 指针到下一个 SEH 记录
0012FFC0 0041F1B4 SE 句柄 //直接去SEH出口下断点,INT3或内存访问断点都可以。
0012FFC4 77E614C7 返回到 kernel32.77E614C7
0012FFC8 77F517E6 返回到 ntdll.77F517E6 来自 ntdll.77F78C4E
0012FFCC 77F51778 返回到 ntdll.77F51778 来自 ntdll.77F517B5
Shift+F9中断在SEH出口继续运行却还有四次SEH异常,先以为它加了几层壳,看OD顶部标题栏发现它只是载入运行库产生SEH异常,因为它的运行库大半都是PECompact 2.06加壳的。
这个简单,重复先前的过程,中断在第一次SEH异常出口后,内存异常设置忽略内存异常。
然后不用慢慢跟踪了,直接Ctrl+F向下找 jmp eax
0041F284 FFE0 jmp eax //F2下断,F9运行。
0041F286 0000 add byte ptr ds:[eax], al
0041F288 0000 add byte ptr ds:[eax], al
0041F28A 0000 add byte ptr ds:[eax], al
0041F28C 0000 add byte ptr ds:[eax], al
0041F28E 0000 add byte ptr ds:[eax], al
0041F290 0000 add byte ptr ds:[eax], al
........................................................................
0040D077 6A 18 push 18 //原来是C++编程的,用Loadpe脱壳吧。
0040D079 68 A04C4100 push pec2gui.00414CA0
0040D07E E8 1D020000 call pec2gui.0040D2A0
0040D083 BF 94000000 mov edi, 94
0040D088 8BC7 mov eax, edi
0040D08A E8 F1F3FFFF call pec2gui.0040C480
0040D08F 8965 E8 mov dword ptr ss:[ebp-18], esp
0040D092 8BF4 mov esi, esp
0040D094 893E mov dword ptr ds:[esi], edi
0040D096 56 push esi
0040D097 FF15 98414100 call dword ptr ds:[414198] ; kernel32.GetVersionExA
0040D09D 8B4E 10 mov ecx, dword ptr ds:[esi+10]
0040D0A0 890D 809E4100 mov dword ptr ds:[419E80], ecx
0040D0A6 8B46 04 mov eax, dword ptr ds:[esi+4]
0040D0A9 A3 8C9E4100 mov dword ptr ds:[419E8C], eax
0040D0AE 8B56 08 mov edx, dword ptr ds:[esi+8]
0040D0B1 8915 909E4100 mov dword ptr ds:[419E90], edx
0040D0B7 8B76 0C mov esi, dword ptr ds:[esi+C]
0040D0BA 81E6 FF7F0000 and esi, 7FFF
0040D0C0 8935 849E4100 mov dword ptr ds:[419E84], esi
0040D0C6 83F9 02 cmp ecx, 2
........................................................................
运行ImportREC,选择这个进程。把OEP改为D077,点IT AutoSearch,点“Get Import”,函数全部有效,FixDump,正常运行!
我们看到它还是7天试用期,看来比较过期的代码不在壳里面。
这个程序没有注册的地方,看来是Keyfile注册。
观察程序除了选项里面有几个灰色选项功能限制,感觉没什么用处,默认选项足够了。主要是7天试用期一定要搞掉它!想办法打乱日期判断。
首先修改日期到2005年的今天,程序肯定过期,果然。
程序,先问你是否网上升级,点Cancel。然后弹出购买软件的对话框,不买就点Exit按钮退出。
退出前先看清对话标题是 Please purchase PECompact
W32dasm 反汇编程序,查找 "Please purchase PECompact"
:0040B175 6A00 push 00000000
:0040B177 6A00 push 00000000
:0040B179 68914E0000 push 00004E91
* Possible StringData Ref from Code Obj ->"PECompact2"
|
:0040B17E 6838494100 push 00414938
:0040B183 8D8C2480000000 lea ecx, dword ptr [esp+00000080]
:0040B18A E8716FFFFF call 00402100
:0040B18F 8D4C2470 lea ecx, dword ptr [esp+70]
:0040B193 C68424A406000002 mov byte ptr [esp+000006A4], 02
:0040B19B E86071FFFF call 00402300
:0040B1A0 68C09C4100 push 00419CC0
:0040B1A5 6880050000 push 00000580
:0040B1AA 680040E428 push 28E44000
:0040B1AF 8D4C247C lea ecx, dword ptr [esp+7C]
:0040B1B3 E82870FFFF call 004021E0
:0040B1B8 A1C09C4100 mov eax, dword ptr [00419CC0]
:0040B1BD 85C0 test eax, eax
:0040B1BF 7F5C jg 0040B21D //一眼就看出这里是爆破点,修改为jmp 0040B21D
* Possible StringData Ref from Code Obj ->"http://www.bitsum.com"
|
:0040B1C1 68D4494100 push 004149D4
* Possible StringData Ref from Code Obj ->"PECompact's continued development "
->"requires support of users like "
->"yourself. Please purchase this "
->"product if you find it useful."
|
:0040B1C6 68B84A4100 push 00414AB8
* Possible StringData Ref from Code Obj ->"Please purchase PECompact"
|
:0040B1CB 68984A4100 push 00414A98
..................................................................
运行程序,果然一切尽在掌握,还剩-358天可以测试。
然后用Winhex修改掉一切让人不悦的字符。
"%d trial days remain"
改到你高兴为止
如 Register To Mr.David
呵呵,字符刚好够用。
别高兴得太早,尝试加壳文件,加壳功能没有了。
安装时还发现这个程序有 PECompact2 Console 即是PEC2.exe,我们运行它,提示已经过期,删除它,主程序提示缺少文件无法工作,果然是它在猫腻。
用命令行调用这个程序,直接运行一闪就退出了。
同样看清楚过期提示后用W32Dasm反汇编程序,倒,还有壳没有脱,先脱壳在说。
00401000 > B8 5C4C4200 mov eax, PEC2.00424C5C 注意切换窗口,别让命令行窗口挡我们的视线,F9运行。
00401005 50 push eax
00401006 64:FF35 0000000>push dword ptr fs:[0]
0040100D 64:8925 0000000>mov dword ptr fs:[0], esp
00401014 33C0 xor eax, eax
00401016 8908 mov dword ptr ds:[eax], ecx
00401018 50 push eax
00401019 45 inc ebp
0040101A 43 inc ebx
0040101B 6F outs dx, dword ptr es:[edi]
0040101C 6D ins dword ptr es:[edi], dx
0040101D 70 61 jo short PEC2.00401080
................................................
堆栈友好提示。
0012FFBC 0012FFE0 指针到下一个 SEH 记录
0012FFC0 00424C5C SE 句柄 //在SEH出口下断点
0012FFC4 77E614C7 返回到 kernel32.77E614C7
0012FFC8 77F517E6 返回到 ntdll.77F517E6 来自 ntdll.77F78C4E
0012FFCC 77F51778 返回到 ntdll.77F51778 来自 ntdll.77F517B5
0012FFD0 7FFDF000
00424C5C B8 053C42F0 mov eax, F0423C05 //取消断点。
00424C61 8D88 7A100010 lea ecx, dword ptr ds:[eax+1000107A]
00424C67 8941 01 mov dword ptr ds:[ecx+1], eax
00424C6A 8B5424 04 mov edx, dword ptr ss:[esp+4]
00424C6E 8B52 0C mov edx, dword ptr ds:[edx+C]
00424C71 C602 E9 mov byte ptr ds:[edx], 0E9
00424C74 83C2 05 add edx, 5
00424C77 2BCA sub ecx, edx
00424C79 894A FC mov dword ptr ds:[edx-4], ecx
00424C7C 33C0 xor eax, eax
00424C7E C3 retn
................................................
然后不用慢慢跟踪了,直接Ctrl+F向下找 jmp eax
00424D2C FFE0 jmp eax //F2下断点,F9运行。
00424D2E 0000 add byte ptr ds:[eax], al
00424D30 0000 add byte ptr ds:[eax], al
00424D32 0000 add byte ptr ds:[eax], al
00424D34 0000 add byte ptr ds:[eax], al
00424D36 0000 add byte ptr ds:[eax], al
00424D38 0000 add byte ptr ds:[eax], al
00424D3A 0000 add byte ptr ds:[eax], al
..............................................................
00413392 6A 18 push 18 //直接用用OD的插件直接脱壳重建输入表方式选1
00413394 68 C8D64100 push PEC2.0041D6C8
00413399 E8 22020000 call PEC2.004135C0
0041339E BF 94000000 mov edi, 94
004133A3 8BC7 mov eax, edi
004133A5 E8 F6FAFFFF call PEC2.00412EA0
004133AA 8965 E8 mov dword ptr ss:[ebp-18], esp
004133AD 8BF4 mov esi, esp
004133AF 893E mov dword ptr ds:[esi], edi
004133B1 56 push esi
004133B2 FF15 84B04100 call dword ptr ds:[41B084] ; kernel32.GetVersionExA
004133B8 8B4E 10 mov ecx, dword ptr ds:[esi+10]
004133BB 890D 2C194200 mov dword ptr ds:[42192C], ecx
004133C1 8B46 04 mov eax, dword ptr ds:[esi+4]
004133C4 A3 38194200 mov dword ptr ds:[421938], eax
004133C9 8B56 08 mov edx, dword ptr ds:[esi+8]
004133CC 8915 3C194200 mov dword ptr ds:[42193C], edx
004133D2 8B76 0C mov esi, dword ptr ds:[esi+C]
004133D5 81E6 FF7F0000 and esi, 7FFF
004133DB 8935 30194200 mov dword ptr ds:[421930], esi
004133E1 83F9 02 cmp ecx, 2
.....................................................
现在可以反汇编了。
查找过期提示YOUR TRIAL PERIOD HAS ENDED
* Possible StringData Ref from Code Obj ->"
YOUR TRIAL PERIOD HAS ENDED! "
->"Please visit http://www.bitsum.com "
->"for purchasing info."
|
:0040AE6B 68C8BF4100 push 0041BFC8
找了半天,有半个小时吧,只怪自己水平太差,没发现什么好的修改点。
继续观察漏洞提示字符,寻找突破口。
"Unregistered version."
令人感兴趣,但registered version 程序里是没有的。
:00409517 68F0D44100 push 0041D4F0
:0040951C 8D8C2490040000 lea ecx, dword ptr [esp+00000490]
:00409523 898424BC660000 mov dword ptr [esp+000066BC], eax
:0040952A 32DB xor bl, bl
:0040952C 8974244C mov dword ptr [esp+4C], esi
:00409530 E88B86FFFF call 00401BC0
:00409535 8D44243C lea eax, dword ptr [esp+3C]
:00409539 50 push eax
:0040953A 6880050000 push 00000580
:0040953F 680040E428 push 28E44000
:00409544 8D8C248C040000 lea ecx, dword ptr [esp+0000048C]
:0040954B 89B424C8660000 mov dword ptr [esp+000066C8], esi
:00409552 E84987FFFF call 00401CA0
:00409557 84C0 test al, al
:00409559 7402 je 0040955D //爆破点,jmp 0040955D
:0040955B B301 mov bl, 01
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00409559(C)
|
* Possible StringData Ref from Code Obj ->"
PECompact v2.x (c)2004 Bitsum "
->"Technologies"
|
:0040955D 68C0D44100 push 0041D4C0
:00409562 E851910000 call 004126B8
* Possible StringData Ref from Code Obj ->"
--------------------------------------------"
->"---------------------------------"
|
:00409567 6870D44100 push 0041D470
:0040956C E847910000 call 004126B8
* Possible StringData Ref from Code Obj ->"2.06 May 3 2004"
|
:00409571 6858D44100 push 0041D458
* Possible StringData Ref from Code Obj ->"
Version: %s"
|
:00409576 6848D44100 push 0041D448
:0040957B E838910000 call 004126B8
* Possible StringData Ref from Code Obj ->"May 3 2004"
|
:00409580 683CD44100 push 0041D43C
* Possible StringData Ref from Code Obj ->"
Build date: %s"
|
:00409585 6828D44100 push 0041D428
:0040958A E829910000 call 004126B8
* Possible StringData Ref from Code Obj ->"06:58:09"
|
:0040958F 681CD44100 push 0041D41C
* Possible StringData Ref from Code Obj ->"
Build time: %s"
|
:00409594 6808D44100 push 0041D408
:00409599 E81A910000 call 004126B8
* Possible StringData Ref from Code Obj ->"
Unregistered version."
|
:0040959E 68F0D34100 push 0041D3F0
:004095A3 E810910000 call 004126B8
* Possible StringData Ref from Code Obj ->"
License for use is granted only "
->"until expire time."
|
:004095A8 68B8D34100 push 0041D3B8
:004095AD E806910000 call 004126B8
* Possible StringData Ref from Code Obj ->"
Distribution of files compressed "
->"with this product is NOT allowed."
|
:004095B2 6870D34100 push 0041D370
:004095B7 E8FC900000 call 004126B8
:004095BC 83C42C add esp, 0000002C
:004095BF 84DB test bl, bl //这里就是判断点,它的值就是0040955B给的,不能是01
:004095C1 0F85A4180000 jne 0040AE6B
:004095C7 8B4C243C mov ecx, dword ptr [esp+3C]
:004095CB 51 push ecx
* Possible StringData Ref from Code Obj ->"
Your evaluation period ends "
->"in %d days." //这里必然有一个地方判断是否过了7天试用期。
|
:004095CC 6840D34100 push 0041D340
...................................................................
呵呵,同主程序一样,我们有-358天可以测试这个程序。
同样Winhex修改掉一切令人不悦的字符,改到你高兴为止。
附脱壳伪破解程序本地下载
到这里日期限制解除。
最后请看胜利截图
【版权声明】 本文纯属技术交流, 转载请注明作者并保持文章的完整!
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)