python 编译成exe vmp加密_简单分析VMProtect V3.3.1
本帖最后由 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相关推荐
- python 编译成exe vmp加密_Python vmp包_程序模块 - PyPI - Python中文网
vmpy是评估typical的工具箱. 骑行性能指标来自骑行数据,如功率.心率.速度, 梯度,节奏流. 包中的所有函数都遵循惯例,其中输入/输出 格式要么是传统的python内置数据结构 或者是nd数 ...
- python编译成exe和exe反编译成python
先看文章概要.再看左侧目录,可准确找到需要内容 文章概要:python文件可编译成exe文件,exe文件也可通过反编译恢复为python文件.下面简单介绍如何生成exe和恢复python python ...
- python编译成exe有意义吗_python工程编译成EXE
前言 python编译成EXE文件后,可以独立使用.亲测,一个复杂的python工程包含多个包多个模块,可以生成exe文件. 目的 windows下将整个python工程编译成单个EXE或者单个目录带 ...
- python打包成exe导入文件_【转载】将python脚本打包成exe文件
标签: exe文件也就是可以直接执行的文件.通常我们编好的带py后缀的脚本文件都是需要在有python的环境下执行, 每次通过Win + R打开运行窗口再输入powershell打开控制台,再千辛万苦 ...
- python编译成exe速度会变快吗_python如何编译成exe
Python 程序都是脚本的方式,一般是在解析器里运行,如果要发布出去,需要提前安装解析器才可以运行,为了在 Windows 里方便发布,只要点击一个 EXE 文件运行,并且打包所需要库文件,这样发布 ...
- Python编译成exe
1.安装pyinstaller pip install pyinstaller 2.编译 pyinstaller -F -w game.py (-F表示打包单个文件,-w是为了打开exe时候不弹出黑 ...
- python 编译成exe黑屏_python''外星人入侵''打包成exe遇到的问题和解决办法,闪退,黑屏。...
利用python写完"外星人入侵之后",尝试打包成exe给自己玩得方便点.然后我在网上查找各种方法.下面按顺序列出. 一:我首先安装好了pyinstaller:在cmd中输入:pi ...
- python转成exe运行出错_使用py2exe将.py转换为.exe:无法运行程序
我试图用py2exe(我有python2.7)使pygame文件可执行.程序由3个脚本组成.在 我写的设置是:from distutils.core import setup import py2ex ...
- python转换成exe后一闪而过_解决python xx.py文件点击完之后一闪而过的问题
解决python xx.py文件点击完之后一闪而过的问题 1.问题复现: 有时候我们去点击.py文件 文件里明明有打印信息,却一闪而过,没有任何显示 比如以下内容 #!/usr/local/bin/p ...
最新文章
- Python 笔试面试合集
- 线程的生命周期其实没有我们想象的那么简单!!
- 1803无法升级到2004_今年的Win10更新很特别,不要随便升级!
- Heinz College of Information Systems and Public Policy Carnegie Mellon University
- 3DSlicer3:模块管理(一)颜色、DCM、数据、模型、注释
- 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...
- python将csv装入mysql_python 从csv读数据到mysql的实例
- PM_我们是怎么做Code Review的
- Python 实训3 简单的好友通讯录管理程序
- 数字签名的生成和验证
- 中奖人js滚动效果_H5实现中奖记录逐行滚动切换效果
- Python轻松实现PDF格式转换(附详细源码)
- 《MySQL DBA修炼之道》——3.3 SQL基础
- 用python画漂亮的图案-使用 Python Turtle 设计简单而又美丽的图形
- 【战国策】之《齐策·张仪为秦连横说齐王曰》
- !=EOF的含义和原理
- 视频 TS 内容详细讲解
- 广九客运段铁路“姐妹花”春运真情服务获旅客点赞
- 内存颗粒版本判断方法和编号解析(三星、美光、海力士)
- php 域名纠错,关闭网通域名纠错系统的解决方法(非常管用)
热门文章
- Ns2简单有限网络仿真实验
- Unity游戏开发官方入门教程:飞机大战(十)——敌人的爆炸和移动
- Linux-groups
- 2017中国国际智慧城市、物联网、大数据博览会会刊(参展商名录)
- 阅读笔记1:A secure and efficient certificateless signature scheme for Internet of Things
- HTML示例02---插入超链接以及超链接颜色设置
- java 爬虫 百度贴吧_实现任意百度贴吧的爬虫
- 【Android】点九图
- 公司官网深度优化之路,半年时间百度收录网页4000+
- 普鸥|欧洲专利局授权的专利与欧盟各国所授权的专利有什么不同?