对Crunch v1.1加壳程序的手动脱壳及反跟踪代码的一点分析
【声明】
我写文章以交流为主,希望大家在转载时能保持文章的完整性。
【前言】
由于我现在还没有破解版的Crunch v1.1,所以就拿未注册版的Crunch来测试。好象未注册版的Crunch加壳的程序的名字有限制,其他的我就不清楚了。由于我DOWN的这个文件是根据看雪论坛的一个贴子提供的地址下载的。连帮助文件也没有。:-(
而且目前我手头也没有注册版的Crunch,所以只好以未注册版的Crunch加壳Notepad.EXE程序来进行说明。
样例文件: bitarts_evaluation.exe (把Notepad.EXE加壳后的文件)
(未注册版Crunch加壳的程序文件名都是这个,不过可以在跟踪中发现文件名比较的地方)
加壳方式: 未注册版Crunch v1.1加壳
目标: 手动脱壳
作者: ljttt
写作日期: 2000-10-02
1、这次我们用ProcDump提供的Bhrama Server的功能来手动脱壳,这样可以简化一点手动脱壳的麻烦。所以首先我们启动ProcDump,选择Option/Rebuild
new import table。点击Bhrama Server,这时就启动了服务器,将等待客户命令。
2、Ctrl-D进入SoftICE,设断点
bpint 3
3、启动PEditor,打开bitarts_evaluation.exe,点击break'n'enter。单击Run。这时将中断进入SoftICE。可以看到如下提示。
?You have to enter "eb eip 55" before you continue ! ?
为了继续跟踪,我们根据提示下指令
eb eip 55
现在将显示如下:
015F:0040D000 55
PUSH EBP <--这就是我们修改后的结果
015F:0040D001 E800000000 CALL
0040D006
015F:0040D006 5D
POP EBP
4、继续跟踪到如下处:
015F:0040D0AC FF95B1320000 CALL
[EBP+000032B1]
015F:0040D0B2 83C408 ADD
ESP,08
015F:0040D0B5 8BB5AD320000 MOV
ESI,[EBP+000032AD]
015F:0040D0BB BFC6000000 MOV
EDI,000000C6
015F:0040D0C0 03FD
ADD EDI,EBP
015F:0040D0C2 8BC8
MOV ECX,EAX
015F:0040D0C4 F3A4
REPZ MOVSB <--在此处停下,此指令执行后,以下的指令将改变,这就是SMC的技巧,以后还有多处,就不一一列举了。
015F:0040D0C6 8B07
MOV EAX,[EDI] <--现在我们看到的是加密的代码,只有上一指令执行后才会显示正确的指令代码
015F:0040D0C8 D581
AAD
015F:0040D0CA C23813 RET
1338
5、在REPZ MOVSB指令执行后我们将看到如下的正确代码:
015F:0040D0C6 8BD5
MOV EDX,EBP
015F:0040D0C8 81C238130000 ADD
EDX,00001338
015F:0040D0CE 52
PUSH EDX
015F:0040D0CF 33C0
XOR EAX,EAX
015F:0040D0D1 8CD8
MOV AX,DS
015F:0040D0D3 A804
TEST AL,04
015F:0040D0D5 7408
JZ 0040D0DF
015F:0040D0D7 B402
MOV AH,02
015F:0040D0D9 CD1A
INT 1A
015F:0040D0DB 8BC2
MOV EAX,EDX
015F:0040D0DD EB02
JMP 0040D0E1
015F:0040D0DF 0F31
RDTSC
015F:0040D0E1 33D2
XOR EDX,EDX
015F:0040D0E3 69C00D661900 IMUL
EAX,EAX,0019660D
015F:0040D0E9 05CD0D0100 ADD
EAX,00010DCD
015F:0040D0EE 8985383A0000 MOV
[EBP+00003A38],EAX
015F:0040D0F4 BB56340200 MOV
EBX,00023456
015F:0040D0F9 43
INC EBX
015F:0040D0FA F7F3
DIV EBX
015F:0040D0FC 8BC2
MOV EAX,EDX
015F:0040D0FE 5A
POP EDX
015F:0040D0FF 90
NOP
015F:0040D100 FFD2
CALL EDX <--在此处我们要停下,如果你想了解反跟踪代码,可以进入看看
015F:0040D102 CC
INT 3
015F:0040D103 CC
INT 3
015F:0040D104 E80E130000 CALL
0040E417
015F:0040D109 E838100000 CALL
0040E146 <--反跟踪
6、在执行到 CALL EDX 指令处时,我们下指令
r eip eip+E
r esi 10
这样就可以跳过这一段反跟踪的代码。
7、这里我们来了解一下 CALL EDX 中的一段反跟踪代码
015F:0040E369 0F010B SIDT
FWORD PTR [EBX] <--取IDTR的内容
015F:0040E36C 8B7302 MOV
ESI,[EBX+02] <--取IDT表的基地址
015F:0040E36F 83C608 ADD
ESI,08
015F:0040E372 8B1E
MOV EBX,[ESI]
<--取int 1的低位偏移
015F:0040E374 53
PUSH EBX
015F:0040E375 56
PUSH ESI
015F:0040E376 83C610 ADD
ESI,10
015F:0040E379 8B36
MOV ESI,[ESI]
<--取int 3的低位偏移
015F:0040E37B 81E6FFFF0000 AND
ESI,0000FFFF
015F:0040E381 81E3FFFF0000 AND
EBX,0000FFFF
015F:0040E387 2BF3
SUB ESI,EBX
015F:0040E389 83FE1E CMP
ESI,1E
<--比较低位偏移
015F:0040E38C B090
MOV AL,90
015F:0040E38E 7427
JZ 0040E3B7
<--关键了!
015F:0040E390 8BDD
MOV EBX,EBP
015F:0040E392 81C311140000 ADD
EBX,00001411
015F:0040E398 0F010B SIDT
FWORD PTR [EBX] <--取IDTR的内容
015F:0040E39B 8B7B02 MOV
EDI,[EBX+02] <--取IDT表的基地址
015F:0040E39E 83C708 ADD
EDI,08
015F:0040E3A1 8B4704 MOV
EAX,[EDI+04] <--取int 1的高位偏移
015F:0040E3A4 668B07 MOV
AX,[EDI] <--取int
1的低位偏移
015F:0040E3A7 8038E9 CMP
BYTE PTR [EAX],E9 <--判断int 1中断处理程序第一个字节是否为JMP指令
015F:0040E3AA B090
MOV AL,90
015F:0040E3AC 7409
JZ 0040E3B7
<--关键了!
015F:0040E3AE 83FE1E CMP
ESI,1E
015F:0040E3B1 B090
MOV AL,90
015F:0040E3B3 7402
JZ 0040E3B7
<--关键了!
015F:0040E3B5 045B
ADD AL,5B
8、这里我们来了解一下 CALL 0040E146 中的反跟踪代码
015F:0040E146 8B8587390000 MOV
EAX,[EBP+00003987]
015F:0040E14C 8B8DC5300000 MOV
ECX,[EBP+000030C5]
015F:0040E152 C1E908 SHR
ECX,08
015F:0040E155 33D2
XOR EDX,EDX
015F:0040E157 B902000000 MOV
ECX,00000002
015F:0040E15C F7F1
DIV ECX
015F:0040E15E 0BD2
OR EDX,EDX
015F:0040E160 7502
JNZ 0040E164
<--关键了!
015F:0040E162 EB27
JMP 0040E18B
==> 0040E164 8BDD
MOV EBX,EBP
015F:0040E166 81C38B390000 ADD
EBX,0000398B
015F:0040E16C 0F010B SIDT
FWORD PTR [EBX] <--取IDTR的内容
015F:0040E16F 8B7302 MOV
ESI,[EBX+02] <--取IDT表的基地址
015F:0040E172 83C608 ADD
ESI,08
015F:0040E175 8B1E
MOV EBX,[ESI]
<--取int 1的低位偏移
015F:0040E177 83C610 ADD
ESI,10
015F:0040E17A 8B36
MOV ESI,[ESI]
<--取int 3的低位偏移
015F:0040E17C 81E6FFFF0000 AND
ESI,0000FFFF
015F:0040E182 81E3FFFF0000 AND
EBX,0000FFFF
015F:0040E188 2BF3
SUB ESI,EBX
<--ESI返回低位偏移之差
015F:0040E18A C3
RET
015F:0040E18B BE10000000 MOV
ESI,00000010 <--ESI返回0x10
015F:0040E190 C3
RET
9、我们继续跟踪来到如下,(这也是由SMC得来的)
015F:0040D1F7 49
DEC ECX
015F:0040D1F8 83F900 CMP
ECX,00
015F:0040D1FB 75EB
JNZ 0040D1E8
015F:0040D1FD 59
POP ECX
015F:0040D1FE 81E942000000 SUB
ECX,00000042
015F:0040D204 51
PUSH ECX
015F:0040D205 E873100000 CALL
0040E27D <--内有反跟踪代码
015F:0040D20A 33C0
XOR EAX,EAX
015F:0040D20C 59
POP ECX
015F:0040D20D 8AC1
MOV AL,CL
015F:0040D20F 8BDD
MOV EBX,EBP
015F:0040D211 81C3A5320000 ADD
EBX,000032A5
015F:0040D217 8BB57D390000 MOV
ESI,[EBP+0000397D]
015F:0040D21D 50
PUSH EAX
015F:0040D21E 51
PUSH ECX
015F:0040D21F 53
PUSH EBX
015F:0040D220 E8D10E0000 CALL
0040E0F6
015F:0040D225 5B
POP EBX
10、进入 CALL 0040E27D 我们来看看其中的反跟踪代码。
==> 0040E29D 8BDD
MOV EBX,EBP
015F:0040E29F 81C311140000 ADD
EBX,00001411
015F:0040E2A5 0F010B SIDT
FWORD PTR [EBX] <--取IDTR内容
015F:0040E2A8 8B7B02 MOV
EDI,[EBX+02] <--取IDT表基地址
015F:0040E2AB 83C708 ADD
EDI,08
015F:0040E2AE 8B4704 MOV
EAX,[EDI+04] <--取int 1的高位偏移
015F:0040E2B1 668B07 MOV
AX,[EDI] <--取int
1的低位偏移
015F:0040E2B4 8038E9 CMP
BYTE PTR [EAX],E9 <--判断int 1中断处理程序第一个字节是否为JMP指令
015F:0040E2B7 750B
JNZ 0040E2C4
<--关键了!
015F:0040E2B9 BE1E000000 MOV
ESI,0000001E <--发现跟踪ESI=1E
015F:0040E2BE 8BDD
MOV EBX,EBP
015F:0040E2C0 52
PUSH EDX
015F:0040E2C1 53
PUSH EBX
015F:0040E2C2 EB28
JMP 0040E2EC
015F:0040E2C4 8BDD
MOV EBX,EBP
015F:0040E2C6 52
PUSH EDX
015F:0040E2C7 53
PUSH EBX
015F:0040E2C8 81C311140000 ADD
EBX,00001411
015F:0040E2CE 0F010B SIDT
FWORD PTR [EBX] <--取IDTR内容
015F:0040E2D1 8B7302 MOV
ESI,[EBX+02] <--取IDT表基地址
015F:0040E2D4 83C608 ADD
ESI,08
015F:0040E2D7 8B1E
MOV EBX,[ESI]
<--取int 1的低位偏移
015F:0040E2D9 83C610 ADD
ESI,10
015F:0040E2DC 8B36
MOV ESI,[ESI]
<--取int 3的低位偏移
015F:0040E2DE 81E6FFFF0000 AND
ESI,0000FFFF
015F:0040E2E4 81E3FFFF0000 AND
EBX,0000FFFF
015F:0040E2EA 2BF3
SUB ESI,EBX
<--计算低位偏移之差
015F:0040E2EC 8BDE
MOV EBX,ESI
015F:0040E2EE 8BD3
MOV EDX,EBX
<--发现跟踪EDX=ESI=1E
015F:0040E2F0 5B
POP EBX
015F:0040E2F1 81C3DB110000 ADD
EBX,000011DB <--以后用不正确的EDX和ESI来SMC自身的代码,你说会发生什么现象!
015F:0040E2F7 33C0
XOR EAX,EAX
015F:0040E2F9 8A03
MOV AL,[EBX]
015F:0040E2FB 03C6
ADD EAX,ESI
015F:0040E2FD 8803
MOV [EBX],AL
015F:0040E2FF 83C304 ADD
EBX,04
015F:0040E302 8A03
MOV AL,[EBX]
015F:0040E304 8BF2
MOV ESI,EDX
015F:0040E306 C1E602 SHL
ESI,02
015F:0040E309 03C6
ADD EAX,ESI
015F:0040E30B 8803
MOV [EBX],AL
015F:0040E30D 5A
POP EDX
015F:0040E30E C3
RET
015F:0040E30F 8BDD
MOV EBX,EBP
015F:0040E311 BE10000000 MOV
ESI,00000010
015F:0040E316 BA10000000 MOV
EDX,00000010 <--未发现跟踪时ESI=10,EDX=10
015F:0040E31B 81C3DB110000 ADD
EBX,000011DB <--以下是用SMC的技巧来还原以后的代码
015F:0040E321 33C0
XOR EAX,EAX
015F:0040E323 8A03
MOV AL,[EBX]
015F:0040E325 03C6
ADD EAX,ESI
015F:0040E327 8803
MOV [EBX],AL
015F:0040E329 83C304 ADD
EBX,04
015F:0040E32C 8A03
MOV AL,[EBX]
015F:0040E32E 8BF2
MOV ESI,EDX
015F:0040E330 C1E602 SHL
ESI,02
015F:0040E333 03C6
ADD EAX,ESI
015F:0040E335 8803
MOV [EBX],AL
015F:0040E337 C3
RET
11、看完反跟踪代码,我们回到主程序继续跟踪到如下代码处
015F:0040D9C2 FFB54C210000 PUSH
DWORD PTR [EBP+0000214C]
015F:0040D9C8 FF956E1E0000 CALL
[EBP+00001E6E]
015F:0040D9CE 83854021000014 ADD
DWORD PTR [EBP+00002140],14
015F:0040D9D5 FF8D94300000 DEC
DWORD PTR [EBP+00003094]
015F:0040D9DB 6683BD9430000000 CMP WORD
PTR [EBP+00003094],00
015F:0040D9E3 0F85FAFDFFFF JNZ
0040D7E3
015F:0040D9E9 B8BB140000 MOV
EAX,000014BB
015F:0040D9EE 03C5
ADD EAX,EBP
015F:0040D9F0 FFE0
JMP EAX <--此处将跳转到文件名比较的地方
015F:0040D9F2 FFA5AB390000 JMP
[EBP+000039AB] <--跳到以下代码处
我们分别先在 JMP EAX 和 JMP [EBP+000039AB] 处设下断点。先我们来看看加壳程序是如何进行文件名比较来防止你修改文件名的。
12、在 JMP EAX 跳转后,我们将来到如下代码处
.....之前的代码将调用GetModuleName得到文件名称,以下的代码是分析比较的部分
015F:0040E503 740F
JZ 0040E514
015F:0040E505 8A1E
MOV BL,[ESI] <--[ESI]指向文件名称字符串
015F:0040E507 80FB5C CMP
BL,5C <--判断是否为"\"字符
015F:0040E50A 7415
JZ 0040E521
015F:0040E50C 80C320 ADD
BL,20 <--转换成小写字母
015F:0040E50F 881E
MOV [ESI],BL
015F:0040E511 4E
DEC ESI
015F:0040E512 EBF1
JMP 0040E505
015F:0040E514 90
NOP
015F:0040E515 8A1E
MOV BL,[ESI]
015F:0040E517 80FB5C CMP
BL,5C
015F:0040E51A 7405
JZ 0040E521
015F:0040E51C 881E
MOV [ESI],BL
015F:0040E51E 4E
DEC ESI
015F:0040E51F EBF4
JMP 0040E515
015F:0040E521 46
INC ESI
015F:0040E522 BF66160000 MOV
EDI,00001666
015F:0040E527 03FD
ADD EDI,EBP <--EDI指向字符串"bitarts"
015F:0040E529 33C9
XOR ECX,ECX
015F:0040E52B 33C0
XOR EAX,EAX
015F:0040E52D 8A06
MOV AL,[ESI]
015F:0040E52F 3C00
CMP AL,00
015F:0040E531 7438
JZ 0040E56B <--判断字符串是否比较结束
015F:0040E533 83F905 CMP
ECX,05
015F:0040E536 7433
JZ 0040E56B <--是否匹配完全相同,是则跳走
015F:0040E538 3807
CMP [EDI],AL <--判断文件名称是否相等
015F:0040E53A 7505
JNZ 0040E541 <--不等,则跳走
015F:0040E53C 46
INC ESI
015F:0040E53D 47
INC EDI
015F:0040E53E 41
INC ECX
015F:0040E53F
JMP 0040E52D <--循环
13、知道了程序如何比较文件名称,按F5继续,将中断在我们设好的断点 JMP [EBP+000039AB] 处。我们继续跟踪到如下代码
015F:00410D99 BBCD150000 MOV
EBX,000015CD
015F:00410D9E 03DD
ADD EBX,EBP
015F:00410DA0 53
PUSH EBX
015F:00410DA1 50
PUSH EAX
015F:00410DA2 FF955E1E0000 CALL
[EBP+00001E5E]
015F:00410DA8 FFD0
CALL EAX
015F:00410DAA 8B8554210000 MOV
EAX,[EBP+00002154]
015F:00410DB0 0185C1300000 ADD
[EBP+000030C1],EAX
015F:00410DB6 FFA59B390000 JMP
[EBP+0000399B] <--此处跳转到最后的一段代码
015F:00410DBC C3
RET
14、在 JMP [EBP+0000399B] 处跳转到如下最后一处代码。这里我们可以DUMP得到完整的文件了。
015F:0040D0C6 61
POPAD
015F:0040D0C7 5D
POP EBP
015F:0040D0C8 8B85C1300000 MOV
EAX,[EBP+000030C1]
015F:0040D0CE 5D
POP EBP
015F:0040D0CF FFE0
JMP EAX
<--此时,EAX就是OEP。在此处我们DUMP的时候到了
在 JMP EAX 处我们下指令(这里我使用的是ICEDUMP 6.0168的命令使用方法)
/bhrama ProcDump32 - Dumper Server
这时程序将回到WINDOWS,过一段时间,如果成功,将出现文件保存对话框让你选择想保存的文件名。存完将回到SoftICE,好!我们按F5结束工作。
【后记】
应该说以上我介绍的并不是以脱壳为主,而是介绍一些Crunch加壳程序的特征,也希望大家以此能进行更多的分析来相互交流。
如果你按此法脱壳,可能你要花费大把大把的时间。如果你想更快的脱壳,可以参考我写的ProcDump的Script,或者根据其中脱壳的方法在加密代码还原后搜索特征代码,那样来得更快。
- 标 题:对Crunch v1.1加壳程序的手动脱壳及反跟踪代码的一点分析 (15千字)
- 作 者:ljttt
- 时 间:2000-10-2 19:01:05
- 链 接:http://bbs.pediy.com