文章总结: 本文通过逆向分析VMProtect3.2虚拟机内部逻辑,利用x32dbg跟踪虚拟指令执行。研究发现VMP通过复杂逻辑运算操作零标志位ZF决定跳转分支。作者演示了在关键指令后手动置位ZF标志,成功改变虚拟机执行流绕过条件检查,实现了对VMP保护程序的爆破,揭示了其基于标志位决策的底层原理。 综合评分: 88 文章分类: 逆向分析,二进制安全,实战经验
对vmp3.2虚拟机内爆破的一点研究
原创
吾爱pojie
吾爱破解论坛
2026年1月10日 08:31 北京
作者论坛账号:yoyoRev
对于vmp虚拟机爆破,网上也有相关帖子,如果没有亲身去跟过vmp,那么估计看那些帖子是看不懂的,因为不知道别人为啥要这么做,所以还是要实践,版本是3.2,保护选虚拟,先研究这种情况,自己去写个简单demo去研究
复制代码 隐藏代码
#include <windows.h>
#include "VMProtectSDK.h"
#pragma comment(lib, "VMProtectSDK32.lib")
int fun1() {
return MessageBoxA(0,"yoyo",0,0);
}
int fun2() {
return MessageBoxA(0, "vmp", 0, 0);
}
int main() {
__asm {
moveax,0x11111111
movebx,0x22222222
movecx,0x33333333
movedx,0x44444444
movebp,0x55555555
movesi,0x66666666
movedi,0x77777777
}
VMProtectBegin("begin");
__asm {
moveax,0x12345678
cmpeax,ebx
jz lab
call fun1
jmp lab2
lab:
call fun2
lab2:
}
VMProtectEnd();
}
可以看到是恒执行fun1的,那么目标就是爆破去执行fun2,将程序拖入x32dbg,到达main函数,可以看到下面的push 和jmp指令然后进入虚拟机
进入虚拟机之后无非还是保存寄存器,为虚拟寄存器和虚拟栈分配空间啥的,这里不再赘述,要明白的是mov eax,0x12345678 这个立即数是解密出来的,可以慢慢单步跟,随时注意寄存器的值,也可以跟踪下相关条件断点, 最后跟到相关指令处
可以看到此时eax的值是0x12345678,在005B78A5地址处的指令mov dword ptr ss:[ebp], eax 将立即数保存了,然后我们直接下硬断,f9执行
程序中断在这里 mov eax, dword ptr ss:[ebp] 将立即数赋值给eax,下面0x5B527D的指令mov dword ptr ss:[esp+edx*1], eax 又将立即数保存,继续下断,f9执行
此时程序中断在第一次下硬断的访问的地址 可以看到此时会取出原先的ebx:0x22222222,然后将这个立即数写入第一次的断点处,继续f9
又将立即数取出放入ecx,后面地址005C7905的指令mov dword ptr ss:[ebp], ecx 放入ebp所指向的内存,断在ebp所指向内存处,继续f9执行
再次中断后,将立即数0x12345678放入ecx中,下面地址005BD0D6的指令mov dword ptr ss:[ebp], ecx 将ecx保存ebp所指向内存处
接下来看一下堆栈,可以看到这三个立即数,接下来就是vmp的相关操作了,对这三个地址下断(其实只要对上一步ebp地址处下断就行,下面两个在之前已经下了),删除第一次下的断点 没啥用了
f9执行,看vmp是如何对这几个立即数进行操作的 也就是别人说的万用门 与非门 或非门啥的,相关指令 mov edx, dword ptr ss:[ebp] mov ecx, dword ptr ss:[ebp+0x04] not edx not ecx and edx, ecx 在执行两条mov指令之后 edx=ecx=0x12345678,执行完这几条指令相当于(not edx) and (not edx) = not edx 就是对立即数进行取反(结果=0xEDCBA987),取反后 会将edx存入内存中(不再给图,不然太多了,其实是我懒)删除不必要的断点,继续执行
看下面的操作,将not之后的结果取出放入eax,将原先的ebx值放入edx,然后add eax,edx 再次将eax(此时eax=0x0FEDCBA9),保存,后续只给关键操作的图 取出保存不再给出
后续的操作如下 mov eax, dword ptr ss:[ebp] mov edx, dword ptr ss:[ebp+0x04] not eax not edx or eax, edx eax =edx = 0x0FEDCBA9 等价于 (not eax) or (not edx) = not eax = 0xF0123456 到这儿之后我再次下断跟之后已经没有意义了,我百思不得其解,没关系 我们有ai啊 看关键点
也就是说如果eax和ebx相等 那么在执行not (not eax + ebx) or (not (not eax + ebx))结果是0,此时or指令会影响标志位zf 后面vmp是根据这个zf位进行判断的,在执行这个or指令后,我们将zf置1,然后运行
可以看到已经成功执行fun2函数了,也就是说后续vmp是根据这个标志位进行决策 从而决定跳转的,继续研究,观察是如何处理的,重新断在or eax,edx这里,执行后将zf置1,继续跟踪 依旧是下面指令 mov eax, dword ptr ss:[ebp] mov edx, dword ptr ss:[ebp+0x04] not eax not edx or eax, edx 在执行mov eax, dword ptr ss:[ebp] eax=0xFFFFF7EA 这个值是一个特定的魔数(not eax = 0x815) mov edx, dword ptr ss:[ebp+0x04] edx=0x2c6,就是上面将zf置1后的eflags 执行完or eax, edx 之后,eax= 0xFFFFFD3D,继续跟踪
接下来跟踪到这儿,依旧是熟悉的指令 mov eax, dword ptr ss:[ebp] mov edx, dword ptr ss:[ebp+0x04] not eax not edx or eax, edx 执行完之后eax=0x2c2
之后进行了一个eax+5 也就是0x2c2+5=0x2c7 暂时看不懂有啥用(应该也是魔数?),依旧保存,继续跟
依旧是熟悉的代码 mov edx, dword ptr ss:[ebp] mov ecx, dword ptr ss:[ebp+0x04] not edx not ecx and edx, ecx 执行完and指令之后edx=0xFFFFFD38
接下来还是熟悉的代码 mov edx, dword ptr ss:[ebp] //edx =0xFFFFFFBF(魔数) mov ecx, dword ptr ss:[ebp+0x04] //ecx = 0xFFFFFD38 not edx not ecx and edx, ecx 执行完and指令之后edx=0x40 二进制0100 0000 位6刚好对应eflags的zf位
然后开始右移判断zf位, 此时eax=0x40 cl=6 shr eax,cl之后eax=1 此时判断出zf的值
那么我们可以写出在右移之前的大致表达式 edx = 2c6 eax = 0xFFFFF7EA (not 0xFFFFFFBF) and(not((not(((not((not eax) or (not edx))) or (not((not eax) or (not edx))))+5)) and (not(((not((not eax) or (not edx))) or (not((not eax) or (not edx))))+5)))) 看起来非常的眼花缭乱 没事交给ai 等价于 not(0xFFFFFFBF) and ((not eax) or (not edx) + 5),再计算得到 0x40。
可以看出来vm使用大量的万用门来进行复杂的计算 相当的恶心人啊 再右移得到1,如果两个值不相等 那么右移之后结果就是0了.继续看后续操作
代码如下 mov eax, dword ptr ss:[ebp] //eax=0xffffffff mov edx, dword ptr ss:[ebp+0x04] //edx=1 即右移的结果 add eax, edx //相加 如果是edx=1 那么add之后eax=0 继续跟,可以看到依旧是熟悉的代码 这里不在写出来了
继续跟,还是熟悉的配方
mov eax, dword ptr ss:[ebp] //eax=0x0xffffffff not 0之后的结果
mov edx, dword ptr ss:[ebp+0x04] //edx=00482F2B
not eax
not edx
or eax,edx //eax = 0xFFB7D0D4
这里不再给图 只给后续逻辑代码 mov eax, dword ptr ss:[ebp] //eax = 0xFFB7D0D4 mov edx, dword ptr ss:[ebp+0x04] //edx = 0xFFB7D0D4 not eax not edx or eax,edx //eax = 0x00482F2B
mov eax, dword ptr ss:[ebp] //eax=0 mov edx, dword ptr ss:[ebp+0x04] //edx= 0x00482F2B add eax,edx //eax= 0x00482F2B
mov eax, dword ptr ss:[ebp] //eax=0x140000 mov edx, dword ptr ss:[ebp+0x04] //edx = 0x00482F2B add eax, edx // eax = 0x005C2F2B 此时得到类似决策的opcode指针
为啥这么说 mov ecx, dword ptr ss:[ebp] // ecx = 0x005C2F2B mov edi, ecx mov ebx, edi //ebx也是解密key 贯穿整个vm虚拟机流程 重新赋值解密key
上面这个图是刚进入虚拟机时会走的分支 解密得到opcode尾指针 更新ebx key 然后继续执行后面的代码 此时我们可以看zf=0的情况 ecx = 0x005C2FBD 和上面ecx = 0x005C2F2B不一致 从而执行不同的分支 key不一样 opcode尾也不一致了 至此整个爆破流程大致分析结束,不足之处多多包涵
结语:今天刚好是25年最后一天,明天元旦 祝愿各位网友万事如意,工作顺利,身体健康,祝愿吾爱越办越好
-官方论坛
www.52pojie.cn
👆👆👆
公众号设置“星标”,您不会错过新的消息通知
如开放注册、精华文章和周边活动等公告
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:吾爱破解论坛 吾爱pojie《对vmp3.2虚拟机内爆破的一点研究》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论