【文章标题】: 促进钢蛋壳升级-简单分析及脱VProtect1.72demo版加密VB程序
【文章作者】: wuqing1501(笨笨鼠)
【作者邮箱】: 看个人资料
【作者主页】: 看个人资料
【作者QQ号】: 看个人资料
【软件名称】: vprotect1.72DEMO
【下载地址】: upk就有
【使用工具】: 老三样了
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
今天闲来无事就看了看钢蛋壳的 IAT加密,在1.62和1.63的时候 就看过那个时候的IAT加密比较简单,当然在VM中的加密还是不好搞的 因为有太多的垃圾代码,一直没有搞定,所以就一直放下不看了,今天老是感觉应该看看VM中的加密是如何修复的,于是就有了这篇文章了。
开始吧!
为了方便研究,我直接用VProtect1.72DEMO版给VB程序加壳分别选取最大速度,中等强度和最高强度!呵呵,为什么选VB程序呢?因为VB的简单修复方式也容易些,用其他IAT被处理的会更复杂一些修复也难,还是先从最简单的看看吧!
准备好了加壳的软件就可以开始了!
在1.62、1.63的时候到OEP是很简单的,直接在CODE段下内存访问断点,然后F9,过了NAG窗口后,就挺停在了解码的位置,然后F7、F8、F9各一次就到达OEP了!但是这次1.72的好像对内存断点进行了处理,也不知道是不是我的系统的问题,用上面的方法就不行了,到达解码位置后,按F7软件就出错了!所以我们换个方法吧!这个软件的大流程是不变的,只要断在解码的地方,然后CODE段下断点,F9就到OEP了,既然壳不然下内存断点,那我们就在CODE段下个硬件写入断点吧,这样解码的时候照样能段下来,断在解码位置后,这次再按F7、F8就没有事了,然后再在CODE段下F2或者内存访问都行,F9一次直接到达OEP!
好了我们正式开始吧
1.先看下最大速度吧
0043A180 > 3BC0 CMP EAX,EAX ; OD载入后停在这里
0043A182 74 1C JE SHORT 0043A1A0
0043A184 EB 00 JMP SHORT 0043A186
0043A186 DB2D 8CA14300 FLD TBYTE PTR DS:[43A18C]
0043A18C FFFF ??? ; Unknown command
0043A18E FFFF ??? ; Unknown command
0043A190 FFFF ??? ; Unknown command
0043A192 FFFF ??? ; Unknown command
然后在CODE段下硬件写入断点
003C0000 00001000 Priv RW RW
00400000 00001000 vb例子_V PE header Imag R RWE
00401000 00009000 vb例子_V .text code Imag R RWE ;在这里双击进去后下硬件写入断点
0040A000 00002000 vb例子_V .data data Imag R RWE
0040C000 00002000 vb例子_V .rsrc resources Imag R RWE
0040E000 0002B000 vb例子_V VProtect Imag R RWE
00439000 00071000 vb例子_V VProtect SFX,imports Imag R RWE
004B0000 00005000 Map R E R E
我们在CODE段双击进去
00401000 00009000 vb例子_V .text code Imag R RWE ;在这里双击进去后下硬件写入断点
来到这里
00401000 0000 ADD BYTE PTR DS:[EAX],AL ;在这里下硬件写入断点
00401002 0000 ADD BYTE PTR DS:[EAX],AL
00401004 0000 ADD BYTE PTR DS:[EAX],AL
00401006 0000 ADD BYTE PTR DS:[EAX],AL
00401008 0000 ADD BYTE PTR DS:[EAX],AL
0040100A 0000 ADD BYTE PTR DS:[EAX],AL
0040100C 0000 ADD BYTE PTR DS:[EAX],AL
然后F9运行,出现了NAG窗口,关掉NAG窗口后,停在了这里
0043BB3A > F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] ;这里就是VP解码的地方
0043BB3C FF2495 54BC4300 JMP DWORD PTR DS:[EDX*4+43BC54]
0043BB43 90 NOP
0043BB44 8BC7 MOV EAX,EDI
0043BB46 BA 03000000 MOV EDX,3
然后F7一次,F8一次,然后在CODE段下F2或者内存访问断点,F9运行来到这里,就是FLY说的光明之巅:
004014B0 68 28264000 PUSH 00402628 ;终于看到了光明之巅了,OEP
004014B5 E8 F0FFFFFF CALL 004014AA
004014BA 0000 ADD BYTE PTR DS:[EAX],AL
004014BC 0000 ADD BYTE PTR DS:[EAX],AL
004014BE 0000 ADD BYTE PTR DS:[EAX],AL
004014C0 3000 XOR BYTE PTR DS:[EAX],AL
004014C2 0000 ADD BYTE PTR DS:[EAX],AL
004014C4 3800 CMP BYTE PTR DS:[EAX],AL
看下IAT吧
0040148C - E9 17D70000 JMP 0040EBA8
00401491 90 NOP
00401492 - E9 39D70000 JMP 0040EBD0
00401497 90 NOP
00401498 - E9 5BD70000 JMP 0040EBF8
0040149D 90 NOP
0040149E - E9 7DD70000 JMP 0040EC20
004014A3 90 NOP
004014A4 - E9 9FD70000 JMP 0040EC48
004014A9 90 NOP
004014AA - E9 C1D70000 JMP 0040EC70
004014AF 90 NOP
都被处理成照样了,然后JMP到壳段,具体的加密方式自己看下加密后软件吧,我们主要看下IAT的解码,主要是下面这几句:
00414B20 B8 7FDE09C4 MOV EAX,C409DE7F
00414F80 BB AD16373C MOV EBX,3C3716AD
0042ABD0 03C3 ADD EAX,EBX
0041BCE0 8B00 MOV EAX,DWORD PTR DS:[EAX]
00419430 8D0418 LEA EAX,DWORD PTR DS:[EAX+EBX]
00413480 874424 24 XCHG DWORD PTR SS:[ESP+24],EAX
上面这几句就是解密IAT的,中间穿插了很多的垃圾指令,当程序运行到过这条 LEA EAX,DWORD PTR DS:[EAX+EBX] 指令的时候,真实的IAT地址就存放在EAX中。感觉这个地方和VMP有些相似!
本人菜鸟不会些解码,但是,既然程序运行过程中在EAX中出现了真实的IAT,那么我们可以写个脚本,在程序中查找被处理的IAT 也就是 E9???????? 这样类型的,然后判断下是不是被处理的IAT,如果不是就查找下一个,如果是的话,就单步,一直到EAX中出现真实的IAT地址,我们就把EAX的值写回到原来调用的地方,最后再后UIF处理一下就可以了。
贴出我写的脚本吧,用以前的脚本修改的,可能有些乱,脚本也写的难看,最主要的是针对这种加密方式,这种处理方式可以说效率特别低,但是我太菜了,没有找到好的处理方式。
var neicuncodebase
var neicuncodesize
var oep
var ptr
var ip1
var addr
var refaddr
var temesp
var ptr1
var code
var kebase1
var kebase2
var iataddr
mov kebase1,0040e000
mov oep,eip
mov temesp,esp
mov eip,kebase1
start:
mov esp,temesp
mov eip,00401000 //???????
mov ptr1,eip
tzm3iatfind:
mov temesp,esp
find ptr1, #e9????????#
je exit
mov ptr,$RESULT
mov ptr1,ptr
mov eip,ptr
mov refaddr, ptr
sti
mov ip1, eip
mov ip1, [ip1]
and ip1, 0ff
cmp ip1, e9
jnz nextfind
sti
mov ip1, eip
mov ip1, [ip1]
and ip1, 0ff
cmp ip1, 68
jnz nextfind
cmp eip,kebase2
ja tzm3iataddrfind
cmp eip,kebase1
jb tzm3iatfind
tzm3iataddrfind:
sti
mov iataddr,eax
gn iataddr
cmp $RESULT,0
je tzm3iataddrfind
tzm3iatfix:
sub eax,refaddr
SUB eax,5
mov refaddr,ptr
mov [refaddr],#e9#
add refaddr,1
mov [refaddr],eax,4
mov esp,temesp
nextfind:
add ptr1,6
jmp tzm3iatfind
exit:
mov esp,temesp
mov eip,oep
ret
照样脚本处理好后,用UIF修复一下,然后LP,然后IR修复就可以了!
2、接下来看些中等强度和最大强度吧
流程和上面是一样的,到达OEP的方法一样,但是中等强度和最大强度,对IAT的加密采取了很WS的方式,代码里面全是垃圾代码,本来我想把垃圾代码全部清除,然后再单步跟的,发现那个不是一般的费劲啊,不过还是写了个脚本来清理垃圾指令。共发现5种,脚本如下:
var addr
var yeip
var temsep
var long
var addr1
huazhiliang1:
mov yeip,eip
mov addr,eip
mov addr1,eip
mov long,460000 //这里是处理的代码长度,可以自己根据实际情况修改,下面的这个参数都一样
add addr1,long
findhua1:
mov temesp,esp
find eip,#740EEB0E????????750E740C????????74F675F4#
cmp $RESULT,0
je exit1
mov eip,$RESULT
mov [eip],#909090909090909090909090909090909090909090909090#
mov esp,temesp
add eip,20
cmp eip,addr1
jg exit1
jmp findhua1
exit1:
mov eip,yeip
huazhiilang2:
var addr
var yeip
var temsep
var long
var addr1
mov yeip,eip
mov addr,eip
mov addr1,eip
mov long,460000
add addr1,long
findhua2:
mov temesp,esp
find eip,#740A7508#
cmp $RESULT,0
je exit2
mov eip,$RESULT
mov [eip],#740A75089090909090909090#
mov esp,temesp
add eip,20
cmp eip,addr1
jg exit2
jmp findhua2
exit2:
mov eip,yeip
huzhiiang3:
var addr
var yeip
var temsep
var long
var addr1
mov yeip,eip
mov addr,eip
mov addr1,eip
mov long,460000
add addr1,long
findhua3:
mov temesp,esp
find eip,#7403#
cmp $RESULT,0
je exit3
mov eip,$RESULT
mov [eip],#7403909090#
mov esp,temesp
add eip,20
cmp eip,addr1
jg exit3
jmp findhua3
exit3:
mov eip,yeip
huazhiling4:
var addr
var yeip
var temsep
var long
var addr1
mov yeip,eip
mov addr,eip
mov addr1,eip
mov long,460000
add addr1,long
findhua4:
mov temesp,esp
find eip,#c3eb08#
cmp $RESULT,0
je exit4
mov eip,$RESULT
mov [eip],#9090909090909090909090#
mov esp,temesp
add eip,20
cmp eip,addr1
jg exit4
jmp findhua4
exit4:
mov eip,yeip
var addr
var yeip
var temsep
var long
var addr1
mov yeip,eip
mov addr,eip
mov addr1,eip
mov long,460000
add addr1,long
findhua5:
mov temesp,esp
find eip,#740EEB0E????????750E740C????????????75F4????????#
cmp $RESULT,0
je exit5
mov eip,$RESULT
mov [eip],#909090909090909090909090909090909090909090909090#
mov esp,temesp
add eip,20
cmp eip,addr1
jg exit5
jmp findhua5
exit5:
mov eip,yeip
ret
既然清理垃圾指令的方法行不同,那我们只好换个方法吧,我的思路是,不管在VM中还是在垃圾指令里,程序总要返回IAT的真实地址的,也就是在垃圾指令或VM中运行过程中,寄存器中总会出现IAT的真实地址的,那我们就先看看在什么地方在那个寄存器里会出现真实的地址,寄存器是固定的还是随机的,写个小 脚本测试一下吧。
var addr
Find:
sti
mov addr,eax
mov addr,[addr]
gn addr
cmp $RESULT,0
jne zt
mov addr,ecx
mov addr,[addr]
gn addr
cmp $RESULT,0
jne zt
mov addr,ebx
mov addr,[addr]
gn addr
cmp $RESULT,0
jne zt
mov addr,edx
mov addr,[addr]
gn addr
cmp $RESULT,0
je Find
mov addr,esp
mov addr,[addr]
gn addr
cmp $RESULT,0
je Find
zt:
pause
具体的代码我就补写了,全是垃圾指令而且很多很多,当寄存器中出现IAT的真实地址的时候OD就会停下来,我们就可以分析到底最关键的出现IAT的代码是那些了!在VM中跑照样的脚本,那不是一般的慢,我都不知道今天晚上电脑跑了多长的时间才跑完的! 最后经过测试中等强度的加密方式会在壳段中以下代码的时候出现真实的地址:
对于中等强度:
0041EE71 C3 RETN
0041EE72 50 PUSH EAX
0041EE73 53 PUSH EBX ;中等强度的加密方式,在壳段中只有一处这个代码,也就是所有的IAT都要经过这里,而当程序运行到这条指令的时候,EBX中就是真实的IAT。
0041EE74 51 PUSH ECX
对于最大强度,和中等强度一样,只是关键代码和寄存器不一样而已;
0041EE71 59 POP ECX
0041EE72 5B POP EBX
0041EE73 58 POP EAX
0041EE74 8BC1 MOV EAX,ECX
0041EE76 8B4F 24 MOV ECX,DWORD PTR DS:[EDI+24]
0041EE79 51 PUSH ECX
0041EE7A 9D POPFD
0041EE7B 03C3 ADD EAX,EBX
0041EE7D 8B5F 44 MOV EBX,DWORD PTR DS:[EDI+44]
0041EE80 8903 MOV DWORD PTR DS:[EBX],EAX
0041EE82 9C PUSHFD ;//最大强度的加密方式,在壳段中只有一处这个代码,也就是所有的IAT都要经过这里,而当程序运行到这条指令的时候,EAX中就是真实的IAT。
0041EE83 58 POP EAX
而且经过测试,对于加密后的VB程序,中等强度和最大强度都存在了这个特征码,而且利用的寄存器是固定的,照样也方便写脚本了。
好了有了上面的分析就可以写个脚本来查找IAT了。没有太多的分析大家看脚本吧,最好用脚本跑一下就能明白了!
脚本如下:
var neicuncodebase
var neicuncodesize
var oep
var ptr
var ip1
var addr
var refaddr
var temesp
var ptr1
var code
var kebase1
var kebase2
var iataddr
mov kebase1,0040e000 //第一个壳段
mov kebase2,00507000 //第二个壳段
mov oep,eip
mov temesp,esp
findkebase1tzm2:
mov eip,kebase1
find eip, #C3505351# //中等强度的特征码,最大强度特征码为“#595B588BC18B4F24519D03C38B5F4489039C58#”
cmp $RESULT,0
je findkebase2tzm2
add $RESULT,2 //因为中等强度代码当运行到PUSH EBX 这条指令的时候,EBX是真实的地址所以这里加2,同理,对于最大强度这里应该加11
/* 0041EE71 C3 RETN
0041EE72 50 PUSH EAX
0041EE73 53 PUSH EBX ;EBX 中就是真实的IAT。
0041EE74 51 PUSH ECX
*/
bp $RESULT
findkebase2tzm2:
mov eip,kebase2
find eip, #C3505351# //中等强度的特征码,最大强度特征码为“#595B588BC18B4F24519D03C38B5F4489039C58#”
cmp $RESULT,0
je exit
add $RESULT,2 //这里同上面,好像这段脚本就没有用,因为只是用了第一个壳段
bp $RESULT
mov esp,temesp
mov eip,00401000 //查找的起始位置
mov ptr1,eip
tzm2iatfind:
mov temesp,esp
find ptr1, #e9????????# //这里查找的就是JMP xxxx
je exit
mov ptr,$RESULT
mov ptr1,ptr
mov eip,ptr
mov refaddr, ptr
sti
mov ip1, eip
mov ip1, [ip1]
and ip1, 0ff
cmp ip1, e9
jnz nextfind
sti
mov ip1, eip
mov ip1, [ip1]
and ip1, 0ff
cmp ip1, 68
jnz nextfind
cmp eip,kebase2
ja tzm2iataddrfind
cmp eip,kebase1
jb tzm2iatfind
tzm2iataddrfind:
esto
mov iataddr,ebx ;//这里就是出现IAT真实地址的寄存器,对于中等加密是EBX,对于最大强度,这里是EAX.
gn iataddr
cmp $RESULT,0
je tzm2iataddrfind
tzm2iatfix:
sub ebx,refaddr
SUB ebx,5
mov refaddr,ptr
mov [refaddr],#e9#
add refaddr,1
mov [refaddr],ebx,4
mov esp,temesp
nextfind:
add ptr1,6
jmp tzm2iatfind
exit:
mov esp,temesp
mov eip,oep
ret
这个脚本只适用于我自己加的VB程序的壳,但是处理的原理是一样的,好了分析就这么多吧,应该说没有怎么分析IAT具体是怎么加密的,只是找到了一个解密IAT的方法,由于脚本中没有做太多的判断,所以运行脚本的时候需要自己看着脚本跑,当修复完IAT后,就自己把脚本停下来,这个时候由于寄存器的值都被破坏了这样修复的程序是不能运行的,不过我们可以打开加壳的软件跑到OEP后根据没有破坏的寄存器把修复好的寄存器的值全都修改过来,然后 再用UIF修复 LP dump IR修复就可以了,一定要记住一点哦,dump 以前一定要取消那些断点啊,尤其是F2断点,由于我刚开始没有取消断点,结果DUMP 修复后的程序不能运行,跟踪后发现是F2断点的原因,DUMP后的程序F2断点的 地方变成了CC 也就INT3 。
好了VP的IAT分析就到这里了,提供一下我练习的加壳后以及
脱壳后的软件吧,方便像我一样的菜鸟练习。
--------------------------------------------------------------------------------
【经验总结】
1、还是自己动手一遍比看别人的文章百遍都起作用。
2、一直以为在VM中或者垃圾指令中的关键代码自己跟踪不到,结果用最笨的方法还是找到了!这就说明不管做什么只要去努力去试试总有成功的机会!
3、建议苦力在下个版本中对于中等强度和最大强度加密中取消那两个特征码,或者F9运行的时候出错那样会增大修复难度,至少现在我感觉,最大速度的加密修复速度却是最慢的!修复的时候F9运行就出错,对于寄存器的使用,是否可以借鉴别的壳改为随机的那样也增加修复难度。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于wuqing1501(笨笨鼠), 转载请注明作者并保持文章的完整, 谢谢!
2010年07月18日 AM 02:31:16
样品及所有脚本
样品及所有的脚本.rar
(1.27 MB, 下载次数: 161)