首页
社区
课程
招聘
VMP导入表修复
发表于: 2021-8-21 11:55 28205

VMP导入表修复

2021-8-21 11:55
28205

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????,获取到对应内存的函数地址进行修复。

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

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的地址附近。

判断这个的目的是确定还原代码开始的地址,最开始我这里是通过模拟得到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,恢复堆栈的指令为:

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

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

所以当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驱动导入表

 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 12
支持
分享
最新回复 (9)
雪    币: 4853
活跃值: (2769)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2

感谢分享!

最后于 2021-8-21 15:41 被Cr2zy编辑 ,原因:
2021-8-21 15:40
0
雪    币: 3565
活跃值: (3950)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
厉害了,我见vmp都垃圾桶。
2021-8-21 20:36
1
雪    币: 3213
活跃值: (5434)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
有意思,不过这个目前研究的人太多了!
2021-8-22 09:28
0
雪    币: 86
活跃值: (1183)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
脱壳机呼之欲出啊
2021-8-22 12:14
0
雪    币: 0
活跃值: (124)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
yysy,这么强的文章应该加精
2021-8-24 11:18
0
雪    币: 4934
活跃值: (4653)
能力值: ( LV10,RANK:171 )
在线值:
发帖
回帖
粉丝
7
如果有具体的实例对比解说就更好了。
2021-8-24 12:17
0
雪    币: 3003
活跃值: (479)
能力值: ( LV15,RANK:1395 )
在线值:
发帖
回帖
粉丝
8
2021-9-3 19:17
0
雪    币: 4
活跃值: (42)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
yyds
2021-9-11 01:37
0
雪    币: 414
活跃值: (1721)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10

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

2021-10-28 17:54
0
游客
登录 | 注册 方可回帖
返回
//