[机翻] [ABD] 07_Miasm框架详解
07 Miasm 框架详解
本文档深入介绍 Miasm 逆向工程框架的架构、IR 结构、核心 API 体系,以及代码示例与实践要点。
⚠️ API 版本说明:本文档中的 Miasm API 代码示例已于 2026-07 更新至 Miasm 0.1.5+ 版本。课程原始材料使用的是 0.1.3 版本(2020年),部分 API 已发生 breaking change。更新处以
【更新】标注,旧版用法以【旧版 v0.1.3】标注。
目录
一、Miasm 简介
Miasm 是一个开源的逆向工程框架,由 CEA(法国原子能委员会)开发并维护,提供完整的 Python 接口。
核心特性
- 二进制分析工具:提供从二进制加载、反汇编、IR 提升到符号执行的完整流水线。
- Python 接口:所有功能均可通过 Python 调用,便于快速原型开发与自动化分析。
- 多格式支持:支持多种文件格式(ELF, PE, Mach-O 等)。
- 多架构支持:支持 x86, x86_64, ARM, ARM64, MIPS, PowerPC 等架构。
- 丰富的功能集:
| 功能 | 说明 |
|---|---|
| Symbolic Execution(符号执行) | 在 IRCFG 上执行符号化计算,收集路径约束 |
| Concolic Execution(混合执行) | 结合具体执行与符号执行,探索程序路径 |
| Program Slicing(程序切片) | 从程序中提取与特定变量相关的代码切片 |
| Emulation (JIT)(JIT 模拟) | 通过 JIT 编译高效模拟指令执行 |
| Simplification(简化) | 对 IR 表达式与 IRCFG 进行语义等价简化 |
二、优势与弱点
1. 优势
- 比 Angr 更好的向后兼容性:Miasm 的 API 相对稳定,版本升级时的破坏性变更较少,已有分析脚本更易维护。
- 比 Triton 更丰富的功能:Miasm 提供了从静态反汇编到动态符号执行的全栈能力,功能覆盖面广于专注动态符号执行的 Triton。
【更新 2026-07】上述比较基于 2020 年版本。当前状态:
- Miasm:已更新至 0.1.5+,经历了
ir→lifter等重命名(见本文档其他部分的【更新】标注),但仍保持相对稳定。- angr:已更新至 9.2.223,经历了多次重大 breaking changes(angr 7/8/9.1),包括
PathGroup→SimulationManager、state.se→state.solver、CFGAccurate→CFGEmulated等。向后兼容性确实不如 Miasm。- Triton:已更新至 v0.9+,核心 API(
TritonContext、Instruction、processing())完全向后兼容,2020 年代码可直接运行。新增了 Bitwuzla 求解器、LLVM 提升等功能。功能仍然聚焦于动态符号执行。
2. 弱点
- 内存中值的简化性差:Miasm 的表达式简化器(
expr_simp)对涉及内存读取的复杂表达式简化能力有限,难以将多层间接内存访问归约为简单形式。 - 难以从 Miasm IR 还原回 x86 代码:Miasm IR 与 x86 之间的双向转换并非直接支持。若需从 IR 重新生成可执行的 x86 代码,需经过多步翻译链:
x86 汇编 → Miasm IR → LLVM IR → x86 汇编
这条翻译链的每一步都可能引入信息丢失或不一致,且 LLVM IR → x86 的代码生成质量受限于 LLVM 后端对 Miasm IR 语义的还原程度。
- 自动分析无法扩展到整个二进制:Miasm 的符号执行、数据流分析等技术在面对大规模二进制(整个可执行文件)时会遭遇路径爆炸与性能瓶颈,通常只能应用于函数级或基本块级片段。
三、Miasm 代码示例
以下展示 Miasm 的标准使用流程:加载二进制 → 反汇编 → 提升 IR → 符号执行。
from miasm.analysis.binary import Container
from miasm.analysis.machine import Machine
from miasm.ir.symbexec import SymbolicExecutionEngine
from miasm.core.locationdb import LocationDB
# 1. 创建位置数据库(LocationDB),用于管理地址与标签的映射
loc_db = LocationDB()
# 2. 加载二进制文件
with open('target.bin', 'rb') as fstream:
# Container.from_stream 解析文件格式(ELF/PE/Mach-O),提取入口点、节区等信息
cont = Container.from_stream(fstream, loc_db)
# Machine 根据二进制架构(如 'x86_32', 'x86_64', 'arml')创建对应的机器实例
machine = Machine(cont.arch)
# 3. 反汇编:从入口点开始,生成汇编级控制流图(AsmCFG)
# dis_engine 是反汇编引擎,dis_multiblock 处理多基本块(含循环、间接跳转)
mdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db)
asmcfg = mdis.dis_multiblock(cont.entry_point)
# 4. 提升:将 AsmCFG 转换为 IR 级控制流图(IRCFG)
# 【更新】machine.ir() → machine.lifter(),IR 分析器重命名为 Lifter
# 【旧版 v0.1.3】machine.ir() 返回架构对应的 IR 分析器(ira)
# 【旧版 v0.1.3】ir = machine.ir(cont.loc_db)
lifter = machine.lifter(cont.loc_db)
# 【更新】ir.new_ircfg_from_asmcfg() → lifter.new_ircfg_from_asmcfg()
ircfg = lifter.new_ircfg_from_asmcfg(asmcfg)
# 5. 为入口点添加可读标签
cont.loc_db.add_location(offset=cont.entry_point, name='entrypoint')
# 6. 符号执行:创建 SymbolicExecutionEngine 实例
# 【更新】SymbolicExecutionEngine(ir, ...) → SymbolicExecutionEngine(lifter)
# 【旧版 v0.1.3】第二个参数为符号化信息(symbolic init),可指定哪些寄存器/内存为符号变量
# 【旧版 v0.1.3】sb = SymbolicExecutionEngine(ir, ...)
# 【更新】v0.1.5+ 中 symbols 参数不再在构造函数中传递,改用 sb.symbols 设置
sb = SymbolicExecutionEngine(lifter)
# 7. 执行符号执行
# run_block_at 从指定地址开始执行一个基本块,返回 PC(程序计数器)值
sb.run_block_at(ircfg, cont.entry_point)
流程总结:
Container.from_stream() → Machine() → dis_engine() → dis_multiblock()
↓ ↓ ↓ ↓
二进制加载 架构选择 反汇编引擎 AsmCFG
↓
lifter.new_ircfg_from_asmcfg() → SymbolicExecutionEngine() → run_block_at()
↓ ↓
IRCFG 符号执行结果
【更新】流程图中
ir.new_ircfg_from_asmcfg()已更新为lifter.new_ircfg_from_asmcfg()。
【旧版 v0.1.3】ir.new_ircfg_from_asmcfg()
四、Miasm 反汇编结构
Miasm 的反汇编结果以控制流图形式组织:
AsmCFG(汇编级控制流图)
- AsmCFG:控制流图(Control Flow Graph),由汇编级基本块(AsmBlock)组成。
- AsmBlock:基本块(Basic Block),即一段顺序执行、无内部跳转的汇编指令序列。
AsmCFG(汇编级控制流图)
├── AsmBlock(基本块 1)
│ ├── 指令 1: mov eax, 0x1
│ ├── 指令 2: add eax, 0x2
│ └── 指令 3: jz 0x401000 ← 跳转指令,基本块边界
│
├── AsmBlock(基本块 2) ← 跳转目标
│ ├── 指令 4: xor eax, eax
│ └── 指令 5: ret
│
└── AsmBlock(基本块 3) ← fall-through
├── 指令 6: sub eax, 0x1
└── 指令 7: jmp 0x401020
AsmCFG 的特点:
- 节点为 AsmBlock,边为控制流转移(跳转、fall-through)。
dis_multiblock()能够处理复杂控制流,包括循环、间接跳转的近似解析。
五、Miasm IR 结构
将 AsmCFG 提升为 IR 后,得到 IRCFG。Miasm 的 IR 结构层次清晰:
层次结构
- IRCFG:IR 级控制流图,由 IRBlock 组成。
- IRBlock:IR 基本块,包含若干 AssignBlock。
- AssignBlock:赋值块,由若干
dst = src赋值组成,采用 SSA 形式。
IRCFG(IR 级控制流图)
├── IRBlock(IR 基本块 1)
│ ├── AssignBlock: dst = src, dst = src, ... ← 对应一条指令的副作用
│ └── AssignBlock: dst = src, dst = src, ... ← 对应下一条指令
│
└── IRBlock(IR 基本块 2)
├── AssignBlock: dst = src, dst = src, ...
└── AssignBlock: dst = src, dst = src, ...
AssignBlock 的含义
- 每条汇编指令被提升为一个 AssignBlock,包含该指令的所有副作用。
- 例如,
add eax, ebx的副作用包括:更新EAX、更新标志位(zf,cf,of等)——这些都打包在同一个 AssignBlock 中。 - AssignBlock 内的赋值采用 SSA 形式,确保每个变量只被赋值一次。
# 示例:add eax, ebx 的 AssignBlock
AssignBlock({
ExprId('EAX', 32): ExprOp('+', ExprId('EAX', 32), ExprId('EBX', 32)),
ExprId('zf', 1): ExprCond(ExprOp('+', ExprId('EAX', 32), ExprId('EBX', 32)),
ExprInt(0, 1), ExprInt(1, 1)),
ExprId('cf', 1): ..., # 进位标志
ExprId('of', 1): ..., # 溢出标志
...
})
六、Miasm IR 元素表
Miasm IR 中的所有表达式都是 Expr 类的子类。下表列出核心元素及其人类可读形式:
| Element(IR 元素) | Human Form(人类可读形式) | 说明 |
|---|---|---|
ExprInt |
0x18 |
整数常量 |
ExprId |
EAX |
变量标识符(寄存器名、临时变量等) |
ExprLoc |
loc_17 |
位置引用(代码地址的符号化表示) |
ExprCond |
A ? B : C |
条件表达式:若 A 非零则取 B,否则取 C |
ExprMem |
@16[ESI] |
内存读取:从地址 ESI 读取 16 位值 |
ExprOp |
A + B |
运算:对操作数应用操作码(+, -, *, <<, >>, &, | 等) |
ExprSlice |
AH = EAX[8:16] |
位切片:取 EAX 的第 8-15 位 |
ExprCompose |
AX = AH.AL |
位组合:将多个切片拼接为新值 |
ExprAssign |
A = B |
赋值:将 B 的值赋给 A。【更新】ExprAff 已弃用,使用 ExprAssign。【旧版 v0.1.3】ExprAff |
各元素详解
ExprInt — 整数常量
from miasm.expression.expression import ExprInt
# 创建一个 32 位的整数常量 0x18
expr = ExprInt(0x18, 32)
# 人类可读形式: 0x18
ExprId — 变量标识符
from miasm.expression.expression import ExprId
# 创建一个 32 位的变量标识符 EAX
expr = ExprId('EAX', 32)
# 人类可读形式: EAX
ExprLoc — 位置引用
# ExprLoc 引用控制流图中的某个位置(地址)
# loc_db 为位置 0x401000 分配标签 loc_17
loc_db.add_location(offset=0x401000, name='loc_17')
# 人类可读形式: loc_17
ExprCond — 条件表达式
from miasm.expression.expression import ExprCond, ExprInt
# cond ? value_if_true : value_if_false
expr = ExprCond(cond_expr, ExprInt(1, 32), ExprInt(0, 32))
# 人类可读形式: cond ? 0x1 : 0x0
ExprMem — 内存读取
from miasm.expression.expression import ExprMem
# 从地址 ESI 读取 16 位值
expr = ExprMem(ExprId('ESI', 32), 16)
# 人类可读形式: @16[ESI]
ExprOp — 运算
from miasm.expression.expression import ExprOp
# EAX + EBX
expr = ExprOp('+', ExprId('EAX', 32), ExprId('EBX', 32))
# 人类可读形式: EAX + EBX
# EAX << 2
expr_shift = ExprOp('<<', ExprId('EAX', 32), ExprInt(2, 32))
# 人类可读形式: EAX << 0x2
ExprSlice — 位切片
from miasm.expression.expression import ExprSlice
# 取 EAX 的第 8 位到第 15 位(即 AH 寄存器)
expr = ExprSlice(ExprId('EAX', 32), 8, 16)
# 人类可读形式: EAX[8:16]
ExprCompose — 位组合
from miasm.expression.expression import ExprCompose
# 将 AH(高字节)和 AL(低字节)组合为 AX
expr = ExprCompose(
(ExprId('AL', 8), 0, 8), # AL 占第 0-7 位
(ExprId('AH', 8), 8, 16), # AH 占第 8-15 位
)
# 人类可读形式: AH.AL
ExprAssign — 赋值
【更新】
ExprAff已弃用,使用ExprAssign替代。ExprAff仍可作为别名使用但会产生弃用警告。
【旧版 v0.1.3】使用ExprAff。
# 【更新】使用 ExprAssign 替代已弃用的 ExprAff
from miasm.expression.expression import ExprAssign
# 【旧版 v0.1.3】from miasm.expression.expression import ExprAff
# EAX = EBX
# 【更新】expr = ExprAssign(ExprId('EAX', 32), ExprId('EBX', 32))
# 【旧版 v0.1.3】expr = ExprAff(ExprId('EAX', 32), ExprId('EBX', 32))
expr = ExprAssign(ExprId('EAX', 32), ExprId('EBX', 32))
# 人类可读形式: EAX = EBX
七、Miasm IR 指令转换示例
以下展示 x86 指令如何被提升为 Miasm IR:
示例 1:mov eax, ebx
mov eax, ebx
→ ExprAssign(ExprId("EAX", 32), ExprId("EBX", 32))
【更新】
ExprAff已弃用,使用ExprAssign。
【旧版 v0.1.3】→ ExprAff(ExprId("EAX", 32), ExprId("EBX", 32))
语义:将 EBX 的值赋给 EAX。仅一条赋值,无副作用。
示例 2:push eax
push eax
→ esp = esp - 0x4; @32[esp - 0x4] = eax
语义:
- 栈指针 ESP 减 4(栈向低地址增长)。
- 将 EAX 的值写入栈顶(新 ESP 指向的地址)。
IR 表示:
AssignBlock({
ExprId('ESP', 32): ExprOp('-', ExprId('ESP', 32), ExprInt(4, 32)),
ExprMem(ExprOp('-', ExprId('ESP', 32), ExprInt(4, 32)), 32): ExprId('EAX', 32)
})
示例 3:cmp eax, ebx
cmp eax, ebx
→ zf = (EAX - EBX) ? 0 : 1; cf = ...; of = ...
语义:cmp 指令执行 EAX - EBX 但不保存结果,仅更新标志位:
zf(零标志):若EAX - EBX == 0(即 EAX == EBX),则 zf = 1,否则 zf = 0。cf(进位标志):若发生借位(即 EAX < EBX,无符号),则 cf = 1。of(溢出标志):若有符号运算溢出,则 of = 1。
IR 表示:
AssignBlock({
ExprId('zf', 1): ExprCond(
ExprOp('-', ExprId('EAX', 32), ExprId('EBX', 32)),
ExprInt(0, 1), ExprInt(1, 1) # 差非零→zf=0,差为零→zf=1
),
ExprId('cf', 1): ..., # 进位标志的具体表达式
ExprId('of', 1): ..., # 溢出标志的具体表达式
ExprId('af', 1): ..., # 辅助进位标志
ExprId('pf', 1): ..., # 奇偶标志
ExprId('sf', 1): ..., # 符号标志
})
八、核心 Miasm API 体系
下表按模块组织 Miasm 的核心 API:
| 模块 | 关键 API | 用途 |
|---|---|---|
analysis.machine |
Machine('x86_32' / 'x86_64') |
架构入口,创建对应架构的机器实例 |
analysis.machine |
machine.lifter(loc_db) / machine.lifter_model_call(loc_db) |
【更新】IR Lifter 创建。【旧版 v0.1.3】machine.ir() / machine.ira() 【已弃用】 |
analysis.binary |
Container.from_stream / from_string |
二进制加载,解析文件格式(ELF/PE 等) |
analysis.data_flow |
DeadRemoval, remove_empty_assignblks, merge_blocks |
数据流优化(死代码移除、空块清理、块合并) |
analysis.cst_propag |
propagate_cst_expr |
常量传播 |
analysis.simplifier |
IRCFGSimplifierCommon |
IRCFG 通用简化 |
analysis.dse |
DSEPathConstraint |
动态符号执行(DSE),含路径约束 |
analysis.sandbox |
Sandbox_Linux_x86_64 |
Linux 沙箱环境,用于安全执行/模拟 |
ir.symbexec |
SymbolicExecutionEngine |
符号执行引擎,在 IRCFG 上执行 |
ir.translators |
Translator.to_language("z3") |
表达式翻译(IR → Z3 / LLVM 等) |
expression.expression |
ExprInt / ExprMem / ExprId / ExprCond / ExprAssign |
表达式构造,构建 IR 元素。【更新】ExprAff 已弃用,使用 ExprAssign。【旧版 v0.1.3】ExprAff |
expression.simplifications |
expr_simp |
表达式简化,语义等价化简 |
core.parse_asm |
parse_txt |
汇编文本解析,从文本生成 AsmCFG |
各模块使用要点
analysis.machine — 架构入口
from miasm.analysis.machine import Machine
# 创建 x86_32 架构实例
machine = Machine('x86_32')
# 【更新】获取 IR Lifter(替代旧版 ira)
# 【旧版 v0.1.3】ir_arch = machine.ira(loc_db) # 【已弃用】
# 【更新】machine.ira() → machine.lifter_model_call(),变量名 ir_arch → lifter
lifter = machine.lifter_model_call(loc_db)
# 获取反汇编引擎
mdis = machine.dis_engine(bin_stream, loc_db=loc_db)
# 【更新】获取 jitter(模拟执行器),jitter 参数命名变化
# 【旧版 v0.1.3】jitter = machine.jitter(loc_db, 'python') # 'python' 或 'gcc' 后端
# 【更新】jitter 的第二个参数改为关键字参数 jit_type
jitter = machine.jitter(loc_db, jit_type='python') # 'python' 或 'gcc' 后端
API 变更说明:
- 【更新】
machine.ir()→machine.lifter()【旧版 v0.1.3 已弃用】- 【更新】
machine.ira()→machine.lifter_model_call()【旧版 v0.1.3 已弃用】- 【更新】
machine.jitter(loc_db, 'python')→machine.jitter(loc_db, jit_type='python')- 【更新】变量命名约定:
ir→lifter,ir_arch→lifter
analysis.binary — 二进制加载
from miasm.analysis.binary import Container
from miasm.core.locationdb import LocationDB
loc_db = LocationDB()
# 从文件流加载
with open('target.elf', 'rb') as f:
cont = Container.from_stream(f, loc_db)
# 从字节串加载
cont = Container.from_string(data, loc_db)
# 访问入口点、节区等
print(cont.arch) # 架构名,如 'x86_32'
print(cont.entry_point) # 入口点地址
print(cont.bin_stream) # 二进制字节流
analysis.data_flow — 数据流优化
from miasm.analysis.data_flow import (
DeadRemoval, # 死代码移除 pass
remove_empty_assignblks, # 移除空赋值块
merge_blocks, # 合并相邻基本块
)
# 死代码移除:基于活跃度分析,删除非活跃的赋值
# 【更新】DeadRemoval(ir_arch)(ircfg) → DeadRemoval(lifter)(ircfg)
# 【旧版 v0.1.3】DeadRemoval(ir_arch)(ircfg)
DeadRemoval(lifter)(ircfg)
# 移除空 AssignBlock(无任何赋值的块)
remove_empty_assignblks(ircfg)
# 合并可合并的相邻 IRBlock
merge_blocks(ircfg)
analysis.cst_propag — 常量传播
from miasm.analysis.cst_propag import propagate_cst_expr
# 对指定地址执行常量传播
# 【更新】ir_arch → lifter(变量名变更)
# 【旧版 v0.1.3】# ir_arch: IR 分析器
# ircfg: IR 控制流图
# addr: 起始地址
# init_infos: 初始符号信息(已知常量值)
# 【旧版 v0.1.3】propagate_cst_expr(ir_arch, ircfg, addr, init_infos)
propagate_cst_expr(lifter, ircfg, addr, init_infos)
analysis.simplifier — IRCFG 通用简化
from miasm.analysis.simplifier import IRCFGSimplifierCommon
# 创建简化器实例
# 【更新】IRCFGSimplifierCommon(ir_arch) → IRCFGSimplifierCommon(lifter)
# 【旧版 v0.1.3】simplifier = IRCFGSimplifierCommon(ir_arch)
simplifier = IRCFGSimplifierCommon(lifter)
# 对整个 IRCFG 执行简化
simplifier.simplify(ircfg)
analysis.dse — 动态符号执行
from miasm.analysis.dse import DSEPathConstraint
# 创建 DSE 实例,带路径约束追踪
# 【更新】DSEPathConstraint(machine, ir_arch, ...) → DSEPathConstraint(machine, loc_db, ...)
# 【旧版 v0.1.3】dse = DSEPathConstraint(machine, ir_arch, ...)
# 【更新】v0.1.5+ 中 DSEPathConstraint 需要 loc_db 参数,ir_arch 参数已移除
# 【更新】dse.ir_arch 属性 → dse.lifter;dse.cur_solver 属性 → dse.z3_cur
dse = DSEPathConstraint(machine, loc_db)
dse.run(...) # 执行动态符号执行
analysis.sandbox — Linux 沙箱
from miasm.analysis.sandbox import Sandbox_Linux_x86_64
# 创建 Linux x86_64 沙箱
sandbox = Sandbox_Linux_x86_64(loc_db, 'target.bin')
# 沙箱提供安全的执行环境,支持系统调用模拟
ir.symbexec — 符号执行引擎
from miasm.ir.symbexec import SymbolicExecutionEngine
# 创建符号执行引擎
# 【更新】SymbolicExecutionEngine(ir, symbols) → SymbolicExecutionEngine(lifter)
# 【旧版 v0.1.3】sb = SymbolicExecutionEngine(ir, symbols)
# 【更新】v0.1.5+ 中 symbols 参数不再在构造函数中传递,通过 sb.symbols 设置
sb = SymbolicExecutionEngine(lifter)
# 执行一个基本块
pc = sb.run_block_at(ircfg, addr)
# 访问符号状态
print(sb.symbols) # 当前符号状态(寄存器/内存的符号值)
ir.translators — 表达式翻译
from miasm.ir.translators import Translator
# 翻译为 Z3 表达式(用于约束求解)
z3_translator = Translator.to_language('z3')
z3_expr = z3_translator.from_expr(miasm_expr)
# 翻译为 LLVM IR(用于复用 LLVM 优化 pass)
llvm_translator = Translator.to_language('llvm')
llvm_expr = llvm_translator.from_expr(miasm_expr)
expression.simplifications — 表达式简化
from miasm.expression.simplifications import expr_simp
# 对表达式进行简化
simplified = expr_simp(complex_expr)
# 例如: (x + 0) → x, (x * 1) → x, (x - x) → 0
core.parse_asm — 汇编文本解析
from miasm.core.parse_asm import parse_txt
from miasm.analysis.machine import Machine
machine = Machine('x86_32')
mn_x86 = machine.mn() # 获取汇编器/反汇编器
assembly = """
main:
MOV EAX, 0x1
MOV EBX, 0x2
ADD EAX, EBX
RET
"""
# 解析汇编文本,生成 AsmCFG
asmcfg, loc_db = parse_txt(mn_x86, 'x86_32', loc_db, assembly)
九、参考资料
- Desclaux, F. and Mougey, É. Miasm: Reverse Engineering Framework. Black Hat USA 2018.
- Miasm 官方文档与 GitHub 仓库:https://github.com/cea-sec/miasm
- Salwan, Bardin, Potet. Symbolic Deobfuscation: From Virtualized Code Back to the Original. DIMVA 2018.(基于 Miasm 的虚拟化代码反混淆)

浙公网安备 33010602011771号