|
PECompact 2.x -> Jeremy Collake
|
闲着也是闲着,无聊时打发时间吧. 也玩玩壳aspack upx upack0.39final Nspack3.7 Petite 2.2这些都是简单的压缩壳,直接ESP定律到OEP再DUMP就OK了.我就不记录了.
PECompact 2.x -> Jeremy Collake
一、查找OEP
00401000 > B8 002A5400 MOV EAX,cpuz.00542A00 ; EP 00401005 50 PUSH EAX ; F8
到这时hr esp,四次F9到OEP 00401006 64:FF35 0000000>PUSH DWORD PTR FS:[0] ------------------------------------------------------------------------
-------------------------- 0047B9BA E8 7BB60000 CALL cpuz.0048703A ;
OEP 0047B9BF ^ E9 16FEFFFF JMP cpuz.0047B7DA 0047B9C4 6A 10 PUSH 10 0047B9C6 68 782F4B00 PUSH cpuz.004B2F78 0047B9CB E8 40070000 CALL cpuz.0047C110
在OEP上设个硬件执行断点,方便下次到达。 he 47b9ba
二、解开输入表 到OEP后 CALL cpuz.0048703A 这个call F7进去, 看到这个 /*48706F*/ CALL DWORD PTR DS:[496184] dd 496184 看看输入表情况
00496100 77EFEF1C gdi32.GetTextExtentPoint32A 00496104 77EFB74C gdi32.GetPixel 00496108 77EF6F79 gdi32.BitBlt 0049610C 77EF5FE0 gdi32.createCompatibleDC 00496110 77EF700A gdi32.createCompatibleBitmap 00496114 00000000 00496118 00AF0000 //这里开始加密 0049611C 00AF0007 00496120 00AF000E 00496124 00AF0015
可以看到gdi32.createCompatibleBitmap下面的IAT都被加密了。
记住加密输入表的开始位置00496118,重新载入程序,在数据窗口中转到地址
00496118,设内存写入断点,F9几次,在代码窗口中看到要写入 00AF0000 时开始
分析:
/*AE1B70*/ MOV DWORD PTR DS:[ESI],EAX ; 断在这里 /*AE1B72*/ MOV DWORD PTR DS:[EDX],EAX /*AE1B74*/ ADD EDX,4 /*AE1B77*/ ADD ESI,4 /*AE1B7A*/ JMP SHORT 00AE1B28 /*AE1B7C*/ XOR EAX,EAX /*AE1B7E*/ POP ESI /*AE1B7F*/ POP EDI /*AE1B80*/ POP EBX /*AE1B81*/ LEAVE /*AE1B82*/ RET 10
------------------------------------------------------------------------ 看看信息窗口:
EAX=00AF0000 DS:[00496118]=00000000 ------------------------------------------------------------------------ 现在按F8来分析,看看这个00BE0000之类的东西是怎么来的:
/*AE1B4F*/ MOV ECX,DWORD PTR SS:[EBP+8] /*AE1B52*/ ADD EAX,DWORD PTR DS:[ECX+8] /*AE1B55*/ XOR ECX,ECX /*AE1B57*/ MOV CX,WORD PTR DS:[EAX] /*AE1B5A*/ PUSH ECX /*AE1B5B*/ INC EAX /*AE1B5C*/ INC EAX /*AE1B5D*/ PUSH EAX /*AE1B5E*/ PUSH DWORD PTR SS:[EBP-4] /*AE1B61*/ CALL DWORD PTR DS:[EBX+10001F4D] //这个CALL是关键,F7进去 /*AE1B67*/ POP EDX /*AE1B68*/ TEST EAX,EAX /*AE1B6A*/ JE 00AE1ADF /*AE1B70*/ MOV DWORD PTR DS:[ESI],EAX /*AE1B72*/ MOV DWORD PTR DS:[EDX],EAX /*AE1B74*/ ADD EDX,4 /*AE1B77*/ ADD ESI,4 /*AE1B7A*/ JMP SHORT 00AE1B28 /*AE1B7C*/ XOR EAX,EAX
跟进/*AE1B61*/处的那个CALL:
/*AE0738*/ PUSH EBP /*AE0739*/ MOV EBP,ESP /*AE073B*/ ADD ESP,-4 /*AE073E*/ PUSH EBX /*AE073F*/ PUSH EDI /*AE0740*/ PUSH ESI /*AE0741*/ CALL 00AE0746 /*AE0746*/ POP EBX /*AE0747*/ SUB EBX,0A810FE /*AE074D*/ PUSH DWORD PTR SS:[EBP+10] /*AE0750*/ PUSH DWORD PTR SS:[EBP+C] /*AE0753*/ PUSH DWORD PTR SS:[EBP+8] /*AE0756*/ CALL DWORD PTR DS:[EBX+A8102F] ; 过这里就看到函数了,应该是个GetProcAddress /*AE075C*/ MOV DWORD PTR SS:[EBP-4],EAX /*AE075F*/ MOV ECX,DWORD PTR DS:[EBX+A81061] /*AE0765*/ CMP ECX,DWORD PTR SS:[EBP+8] /*AE0768*/ JNZ SHORT 00AE07CD ; 这里必须要跳,改成JMP就可避开输入表加密
/*AE076A*/ XOR EAX,EAX /*AE076C*/ ADD EAX,DWORD PTR DS:[EBX+A81043] /*AE0772*/ JE SHORT 00AE0781 /*AE0774*/ ADD EAX,7 /*AE0779*/ CMP EAX,DWORD PTR DS:[EBX+A81047] /*AE077F*/ JB SHORT 00AE07A6 /*AE0781*/ PUSH 40 /*AE0783*/ PUSH 1000 /*AE0788*/ PUSH 1000 /*AE078D*/ PUSH 0 /*AE078F*/ CALL DWORD PTR DS:[EBX+A8103F] /*AE0795*/ MOV DWORD PTR DS:[EBX+A81043],EAX ------------------------------------------------------------------------ 现在在地址 AE0768 上设个硬件执行断点,重新载入程序,F9,断在刚才设的硬件
断点上。删掉这个硬件断点,现在把地址 AE0768 处的 JNZ 改成 JMP,F9,会断在
我们在 OEP 设的硬件断点上。这时我们打开 ImportREC,选 目标进程,OEP 填
0007B9BA,点"自动查找 IAT",会获得输入表。现在看看还有没有无效的,嗯,
还有一个:
004962D0 7C80B4CF kernel32.GetModuleFileNameA 004962D4 00BD05C4 ;这个无效 004962D8 7C8310F2 kernel32.GlobalMemoryStatus
通过上面的三个函数,可以知道这个无效的函数应该是 kernel32.dll 中的。这样
我们就在无效函数的前一个地址设内存写入断点,看看壳是怎么处理这个加密函数
的。
在地址 AE0768 上设个硬件执行断点,现在我们 CTR+F2 重来。F9运行,硬件断点
断下后删掉 AE0768 的硬件断点,把地址 AE0768 处的 JNZ 改成 JMP。
数据窗口中在地址 004962D0 上设内存写入断点,在代码窗口中看到要往 004962D0
写内容时开始分析,发现还是断在老地方:
/*AE1B70*/ MOV DWORD PTR DS:[ESI],EAX ; 断在这里 /*AE1B72*/ MOV DWORD PTR DS:[EDX],EAX /*AE1B74*/ ADD EDX,4 /*AE1B77*/ ADD ESI,4 /*AE1B7A*/ JMP SHORT 00AE1B28 /*AE1B7C*/ XOR EAX,EAX /*AE1B7E*/ POP ESI /*AE1B7F*/ POP EDI /*AE1B80*/ POP EBX /*AE1B81*/ LEAVE /*AE1B82*/ RET 10
前面我们分析时地址 AE0756 处的那个 CALL 我们没分析,只是猜测应该是个
GetProcAddress 的功能。这次我们进去看看:
/*AE0756*/ CALL DWORD PTR DS:[EBX+A8102F]
进去后是call都F7进去看看
在这 /*AE05A9*/ CALL DWORD PTR DS:[EBX+A81029] F7
00AE0416 75 06 JNZ SHORT 00BD041E
; 这里改成 JMP 就可以跳过加密
两个要改的位置都知道了,现在就可以获取完整的输入表了。从上面的分析内容,
应该可以总结一下对于加密的输入表,在相应的加密输入表地址处设内存写入断点
,能较快的找到加密的位置。 ------------------------------------------------------------------------
脱完壳修复优化后加载会出现一个实时错误,原因是第二个区段 .rdata 的特征值
应为 40000040。 出现R6002~浮点未加载 也可以用upx203压缩下就OK了.
其实这个不是为了脱壳而脱壳. 只是说明一种避开加密输入表的方法,学习一种方法比学习脱一个壳作用大的多. 这个完全是学习CCDebuger的思路.
http://www.kyospace.com/feedcomm.asp?logID=312 |