mcpField
S
symbolic-execution-tools

symbolic-execution-tools

github.com/yaklang安全2.6k3.7k 次安装6 周前更新
代码仓库

关于 symbolic-execution-tools

面向安全分析人员的符号执行与仿真指南,涵盖 CTF 和二进制分析。内容按任务介绍 angr、Z3、Unicorn 与 Qiling 的选择、配置、钩子和路径管理。

主要功能

  1. 01angr 二进制路径探索
  2. 02Z3 约束求解
  3. 03Unicorn 代码仿真
  4. 04函数钩子与 SimProcedure
  5. 05路径爆炸管理

适用场景

  1. 01求解 CTF 二进制检查
  2. 02从约束中恢复数值
  3. 03仿真代码以解包或解密
  4. 04分析固件或自定义 VM 例程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaklang/hack-skills --skill symbolic-execution-tools

安装后在 Claude Code 中输入/symbolic-execution-tools确认已加载。

附带文件ANGR_COOKBOOK.md

详细介绍

技能:符号执行工具——专家分析手册

AI 加载说明:介绍使用 angr、Z3 和 Unicorn Engine 的专家级符号执行技巧。涵盖 CTF 挑战自动化、约束求解模式、函数 Hook、SimProcedure 替换和基于仿真的解包。由于状态初始化不正确或缺少 libc 函数的 Hook,基础模型经常会生成有问题的 angr 脚本。

0. 相关路由

进阶参考

遇到以下需求时,也请加载 ANGR_COOKBOOK.md:

  • 15+ 种适用于常见 CTF 挑战的即用型 angr 脚本模式
  • scanf、printf、malloc、strcmp 的 Hook 模板
  • 符号化文件输入、stdin、argv 模式
  • 管理路径爆炸的优化技巧
何时使用哪种工具
场景最佳工具原因
纯数学问题/方程组Z3直接求解约束,无需二进制文件
带控制流的二进制文件angr探索路径,自动管理约束
仿真特定代码区域Unicorn速度快,无符号执行开销,适合解包
复杂二进制文件 + 自定义 VMangr + Unicorn(组合使用)angr 负责控制流,Unicorn 负责 VM 处理程序
内核/固件代码Qiling提供具备 OS 感知能力的完整系统仿真

1. ANGR——核心概念

1.1 流程
Project(binary)
  → Factory.entry_state() / blank_state(addr=)
    → SimulationManager(state)
      → explore(find=target, avoid=bad)
        → found[0].solver.eval(symbolic_var)
1.2 基本设置
import angr
import claripy

proj = angr.Project('./challenge', auto_load_libs=False)

# Entry state: start from program entry point
state = proj.factory.entry_state()

# Blank state: start from arbitrary address
state = proj.factory.blank_state(addr=0x401000)

# Full init state: with command-line args
state = proj.factory.full_init_state(args=['./challenge', arg1_sym])

simgr = proj.factory.simulation_manager(state)
simgr.explore(find=0x401234, avoid=[0x401300])

if simgr.found:
    found = simgr.found[0]
    solution = found.solver.eval(symbolic_input, cast_to=bytes)
    print(f"Solution: {solution}")
1.3 符号变量(claripy)
# Bitvector (fixed-size integer)
sym_input = claripy.BVS("input", 64)        # 64-bit symbolic
sym_byte = claripy.BVS("byte", 8)           # 8-bit symbolic
sym_buf = claripy.BVS("buffer", 8 * 32)     # 32-byte buffer

# Concrete bitvector
concrete = claripy.BVV(0x41, 8)             # concrete value 0x41

# Constraints
state.solver.add(sym_input > 0)
state.solver.add(sym_input < 100)
state.solver.add(sym_byte >= 0x20)           # printable ASCII
state.solver.add(sym_byte <= 0x7e)

# Evaluate
value = state.solver.eval(sym_input)
all_values = state.solver.eval_upto(sym_input, 10)  # up to 10 solutions
1.4 符号化 stdin
flag_len = 32
sym_stdin = claripy.BVS("stdin", 8 * flag_len)

state = proj.factory.entry_state(stdin=sym_stdin)

# Constrain to printable ASCII
for i in range(flag_len):
    byte = sym_stdin.get_byte(i)
    state.solver.add(byte >= 0x20)
    state.solver.add(byte <= 0x7e)
1.5 Hook 函数
# Hook by address (skip N bytes of original code)
@proj.hook(0x401100, length=5)
def skip_check(state):
    state.regs.eax = 1  # force success

