本帖最后由 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 = [] write = [10]

//上面这个代码块是在备份虚拟机执行环境,以及重定位信息

456DBA mov ebp,dword ptr [esp + 0x28] read = [0] write = []

456DC2 neg ebpread = [] write = []

456DC4 dec ebpread = [] write = []

456DC9 rol ebp,3 read = [] write = []

456DCC xor ebp,0x3684751d read = [] write = []

456DDC lea ebp,[ebp + 0x5bae11e7] read = [] write = []

456DEA neg ebpread = [] write = []

456DEC add ebp,eax read = [] write = []

//上面这个代码块取出了压入的加密常数,进行一系列解密操作后得到指令流起始地址,并赋值给了ebp,故ebp作为新的指令流寄存器,add ebp,eax是修正重定位操作

456DF1 mov edi,esp read = [] write = []

//edi是虚拟机堆栈

456E0B mov ebx,ebp read = [] write = []

//初始化执行密钥,ebx仍然是密钥寄存器

456E26 lea esi,[0x456e26] read = [] write = []

//esi = 0x456e26

456E33 mov ecx,dword ptr [ebp] read = [] write = []

456E37 add ebp,4 read = [] write = []

456E40 xor ecx,ebx read = [] write = []

456E42 dec ecxread = [] write = []

456E44 xor ecx,0x25873dcc read = [] write = []

4691EB inc ecxread = [] write = []

4691EF neg ecxread = [] write = []

4691F1 xor ebx,ecx read = [] write = []

4691F3 add esi,ecx read = [] write = []

41F273 push esiread = [] write = [59]

41F274 ret read = [59] write = []

//上面这个代码块从指令流中取出了一个DWORD,赋予ecx,并递增了指令流指针。将取出的指令流用密钥进行解密,而后与esi相加,得到下一条Handle的地址

总结:在本样本的虚拟机结构中,edi作为虚拟机堆栈,ebp作为指令流指针,ebx仍然作为执行密钥,esi作为中转基址,esp作为上下文指针。传统的分发器结构消失了,取而代之的是一种新的链式结构的虚拟机。不同样本可能会有不同的架构,不像VMP2.X架构,3.X中寄存器是随机选用的。新架构又需要新的分析工具,不知道何年何月才会有牛人共享出来……

再探

vPopImm32

使用脚本对其解混淆后的代码如下。注意,如果后文中没有特殊说明,贴出的代码均为解混淆后的代码。

[AppleScript] 纯文本查看 复制代码46C27Fmov edx, dword ptr [edi] read = [] write = []

46C28Cadd edi, 4 read = [] write = []

//从虚拟机堆栈中弹出操作数

46C292movzx ecx, byte ptr [ebp] read = [] write = []

46C297lea ebp, [ebp + 1] read = [] write = []

46C2A3xor cl, bl read = [] write = []

46C2A5neg cl read = [] write = []

442B1Ainc cl read = [] write = []

442B1Dror cl, 1 read = [] write = []

412AB8neg cl read = [] write = []

412AC0xor bl, cl read = [] write = []

//从指令流中取出操作数(在上下文结构中的偏移),并解密,更新密钥,递增指令流

412AC3mov dword ptr [esp + ecx], edx read = [] write = []

412AC8mov ecx, dword ptr [ebp] read = [] write = []

//写入上下文结构

412AD0add ebp, 4 read = [] write = []

412AD7xor ecx, ebx read = [] write = []

412ADFsub ecx, 0x2d2f25e5 read = [] write = []

412AE5rol ecx, 2 read = [] write = []

412AE8sub ecx, 0x1a4c24fd read = [] write = []

43CA2Aror ecx, 3 read = [] write = []

43CA2Dxor ebx, ecx read = [] write = []

43CA34add esi, ecx read = [] write = []

43CA36jmp esi read = [] write = []

该Handle从虚拟机栈中弹出一个DWORD,并写入上下文结构中指定字段。

vPushImm32

[AppleScript] 纯文本查看 复制代码48D637mov eax, dword ptr [ebp] read = [] write = []

48D63Blea ebp, [ebp + 4] read = [] write = []

48D646xor eax, ebx read = [] write = []

48D64Cadd eax, 0xb4c16be read = [] write = []

48D651not eax read = [] write = []

48D656lea eax, [eax - 0x51cc037d] read = [] write = []

