angr 系列教程(一)核心概念及模块解读
字数 1767 2025-08-24 20:49:31
angr 核心概念及模块详解
1. 概述
angr 是一个功能强大的二进制分析框架,用于执行符号执行、控制流分析、数据依赖分析等多种二进制分析任务。本教程将详细介绍 angr 的核心概念和主要模块。
2. 安装
安装 angr 可以通过 pip 直接安装:
pip install angr
3. 顶层接口
3.1 Project
Project 是 angr 模块的主类,用于包含一组二进制文件及其关系,并对其执行分析。
import angr
proj = angr.Project('/bin/true')
基本属性:
proj.arch- 架构信息proj.entry- 入口地址proj.filename- 文件名
3.2 Loader
CLE 模块用于将二进制文件载入虚拟地址空间,主要接口是 loader 类。
proj.loader # 查看加载器信息
proj.loader.shared_objects # 获取共享库信息
proj.loader.min_addr # 最小地址
proj.loader.max_addr # 最大地址
3.3 Factory
AngrObjectFactory,提供重要分析对象的接口:
# 获取基本块
block = proj.factory.block(proj.entry)
# 创建状态
state = proj.factory.entry_state()
3.4 States
SimState 对象代表程序的一个实例镜像,模拟执行某个时刻的状态。
state = proj.factory.entry_state()
访问寄存器和内存:
state.regs.rip # 获取寄存器值
state.mem[proj.entry].int.resolved # 读取内存
3.5 Simulation Managers
用于管理 state,执行运行、模拟等操作。
simgr = proj.factory.simulation_manager(state)
simgr.step() # 执行一个基本块
3.6 Analyses
angr 内置分析方法:
proj.analyses.CFGFast() # 快速控制流分析
proj.analyses.BackwardSlice() # 后向切片分析
4. 核心模块详解
4.1 Loader 加载模块
4.1.1 已加载的对象
proj.loader.main_object # 主对象
proj.loader.all_objects # 所有对象
获取 ELF 信息:
obj.sections # 分段信息
obj.plt # PLT 表
obj.linked_base # 预链接基址
obj.mapped_base # 实际装载基址
4.1.2 符号和重定位
查找符号:
malloc = proj.loader.find_symbol('malloc')
符号地址:
.rebased_addr- 全局地址空间的地址.linked_addr- 相对于预链接基址的地址.relative_addr- 相对于对象基址的地址
4.1.3 加载选项
常用选项:
auto_load_libs- 是否自动加载依赖skip_libs- 避免加载的库except_missing_libs- 无法解析共享库时是否抛出异常
proj = angr.Project('/bin/true', load_options={"auto_load_libs": False})
4.1.4 pre-binary 选项
angr.Project('binary',
main_opts={'backend': 'blob', 'arch': 'i386'},
lib_opts={'libc.so.6': {'backend': 'elf'}})
backend 类型:
- elf - ELF 文件加载器
- pe - PE 文件加载器
- blob - 平面镜像加载器
4.2 符号函数摘要集
SimProcedures 用符号摘要替换库函数:
angr.SIM_PROCEDURES['libc']['malloc'] # malloc 摘要
4.3 Hooking
Hook 机制:
# 使用 SimProcedure 进行 hook
stub_func = angr.SIM_PROCEDURES['stubs']['ReturnUnconstrained']
proj.hook(0x10000, stub_func())
# 自定义 hook 函数
@proj.hook(0x20000, length=5)
def my_hook(state):
state.regs.rax = 1
4.4 States 状态管理
4.4.1 状态预设
entry_state() # 入口状态
blank_state() # 空白状态
call_state() # 函数调用状态
full_init_state() # 完整初始化状态
4.4.2 访问寄存器
state.regs.rip # 指令指针
state.regs.rax # 通用寄存器
4.4.3 访问内存
# 使用 state.memory 接口
state.memory.store(0x4000, state.solver.BVV(0x1234, 128))
state.memory.load(0x4004, 6) # 读取6字节
# 设置端序
state.memory.load(0x4000, 4, endness=archinfo.Endness.LE)
4.4.4 状态选项
# 添加选项
s.options.add(angr.options.LAZY_SOLVES)
# 创建时设置选项
s = proj.factory.entry_state(add_options={angr.options.LAZY_SOLVES})
4.4.5 状态插件
- history 插件:
for addr in state.history.bbl_addrs: # 执行过的基本块地址
print(hex(addr))
- callstack 插件:
state.callstack.func_addr # 当前函数地址
state.callstack.ret_addr # 返回地址
4.5 模拟管理器(Simulation Managers)
4.5.1 基本操作
simgr = proj.factory.simgr(state)
simgr.step() # 执行一步
simgr.run() # 执行到结束
4.5.2 stash 管理
特殊 stash:
- active - 默认执行的状态
- deadend - 无法继续执行的状态
- pruned - 被剪枝的状态
- unconstrained - 不受约束的状态
移动状态:
simgr.move(from_stash='deadended', to_stash='authenticated',
filter_func=lambda s: b'Welcome' in s.posix.dumps(1))
4.5.3 explore 探索
simgr.explore(find=lambda s: b"Congrats" in s.posix.dumps(1))
s = simgr.found[0] # 获取找到的状态
4.5.4 explore 技术
# 使用 DFS 策略
tech = angr.exploration_techniques.DFS()
simgr.use_technique(tech)
其他技术:
- LengthLimiter - 限制路径长度
- Tracer - 跟踪动态轨迹
- Oppologist - 处理不支持指令
4.6 求解引擎
4.6.1 位向量
# 创建具体值
one = state.solver.BVV(1, 64) # 64位值1
# 创建符号变量
x = state.solver.BVS("x", 64) # 64位符号变量x
4.6.2 符号约束
state.solver.add(x > y) # 添加约束
state.solver.add(y > 2)
state.solver.add(10 > x)
4.6.3 约束求解
state.solver.eval(x) # 求解一个可行解
state.solver.eval_one(x) # 求解唯一解
state.solver.eval_upto(x, 5) # 最多5个解
state.solver.min(x) # 最小解
state.solver.max(x) # 最大解
4.7 执行引擎
angr 使用多种引擎模拟代码执行:
- failure engine - 处理不可继续状态
- syscall engine - 处理系统调用
- hook engine - 处理 hook
- unicorn engine - 使用 Unicorn 引擎
- VEX engine - 默认引擎
4.8 分析模块
4.8.1 CFG 分析
cfg = p.analyses.CFGFast() # 快速静态分析
cfg = p.analyses.CFGEmulated() # 动态模拟分析
4.8.2 后向切片
cfg = b.analyses.CFGEmulated(keep_state=True)
cdg = b.analyses.CDG(cfg) # 控制依赖图
ddg = b.analyses.DDG(cfg) # 数据依赖图
bs = b.analyses.BackwardSlice(cfg, cdg=cdg, ddg=ddg, targets=[(target_node, -1)])
4.8.3 函数识别
idfer = p.analyses.Identifier()
for addr, symbol in idfer.run():
print(hex(addr), symbol)
5. 更新说明
已变更的接口:
- SimuVEX 已被移除
- Surveyors 已被移除
- 使用 Simulation Manager 代替 Path Group
- 求解引擎接口是 state.solver 而不是 state.se
- CFGAccurate 更名为 CFGEmulated
6. 总结
angr 使用基本流程:
- 创建 project 并设置 state
- 新建符号量/位向量并在内存或其他地方设置
- 设置 Simulation Managers
- 运行,探索满足需要的路径
- 约束求解,获取执行结果
angr 是一个功能强大但复杂的框架,需要结合实践逐步掌握。建议参考官方文档和源码深入理解各模块的实现细节。