首页
论坛
课程
招聘
VMP导入表修复
2021-8-21 11:55 19123

VMP导入表修复

2021-8-21 11:55
19123

一、VMP的IAT处理的几种情况:

1、call ds:[xxx]
2、jmp ds:[xxx]
3、mov reg,ds:[xxx] + call reg
4、壳开始运行时填充到原来的导入表地址,不改变指令。

 

在1和2的情况下,原来都是FF 15或FF 25的6字节,vmp iat保护后,代码中也会变为1字节push/pop reg+5字节E8 call vmp0或5字节E8 call vmp0+1字节的的两种类型:
第一种类型:
原来:

保护后变为call vmp0 + 1字节,这里call 后面不全是填充的retn,有可能是其他字节:

 

第二种类型:
原来:

保护后变为push/pop reg + call vmp0:

 

在3的情况下,根据原来对寄存器是否为eax的赋值,也会有两种类型:
第一种:
5字节A1 开头的mov eax,ds:[xxx] 直接变为5字节的E8 call vmp0
第二种:
6字节8B 开头的mov reg,ds:[xxx],则变为5+1或1+5类型的E8 call vmp0

 

在4的情况下,原始的指令代码call ds:[xxx],jmp ds:[xxx],push ds:[xxx],mov reg,ds:[xxx]不改变,壳在启动时候直接填充函数地址到xxx。这类情况直接搜代码段FF??,8B??,A1????,获取到对应内存的函数地址进行修复。

二、获取call vmp0指令地址:

这里我直接对text段进行爆搜E8字节,然后判断是否是call到的vmp0区段,这样筛选出一堆地址,分析时候发现call vmp0区段后是以nop 0x90开头,之后再通过unicorn模拟获取在retn指令时候的返回地址,如果返回地址是当前其他模块的导出函数,则认为是没加壳程序原来调用导入函数的地址

三、判断哪种IAT处理类型:

1、对于jmp ds:[xxx]类型,由于本身不会对堆栈进行操作,而保护后改为了E8 Call方式,所以vmp为了恢复堆栈在最后retn时候是采用retn 0x4方式,对应64位为retn 0x8。

2、对于mov reg,ds:[xxx]方式,通过unicorn模拟可以发现返回地址是在E8 call vmp0导致的+5或者+6位置,对应上面1+5和5+1情况,同时只会写入除了ESP外的一个寄存器。

3、对于call ds:[xxx]情况,返回时候是以retn返回,并且返回的地址不在调用call的地址附近。

四、判断5+1或者1+5或者只有5字节模式:

判断这个的目的是确定还原代码开始的地址,最开始我这里是通过模拟得到retn时候的返回地址和E8 call的地址进行对比是+6还是+5从而判断是5+1还是1+5情况,但是这种方式对于jmp ds:[xxx]类型不能取到返回地址,对于mov reg,ds:[xxx]方式也会因为有5字节的mov eax,ds:[xxx]而判断错误。

 

后面分析的时候发现对于1+5情况使用push/pop reg + E8 call方式,模拟时候把除了esp外的寄存器值都初始化为0:
1、对于push reg +E8 call方式在 call内会通过pop reg来恢复call前因为push reg减少的堆栈,比如如下调用,模拟开始给的esp是0x1000,恢复堆栈的指令为:

1
2
pop ebx            //恢复堆栈,同时ebx = 返回地址
xchg ebx,[esp]        //将返回地址和ebx值还原

所以此时会出现esp = 0x1004,并且堆栈为:
[0x1000+4] = 返回地址
[0x1000+8] = 0

 

2、pop reg+E8 call方式会在call中进行xchg reg,[esp],push reg操作,将原先保存在reg中的参数和返回地址互换,并且重新压入返回地址:

1
2
xchg edi,[esp]        //执行后edi = 返回地址,[esp] = 之前的参数
push edi            //push 返回地址

所以当xchg指令执行后会出现esp = 0x1000,并且堆栈为:
[0x1000] = 0
[0x1000+4] = 0

 

3、其他除了5字节的mov eax,ds:[xxx]外都是E8 call + 1字节的情况

五、代码:

代码直接在这个基础上改动https://github.com/mike1k/VMPImportFixer,原代码把所有的指令都判断为FF 15类型,并且没有判断5+1、1+5和5的模式,以及mov reg,xxx类型和直接填充的类型。

 

参考:
1、https://github.com/mike1k/VMPImportFixer
2、使用模拟器进行x64驱动的Safengine脱壳+导入表修复
3、手动分析VMP加密的x64驱动导入表


2022 KCTF春季赛【最佳人气奖】火热评选中!快来投票吧~

上传的附件:
收藏
点赞8
打赏
分享
最新回复 (9)
雪    币: 1752
活跃值: 活跃值 (580)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
Cr2zy 活跃值 2021-8-21 15:40
2
0

感谢分享!

最后于 2021-8-21 15:41 被Cr2zy编辑 ,原因:
雪    币: 350
活跃值: 活跃值 (428)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
院士 活跃值 2021-8-21 20:36
3
1
厉害了,我见vmp都垃圾桶。
雪    币: 1526
活跃值: 活跃值 (1022)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zylrocket 活跃值 2021-8-22 09:28
4
0
有意思,不过这个目前研究的人太多了!
雪    币: 75
活跃值: 活跃值 (369)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
luzhmu 活跃值 2021-8-22 12:14
5
0
脱壳机呼之欲出啊
雪    币: 0
活跃值: 活跃值 (73)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
图zhang 活跃值 2021-8-24 11:18
6
0
yysy,这么强的文章应该加精
雪    币: 2143
活跃值: 活跃值 (1954)
能力值: ( LV8,RANK:131 )
在线值:
发帖
回帖
粉丝
coneco 活跃值 2 2021-8-24 12:17
7
0
如果有具体的实例对比解说就更好了。
雪    币: 2964
活跃值: 活跃值 (94)
能力值: ( LV15,RANK:1395 )
在线值:
发帖
回帖
粉丝
lacoucou 活跃值 12 2021-9-3 19:17
8
0
雪    币: 4
活跃值: 活跃值 (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wx_职业玩家 活跃值 2021-9-11 01:37
9
0
yyds
雪    币: 429
活跃值: 活跃值 (1135)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
metaworm 活跃值 2021-10-28 17:54
10
0

感谢大佬分享;参照大佬的文章实现了udbg的VMP导入表解析插件,除了可以看一般进程模块的VM的导入表,还可以看内核驱动模块的

游客
登录 | 注册 方可回帖
返回