本帖最后由 Crazyman_Army 于 2019-2-15 15:05 编辑
前言
VMProtect3很早就出来了,据说代码使用C++重构了,而且虚拟机架构也有很大的变化。网上关于VMP3.X的帖子不是很多,我这个弱鸡也来上篇文章分析一下。
文章里面用到了一个解混淆的脚本,附录中我会给出这个破脚本的下载链接及大概原理。
三十二变
2019.2.13
准备工作
先对一段VREY EASY的汇编代码进行加密。如下。
1.png (33.99 KB, 下载次数: 1)
2019-2-13 21:21 上传
配置VMProtect V3.3.1对@Main过程进行加密。注意将除代码虚拟化以外的保护全部去除勾选。
附注:那个szText变量请无视,我是写完文章才发现这个坑的,已经懒得改了。
2.png (29.33 KB, 下载次数: 4)
2019-2-13 21:22 上传
3.png (57.73 KB, 下载次数: 5)
2019-2-13 21:22 上传
编译后,发现文件大小为552KB!意思是说,不包含外壳的代码,只虚拟机部分的代码就膨胀了550KB!不敢想象这是一个怎样的存在,开始我认为是虚拟化的混淆程度又有加强,分析完后才发现原来是虚惊一场……
初探
使用IDA的Trace功能对虚拟机的运行全过程进行记录。发现共执行了1486条语句,这个膨胀率相比与VMP2.X架构可以说是非常小了。加密7条语句,在VMP2.X中光虚拟机指令就可以膨胀到700条左右。
仍然在Trace文件中从头部开始搜索RET指令。如下。
4.png (7.15 KB, 下载次数: 11)
2019-2-13 21:23 上传
有一个比较令人惊讶的发现,VMP3.X没有采用栈混淆。纵览进入虚拟机的环境备份代码,发现只有简单的针对寄存器的插入死代码。
注意,不完全是以push esi/retn指令对的形式进行转移,还有以jmp esi实现流程转移的情况,事实上前者完全可以看成后者的一个变形。
运行脚本,按要求输入进程ID,起始地址(可以输入Dispatch或Handle的起始地址)。
则会输出解混淆后的代码。如下。
5.png (5.17 KB, 下载次数: 6)
2019-2-13 21:24 上传
6.png (65.91 KB, 下载次数: 3)
2019-2-13 21:24 上传
7.png (4.28 KB, 下载次数: 6)
2019-2-13 21:25 上传
注意,栈中的数据被以DWORD为单位从0开始编号,read/write列表中包含每条指令读取/写入的栈变量序号。
[AppleScript] 纯文本查看 复制代码45E756 push0x6dae122f read = [] write = [0]
//此处压入一个加密后的常数,经解码后可以取出指令流地址
4748B1 push esiread = [] write = [2]
4748B5 push ebxread = [] write = [3]
4748B8 push ediread = [] write = [4]
4748BF push edxread = [] write = [5]
4748C7pushfd read = [] write = [6]
4748C8 push ecxread = [] write = [7]
4748C9 push ebpread = [] write = [8]
4748CA push eaxread = [] write = [9]
456DA6 mov eax,0 read = [] write = []
456DB2 push eaxread = [] writ