# SimProcedure: replace library function
class MyStrcmp(angr.SimProcedure):
    def run(self, s1, s2):
        return claripy.If(
            self.state.memory.load(s1, 32) == self.state.memory.load(s2, 32),
            claripy.BVV(0, 32),
            claripy.BVV(1, 32)
        )

proj.hook_symbol('strcmp', MyStrcmp())

# Hook common problematic functions
proj.hook_symbol('printf', angr.SIM_PROCEDURES['libc']['printf']())
proj.hook_symbol('scanf', angr.SIM_PROCEDURES['libc']['scanf']())
proj.hook_symbol('puts', angr.SIM_PROCEDURES['libc']['puts']())
1.6 内存操作
# Read memory (symbolic-aware)
data = state.memory.load(addr, size)          # returns BV
data_concrete = state.solver.eval(data, cast_to=bytes)

# Write memory
state.memory.store(addr, claripy.BVV(0x41, 8))
state.memory.store(addr, sym_buf)

# Read/write registers
rax = state.regs.rax
state.regs.rdi = claripy.BVV(0x1000, 64)

2. Z3 约束求解

2.1 核心 API
from z3 import *

# Sorts
x = BitVec('x', 32)    # 32-bit bitvector
y = Int('y')             # arbitrary precision integer
b = Bool('b')            # boolean

# Solver
s = Solver()
s.add(x + y == 42)
s.add(x > 0)
s.add(y > 0)

if s.check() == sat:
    m = s.model()
    print(f"x = {m[x]}, y = {m[y]}")
2.2 常见 CTF 模式
# Serial key validation: each char satisfies constraints
key = [BitVec(f'k{i}', 8) for i in range(16)]
s = Solver()
for k in key:
    s.add(k >= 0x30, k <= 0x7a)  # alphanumeric-ish

# XOR key recovery
plaintext = b"known_plaintext"
ciphertext = b"\x12\x34..."
key_byte = BitVec('key', 8)
s = Solver()
for p, c in zip(plaintext, ciphertext):
    s.add(p ^ key_byte == c)

# System of linear equations (modular)
a, b, c = BitVecs('a b c', 32)
s = Solver()
s.add(3*a + 5*b + 7*c == 0x12345678)
s.add(2*a + 4*b + 6*c == 0xDEADBEEF)
s.add(a ^ b ^ c == 0xCAFEBABE)
2.3 优化
from z3 import Optimize

opt = Optimize()
x = BitVec('x', 32)
opt.add(x > 0)
opt.add(x < 1000)
opt.minimize(x)  # find smallest satisfying value
opt.check()
print(opt.model())

3. UNICORN ENGINE——代码仿真

3.1 基本设置
from unicorn import *
from unicorn.x86_const import *
from capstone import Cs, CS_ARCH_X86, CS_MODE_64

mu = Uc(UC_ARCH_X86, UC_MODE_64)

CODE_ADDR = 0x400000
STACK_ADDR = 0x7fff0000
STACK_SIZE = 0x10000

mu.mem_map(CODE_ADDR, 0x10000)
mu.mem_map(STACK_ADDR, STACK_SIZE)

mu.mem_write(CODE_ADDR, code_bytes)
mu.reg_write(UC_X86_REG_RSP, STACK_ADDR + STACK_SIZE - 0x1000)
mu.reg_write(UC_X86_REG_RBP, STACK_ADDR + STACK_SIZE - 0x1000)

mu.emu_start(CODE_ADDR, CODE_ADDR + len(code_bytes))

result = mu.reg_read(UC_X86_REG_RAX)
3.2 Hook 内存和指令
# Hook memory access
def hook_mem(uc, access, address, size, value, user_data):
    if access == UC_MEM_WRITE:
        print(f"Write {value:#x} to {address:#x}")
    elif access == UC_MEM_READ:
        print(f"Read from {address:#x}")

mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem)

# Hook specific instruction (for tracing)
def hook_code(uc, address, size, user_data):
    code = uc.mem_read(address, size)
    md = Cs(CS_ARCH_X86, CS_MODE_64)
    for insn in md.disasm(bytes(code), address):
        print(f"  {insn.address:#x}: {insn.mnemonic} {insn.op_str}")

mu.hook_add(UC_HOOK_CODE, hook_code)
3.3 使用场景
使用场景方法
解包 shellcode映射 shellcode,进行仿真,并转储解码后的载荷
解密字符串使用受控输入仿真解密函数
暴力破解短密钥使用不同密钥输入循环仿真
分析混淆函数仿真函数,观察寄存器/内存状态
固件代码仿真映射固件内存布局,仿真例程

