angr用户手册:二进制程序静态分析与动态符号执行详解
1. 什么是angr?
angr是一个功能强大且用户友好的二进制分析平台(Binary Analysis Platform),它能够对二进制程序进行深度分析,包括反汇编、中间表示转换、符号执行、控制流分析等多种高级功能。无论是CTF竞赛中的漏洞研究,还是软件安全审计,angr都能提供强大的技术支持。
读完本文后,您将能够:
- 理解angr的核心概念和工作原理
- 掌握二进制程序加载与基本分析方法
- 学会使用符号执行技术解决实际问题
- 了解静态分析与动态分析的结合应用
2. 安装与快速入门
2.1 安装angr
angr可以通过Python包管理器pip直接安装:
mkvirtualenv --python=$(which python3) angr && python -m pip install angr
2.2 第一个angr程序
以下是一个简单的angr程序示例,用于分析二进制文件:
import angr
# 创建一个angr项目,加载二进制文件
project = angr.Project("binary_file", auto_load_libs=False)
# 在指定地址设置钩子函数
@project.hook(0x400844)
def print_flag(state):
print("找到的验证值:", state.posix.dumps(0))
project.terminate_execution()
# 执行分析
project.execute()
官方文档:docs/quickstart.rst
3. 核心概念解析
angr的核心架构基于几个关键概念,理解这些概念对于有效使用angr至关重要:
3.1 项目(Project)
Project是angr分析的起点,它代表一个二进制程序及其分析环境。通过Project可以访问程序的各种信息和分析工具。
import angr
proj = angr.Project("/bin/true") # 加载系统自带的true程序
print(proj.arch) # 打印程序架构信息
3.2 加载器(Loader)
CLE(CLE Loads Everything)是angr的二进制加载组件,负责将二进制文件及其依赖库加载到内存空间中,并提供统一的访问接口。
# 获取主程序对象
main_obj = proj.loader.main_object
print(f"程序入口点: 0x{main_obj.entry:x}")
print(f"程序地址范围: 0x{main_obj.min_addr:x} - 0x{main_obj.max_addr:x}")
# 查找符号
symbol = proj.loader.find_symbol('strcmp')
print(f"符号strcmp地址: 0x{symbol.rebased_addr:x}")
核心概念文档:docs/core-concepts/index.rst 加载器详细文档:docs/core-concepts/loading.rst
4. 静态分析技术
4.1 控制流分析
angr提供了强大的控制流分析能力,可以构建程序的控制流图(CFG),帮助理解程序结构。
# 构建控制流图
cfg = proj.analyses.CFG()
# 获取函数列表
functions = cfg.functions.values()
print(f"找到 {len(functions)} 个函数")
# 查找主函数
main_func = cfg.functions.function(name="main")
if main_func:
print(f"主函数地址: 0x{main_func.addr:x}")
# 打印主函数的基本块
for block in main_func.blocks:
print(f"基本块: 0x{block.addr:x} - 0x{block.addr + block.size:x}")
控制流分析源码:angr/analyses/cfg/
4.2 数据依赖分析
数据依赖分析可以帮助追踪程序中数据的传播路径,对于理解程序逻辑和发现漏洞非常有用。
# 执行数据依赖分析
ddg = proj.analyses.DDG()
# 查找特定地址的数据依赖
dependencies = ddg.get_dependencies(0x4005a0)
print(f"地址0x4005a0的数据依赖: {dependencies}")
数据依赖分析源码:angr/analyses/data_dep/
5. 动态符号执行
符号执行是angr最强大的功能之一,它允许程序以符号值作为输入,探索所有可能的执行路径,从而发现程序中的漏洞和后门。
5.1 状态(State)
State代表程序执行的一个状态,包含寄存器、内存、文件系统等所有信息。符号执行就是通过创建和修改状态来探索程序路径。
# 创建初始状态
state = proj.factory.entry_state()
# 设置符号输入
input_len = 32
symbolic_input = state.solver.BVS("input", input_len * 8)
state.posix.files[0].write(symbolic_input)
state.posix.files[0].seek(0)
# 创建模拟管理器
simgr = proj.factory.simulation_manager(state)
# 探索执行路径
simgr.explore(find=0x400844, avoid=0x400855)
# 检查是否找到目标状态
if simgr.found:
found_state = simgr.found[0]
# 求解输入值
solution = found_state.solver.eval(symbolic_input, cast_to=bytes)
print(f"找到的验证值: {solution.decode()}")
状态管理源码:angr/sim_state.py
5.2 路径探索
angr提供了灵活的路径探索机制,可以通过各种策略引导符号执行过程,提高分析效率。
# 使用深度优先搜索策略
simgr = proj.factory.simulation_manager(state, strategies=[angr.exploration_techniques.DFS()])
# 自定义路径评分函数
def score_path(path):
# 优先探索包含特定字符串引用的路径
if b"secret" in path.state.posix.dumps(1):
return 100
return path.length
# 使用自定义评分策略
simgr.use_technique(angr.exploration_techniques.LoopSeer())
simgr.use_technique(angr.exploration_techniques.Oppologist(score_func=score_path))
# 运行探索
simgr.run()
探索技术源码:angr/exploration_techniques/
6. 高级功能
6.1 钩子(Hook)机制
angr允许用户在指定地址设置钩子,替换或增强原始二进制代码的功能,这对于简化复杂函数或模拟特定行为非常有用。
# 使用内置的SimProcedure钩子
strcmp_stub = angr.SIM_PROCEDURES['libc']['strcmp']
proj.hook_symbol('strcmp', strcmp_stub())
# 自定义钩子函数
@proj.hook(0x400600, length=5)
def my_hook(state):
# 自定义逻辑:将返回值设置为1
state.regs.rax = 1
# 检查钩子状态
if proj.is_hooked(0x400600):
print("地址0x400600已设置钩子")
SimProcedure源码:angr/sim_procedure.py
6.2 反编译
angr集成了反编译功能,可以将二进制代码转换为类C的伪代码,大大提高分析效率。
# 对指定函数进行反编译
func = proj.kb.functions.function(name="main")
if func:
decompiler = proj.analyses.Decompiler(func)
print(decompiler.code)
反编译模块源码:angr/analyses/decompiler/
7. 实际应用案例
7.1 CTF验证场景
在CTF竞赛中,angr可以快速定位验证点并找到通过方法:
import angr
def solve_ctf_challenge(binary_path):
proj = angr.Project(binary_path, auto_load_libs=False)
# 寻找成功状态和失败状态
success_addr = 0x400844 # 成功条件地址
fail_addr = 0x400855 # 失败条件地址
# 创建初始状态
state = proj.factory.entry_state()
# 创建模拟管理器并探索路径
simgr = proj.factory.simulation_manager(state)
simgr.explore(find=success_addr, avoid=fail_addr)
if simgr.found:
# 求解输入
solution = simgr.found[0].solver.eval(state.posix.files[0].content.load(0, 32), cast_to=bytes)
return solution.decode()
return None
# 使用示例
result = solve_ctf_challenge("ctf_binary")
print(f"找到的验证值: {result}")
CTF示例代码:angr/main.py
7.2 恶意软件分析
angr可以帮助分析恶意软件的行为,如字符串解密、网络行为等:
def analyze_malware(binary_path):
proj = angr.Project(binary_path, auto_load_libs=True)
# 查找所有字符串引用
strings = proj.analyses.Identifier()
# 监控网络相关函数调用
@proj.hook_symbol('connect')
def connect_hook(state):
ip = state.solver.eval(state.regs.rdi)
port = state.solver.eval(state.regs.rsi)
print(f"恶意软件尝试连接: {ip}:{port}")
# 执行分析
proj.factory.entry_state().simulate()
return strings
# 使用示例
malware_strings = analyze_malware("malware_sample")
字符串识别源码:angr/analyses/code_tagging.py
8. 总结与资源
8.1 常用资源
- 官方文档:docs/
- 核心API:angr/init.py
- 测试案例:tests/
- 项目教程:README.md
8.2 最佳实践
- 合理设置分析范围:大型程序分析时,使用
auto_load_libs=False减少分析复杂度 - 利用已有分析结果:通过
kb(Knowledge Base)共享不同分析模块间的信息 - 定制探索策略:根据程序特点选择合适的路径探索技术
- 结合静态与动态分析:先用静态分析了解程序结构,再用动态符号执行深入特定路径
8.3 未来展望
angr作为一个活跃发展的开源项目,不断引入新的分析技术和优化。未来版本将进一步提升性能,扩展对新型架构和二进制格式的支持,并增强与其他工具的集成能力。
无论您是安全研究员、逆向工程师还是CTF爱好者,angr都能为您的二进制分析工作提供强大支持。通过不断实践和探索,您将能充分发挥angr的潜力,解决复杂的二进制分析问题。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



