标题: 小丁丁 和 WinDos2000 过来看看(多谢帮助 ^_^),哪位1212也过来看看吧
----对PE-ShiELD v0.2b2加壳程序的脱壳的一点分析
内容:
对PE-ShiELD v0.2b2加壳程序的脱壳的一点分析
【声明】
我写文章以交流为主,希望大家在转载时能保持文章的完整性。
【前言】
脱PE-ShiELD v0.2b2的壳很花功夫,不过为了感谢丁丁虾和WinDos2000的帮助,还是赶写了此文,选这个壳的原因,并不是它很简单,只因为正好碰上一位1212想了解这个壳,而我又有过这个壳的脱壳经验。所以就选它了。不过现在这个版本据说已经有脱壳机了,而我当时脱壳时还没有。所以,如果你只为了脱壳,就没有必要看此文了。找脱壳机就是了。
这个程序的手动脱壳很花功夫,这里写这篇文章主要侧重一点它的保护机制。在我跟踪此程序的过程中发现他反跟踪的地方相当多,不过幸亏没有多少故意让你死机的代码。列举一下他反跟踪的种类:
1、检测 \\.\SICE 来防范SoftICE的跟踪
2、检测 \\.\TRW 来防范TRW2000的跟踪
3、在对UnhandledExceptionFilter及其要引入的API函数在调用之前检查入口代码是否为0xCC。防范在API函数上设断点跟踪。
4、在对要引入的API函数在调用时,并不从入口处执行,而是进入其中的代码执行。防范在入口几处的代码上设断点跟踪。
4、检测 EntryPoint 和 NumberOfSections 是否被修改,来防范程序被修改,或者是SMC的方法进行破解。
5、把文件头部的所有数据进行累加和CRC比较是否被修改,来防范程序被修改或者破解。
6、使用"花指令"和SMC的方法来分段还原代码,来防范静态分析或者增加动态跟踪的难度。
7、修改了代码段中的JMP [xxxxxxxx]使之指向指向内存中动态申请的地址,防范用一般方法脱壳。
8、运行时破坏了PE结构中的所有数据,来防范用ProcDump等工具脱壳或者DUMP内存映象。
9、修改了WINDOWS加载环境中保留的PE结构,来防范ProcDump等工具脱壳或者DUMP内存映象。
还有一些,不足列举。
样例文件: znzdatII.exe (指南针数据转换程序)
下载地址: http://202.102.230.15/tanfu/soft/mdat/znzdatII.exe
加壳方式: PE-ShiELD v0.2b2
检测工具: FileInfo v2.30
目标: 手动脱壳
脱壳工具: SoftICE 4.05,ICEDUMP 6.0168,PEditor 1.6,HEX WorkShop
2.10,HIEW 5.91
作者: ljttt
写作日期: 2000-10-28
1、启动ICEDUMP。
2、Ctrl-D进入SoftICE,设下断点
bpint 3
3、用PEditor 1.6打开znzdatII.exe,记下其中的关键,然后单击 break'n'enter按钮,单击 Run 按钮。将中断进入SoftICE。
Entry Point: AA000
Image Base: 400000
Image Size: AD000
Size of Headers: 600
4、现在开始了我们的艰苦历程。由于显示的都是"花指令",所以无法正确显示出正确的反汇编结果。列举代码也没有意义。不过跟踪了一次后,心里有数以后,可以在某些自己认为比较关键的代码处设下断点,以便下次跟踪时可以快速按F5到此。
5、我们来看看 UnhandleExceptionFilter 函数入口代码的比较代码:
015F:004AA2F9 EB01
JMP 004AA2FC
<--反汇编正确的代码
015F:004AA2FB E98D9DB511 JMP
1200408D
<--反汇编不正确的代码
015F:004AA300 0000
ADD [EAX],AL
015F:004AA302 EB02
JMP 004AA306
015F:004AA304 CD20
INT 20 VXDJmp 000D,4DE8
015F:004AA30A 00EB
ADD BL,CH
015F:004AA30C 01EA
ADD EDX,EBP
015F:004AA30E 8038CC CMP
BYTE PTR [EAX],CC <--这句是关键!
015F:004AA311 EB01
JMP 004AA314
015F:004AA313 E90F84AF03 JMP
03FA2727
015F:004AA318 0000
ADD [EAX],AL
可以看到许多代码反汇编的结果不正确。这是其中一处在主程序中反跟踪代码,还有许多在子程序中的反跟踪代码就不一一列举了。
我们可以记住 CMP BYTE BTR [EAX],CC 的代码地址 004AA30E ,那么设下断点后下次跟踪时就方便了。其他类似。
6、我们再来看看 检测 TRW2000 的地方。(记住代码地址 004AA5C3 )
015F:004AA59C 6800008000 PUSH
00800000
015F:004AA5A1 EB01
JMP 004AA5A4
<--反汇编正确的代码
015F:004AA5A3 C78D8560100000EB02EAMOV DWORD PTR [EBP+00106085],EA02EB00
<--反汇编不正确的代码
015F:004AA5AD 0450
ADD AL,50
015F:004AA5AF EB01
JMP 004AA5B2
015F:004AA5B1 C78B858D110000EB01EAMOV DWORD PTR [EBX+00118D85],EA01EB00
015F:004AA5BB E821070000 CALL
004AACE1
<--反跟踪,检测 \\.\TRW.VXD 来防范TRW2000的跟踪
015F:004AA5C0 EB01
JMP 004AA5C3
015F:004AA5C2 C783F8FFEB01EA0F85E3MOV DWORD PTR [EBX+01EBFFF8],E3850FEA
015F:004AA5C3 83F8FF CMP
EAX,-01
<--比较的地方
015F:004AA5C6 EB01
JMP 004AA5C9
015F:004AA5C8 EA0F85E3000000 JMP
0000:00E3850F
015F:004AA5CF 8D8585100000 LEA
EAX,[EBP+00001085]
015F:004AA5D5 EB01
JMP 004AA5D8
015F:004AA5D7 EA8D9D92100000 JMP
0000:10929D8D
015F:004AA5DE EB02
JMP 004AA5E2
7、好了,现在快到了关键的地方了。我们来看看:
015F:004AA638 6A00
PUSH 00
015F:004AA63A EB01
JMP 004AA63D
<--反汇编正确的代码
015F:004AA63C E96A00EB01 JMP
0235A6AB
<--反汇编不正确的代码
015F:004AA641 C78B8592100000EB01EAMOV DWORD PTR [EBX+00109285],EA01EB00
015F:004AA64B E891060000 CALL
004AACE1
<--好象是CreateThread调用
015F:004AA650 EB01
JMP 004AA653
015F:004AA652 E9FF95A510 JMP
10F03C56
015F:004AA653 FF95A5100000 CALL
[EBP+000010A5] <--这里是ExitThread调用
015F:004AA659 8B859D110000 MOV
EAX,[EBP+0000119D] <--注意要先在此处设下断点
015F:004AA65F E97D060000 JMP
004AACE1
015F:004AA664 8B85E0110000 MOV
EAX,[EBP+000011E0]
015F:004AA66A E972060000 JMP
004AACE1
015F:004AA66F 8B85E4110000 MOV
EAX,[EBP+000011E4]
在 CALL [EBP+000010A5] 处我们停下来,在其后的代码 MOV EAX,[EBP+0000119D] 处设下断点
bpx 004AA659
然后按F10继续,否则程序将直接执行。那么这一次的跟踪就结束了。如果对比在 CALL [EBP+0000119D] 执行前后的 401000 代码处的数据就可以发现执行完后代码加载到内存中了。这时的代码是还原后的代码。不过还有些没有还原。这也是PE-SHiELD防范脱壳的技巧吧。其中一处是代码段中
JMP [xxxxxxxxx] 语句没有完全还原,另外就是 .idata Section所在的Import Table部分没有还原了。
8、我们继续跟踪,现在我们来看看如何得到完整的 .idata Section 。当我们到如下代码处时:
015F:004AA94B 0FB6C9 MOVZX
ECX,CL
015F:004AA94E EB01
JMP 004AA951
015F:004AA950 EA8B06EB01C889 JMP
89C8:01EB068B
015F:004AA957 16
PUSH SS
015F:004AA958 EB01
JMP 004AA95B
015F:004AA95A 6833D3EB01 PUSH
01EBD333
015F:004AA95F CA8907 RETF
0789
015F:004AA962 EB01
JMP 004AA965
015F:004AA964 C783C604EB01E283C704MOV DWORD PTR [EBX+01EB04C6],04C783E2
015F:004AA96E EB01
JMP 004AA971
015F:004AA970 684B75DAEB PUSH
EBDA754B
015F:004AA975 02EA
ADD CH,DL
015F:004AA977 04F3
ADD AL,F3
015F:004AA979 A4
MOVSB
015F:004AA97A 8B9549110000 MOV
EDX,[EBP+00001149] <--从这里开始的代码将没有"花指令"了,我们终于走出了沼泽地
015F:004AA980 2B9541110000 SUB
EDX,[EBP+00001141]
015F:004AA986 0395C9110000 ADD
EDX,[EBP+000011C9]
015F:004AA98C 89954D110000 MOV
[EBP+0000114D],EDX
015F:004AA992 8BB589110000 MOV
ESI,[EBP+00001189]
015F:004AA998 0BF6
OR ESI,ESI
015F:004AA99A 7433
JZ 004AA9CF
015F:004AA99C 03B5C9110000 ADD
ESI,[EBP+000011C9]
015F:004AA9A2 83C610 ADD
ESI,10
015F:004AA9A5 8B9549110000 MOV
EDX,[EBP+00001149]
015F:004AA9AB 2B95C5110000 SUB
EDX,[EBP+000011C5]
015F:004AA9B1 0BD2
OR EDX,EDX
015F:004AA9B3 7405
JZ 004AA9BA
015F:004AA9B5 E854040000 CALL
004AAE0E
015F:004AA9BA 8B95C9110000 MOV
EDX,[EBP+000011C9]
015F:004AA9C0 2B95D1110000 SUB
EDX,[EBP+000011D1]
015F:004AA9C6 0BD2
OR EDX,EDX
015F:004AA9C8 7405
JZ 004AA9CF
015F:004AA9CA E83F040000 CALL
004AAE0E
015F:004AA9CF 80BD3C11000000 CMP
BYTE PTR [EBP+0000113C],00
015F:004AA9D6 7424
JZ 004AA9FC
015F:004AA9D8 6A04
PUSH 04
015F:004AA9DA 6800100000 PUSH
00001000
015F:004AA9DF FFB5AD110000 PUSH
DWORD PTR [EBP+000011AD]
015F:004AA9E5 6A00
PUSH 00
015F:004AA9E7 E86DFCFFFF CALL
004AA659
015F:004AA9EC 0BC0
OR EAX,EAX
015F:004AA9EE 0F8469FDFFFF JZ
004AA75D
015F:004AA9F4 8BF0
MOV ESI,EAX
015F:004AA9F6 8985A1110000 MOV
[EBP+000011A1],EAX
015F:004AA9FC 8B8DC9110000 MOV
ECX,[EBP+000011C9]
015F:004AAA02 8B9549110000 MOV
EDX,[EBP+00001149]
015F:004AAA08 8B420C MOV
EAX,[EDX+0C]
<--大循环体开始处
015F:004AAA0B 0BC0
OR EAX,EAX
015F:004AAA0D 0F84F3000000 JZ
004AAB06
015F:004AAA13 894A0C MOV
[EDX+0C],ECX
<--注意!
015F:004AAA16 03854D110000 ADD
EAX,[EBP+0000114D]
015F:004AAA1C 52
PUSH EDX
015F:004AAA1D 51
PUSH ECX
015F:004AAA1E 50
PUSH EAX
015F:004AAA1F 50
PUSH EAX
015F:004AAA20 C6853F11000000 MOV
BYTE PTR [EBP+0000113F],00
015F:004AAA27 8B18
MOV EBX,[EAX]
015F:004AAA29 81E3DFDFDF00 AND
EBX,00DFDFDF
015F:004AAA2F 81FB4D464300 CMP
EBX,0043464D
015F:004AAA35 7518
JNZ 004AAA4F
015F:004AAA37 8B5805 MOV
EBX,[EAX+05]
015F:004AAA3A 81E3FFDFDFDF AND
EBX,DFDFDFFF
015F:004AAA40 81FB2E444C4C CMP
EBX,4C4C442E
015F:004AAA46 7507
JNZ 004AAA4F
015F:004AAA48 C6853F11000001 MOV
BYTE PTR [EBP+0000113F],01
015F:004AAA4F 8BD8
MOV EBX,EAX
015F:004AAA51 E80EFCFFFF CALL
004AA664
<--记得好象是把DLL链接库名称还原
015F:004AAA56 5B
POP EBX
015F:004AAA57 59
POP ECX
015F:004AAA58 5A
POP EDX
015F:004AAA59 0BC0
OR EAX,EAX
015F:004AAA5B 7512
JNZ 004AAA6F
015F:004AAA5D 52
PUSH EDX
015F:004AAA5E 51
PUSH ECX
015F:004AAA5F 53
PUSH EBX
015F:004AAA60 E80AFCFFFF CALL
004AA66F
<--记得好象是加载DLL链接库吧
015F:004AAA65 0BC0
OR EAX,EAX
015F:004AAA67 0F8473FCFFFF JZ
004AA6E0
015F:004AAA6D 59
POP ECX
015F:004AAA6E 5A
POP EDX
015F:004AAA6F E8EF000000 CALL
004AAB63
<--注意!把DLL链接库名称K掉
015F:004AAA74 8985D40A0000 MOV
[EBP+00000AD4],EAX
015F:004AAA7A 8B32
MOV ESI,[EDX]
015F:004AAA7C 890A
MOV [EDX],ECX
<--注意!
015F:004AAA7E 8B7A10 MOV
EDI,[EDX+10]
015F:004AAA81 894A10 MOV
[EDX+10],ECX
<--注意!
015F:004AAA84 0BF6
OR ESI,ESI
015F:004AAA86 7502
JNZ 004AAA8A
015F:004AAA88 8BF7
MOV ESI,EDI
015F:004AAA8A 03B54D110000 ADD
ESI,[EBP+0000114D]
015F:004AAA90 03BD4D110000 ADD
EDI,[EBP+0000114D]
015F:004AAA96 8B06
MOV EAX,[ESI]
<--小循环体开始处
015F:004AAA98 0BC0
OR EAX,EAX
015F:004AAA9A 7462
JZ 004AAAFE
015F:004AAA9C 890E
MOV [ESI],ECX
<--注意!
015F:004AAA9E 7905
JNS 004AAAA5
015F:004AAAA0 0FB7C0 MOVZX
EAX,AX
015F:004AAAA3 EB26
JMP 004AAACB
015F:004AAAA5 03854D110000 ADD
EAX,[EBP+0000114D]
015F:004AAAAB 66C7000000 MOV
WORD PTR [EAX],0000 <--注意!
015F:004AAAB0 40
INC EAX
015F:004AAAB1 40
INC EAX
015F:004AAAB2 53
PUSH EBX
015F:004AAAB3 56
PUSH ESI
015F:004AAAB4 50
PUSH EAX
015F:004AAAB5 8B9DA9110000 MOV
EBX,[EBP+000011A9]
015F:004AAABB 8BF0
MOV ESI,EAX
015F:004AAABD E8A8030000 CALL
004AAE6A
<--记得好象是还原引入函数名称
015F:004AAAC2 899DA9110000 MOV
[EBP+000011A9],EBX
015F:004AAAC8 58
POP EAX
015F:004AAAC9 5E
POP ESI
015F:004AAACA 5B
POP EBX
015F:004AAACB 50
PUSH EAX
015F:004AAACC 52
PUSH EDX
015F:004AAACD 56
PUSH ESI
015F:004AAACE 57
PUSH EDI
015F:004AAACF 51
PUSH ECX
015F:004AAAD0 53
PUSH EBX
015F:004AAAD1 50
PUSH EAX
015F:004AAAD2 50
PUSH EAX
015F:004AAAD3 6878563412 PUSH
12345678
015F:004AAAD8 E89DFBFFFF CALL
004AA67A
<--加载引入函数获得函数地址
015F:004AAADD 5B
POP EBX
015F:004AAADE 0BC0
OR EAX,EAX
015F:004AAAE0 0F8443FCFFFF JZ
004AA729
015F:004AAAE6 E878000000 CALL
004AAB63
<--注意!把引入函数名称K掉
015F:004AAAEB 5B
POP EBX
015F:004AAAEC 59
POP ECX
015F:004AAAED 5F
POP EDI
015F:004AAAEE E887000000 CALL
004AAB7A
<--注意!把IMPORT_THUNK_DATA区K掉
015F:004AAAF3 5E
POP ESI
015F:004AAAF4 5A
POP EDX
015F:004AAAF5 5B
POP EBX
015F:004AAAF6 83C604 ADD
ESI,04
015F:004AAAF9 83C704 ADD
EDI,04
015F:004AAAFC EB98
JMP 004AAA96
<--小循环体结束处
015F:004AAAFE 83C214 ADD
EDX,14
015F:004AAB01 E902FFFFFF JMP
004AAA08
<--大循环体结束处
015F:004AAB06 EB01
JMP 004AAB09
<--大循环退出后将到此
以上列出的所有代码所做的工作主要获得函数地址,但是其中有许多代码来防止你跟踪后DUMP得到完整的Import Table。以下说明一下:
首先程序把加密的idata Section复制到申请的内存中(内存地址保存在 EDI 中)。把加密的DLL名称还原,然后LoadLibrary加载DLL动态链接库,完成后又把DLL名称用'K'掉。然后把该DLL加密的引入函数名称还原,用GetProcAddress得到函数地址。完成后又把函数名称用'K'掉。而且其中还有多处代码对IMPORT_THUNK_DATA区的数据进行了处理。这样来防止你得到完整的Import
Table。因此如果不做处理,内存中始终不会存在一个完整的Import Table。这也是加壳程序用到的防脱壳的技巧吧。分析了其中的代码后,我们仍然可以想办法得到完整的Import
Table。
其中我标记为"注意!"的代码共有8处,列举如下:
1、015F:004AAA13 894A0C
MOV [EDX+0C],ECX
<--注意!
2、015F:004AAA6F E8EF000000 CALL
004AAB63
<--注意!把DLL链接库名称K掉
3、015F:004AAA7C 890A
MOV [EDX],ECX
<--注意!
4、015F:004AAA81 894A10
MOV [EDX+10],ECX
<--注意!
5、015F:004AAA9C 890E
MOV [ESI],ECX
<--注意!
6、015F:004AAAAB 66C7000000 MOV
WORD PTR [EAX],0000
<--注意!
7、015F:004AAAE6 E878000000 CALL
004AAB63
<--注意!把引入函数名称K掉
8、015F:004AAAEE E887000000 CALL
004AAB7A
<--注意!把IMPORT_THUNK_DATA区K掉
好!我们把这些地址的代码全部用NOP代替。(注意代码长度不同,NOP掉的字节数也不一样)这样在循环结束时我们就有了一个完整的Import Table了。
9、由于以上代码是个循环,我们并不需要详细跟踪他,所以可以在 JMP 004AAB09 处设下一个断点
bpx 004AAB06
然后按F5键,这时,程序中断在此处,这时,我们需要DUMP出这个完整的idata Section了(也就是Import Table)。下指令
/dump 5D0000 3000 c:\temp\idata.bin
(其中 5D0000 中申请的内存地址的首地址, 3000 为 idata Section 的大小,此命令用法为ICEDUMP 6.0168,低版本不同)
10、然后,我们继续跟踪,不远处就会到如下:
015F:004AAB53 B95B0B0000 MOV
ECX,00000B5B
015F:004AAB58 EB01
JMP 004AAB5B
015F:004AAB5A EAF3AA61EB01EA JMP
EA01:EB61AAF3
015F:004AAB61 FFE0
- 标 题:小丁丁 和 WinDos2000 过来看看(多谢帮助 ^_^),哪位1212也过来看看吧 ----对PE-ShiELD v0.2b2加壳程序的脱... (16千字)
- 作 者:ljttt
- 时 间:2000-10-28 20:16:41
- 链 接:http://bbs.pediy.com