4. ANGR 探索策略

4.1 find/avoid
simgr.explore(
    find=lambda s: b"Correct" in s.posix.dumps(1),   # stdout contains "Correct"
    avoid=lambda s: b"Wrong" in s.posix.dumps(1)      # avoid "Wrong" output
)
4.2 管理路径爆炸
策略实现方式
限制输入空间添加约束(可打印字符、长度限制)
避开死胡同路径使用 avoid= 指定已知失败地址
Hook 复杂函数替换为简化的 SimProcedure
限制循环迭代次数state.options.add(angr.options.LAZY_SOLVES)
使用 veritestingsimgr.explore(..., technique=angr.exploration_techniques.Veritesting())
使用 DFS 而非 BFSsimgr.use_technique(angr.exploration_techniques.DFS())
设置每条路径的超时simgr.explore(..., num_find=1) + 超时封装
4.3 具体执行与符号执行混合模式
state = proj.factory.entry_state(
    add_options={angr.options.UNICORN}  # use Unicorn for concrete regions
)

这会大幅提升执行速度:具体代码通过 Unicorn 原生运行,只有涉及符号变量时才切换到符号执行。


5. 实用工作流

5.1 CTF 二进制求解工作流
1. Static analysis: identify input method, success/fail conditions
   └─ Find "Correct" / "Wrong" strings → get their xref addresses

2. Choose tool:
   ├─ Pure math (no binary needed) → Z3
   ├─ Small binary, clear success/fail → angr explore
   └─ Specific function to emulate → Unicorn

3. Set up symbolic input:
   ├─ stdin → claripy.BVS + entry_state(stdin=)
   ├─ argv → full_init_state(args=[...])
   ├─ file input → SimFile
   └─ specific memory → state.memory.store(addr, sym)

4. Hook problematic functions:
   ├─ printf/puts → SimProcedure or no-op
   ├─ scanf → custom handler
   ├─ time/random → return concrete value
   └─ anti-debug → skip entirely

5. Explore and extract:
   └─ simgr.explore(find=, avoid=) → solver.eval()

6. 决策树

Need to solve a reversing challenge?
│
├─ Is the challenge pure math / equations?
│  └─ Yes → Z3
│     ├─ Linear equations → BitVec + Solver
│     ├─ Modular arithmetic → BitVec (natural mod 2^n)
│     ├─ Boolean logic → Bool + Solver
│     └─ Optimization → Optimize + minimize/maximize
│
├─ Is it a compiled binary with clear success/fail?
│  └─ Yes → angr
│     ├─ Input via stdin → symbolic stdin
│     ├─ Input via argv → full_init_state with symbolic args
│     ├─ Input via file → SimFile
│     ├─ Path explosion → add constraints, avoid paths, hook loops
│     └─ Complex library calls → hook with SimProcedure
│
├─ Need to emulate a specific function/region?
│  └─ Yes → Unicorn Engine
│     ├─ Decryption routine → map code + data, emulate, read result
│     ├─ Shellcode analysis → map shellcode, hook syscalls
│     └─ Key schedule → emulate with different inputs
│
├─ Need to analyze firmware / exotic arch?
│  └─ Yes → Qiling (full system emulation with OS support)
│
├─ Binary has VM protection?
│  └─ angr for handler analysis + Z3 for bytecode constraints
│
└─ None of the above working?
   ├─ Combine: Unicorn for concrete regions + Z3 for constraints
   ├─ Manual reverse engineering with debugger
   └─ Side-channel approach (timing, power analysis for hardware)

7. 常见问题与修复方法

问题原因修复方法
angr 永远卡住循环中路径爆炸为循环回边添加 avoid=,或挂钩循环
Z3 返回 unknown非线性约束过于复杂简化约束,将问题拆分为多个子问题,使用 set_param("timeout", 5000)
Unicorn 遇到系统调用时崩溃系统调用未处理挂钩系统调用中断,并进行处理或跳过
angr 结果错误状态初始化有误确认初始内存布局与实际二进制文件一致
符号内存过大符号化读取无界尽可能具体化数组索引
SimProcedure 类型错误参数类型不匹配检查调用约定(cdecl 还是 fastcall)
angr 无法加载二进制文件缺少库使用 auto_load_libs=False,并挂钩所需符号

8. 工具版本与安装

# angr (Python 3.8+)
pip install angr

# Z3
pip install z3-solver

# Unicorn Engine
pip install unicorn

# Capstone (disassembly, pairs with Unicorn)
pip install capstone

# Keystone (assembly)
pip install keystone-engine

评论

支持 Markdown