trace不说了,试试自实现反编译器还原VMP吧!
注册参数如下:

image.png (342.1 KB, 下载次数: 0)
下载附件
2025-6-22 18:04 上传
返回位置如下:

image.png (362.5 KB, 下载次数: 0)
下载附件
2025-6-22 18:06 上传
虚拟机解释器如下:

image.png (135.17 KB, 下载次数: 0)
下载附件
虚拟机引擎
2025-6-22 21:39 上传
开始分析VMP结构:
一、VMP指令集

image.png (18.18 KB, 下载次数: 0)
下载附件
2025-6-22 18:09 上传
请求首页,302跳转下发js-challenge页面,有加密配置参数,里面包含指令集字符串(图片所示),很好拿到,后续调用atob解密,并 &255保留低8位,得到字节数组形式的指令集
二、虚拟机上下文分析

image.png (67.38 KB, 下载次数: 0)
下载附件
虚拟机上下文
2025-6-22 18:55 上传
这是分析vmp之后提取出来的虚拟机上下文,Z是虚拟寄存器集合,一共512个
其中关键的几个寄存器有,
36号PC寄存器,
336号内层虚拟机PC寄存器,
184号轮密钥种子寄存器
280 115 509 234 147 44 136 511 210 471 这些寄存器存放生成加密参数所需上下文
关键虚拟机函数有:

image.png (28.56 KB, 下载次数: 0)
下载附件
操作寄存器函数
2025-6-22 19:09 上传
N函数,写入寄存器函数

image.png (16.6 KB, 下载次数: 0)
下载附件
2025-6-22 18:34 上传
y函数 ,读取寄存器值

image.png (82.01 KB, 下载次数: 0)
下载附件
2025-6-22 18:45 上传
C函数,从虚拟机字节码中读取指令并解码复杂指令集为不同的指令类型,分发给B8解密指令

image.png (114.78 KB, 下载次数: 0)
下载附件
2025-6-22 18:24 上传
B8函数,读取指令并根据参数判断是否密钥变换表,使用当前字节块的轮密钥对指令进行解密

image.png (37.3 KB, 下载次数: 0)
下载附件
2025-6-22 18:28 上传
hJ函数,生成8字节解密表,用于取指之后,对指令进行异或解密
三、虚拟机执行逻辑分析
1.先从PC寄存器取字节码索引,然后同步到内层虚拟机的PC寄存器,然后调用C函数解码

image.png (93.75 KB, 下载次数: 0)
下载附件
2025-6-22 18:30 上传
2.C函数将指令解码为长短指令等复杂指令集,函数体一共有5个分支,分别对应
1.(w | 48) == w 分支 往寄存器中存值
2.(w - 5 | 5) >= w && (w + 4 & 43) > 1 & 12) > 4 >= 3分支 处理变长操作码 先读取1字节,判断高位是否为1,扩展为长指令
4.w + 5 >> 3 == 1 分支 将寄存器的值变为闭包变量

image.png (48.71 KB, 下载次数: 0)
下载附件
第5分支
2025-6-22 21:06 上传
5.(w + 7 ^ 27) = w 分支 操作码读取 读取8位并开启密钥变换,或者读取低7位,左移2位组成9位操作码
3.C函数解码完成之后,下发给B8函数,按照C的解码规则来读取指令,详情如下:

image.png (119.81 KB, 下载次数: 0)
下载附件
B8
2025-6-22 21:14 上传
首先从36 PC寄存器取出指定位数,同时判断是否超出索引
判断现在解密的位数属于第几组解密块,如果是新的解密块,需要调用hj更新轮密钥变换表
对取到的字节和当前轮的轮密钥进行异或解密
计算已经解密的字节,并向前推进对应位数,对齐到字节最低位,提取结果,并更新PC寄存器值
B8返回操作码,并根据高位判断是否为长指令,如果是长指令需要扩展为对应的操作码

image.png (51.69 KB, 下载次数: 0)
下载附件
取handler
2025-6-22 21:48 上传
4.C返回对应的操作码之后,调用y函数从寄存器取操作码对应的handler,
不同的操作码对应不同的handler,利用handler执行操作码,操作数是基于操作码计算得到的
5.每执行完一轮操作码之后,进行检测。然后跳出循环执行下一个取指解码操作
完整流程是:取索引下标(利用PC)————解码(C函数)————取指(B8)————执行(跳转到对应handler)————检测(js文件被我处理过,移除了反调试和检测函数)
四、操作码分析
1.生成数值型操作码

image.png (1.74 KB, 下载次数: 0)
下载附件
2025-6-22 18:40 上传
操作码 24 生成4字节数值

image.png (1.57 KB, 下载次数: 0)
下载附件
操作码66
2025-6-22 21:59 上传
操作码66,生成1字节数值

image.png (1.63 KB, 下载次数: 0)
下载附件
2025-6-22 22:00 上传
操作码105 ,生成双字节数值
不一一列举
这些操作码的作用都是生成对应字节数值,并存储到寄存器
2.生成字符串型操作码

image.png (75.77 KB, 下载次数: 0)
下载附件
操作码304
2025-6-22 22:02 上传
操作码304 生成字符串 (调试的时候忘了截图!!)
可以看出来操作数是基于操作码计算得到的
3.函数调用型操作码

image.png (84.5 KB, 下载次数: 0)
下载附件
操作码302
2025-6-22 22:05 上传
操作码302 进行函数调用
4.属性访问型操作码

image.png (16.57 KB, 下载次数: 0)
下载附件
操作码495
2025-6-22 22:08 上传
操作码495 访问浏览器对象下的属性
另外,
- **操作码122**:生成`eval`函数调用。
- **操作码149、220、446**:处理数组操作(增大数组`register_280`)。
- **操作码265、495**:对象属性赋值。
- **操作码319**:生成数组。
- **操作码477**:创建新对象
五、编写反编译器
分析完了,开始写反编译器,流程如下:
1.初始化节点

image.png (28.55 KB, 下载次数: 0)
下载附件
2025-6-22 18:53 上传
2.创建空AST

image.png (4.71 KB, 下载次数: 0)
下载附件
2025-6-22 18:54 上传
3.模拟虚拟机执行环境
4.加载base64解码后的指令

image.png (28.86 KB, 下载次数: 0)
下载附件
2025-6-22 18:55 上传
5.指令处理循环 读取操作码 处理不同的操作码 解码操作码语义

image.png (77.73 KB, 下载次数: 0)
下载附件
解码操作码语义
2025-6-22 22:11 上传
6. 类型推断生成ast 生成不同类型节点 根据值类型生成对应AST节点

image.png (41.56 KB, 下载次数: 0)
下载附件
2025-6-22 18:57 上传
7.ast生成 根据操作类型创建对应的AST节点 将节点添加到程序体

image.png (23.3 KB, 下载次数: 0)
下载附件
2025-6-22 18:56 上传
六、输出虚拟化之前的js代码

image.png (123.73 KB, 下载次数: 0)
下载附件
2025-6-22 18:52 上传
一个变种白盒AES,一个变异的base64
web端协议参数生成

image.png (325.81 KB, 下载次数: 0)
下载附件
协议
2025-6-22 22:17 上传
app端webview参数生成

image.png (198.22 KB, 下载次数: 0)
下载附件
app
2025-6-22 22:19 上传