ARM64 ELF 虚拟机保护系统
ARM64 ELF Virtual Machine Protection System
将 ARM64 原生指令翻译为自定义虚拟机字节码,实现函数级代码保护
Features • Architecture • Quick Start • Usage • Building • License
VMPacker 是一个针对 ARM64 (AArch64) Linux ELF 二进制文件的虚拟机代码保护(VMP)系统。它将目标函数的原生 ARM64 指令解码为中间表示,再翻译为自定义 VM 字节码,并将嵌入式 VM 解释器注入 ELF 文件中,运行时由 VM 解释执行被保护函数。
ARM64 Native Code → Decode → Translate → Custom VM Bytecode
↓
Original ELF ← Inject ← VM Interpreter Stub
| 防护层 | 技术 | 说明 |
|---|---|---|
| VM 保护 | 自定义 ISA | 随机映射操作码,逆向者无法直接识别指令含义 |
| OpcodeCryptor | 逐指令 opcode 加密 | enc[pc] = op[pc] ^ (key ^ (pc * 0x9E3779B9)) |
| 字节码反转 | 执行序反转 | 指令按逆序存储,解释器反向遍历 |
| Token 入口 | 3 指令跳板 | 原函数替换为 token 化入口,隐藏实际字节码位置 |
| 间接 Dispatch | 函数指针跳转表 | 栈上运行时填充,断裂 IDA 交叉引用 |
![]() |
![]() |
![]() |
| 目标函数列表 | 函数分析选择 | 保护选项配置 |
![]() |
![]() |
|
| 实时日志输出 | 保护完成反馈 |
vmp/
├── cmd/vmpacker/ # CLI 入口
│ ├── main.go # 命令行参数解析 + 流程编排
│ └── vm_interp.bin # 编译后的 VM 解释器 (GCC, go:embed)
│
├── pkg/ # Go 核心库
│ ├── arch/arm64/ # ARM64 架构支持
│ │ ├── decoder.go # 表驱动指令解码器 (实现 vm.Decoder)
│ │ ├── decode_*.go # 解码模式表 (DP-IMM/DP-REG/Branch/LdSt)
│ │ ├── translator.go # ARM64 → VM 字节码翻译器
│ │ ├── tr_alu.go # ALU 指令翻译
│ │ ├── tr_branch.go # 分支指令翻译
│ │ ├── tr_loadstore.go # 内存指令翻译
│ │ ├── tr_bitfield.go # 位域指令翻译
│ │ └── tr_special.go # 特殊指令翻译 (ADRP/ADR)
│ ├── vm/ # VM ISA 定义
│ │ ├── types.go # 公共类型 + 接口 (Decoder/Translator/Packer)
│ │ ├── opcodes.go # 58+ 条 VM 操作码定义 (随机映射值)
│ │ └── disasm.go # VM 字节码反汇编器
│ └── binary/elf/ # ELF 二进制操作
│ ├── packer.go # ELF VMP 注入 (PT_NOTE hijack, 跳板生成)
│ └── trampoline.go # 跳板代码生成
│
├── stub/ # C VM 解释器 (编译为 PIC flat binary)
│ ├── vm_interp_clean.c # 解释器主循环 + 入口点
│ ├── vm_types.h # VM CPU 上下文 (vm_ctx_t)
│ ├── vm_opcodes.h # C 侧操作码定义 (与 opcodes.go 同步)
│ ├── vm_decode.h # 字节码读取工具函数
│ ├── vm_token.h # Token 编解码 + 描述符表
│ ├── vm_dispatch.h # 间接 Dispatch 跳转表
│ ├── vm_crc.h # CRC32 完整性校验
│ ├── vm_sections.h # Handler Section 分散宏
│ ├── vm_interp.lds # 链接脚本
│ └── vm_handlers/ # 模块化指令处理器
│ ├── h_alu.h # 算术/逻辑运算
│ ├── h_mem.h # 内存访问
│ ├── h_branch.h # 分支/跳转
│ ├── h_cmp.h # 比较/条件
│ ├── h_mov.h # 数据移动
│ ├── h_stack.h # 栈操作 (PUSH/POP)
│ └── h_system.h # 系统 (SVC/MRS/BLR/BR/RET)
│
├── vmp-gui/ # Wails GUI 前端
│ ├── frontend/ # Vue 3 + Element Plus
│ └── backend/ # Go 后端绑定
│
└── build/ # 预编译工具 + 测试产物
项目采用接口驱动的模块化架构,便于扩展到新的指令集和二进制格式:
// 架构解码器接口 — 未来可扩展 x86, RISC-V
type Decoder interface {
Decode(raw uint32, offset int) Instruction
InstName(op int) string
}
// 字节码翻译器接口
type Translator interface {
Translate(instructions []Instruction) (*TranslateResult, error)
}
// 二进制格式注入器接口 — 未来可扩展 PE, Mach-O
type Packer interface {
Process() error
}
graph LR
A[输入 ELF] --> B[查找目标函数]
B --> C[提取 ARM64 指令]
C --> D[解码 ARM64]
D --> E[翻译为 VM 字节码]
E --> F[XOR 加密字节码]
F --> G[注入 VM 解释器]
G --> H[生成跳板代码]
H --> I[替换原函数入口]
I --> J[输出保护后 ELF]
git clone https://github.com/LeoChen-CoreMind/VMPacker.git
cd VMPacker
make all
# 保护单个函数
./vmpacker -func check_license -v -o protected.elf original.elf
# 保护多个函数
./vmpacker -func "check_license,verify_token" -v -o protected.elf original.elf
# 指定地址范围
./vmpacker -addr "0x4006AC-0x400790:main" -v -o protected.elf original.elf
# 混合模式
./vmpacker -addr "0x4006AC-0x400790:main" -func verify -o protected.elf original.elf
./vmpacker -info input.elf
| 选项 | 默认值 | 说明 |
|---|---|---|
-func | — | 要保护的函数名(逗号分隔) |
-addr | — | 按地址保护(格式: 0xSTART-0xEND[:name]) |
-o | input.vmp | 输出文件路径 |
-v | false | 详细输出(显示反汇编) |
-strip | true | 清除符号表 |
-debug | false | 生成 ARM64 → VM 字节码对照文件 |
-token | true | Token 化入口模式 |
-info | false | 仅打印 ELF 信息 |
# 标准版 (GCC)
aarch64-linux-gnu-gcc -Os -nostdlib -fPIC -ffreestanding \
-o stub.elf stub/vm_interp_clean.c \
-T stub/vm_interp.lds
aarch64-linux-gnu-objcopy -O binary stub.elf vm_interp.bin
# OLLVM 混淆版
# 使用 OLLVM 交叉编译器替换 GCC,启用 -mllvm 混淆选项
# vmpacker (Go 二进制,内嵌 stub blob)
go build -o vmpacker ./cmd/vmpacker/
cd vmpacker
make gui
VMPacker 定义了一套自定义指令集架构(ISA),操作码采用随机映射值以增加逆向难度。
| 操作码 | 助记符 | 格式 | 说明 |
|---|---|---|---|
0x5A | MOV_IMM64 | [op][r][imm64] 10B | 64 位立即数加载 |
0x49 | MOV_IMM32 | [op][r][imm32] 6B | 32 位立即数加载 |
0x2F | MOV_REG | [op][d][s] 3B | 寄存器间移动 |