48D65Cmov cl, 0x42 read = [] write = []

48D65Eneg eax read = [] write = []

48D66Cror eax, 1 read = [] write = []

48D676lea eax, [eax - 0x61b03f11] read = [] write = []

//从指令流中取出操作数,并进行解密操作

48D67Cxor ebx, eax read = [] write = []

48D67Flea edi, [edi - 4] read = [] write = []

48D688mov dword ptr [edi], eax read = [] write = []

//将解密后的操作数压入虚拟机堆栈

48D691mov ecx, dword ptr [ebp] read = [] write = []

48D695lea ebp, [ebp + 4] read = [] write = []

40E56Dxor ecx, ebx read = [] write = []

40E570rol ecx, 3 read = [] write = []

40E576sub ecx, 0x1865595b read = [] write = []

40E583bswap ecx read = [] write = []

40E586lea ecx, [ecx - 0x7c371840] read = [] write = []

40E58Dxor ebx, ecx read = [] write = []

422848add esi, ecx read = [] write = []

4520F4lea eax, [esp + 0x60] read = [] write = []

48294Cpush esi read = [] write = [0]

48294Dret read = [0] write = []

每次执行入栈操作后,都会检查边界,判断虚拟机栈指针与上下文指针是否接近,如果是,则会将上下文结构向下移动,如下。

[Asm] 纯文本查看 复制代码lea eax, [esp+60h]

cmp edi, eax

但是我写的那个破脚本脚本没考虑到这点,会将这段代码舍去,所以需要特别注意一下。

该Handle向虚拟机堆栈中压入一个DWORD大小的常数。

vPushRx32

[AppleScript] 纯文本查看 复制代码413B2Amovzx edx, byte ptr [ebp] read = [] write = []

413B2Fsetge al read = [] write = []

413B32shl ah, 0x30 read = [] write = []

413B35add ebp, 1 read = [] write = []

413B46xor dl, bl read = [] write = []

413B51ror dl, 1 read = [] write = []

413B53sub dl, 0x3e read = [] write = []

413B5Aneg dl read = [] write = []

413B5Frol dl, 1 read = [] write = []

413B61inc dl read = [] write = []

413B6Arol dl, 1 read = [] write = []

413B78xor bl, dl read = [] write = []

//取出操作数(在上下文结构中的偏移,并解密)

413B7Dmov eax, dword ptr [esp + edx] read = [] write = []

//取出指定字段

413B89sub edi, 4 read = [] write = []

413B91mov dword ptr [edi], eax read = [] write = []

//压栈

413B93mov edx, dword ptr [ebp] read = [] write = []

413B9Dadd ebp, 4 read = [] write = []

413BAAxor edx, ebx read = [] write = []

413BADror edx, 1 read = [] write = []

413BB3neg edx read = [] write = []

413BB9lea edx, [edx - 0x796d16c6] read = [] write = []

413BC2not edx read = [] write = []

413BC9xor ebx, edx read = [] write = []

413BCBadd esi, edx read = [] write = []

4520F4lea eax, [esp + 0x60] read = [] write = []

48294Cpush esi read = [] write = [0]

48294Dret read = [0] write = []

该Handle从上下文结构中取出指定字段,并压入堆栈。

vRET

注意,那个破脚本对这条Handle完全不适用了,等我有空再看看BUG。

[Asm] 纯文本查看 复制代码mov esp, edi

pop eax

pop ebp

pop ecx

popf

pop edx

pop edi

pop ebx

pop esi

retn

//还原堆栈,同时还原环境

总结:结合上述介绍的Handle,读者可自行完成对本文附带的例子的分析。该例并不复杂,与原汇编代码基本可以说是一一对应的关系。稍微注意一下,对于函数调用,VMP3.X的处理方式是先退出虚拟机,同时将返回地址设为进入虚拟机的代码地址。

举个例子。如下。

[AppleScript] 纯文本查看 复制代码0012FFA8 00401032

0012FFAC 004207C7 1_vmp.004207C7

0012FFB0 00000000

0012FFB4 00403000 ASCII "VMProtect V2.12.3"

0012FFB8 00403012 ASCII "三十二变"

0012FFBC 00000000

[align=left]

这是在执行vRET的最后一条retn指令时的堆栈环境。

调用完成后,返回到0x004207C7,又重新进入虚拟机。

