Ponce4Ghidra

Ghidra 交互式符号执行插件。右键选择地址,符号化输入,一键求解——密码、License Key、CTF Flag,通通搞定。

angr + Z3 Ghidra 11.4+ ELF / Mach-O / .so Veritesting + Unicorn
GitHub 仓库 →

English  |  中文

5 步破解密码

1. 在 Ghidra 中打开 test_crackme
2. 右键 0x1000004d7 (return 1) → Set as Find Target
3. 右键 0x100000484 (return 0) → Set as Avoid
4. Ponce4Ghidra → Symbolize argv[1] (size: 4)
5. Solve Constraints → argv1 = P4Rg
Ponce4Ghidra 约束面板
约束面板:Z3 的求解路径——每条约束对应密码 P4Rg 的一个字节

工作原理

不是暴力破解,不是 fuzzing——是解方程。16 字节输入有 2128 种可能,约束条件将其化简为 Z3 秒级求解的方程组。

用户 设置目标 符号化输入 Ghidra 插件 Java 4 标签页面板 8 个菜单操作 会话保存/恢复 JSON/TCP :13370 angr 引擎 Python 符号执行 路径分叉 约束收集 + Veritesting + Unicorn (可选) 约束条件 Z3 求解器 SAT + 理论求解 CDCL 引擎 位向量、数组理论 P4Rg
1
符号化——用数学变量替换具体输入
argv[1] 变成 4 字节未知量:BVS("argv1", 32)
2
分叉——遇到依赖符号输入的分支,两边同时探索
if (input[0] == 'P') → 一条路径加约束 byte0 == 0x50,另一条加 byte0 != 0x50
3
收集——每条路径沿途累积约束
到达目标的路径:byte0==0x50 ∧ byte1==0x34 ∧ byte2^0x42==0x10 ∧ byte3+0x20==0x87
4
求解——把所有约束交给 Z3
Z3 的 CDCL 引擎毫秒级解出 → P4Rg

Triton 后端:Concolic 混合执行

Ponce4Ghidra 内置两个引擎。angr 探索所有路径;Triton 沿一条具体路径执行,同时追踪符号状态——永远不会路径爆炸。

angr — Symbolic Execution entry x[0]==0x50 ✓ x[0]!=0x50 ✗ x[1]==0x34 ✓ x[1]!=0x34 ✗ ... 更多分叉 ... 同时探索所有路径 ⚠ 大二进制路径爆炸 Triton — Concolic Execution entry cmp [rdi],0x50 concrete: ZF=0 sym: x[0]==0x50 cmp [rdi+1],0x34 ... 单条路径 ... 沿一条路径执行,记录约束 ✓ 永远不会路径爆炸

Triton 原理 — 指令级语义建模

Triton 将每条 CPU 指令翻译为数学表达式。没有中间表示——直接在 x86/ARM 机器码上建立 AST。

CPU 指令 xor eax, 0x42 35 42 00 00 00 Triton 处理 eax_new = eax_old ⊕ 0x42 ZF = (eax_new == 0) SF = eax_new[31] + CF, OF, PF, AF 标志位 具体值 eax = 0x12 符号表达式 eax = input_0 ⊕ 0x42 Jonathan Salwan 的核心贡献:为每条指令编写精确的数学语义 x86_64: ~1500 条 AArch64: ~500 条 ARM32: ~300 条 RISC-V: ~200 条 每条指令建模包括所有标志位副作用(EFLAGS: CF, ZF, SF, OF, PF, AF)

什么时候用哪个引擎

场景angrTriton
小函数,找密码 最佳 — 探索所有路径,保证找到 可用 — 但需要一个具体输入作为起点
大二进制,DRM key 派生 路径爆炸 最佳 — 沿一条 trace 走,不会爆炸
混淆代码(VM/白盒加密) 约束爆炸 最佳 — 不需要"理解"代码
有 Frida trace 无法回放 trace 最佳 — 回放 trace 同时追踪符号状态
没有具体输入 最佳 — 从零开始 需要一个起始输入
想找所有可能的解 最佳 — 找到每条满足路径 一次一条路径(取反分支 + 重跑)

真实测试:angr vs Triton

两个引擎在同一台机器上求解相同的二进制,使用 symbolize_function_argument:

二进制输入大小angrTriton胜出
test_crackme
4 个字节比较,无 libc 调用
4 字节 0.18s ✓ 0.065s ✓ Triton 快 2.8 倍
test_license
19 字节密钥,含 strlen、XOR、校验和
19 字节 3.65s ✓ 超时 ✗ angr

为什么有差异?

Triton 胜出的场景:纯计算——没有路径分叉开销,直接指令→AST 翻译。对 check_password(4 个简单字节比较),快 3 倍。

angr 胜出的场景:函数调用了 libc(strlen、printf)——angr 自动用 SimProcedures 接管,而 Triton 试图执行真实指令(Mach-O 的 libc 桩没有加载)。对复杂的真实函数,angr 的 SimOS 层是决定性优势。

经验法则:默认用 angr。当 angr 在大函数上路径爆炸,或者你有 Frida trace 要回放时,切换到 Triton。

DRM 逆向工作流

Frida 采集运行时数据(密钥、I/O 样本)→ Ponce4Ghidra 分析算法(小函数用 angr,大函数用 Triton)→ unidbg 复现为独立服务。

功能特性

Σ

多解求解器

每个变量最多返回 5 个不同的解。密码可能有多个合法输入。

C

约束可视化

查看求解器收集的每一条约束。理解路径为什么可达——不只是"可达"。

V

Veritesting

循环边界智能路径合并。大型二进制不会路径爆炸。

U

Unicorn 引擎

不涉及符号变量的代码块通过 Unicorn 快速具体执行,仅在符号分支处切回符号执行。

↻

会话持久化

跨 Ghidra 重启保存/恢复会话。Find/Avoid 目标和符号化命令不会丢失。

⚡

实时进度

探索过程中状态栏每秒更新:活跃路径数、已找到路径数、步数、耗时。

何时使用哪种符号化方式

方式适用场景速度
Function Argument 已知哪个函数负责校验输入。分析 .so 库。大型二进制。 快
argv[N] 程序从命令行读取输入。小型/简单二进制。需要完整程序上下文。 中等
Register 未知量是标量(int/long),不是缓冲区。 快
Memory 未知量位于已知固定内存地址(全局变量、结构体字段)。 快

经验法则:优先使用 Function Argument。只有需要完整程序执行上下文时才用 argv。

平台支持

格式架构状态
Mach-Ox86_64完整测试
ELFx86_64, ARM64, ARM32, MIPS已测试(静态链接)
Android .soARM64, ARM32支持(延迟状态创建)

安装

# 1. 创建 Python 虚拟环境 python3 -m venv .venv source .venv/bin/activate pip install angr pip install unicorn # 可选:加速具体执行 # 2. 构建 Ghidra 扩展 export GHIDRA_INSTALL_DIR=/path/to/ghidra gradle buildExtension # 3. 安装到 Ghidra # File → Install Extensions → Add → dist/*.zip

核心论文

Z3: An Efficient SMT Solverde Moura, Bjørner (2008, TACAS) — Ponce4Ghidra 背后的求解引擎
angr: (State of) The Art of WarShoshitaishvili 等 (2016, IEEE S&P) — 符号执行框架
GRASP: Conflict-Driven Clause LearningMarques-Silva, Sakallah (1996, ICCAD) — 让 SAT 求解变得实用的算法
KLEE: Automatic Test GenerationCadar, Dunbar, Engler (2008, OSDI) — 源码级符号执行里程碑