“逆向VM字节码程序”的学习(四)

admin 2026-02-02 00:06:08 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文通过IDAPro逆向分析SimpleVM.exe程序,详细剖析了VM解释器架构、状态结构及13条指令集功能。文章分析了字节码数据位置与执行流程,指出程序具备PC边界、算术溢出及栈边界检查等安全特性。建议读者提取完整字节码、编写反汇编器及VM模拟器进行动态分析,加深对虚拟机保护技术的理解。 综合评分: 88 文章分类: 逆向分析,二进制安全


cover_image

“逆向VM字节码程序”的学习(四)

原创

MicroPest MicroPest

MicroPest

2026年2月1日 17:21 安徽

昨天,我们通过编写VM字节码程序(《“逆向VM字节码程序”的学习(三)》)了解了它的“取码、译码、执行”规则。今天,我们继续对昨天编写的程序进行一次逆向分析,再次加深理解和感悟。

通过网盘分享的程序1:smokestack.exe(《“逆向VM字节码程序”的学习》)

链接: https://pan.baidu.com/s/1Wdw3BNPQfmXTu7If5Fz_RA 提取码: 4v4q

网盘分享的程序2:SimpleVM.exe(《“逆向VM字节码程序”的学习(三)》)

链接: https://pan.baidu.com/s/1alCw5cm2JB_4ChuznOIacg 提取码: ur5m

VM字节码程序分析报告(对SimpleVM.exe逆向分析)

一、 程序概览

通过IDA Pro MCP分析,该程序是一个基于虚拟机(VM)的应用程序,使用自定义字节码来执行逻辑。

二、 VM架构分析

1、 VM解释器函数

  • 地址

    0x41EBA8 (sub_41EBA8)

  • 功能

    : 核心VM解释器,循环读取并执行字节码指令

2、 VM状态结构

VM状态存储在一个数据结构中,关键字段包括:

  • offset +5120 (0x1400)

    : 程序计数器(PC)

  • offset +5124 (0x1404)

    : 未知寄存器(-1初始值)

  • offset +5128 (0x1408)

    : 停止标志(halt flag)

  • offset +0-4095

    : 字节码数组(1024个DWORD,即4KB字节码空间)

3、 VM指令集

通过反编译解释器函数,识别出以下13条指令:

指令 0: HALT

  • 操作

    : 停止VM执行

  • PC变化

    : PC++

  • 功能

    : 程序正常退出

指令 1: PUSH (立即数)

  • 操作

    : 将下一个DWORD作为立即数压入栈

  • PC变化

    : PC += 2

  • 功能

    : 压栈操作数

  • 格式

    [1] [immediate_value]

指令 2: POP

  • 操作

    : 从栈中弹出一个值

  • PC变化

    : PC++

  • 功能

    : 出栈

指令 3: ADD

  • 操作

    : 弹出两个值,相加后压栈

  • PC变化

    : PC++

  • 功能

    : 加法运算 (v2 = pop(); v1 = pop(); push(v1 + v2))

  • 错误检查

    : 检查溢出

指令 4: SUB

  • 操作

    : 弹出两个值,相减后压栈

  • PC变化

    : PC++

  • 功能

    : 减法运算 (v2 = pop(); v1 = pop(); push(v1 – v2))

  • 错误检查

    : 检查溢出

指令 5: MUL

  • 操作

    : 弹出两个值,相乘后压栈

  • PC变化

    : PC++

  • 功能

    : 乘法运算 (v2 = pop(); v1 = pop(); push(v1 * v2))

  • 错误检查

    : 检查乘法溢出

指令 6: DIV

  • 操作

    : 弹出两个值,相除后压栈

  • PC变化

    : PC++

  • 功能

    : 除法运算 (v2 = pop(); v1 = pop(); push(v1 / v2))

  • 错误检查

    : 除数为0时报错 “Division by zero”

指令 7: JMP (无条件跳转)

  • 操作

    : 直接跳转到指定地址

  • PC变化

    : PC = [PC+1]

  • 功能

    : 无条件跳转

  • 格式

    [7] [target_address]

指令 8: JNZ (条件跳转)

  • 操作

    : 如果栈顶非零则跳转

  • PC变化:

  • 如果pop() != 0: PC += 2

  • 否则: PC = [PC+1]

  • 功能: 条件跳转

  • 格式: [8] [target_address]

指令 9: INPUT

  • 操作

    : 读取用户输入并压栈

  • PC变化

    : PC++

  • 功能

    : 输入操作

指令 10: SWAP

  • 操作

    : 交换栈顶两个元素

  • PC变化

    : PC++

  • 功能

    : v2 = pop(); v1 = pop(); push(v2); push(v1)

指令 11: OUTPUT

  • 操作

    : 输出栈顶值

  • PC变化

    : PC++

  • 功能

    : 输出操作

指令 12: EXIT

  • 操作

    : 设置停止标志

  • PC变化

    : 不变

  • 功能

    : 强制退出VM

三、 字节码数据位置

1、 字节码段1

  • 地址

    0x423524

  • 大小

    : 至少11个DWORD

  • 内容:

01 00 00 00  ; PUSH
05 00 00 00  ; [value: 5]
01 00 00 00  ; PUSH
03 00 00 00  ; [value: 3]
01 00 00 00  ; PUSH
02 00 00 00  ; [value: 2]
05 00 00 00  ; MUL
03 00 00 00  ; ADD
0b 00 00 00  ; OUTPUT
0c 00 00 00  ; EXIT
00 00 00 00  ; HALT

分析: 这段代码计算 5 + (3 * 2) = 11 并输出

2、 字节码段2

  • 地址

    0x423554

  • 大小

    : 至少14个DWORD

  • 内容:

01 00 00 00  ; PUSH
05 00 00 00  ; [value: 5]
01 00 00 00  ; PUSH
05 00 00 00  ; [value: 5]
04 00 00 00  ; SUB
08 00 00 00  ; JNZ
0b 00 00 00  ; [target: 11]
01 00 00 00  ; PUSH
78 03 00 00  ; [value: 0x378 = 888]
0b 00 00 00  ; OUTPUT
0c 00 00 00  ; EXIT
01 00 00 00  ; PUSH
e7 03 00 00  ; [value: 0x3e7 = 999]
0b 00 00 00  ; OUTPUT
0c 00 00 00  ; EXIT

分析:

  1. 计算 5 – 5 = 0
  2. 如果结果非0跳转到地址11
  3. 否则输出888并退出
  4. 跳转目标: 输出999并退出

后续还有函数指针表数据。

四、 程序执行流程

1 初始化流程

(1)start

(0x421984) – 程序入口

(2)sub_41F0C4

sub_41F104 – 加载字节码到VM

(3)sub_41F060

  • 拷贝字节码数组

(4)sub_41E9B8

  • 初始化VM状态

(5)sub_41EBA8

  • 执行字节码

2 VM执行过程

(1)检查halt标志

(2)检查PC是否越界 (PC < 0x400)

(3)读取当前指令: opcode = vm[PC]

(4)根据opcode执行相应操作

(5)更新PC

(6)循环执行直到halt

五、辅助函数

  • sub_41EA08

    : 栈PUSH操作

  • sub_41EA9C

    : 栈POP操作

  • sub_41EB30

    : INPUT操作

  • sub_405A70

    sub_405D70sub_4044E4: OUTPUT相关

  • sub_405F50

    : PC越界错误处理

  • sub_405F58

    : 溢出错误处理

  • sub_41B698

    : 错误信息显示

  • sub_407684

    : 错误退出

六、安全特性

程序包含多项安全检查:

  1. PC边界检查

    : 防止代码执行越界

  2. 算术溢出检查

    : ADD/SUB/MUL操作检查溢出

  3. 除零检查

    : DIV操作检查除数

  4. 栈边界检查

    : 防止栈溢出/下溢

七、逆向分析建议

1 提取完整字节码

可以通过以下方式提取完整字节码:

  • 从 0x423524 和 0x423554 读取完整数据
  • 分析调用 sub_41F060 时传递的长度参数

2 编写反汇编器

基于识别的指令集,可以编写Python脚本将字节码反汇编为可读格式。

3 编写VM模拟器

可以用Python重新实现VM解释器,用于动态分析和调试。

八、 示例分析

字节码段1执行过程:

PUSH 5 &nbsp; &nbsp; &nbsp;; stack = [5]
PUSH 3 &nbsp; &nbsp; &nbsp;; stack = [5, 3]
PUSH 2 &nbsp; &nbsp; &nbsp;; stack = [5, 3, 2]
MUL &nbsp; &nbsp; &nbsp; &nbsp; ; stack = [5, 6] &nbsp;(3*2)
ADD &nbsp; &nbsp; &nbsp; &nbsp; ; stack = [11] &nbsp; &nbsp;(5+6)
OUTPUT &nbsp; &nbsp; &nbsp;; 输出: 11
EXIT &nbsp; &nbsp; &nbsp; &nbsp;; 退出
HALT

字节码段2执行过程:

PUSH 5 &nbsp; &nbsp; &nbsp;; stack = [5]
PUSH 5 &nbsp; &nbsp; &nbsp;; stack = [5, 5]
SUB &nbsp; &nbsp; &nbsp; &nbsp; ; stack = [0] &nbsp; &nbsp; (5-5)
JNZ 11 &nbsp; &nbsp; &nbsp;; 0==0, 不跳转
PUSH 888 &nbsp; &nbsp;; stack = [888]
OUTPUT &nbsp; &nbsp; &nbsp;; 输出: 888
EXIT &nbsp; &nbsp; &nbsp; &nbsp;; 退出

九、 总结

这是一个设计良好的基于栈的虚拟机实现,具有:

  • 完整的算术运算指令集
  • 控制流指令(JMP/JNZ)
  • I/O操作(INPUT/OUTPUT)
  • 完善的错误检查机制
  • 清晰的架构设计

该VM可用于:

  • 代码混淆
  • 程序保护
  • 脚本执行引擎
  • CTF挑战

十、 进一步研究方向

  1. 提取并分析所有字节码段
  2. 分析INPUT函数的具体实现
  3. 查找可能的flag检查逻辑
  4. 编写完整的VM模拟器用于动态分析
  5. 寻找可能的VM漏洞或绕过机制

十一、感悟

通过四篇系列文章,我们完成了从对“VM字节码”逆向学习到编程学习的不断深化前进的工作,收获颇多。总体感觉到字节码技术作为编程语言与硬件之间的桥梁,在现代软件工程中扮演着越来越重要的角色:

核心价值

  1. 跨平台性
  • 一次编译,到处运行
  1. 安全性
  • 沙箱隔离、代码保护
  1. 可移植性
  • 中间表示的标准化
  1. 优化空间
  • JIT/AOT编译机会

发展方向

  • 🚀 性能接近原生 (WebAssembly, GraalVM)
  • 🔐 安全性增强 (形式化验证, 沙箱技术)
  • 🌍 应用场景扩展 (区块链, 边缘计算, IoT)
  • 🤖 AI/ML融合 (模型部署, 推理优化)

字节码技术不会消亡,反而会在云原生、Web3、边缘计算等新兴领域找到更广阔的应用空间!


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:MicroPest MicroPest MicroPest《“逆向VM字节码程序”的学习(四)》

评论:0   参与:  0