[AppleScript] 纯文本查看 复制代码004207C7 68 B31D7ABA push 0xBA7A1DB3

004207CC E8 FD8FFEFF call 1_vmp.004097CE

奇技淫巧之简单爆破因为业务需要不同,对VM的研究程度也不同,所以对应的也会产生一些奇技淫巧,比如,无脑爆破……不是我BS这种方法,是真的无脑,但很多分析虚拟机的文章都会介绍这个,作为一篇自重自爱的虚拟机介绍文章,本文当然也不会省略这个环节。

举一个例子,如下。

[Asm] 纯文本查看 复制代码cmp eax,2010

je label1

我们可以修改cmp指令实现爆破,同样可以修改je指令实现爆破。无脑就无脑到底好了,本文介绍修改跳转指令,因为它不需要了解复杂的逻辑门运算知识。

以爆破je指令为例。

以下为未加密前的源文件。

[Asm] 纯文本查看 复制代码@Main proc

mov eax,2018h

.if eax == 2019h

invoke MessageBox,0,offset szOK,offset szTitle,MB_OK

.else

invoke MessageBox,0,offset szNO,offset szTitle,MB_OK

.endif

ret

@Main endp

因为VMP有执行密钥,用来动态解密指令流。跳转指令有两个分支,两条分支下去,不可能还能再用同一个密钥继续编码下去。所以遇到流程转移指令一定会重新设置密钥,我们直接搜索mov ebx语句。

第二次对ebx(密钥)直接赋值的地方与第一次(进入虚拟机)相差很远,我们再以此为基准向上搜索00000040(对应的是ZF标志位为1的EFLAGS)。

搜索3次后来到此处。

8.png (29.94 KB, 下载次数: 4)

2019-2-13 22:25 上传

注意这条shr指令,这表明我们目前处于vShr4 Handle中。

在OD中动态调试,在该处下一个条件断点。可以按当时指令流来设置。

中断时,将EAX由0x40修改为0x0即可。

9.png (18.23 KB, 下载次数: 5)

2019-2-13 22:28 上传

10.png (4.7 KB, 下载次数: 4)

2019-2-13 22:28 上传

如果想要深入了解,请去参阅布尔代数,一般讲离散数学的书都有这个内容。

附录

文章中用到的破脚本可以到我的GITEE上面下载。

大概原理就是消除死代码。比如。

[C] 纯文本查看 复制代码int x;

x = 10; ///1

x = 5; //2

x += 20;

printf("%d", x);

其中1是死代码,因为1仅对x进行赋值操作而x在引用前就被重新定值了。

因为VMP3.X中没有栈混淆,所以可以直接对寄存器进行消除死代码。

而VMP2.X因为有栈混淆,所以可能复杂一些,思路就是将栈中的数据以DWORD为单位开始编号,仍然将它们视为变量,进行消除死代码。

以栈变量活跃分析为例(寄存器与标志位的活跃分析是一样的),需要遵循以下原则。

1.活跃分析应从底部向顶部分析

2.出口代码处的所有栈变量都是活跃的

3.栈变量的活跃性持续向上传递,但遇到对该栈变量的读写操作时,会变更活跃性

4.当某一栈变量向上传递活跃性遇到写操作时,则活跃性变为死状态,若遇到读操作时,则活跃性变为活状态

5.当出现对同一栈变量进行读写操作时,我们默认读操作先于写操作

具体实现请看脚本……

使用需基于capstone、pythonwin

安装capstone:

1.      pip install capstone

安装pythonwin:

1.      百度搜索pythonwin,找到对应你的python版本即可

简单分析VMP3.X.rar

(778.05 KB, 下载次数: 4)

2019-2-13 22:32 上传

点击文件名下载附件

附件

下载积分: 魔法币 -5

