安全与风控
在CTF逆向、二进制分析、恢复密钥或绕过检查时…
适用于CTF逆向、恢复密钥、绕过检查或自动化二进制分析,按问题类型选择angr、Z3、Unicorn(或Qiling)执行符号执行与约束求解。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在CTF逆向、二进制分析、恢复密钥或绕过特定
解决思路
- 按问题类型选择工具:纯数学/方程组用 Z3;有控制流的二进制用 angr;只想模拟特定代码区域用 Unicorn;复杂二进制加自定义 VM 用 angr+Unicorn 组合;内核/固件代码用 Qiling。
- 当需要符号化绕过反调试检查时,加载 anti-debugging-techniques 技能。
- 当使用符号执行做去混淆时,加载 code-obfuscation-deobfuscation 技能。
- 当把 angr 用于自定义 VM 挑战时,加载 vm-and-bytecode-reverse 技能。
- 需要 15+ 个可直接使用的 angr 脚本模板、scanf/printf/malloc/strcmp 的 Hook 模板、符号文件输入/stdin/argv 模式、路径爆炸优化技巧时,加载 ANGR_COOKBOOK.md。
- angr 基本流水线按 Project(binary) → Factory.entry_state()/blank_state(addr=) → SimulationManager(state) → explore(find=target, avoid=bad) → found[0].solver.eval(symbolic_var) 执行。
- 导入 angr 和 claripy,用 proj = angr.Project('./challenge', auto_load_libs=False) 创建项目。
- 从程序入口点开始时,用 state = proj.factory.entry_state()。
- 从任意地址开始时,用 state = proj.factory.blank_state(addr=0x401000)。
- 需要命令行参数时,用 state = proj.factory.full_init_state(args=['./challenge', arg1_sym])。
- 创建模拟管理器:simgr = proj.factory.simulation_manager(state)。
- 探索路径:simgr.explore(find=0x401234, avoid=[0x401300])。
- 找到路径后取结果:found = simgr.found[0];solution = found.solver.eval(symbolic_input, cast_to=bytes);print(f'Solution: {solution}')。
- 创建固定大小整数符号变量:sym_input = claripy.BVS('input', 64);sym_byte = claripy.BVS('byte', 8);sym_buf = claripy.BVS('buffer', 8 * 32)。
- 创建具体值:concrete = claripy.BVV(0x41, 8)。
- 添加约束:state.solver.add(sym_input > 0);state.solver.add(sym_input < 100);state.solver.add(sym_byte >= 0x20);state.solver.add(sym_byte <= 0x7e)。
- 求解变量:value = state.solver.eval(sym_input);多解用 all_values = state.solver.eval_upto(sym_input, 10)。
- 处理符号 stdin:flag_len = 32;sym_stdin = claripy.BVS('stdin', 8 * flag_len);state = proj.factory.entry_state(stdin=sym_stdin)。
- 约束 stdin 为可打印 ASCII:循环 i in range(flag_len),byte = sym_stdin.get_byte(i),state.solver.add(byte >= 0x20),state.solver.add(byte <= 0x7e)。
- 按地址 Hook 并跳过原始代码:@proj.hook(0x401100, length=5),在 skip_check(state) 中设置 state.regs.eax = 1 强制成功。
- 用 SimProcedure 替换库函数:定义 class MyStrcmp(angr.SimProcedure),run(self, s1, s2) 返回 claripy.If(self.state.memory.load(s1, 32) == self.state.memory.load(s2, 32), claripy.BVV(0, 32), claripy.BVV(1, 32))。
- 注册 SimProcedure:proj.hook_symbol('strcmp', MyStrcmp())。
- Hook 常见问题函数: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']())。
- 读内存:data = state.memory.load(addr, size);具体化用 data_concrete = state.solver.eval(data, cast_to=bytes)。
- 写内存:state.memory.store(addr, claripy.BVV(0x41, 8));state.memory.store(addr, sym_buf)。
- 读写寄存器:rax = state.regs.rax;state.regs.rdi = claripy.BVV(0x1000, 64)。
- Z3 创建变量:x = BitVec('x', 32);y = Int('y');b = Bool('b')。
- Z3 求解: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]}')。
- 序列号校验模式:key = [BitVec(f'k{i}', 8) for i in range(16)];s = Solver();为每个 k 添加 s.add(k >= 0x30, k <= 0x7a)。
- XOR 密钥恢复模式:定义 plaintext 和 ciphertext 字节串,key_byte = BitVec('key', 8),s = Solver(),对 zip(plaintext, ciphertext) 中的每对 p, c 添加 s.add(p ^ key_byte == c)。
- 线性/模方程组模式: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)。
- Z3 优化:from z3 import Optimize;opt = Optimize();x = BitVec('x', 32);opt.add(x > 0);opt.add(x < 1000);opt.minimize(x);opt.check();print(opt.model())。
- Unicorn 基本设置: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)。
- Unicorn 映射内存:CODE_ADDR = 0x400000;STACK_ADDR = 0x7fff0000;STACK_SIZE = 0x10000;mu.mem_map(CODE_ADDR, 0x10000);mu.mem_map(STACK_ADDR, STACK_SIZE)。
- Unicorn 写入代码和初始化栈: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)。
- Unicorn 启动和读结果:mu.emu_start(CODE_ADDR, CODE_ADDR + len(code_bytes));result = mu.reg_read(UC_X86_REG_RAX)。
- Unicorn 内存 Hook:定义 hook_mem(uc, access, address, size, value, user_data),在 UC_MEM_WRITE 时打印写入地址和值,在 UC_MEM_READ 时打印读取地址。
- 注册内存 Hook:mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem)。
- Unicorn 指令 Hook:定义 hook_code(uc, address, size, user_data),用 uc.mem_read(address, size) 读取,再用 Cs(CS_ARCH_X86, CS_MODE_64) 反汇编并打印 insn.address、insn.mnemonic、insn.op_str。
- 注册指令 Hook:mu.hook_add(UC_HOOK_CODE, hook_code)。
- Unicorn 用例:解包 shellcode 时映射 shellcode、仿真、dump 解码后的 payload。
- Unicorn 用例:解密字符串时用受控输入仿真解密函数。
- Unicorn 用例:暴力破解短密钥时循环仿真不同 key 输入。
- Unicorn 用例:分析混淆函数时仿真函数并观察寄存器/内存状态。
- Unicorn 用例:仿真固件代码时映射固件内存布局并仿真例程。
- angr 用 find/avoid 按输出预测收敛:simgr.explore(find=lambda s: b'Correct' in s.posix.dumps(1), avoid=lambda s: b'Wrong' in s.posix.dumps(1))。
- 管理路径爆炸:添加约束限制输入空间,例如 printable、长度限制。
- 管理路径爆炸:对已知失败地址使用 avoid=。
- 管理路径爆炸:用简化 SimProcedure 替换复杂函数。
- 管理路径爆炸:限制循环迭代,例如 state.options.add(angr.options.LAZY_SOLVES)。
- 管理路径爆炸:使用 veritesting:simgr.explore(..., technique=angr.exploration_techniques.Veritesting())。
- 管理路径爆炸:用 DFS 替代 BFS:simgr.use_technique(angr.exploration_techniques.DFS())。
- 管理路径爆炸:限制每路径时间,例如 simgr.explore(..., num_find=1) 并套 timeout wrapper。
- 具体+符号混合执行:state = proj.factory.entry_state(add_options={angr.options.UNICORN}),让具体代码通过 Unicorn 原生执行,仅在涉及符号变量时切换到符号执行。
- CTF 二进制求解工作流第 1 步:静态分析,识别输入方式、成功/失败条件;查找 'Correct' / 'Wrong' 字符串并获取其 xref 地址。
- CTF 二进制求解工作流第 2 步:选择工具;纯数学无需二进制用 Z3;小型二进制且成功/失败清晰用 angr explore;只想仿真特定函数用 Unicorn。
- CTF 二进制求解工作流第 3 步:设置符号输入;stdin 用 claripy.BVS + entry_state(stdin=);argv 用 full_init_state(args=[...]);文件输入用 SimFile;特定内存用 state.memory.store(addr, sym)。
- CTF 二进制求解工作流第 4 步:Hook 问题函数;printf/puts 用 SimProcedure 或 no-op;scanf 用自定义 handler;time/random 返回具体值;anti-debug 直接跳过。
- CTF 二进制求解工作流第 5 步:探索并提取结果;simgr.explore(find=, avoid=),然后用 solver.eval()。
- 决策树:纯数学/方程用 Z3;线性方程用 BitVec + Solver;模运算用 BitVec(自然 mod 2^n);布尔逻辑用 Bool + Solver;优化用 Optimize + minimize/maximize。
- 决策树:编译二进制且有清晰成功/失败用 angr;输入经 stdin 用符号 stdin;经 argv 用 full_init_state 的符号 args;经文件用 SimFile;路径爆炸则加约束、avoid 路径、Hook 循环;复杂库调用用 SimProcedure Hook。
- 决策树:需要仿真特定函数/区域用 Unicorn Engine;解密例程映射代码+数据后仿真并读结果;Shellcode 分析映射 shellcode 并 Hook syscall;Key schedule 用不同输入仿真。
- 决策树:需要分析固件/特殊架构用 Qiling(带 OS 支持的完整系统仿真)。
- 决策树:二进制有 VM 保护时,用 angr 做 handler 分析 + Z3 做字节码约束。
- 决策树:以上都不行时,组合 Unicorn 处理具体区域 + Z3 处理约束;用调试器手工逆向;或硬件用侧信道方法(timing、power analysis)。
- 修复 angr 永久挂起:原因是循环中路径爆炸;用 avoid= 排除回边,或 Hook 该循环。
- 修复 Z3 返回 unknown:原因是非线性约束太复杂;简化、拆成子问题,或用 set_param('timeout', 5000)。
- 修复 Unicorn 在 syscall 崩溃:原因是 syscall 未处理;Hook syscall 中断,处理或跳过。
- 修复 angr 结果错误:原因是状态初始化不正确;验证初始内存布局与实际二进制匹配。
- 修复符号内存过大:原因是无界符号读取;尽可能具体化数组索引。
- 修复 SimProcedure 类型错误:原因是参数类型不匹配;检查调用约定(cdecl vs fastcall)。
- 修复 angr 无法加载二进制:原因是缺少库;使用 auto_load_libs=False 并 Hook 需要的符号。
- 安装 angr:pip install angr(Python 3.8+)。
- 安装 Z3:pip install z3-solver。
- 安装 Unicorn Engine:pip install unicorn。
- 安装 Capstone(反汇编,配合 Unicorn):pip install capstone。
- 安装 Keystone(汇编):pip install keystone-engine。
适用边界 · 注意事项
- 当目标不需要自动化求解,或无法定义明确的 find/avoid、成功/失败条件时,不适用。
- 当路径爆炸极严重且无法通过约束、Hook、veritesting 等手段控制时,符号执行可能超时或无结果。
- 当约束是高度非线性且 Z3 返回 unknown,且无法拆分或简化时,不适用。