第4章:Angr环境搭建
说实话,Angr 的安装曾经是劝退不少人的第一道坎。
我记得 2018 年那会儿,我第一次在 Ubuntu 16.04 上装 Angr,折腾了整整一个下午。依赖冲突、Python 版本不对、编译报错……各种问题轮着来。后来我学乖了,直接用 Docker,五分钟搞定。
这一章,我就把这几年的经验总结一下。你跟着走,基本不会踩坑。
4.1 安装前的准备
Angr 对 Python 版本有要求。我个人习惯用 Python 3.8 或 3.9,太新或太旧都可能出问题。
先检查你的环境:
python3 --version
pip3 --version
如果版本不对,建议用 pyenv 或 conda 管理 Python 版本。我推荐 conda,省心。
我的建议: 创建一个干净的虚拟环境,别跟系统 Python 混在一起。
4.2 直接安装(pip 方式)
最直接的方法:
pip install angr
嗯,就这么简单。但实际执行时,可能会遇到一些问题。
常见问题:
- 编译错误: Angr 依赖的组件(比如 pyvex、unicorn)需要编译 C 扩展。如果你缺少 gcc、make 等工具,会报错。
- 依赖冲突: 特别是 z3-solver 的版本问题。我曾经因为系统里装了两个版本的 z3,导致 Angr 启动就崩溃。
解决办法:
# Ubuntu/Debian
sudo apt-get install build-essential python3-dev
# macOS
xcode-select --install
注意: 不要在 Windows 上直接 pip install angr。我试过,坑太多。建议用 WSL 或 Docker。
4.3 使用 Docker(推荐)
说实话,我现在基本都用 Docker 跑 Angr。为什么?
- 环境隔离,不影响宿主机
- 版本可控,团队协作方便
- 部署简单,一条命令搞定
官方提供了 Docker 镜像:
docker pull angr/angr
启动容器:
docker run -it --rm angr/angr
如果你想挂载本地目录:
docker run -it --rm -v $(pwd):/home/angr angr/angr
这样你本地的代码就能在容器里直接跑了。
小技巧: 我习惯在 Dockerfile 里加一行
RUN pip install ipython,交互式调试方便很多。
4.4 验证安装
装好之后,验证一下:
python3 -c "import angr; print(angr.__version__)"
如果输出版本号,说明安装成功。
你也可以跑一个简单的测试:
python3 -c "
import angr
proj = angr.Project('/bin/ls')
print(proj.arch)
print(proj.entry)
"
能看到架构和入口点信息,就对了。
4.5 第一个 Angr 脚本
好了,环境搭好了,我们来写第一个脚本。
目标:分析一个简单的二进制文件,找到能到达「成功」路径的输入。
假设我们有这样一个 C 程序:
// test.c
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char buf[16];
if (argc < 2) return 1;
strcpy(buf, argv[1]);
if (buf[0] == 'A' && buf[1] == 'B' && buf[2] == 'C') {
printf("Success!\n");
} else {
printf("Failed.\n");
}
return 0;
}
编译:
gcc -o test test.c
现在,用 Angr 自动找到输入 "ABC":
import angr
import claripy
# 加载二进制文件
proj = angr.Project('./test', auto_load_libs=False)
# 设置起始状态
state = proj.factory.entry_state()
# 创建符号化的 argv[1]
argv1 = claripy.BVS('argv1', 8 * 16) # 16 字节
state = proj.factory.entry_state(args=['./test', argv1])
# 创建模拟管理器
simgr = proj.factory.simulation_manager(state)
# 找到打印 "Success" 的地址
# 先反汇编看看地址,假设是 0x4005a0
success_addr = 0x4005a0
fail_addr = 0x4005c0
# 探索
simgr.explore(find=success_addr, avoid=fail_addr)
if simgr.found:
found_state = simgr.found[0]
solution = found_state.solver.eval(argv1, cast_to=bytes)
print(f"Found solution: {solution}")
else:
print("No solution found.")
跑一下看看:
python3 solve.py
输出应该是:
Found solution: b'ABC\x00...'
嗯,Angr 成功找到了 "ABC"。
核心逻辑: 符号执行的核心就是把输入变成符号变量,然后让程序「探索」所有可能的路径。找到目标路径后,从约束求解器里提取出具体的值。
4.6 知识体系总览
下面这张图,帮你理清 Angr 环境搭建和第一个脚本的完整流程:
4.7 避坑指南
最后,分享几个我踩过的坑:
- Python 版本: 我曾经用 Python 3.11 装 Angr,结果 z3 编译失败。降级到 3.9 就好了。
- Docker 权限: 如果你在 Linux 上用 Docker,记得把当前用户加到 docker 组,不然每次都要 sudo。
- auto_load_libs: 第一个脚本里我设了
auto_load_libs=False。为什么?因为加载系统库会让分析变慢,而且容易出问题。除非你需要分析库函数,否则关掉它。 - 符号变量长度: 我一开始设 argv1 为 8 字节,结果怎么都找不到解。后来发现输入长度不够,改成 16 字节就好了。
我的经验: 刚开始学 Angr,别急着分析复杂的二进制。先拿简单的 C 程序练手,理解符号执行的基本流程。等你熟悉了 Project、state、simgr 这几个核心概念,再挑战 real-world 的样本。
好了,环境搭好了,第一个脚本也跑通了。接下来你就可以拿 Angr 去分析真实的二进制文件了。记住,遇到问题先看官方文档,再看 GitHub Issues,最后再问我——当然,我大概率也遇到过。
公众号:蓝海资料掘金营,微信deep3321