python 编译成exe vmp加密_简单分析VMProtect V3.3.1相关推荐

  1. python 编译成exe vmp加密_Python vmp包_程序模块 - PyPI - Python中文网

    vmpy是评估typical的工具箱. 骑行性能指标来自骑行数据,如功率.心率.速度, 梯度,节奏流. 包中的所有函数都遵循惯例,其中输入/输出 格式要么是传统的python内置数据结构 或者是nd数 ...

  2. python编译成exe和exe反编译成python

    先看文章概要.再看左侧目录,可准确找到需要内容 文章概要:python文件可编译成exe文件,exe文件也可通过反编译恢复为python文件.下面简单介绍如何生成exe和恢复python python ...

  3. python编译成exe有意义吗_python工程编译成EXE

    前言 python编译成EXE文件后,可以独立使用.亲测,一个复杂的python工程包含多个包多个模块,可以生成exe文件. 目的 windows下将整个python工程编译成单个EXE或者单个目录带 ...

  4. python打包成exe导入文件_【转载】将python脚本打包成exe文件

    标签: exe文件也就是可以直接执行的文件.通常我们编好的带py后缀的脚本文件都是需要在有python的环境下执行, 每次通过Win + R打开运行窗口再输入powershell打开控制台,再千辛万苦 ...

  5. python编译成exe速度会变快吗_python如何编译成exe

    Python 程序都是脚本的方式,一般是在解析器里运行,如果要发布出去,需要提前安装解析器才可以运行,为了在 Windows 里方便发布,只要点击一个 EXE 文件运行,并且打包所需要库文件,这样发布 ...

  6. Python编译成exe

    1.安装pyinstaller pip install pyinstaller 2.编译 pyinstaller -F -w game.py  (-F表示打包单个文件,-w是为了打开exe时候不弹出黑 ...

  7. python 编译成exe黑屏_python''外星人入侵''打包成exe遇到的问题和解决办法,闪退,黑屏。...

    利用python写完"外星人入侵之后",尝试打包成exe给自己玩得方便点.然后我在网上查找各种方法.下面按顺序列出. 一:我首先安装好了pyinstaller:在cmd中输入:pi ...

  8. python转成exe运行出错_使用py2exe将.py转换为.exe:无法运行程序

    我试图用py2exe(我有python2.7)使pygame文件可执行.程序由3个脚本组成.在 我写的设置是:from distutils.core import setup import py2ex ...

  9. python转换成exe后一闪而过_解决python xx.py文件点击完之后一闪而过的问题

    解决python xx.py文件点击完之后一闪而过的问题 1.问题复现: 有时候我们去点击.py文件 文件里明明有打印信息,却一闪而过,没有任何显示 比如以下内容 #!/usr/local/bin/p ...

最新文章

  1. Python 笔试面试合集
  2. 线程的生命周期其实没有我们想象的那么简单!!
  3. 1803无法升级到2004_今年的Win10更新很特别,不要随便升级!
  4. Heinz College of Information Systems and Public Policy Carnegie Mellon University
  5. 3DSlicer3:模块管理(一)颜色、DCM、数据、模型、注释
  6. python 1+2+3+4+5+6+7+8+9累加求和_求1!+2!+3!+4!+5!+6!+7!+8!+9!+10!+...+N! N阶阶乘求和算法 JAVA C Python...
  7. python将csv装入mysql_python 从csv读数据到mysql的实例
  8. PM_我们是怎么做Code Review的
  9. Python 实训3 简单的好友通讯录管理程序
  10. 数字签名的生成和验证
  11. 中奖人js滚动效果_H5实现中奖记录逐行滚动切换效果
  12. Python轻松实现PDF格式转换(附详细源码)
  13. 《MySQL DBA修炼之道》——3.3 SQL基础
  14. 用python画漂亮的图案-使用 Python Turtle 设计简单而又美丽的图形
  15. 【战国策】之《齐策·张仪为秦连横说齐王曰》
  16. !=EOF的含义和原理
  17. 视频 TS 内容详细讲解
  18. 广九客运段铁路“姐妹花”春运真情服务获旅客点赞
  19. 内存颗粒版本判断方法和编号解析(三星、美光、海力士)
  20. php 域名纠错,关闭网通域名纠错系统的解决方法(非常管用)

热门文章

  1. Ns2简单有限网络仿真实验
  2. Unity游戏开发官方入门教程:飞机大战(十)——敌人的爆炸和移动
  3. Linux-groups
  4. 2017中国国际智慧城市、物联网、大数据博览会会刊(参展商名录)
  5. 阅读笔记1:A secure and efficient certificateless signature scheme for Internet of Things
  6. HTML示例02---插入超链接以及超链接颜色设置
  7. java 爬虫 百度贴吧_实现任意百度贴吧的爬虫
  8. 【Android】点九图
  9. 公司官网深度优化之路,半年时间百度收录网页4000+
  10. 普鸥|欧洲专利局授权的专利与欧盟各国所授权的专利有什么不同?