能,但需绕过C++运行时干扰:禁用自动加载库、从main开始执行、手动patch vtable、避免全符号化std::string、启用CXX_EXCEPTIONS选项并控制堆分配。

angr 能直接分析 C++ 二进制吗?
能,但不是“直接”——angr 分析的是底层机器码和符号化执行路径,不关心源语言是 C 还是 C++。真正影响分析效果的,是 C++ 特性带来的运行时行为:name mangling、vtable 调用、异常处理、RTTI、std::string / std::vector 等 ABI 相关实现。这些会让符号执行路径更复杂、约束更难解、状态爆炸风险更高。
为什么 C++ 二进制在 angr 中容易卡住或漏路径?
常见现象:state.solver.eval() 卡死、simulation_manager.run() 长时间无进展、找不到已知漏洞路径。核心原因有三个:
- C++ 运行时初始化(如
__libc_start_main→__cxx_global_var_init)会触发大量不可控的符号化内存读写,尤其涉及std::ios_base::Init或静态对象构造时 - vtable 指针被符号化后,
state.memory.load(vptr)可能产生成百上千个可能目标,analyzer 默认不剪枝 -
std::string内部结构(小字符串优化 SSO / 大字符串堆分配)导致长度、data 指针、capacity 三者强耦合,约束求解器难以同时满足
怎么让 angr 实际跑通一个 C++ 可执行文件?
关键不是“支持 C++”,而是“绕过/简化 C++ 运行时干扰”。实操建议如下:
- 用
angr.Project(..., load_options={'auto_load_libs': False})禁用自动加载 libc/libstdc++,避免符号化第三方代码 - 跳过 C++ 初始化:找到
_start后第一个用户函数(比如main),用project.factory.entry_state(addr=main_addr)直接从那里开始执行 - 对已知 vtable 调用点,手动 patch 成直接跳转:用
state.memory.store(vptr_addr, claripy.BVV(real_vfunc_addr, 64))固定虚函数地址 - 遇到
std::string输入,别用state.solver.BVS('input', 100*8)全符号化;改用 concrete 字符串 +state.memory.store()注入,并只符号化关键字段(如长度字节)
用 angr 找 C++ 常见漏洞要注意什么?
典型场景如 std::vector::at() 越界、std::string::operator[] 无检查访问、虚函数表劫持。但实际挖掘中:
立即学习“C++免费学习笔记(深入)”;
-
std::vector::at()抛出std::out_of_range异常 → angr 默认不模拟 C++ exception unwind 流程,会直接退出路径,需用state.options.add(angr.options.CXX_EXCEPTIONS)(仍不稳定)或改查std::vector::_M_range_check内联检查逻辑 - 虚函数调用漏洞(如 UAF 后调用虚函数)依赖 vtable 指针可控,但 angr 对 heap 块重用建模弱;建议配合
heap_allocator插件 + 显式state.heap.malloc()控制分配布局 - 所有涉及
std::allocator的路径,优先关闭其符号化:用state.libc.heap.arch = 'x86_64'并禁用angr.options.USE_SYSTEM_STACK,否则 malloc 返回地址可能变成全符号值,后续指针运算彻底不可控
最麻烦的从来不是“能不能跑”,而是 C++ ABI 细节(比如 Itanium ABI 的 vtable 偏移规则、GCC 的 std::string 内存布局版本差异)会让同一段代码在不同编译器/版本下路径分叉严重——你得先确认目标二进制用的是哪个 libstdc++ 版本,再决定要不要手写 hook 替换关键函数逻辑。



















