今天闲着没事,就把一些简单的壳分析http://bbs.pediy.com/showthread.php?t=106596里面的附件都练习了一下,顺便做个笔记。
1、Upx
这个是个压缩壳,第一行指令PUSHAD,没什么可说的硬件断点就搞定了,如下是脚本,用于找到入口点(两次到入口),准确的说在入口的下一行
var addr
mov addr,esp
sub addr,4
bphws addr,"w"
run
run
2、Aspack
这个压缩壳跟上面的如出一辙,下面脚本就搞定了:
var addr
mov addr,esp
sub addr,4
bphws addr,"w"
run
BPHWC addr
sti
3、Petite
这个也跟上面差不多,只是入口貌似有点复杂罢了,不过没关系还是直接上硬件断点。这个中断3次就可以到入口了。最后转存的文件需要重建一下。
var addr
var count
mov count,0
mov addr,esp
sub addr,4
bphws addr,"w"
lb:
run
add count,1
cmp count,3
jb lb
4、Winunpack
这个文件运行错误,不管。
5、Pencrypt
这个壳运行开头在原来的代码区域内,不过后面有个跨区块的跳转,不用说肯定就是去处理代码的。对于这种情况用内存断点搞定。在这里我先用硬件断点停在外壳代码处,然后对数据段下写断点,最后在数据段下访问断点,其实没啥说滴,脚本奉上:
var addr
mov addr,esp
sub addr,4
bphws addr,"w"
run
bphwc addr
bpwm 405000,1000//数据段内存写入断点
run
bpmc
bprm 401000,4000
run//抵达入口
6、Acprotect
这个壳有点难度,花了我好几个小时。这个壳找入口倒不难,内存断点直接搞定。先在.idata(开始用.data不成功,也没有继续研究)下内存写入断点,中断后,在.text下内存访问断点。
004010DD 3C 22 CMP AL,22
004010DF 75 1B JNZ SHORT UltraPro.004010FC
004010E1 56 PUSH ESI
004010E2 FF15 F4644000 CALL DWORD PTR DS:[4064F4] ; UltraPro.0040D4D6
上面的汇编代码是入口代码,不过肯定是假的入口了。从上面还可以看到函数调用已经被替换了,先从4010E2这个调用看看。
0040D4D6 68 80F55277 PUSH 7752F580
0040D4DB 813424 C0198100 XOR DWORD PTR SS:[ESP],8119C0
0040D4E2 C3 RETN
运行到0040D4E2就可以看到函数的真正地址了,不过就靠一个xor加密有点......这时候如果用ImportREC会发现很多函数是无效的,不管了必须要把IAT弄好。以【4064F4】为例子,去找找函数入口。
4064F4指向40D4D6,在40D4D6通过一个以后运算就可以获得地址了。如果去4064F4内存看看,就可以发现大量的这样的调用入口。通过遍历这些入口,然后把地址回填到原来的地方,就可以恢复IAT了。当然这样重复的工作就交给脚本干了:
var addr
BPWM 406000,1000
run
bprm 401000,4000
run
bpmc
mov addr,40635c//这个地址是替换函数内存地址开始的地方
l:
cmp [addr],70000000
ja l2
cmp [addr],0
je l2
mov eip,[addr]
Sti//运行两步
sti
mov [addr],[esp]//计算完毕地址回填
l2:
add addr,4
log addr
cmp addr,406504//超过这个地址,就没有地址表了
jb l
log "end"
IAT弄好了,这个程序还是不能运行的,入口还没弄好呢。
先观察一下伪入口:
EAX 00151E22
ECX 0012FFB0
EDX 7C92EB94 ntdll.KiFastSystemCallRet
EBX 7FFDE000
ESP 0012FF78
EBP 0012FFC0
ESI 00151EE0 ASCII 22,"C:\Documents and Settings\Administ"
EDI 7C930738 ntdll.7C930738
再看程序运行的入口:
EAX 00000000
ECX 0012FFB0
EDX 7C92EB94 ntdll.KiFastSystemCallRet
EBX 7FFD4000
ESP 0012FFC4
EBP 0012FFF0
ESI FFFFFFFF
EDI 7C930738 ntdll.7C930738
看到了区别了吧,ESI指向了一个字符串,这个字符串应该是程序的路径。EAX变化也挺大的,这里可以猜测是因为函数调用引起的,而且它的值跟ESI有点关系。最后看看堆栈,堆栈的空间加大了4C空间。除去ebp,还有48H的空间。这里再向下看,看什么呢?要看堆栈空间的使用情况。
0040112D 8D4D BC LEA ECX,DWORD PTR SS:[EBP-44]
00401130 51 PUSH ECX
00401131 FF15 98634000 CALL DWORD PTR DS:[406398] ; kernel32.GetStartupInfoA
虽然还有几处堆栈空间的使用指令,但是这个地方能够确定这个局部变量的使用空间的大小。GetStartupInfoA的指针参数是一个大小为44H的结构体STRATUPINFO。最后看 0012FF78这个堆栈地址中有什么,全是FFFFFFFF。ESI的初始值就是这个,而且ESI在后面要使用,那应该会保护一下。根据上面的计算,可以猜测出如下代码:
PUSH EBP
MOV EBP,ESP
SUB ESP,44
PUSH ESI
前面已经说过ESI的值可能来自命令行,那这里就再GetCommandLineA下断点,中断第二次才到程序空间(中断再004260E9)。中间乱七八糟的代码真多,进栈出栈相当热闹。这些代码都不要管,我只关心ESI和EAX的值就行了(这段代码中还看到计算4010DD的代码)。总之最后ESI的值指向了命令行字符串,而EAX的值在下面一行中被修改。
004261F4 8A00 MOV AL,BYTE PTR DS:[EAX]
所以被偷掉的另一段代码为:
CALL DWORD PTR [4063E4]
MOV ESI,EAX
MOV AL,BYTE PTR [EAX]
最后dump一下,修复IAT但是还缺一个函数,这个我就没有继续跟踪了,脱壳后的文件能运行就行,别的就不想关心了。
7、PE-Armor
这个壳的脱壳过程在我的前两天的帖子里有叙述,这里就不说了。
总结:在脱壳找入口点的过程中,没有跟踪代码的执行(其实我觉得没必要跟那些花指令及各种反调试反dump手段较劲,如果不挡道直接忽略就行),当然也无从知道壳有哪些反脱壳的手段。所有的入口查找都是通过硬件断点、内存断点或者两者结合的方式来进行的。学习脱壳只有几天时间,还有很多东西不熟悉,还请高人指点一下。
2010.2.10
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!