吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1089|回复: 6
上一主题 下一主题
收起左侧

[原创] 对vmp3.2虚拟机内爆破的一点研究

[复制链接]
跳转到指定楼层
楼主
yoyoRev 发表于 2025-12-31 22:22 回帖奖励
对于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 {
        mov eax,0x11111111
        mov ebx,0x22222222
        mov ecx,0x33333333
        mov edx,0x44444444
        mov ebp,0x55555555
        mov esi,0x66666666
        mov edi,0x77777777
    }
    VMProtectBegin("begin");
    __asm {

        mov eax,0x12345678
        cmp eax,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年最后一天,明天元旦 祝愿各位网友万事如意,工作顺利,身体健康,祝愿吾爱越办越好




免费评分

参与人数 4吾爱币 +5 热心值 +4 收起 理由
mycc + 2 + 1 我很赞同!
milkdragon + 1 + 1 热心回复!
max2012 + 1 + 1 热心回复!
schm168 + 1 + 1 虽然看得一头雾水,但很膜拜大神的水平!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
kkkwz 发表于 2026-1-1 10:38
虚拟机就是一个笑话,小儿科,不会以前觉得很难,等你会就是屁,关键在于解决问题思路,如何向科学家一样思维,所有问题迎刃而解
沙发
小南跑 发表于 2025-12-31 22:48
push jmp就是冲击口虚拟机河流,紧跟着就是push call虚拟机入口,初始化,然后是以变异为分隔符的代码快,VMP读取指令后,返回一个大的循环结构,然后到循环代码快,循环代码块执行后又返回这个大的循环结构,然后接着读取下一条指令,以此往复,硬刚VM非常恶心
4#
董督秀 发表于 2026-1-1 12:16
kkkwz 发表于 2026-1-1 10:38
虚拟机就是一个笑话,小儿科,不会以前觉得很难,等你会就是屁,关键在于解决问题思路,如何向科学家一样思 ...

关于虚拟机分析,我更感兴趣的是,能否真正意义上的逆出原汇编?类似虚拟化分析的篇章很多,也没见个实际应用的所以然,大多数是理论或者处理跳转改寄存器等。举例,一段cpp代码的算法全vm了,能否逆出源代码并做出原算法keygen?
5#
JMYJ0001 发表于 2026-1-1 17:44
这个正需要呢这就来了
6#
zhanggoat 发表于 2026-1-2 11:09
挺厉害的
7#
mycc 发表于 2026-1-2 15:14
十年没分析过了VMP,看了楼主的文,它升级多年内部流程基本还是一致
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-1-3 00:07

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表