ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

QSYM 核心架构全解析:从 PIN 插桩到 Z3 求解

2026/8/16 14:19:18 拓冰建站 浏览量
QSYM 核心架构全解析:从 PIN 插桩到 Z3 求解 QSYM 核心架构全解析从 PIN 插桩到 Z3 求解【免费下载链接】qsymQSYM: A Practical Concolic Execution Engine Tailored for Hybrid Fuzzing项目地址: https://gitcode.com/gh_mirrors/qs/qsymQSYM 是一款面向混合模糊测试Hybrid Fuzzing的实用化符号执行引擎它的核心价值在于把传统模糊测试的暴力枚举与符号执行的精确求解结合起来大幅提升漏洞挖掘效率。本文将从底层动态插桩到上层约束求解完整拆解 QSYM 的核心架构帮助你理解它如何做到既快又准。什么是 QSYM混合模糊测试的加速器在解释架构之前先明确 QSYM 的定位。QSYM 全称是A Practical Concolic Execution Engine Tailored for Hybrid Fuzzing由 Georgia Tech 团队提出并发表于 USENIX Security 2018。传统模糊测试如 AFL靠随机变异输入来探索程序速度快但遇到复杂的魔法值比较如if (x 0xdeadbeef)就很容易卡住而经典符号执行能精确求解路径约束却因为性能开销大而难以大规模落地。QSYM 的策略是取两者之长让 AFL 负责大规模随机探索让 QSYM 在后台做快速的符号执行一旦发现 AFL 难以通过的深水区分支就生成新输入交给 AFL 继续跑从而形成正向循环。QSYM 的整体架构四层流水线QSYM 的代码仓库结构清晰地反映了它的分层设计核心源码位于 qsym/pintool/ 目录下大致可以抽象为四层流水线插桩层基于 Intel PIN 的动态二进制插桩捕获每条指令的执行轨迹符号执行层把影响控制流的数据抽象为符号表达式追踪内存与寄存器的依赖关系约束求解层把路径条件交给 Z3 求解器反解出能触发新分支的输入协同层通过共享的 AFL 覆盖率位图与队列文件实现与 AFL 的双向协作。下面逐层深入。第一层PIN 动态二进制插桩捕获执行轨迹QSYM 之所以比传统符号执行快一个数量级关键在于它不需要对目标程序做任何源码改动或重编译而是借助 Intel PIN 在运行时直接插桩。入口在 main.cpp程序先调用PIN_InitSymbols()与PIN_Init()完成 PIN 运行环境初始化然后通过hookSyscalls()挂钩系统调用支持 stdin、文件、网络三种输入来源最后调用initializeQsym()注册插桩回调并执行PIN_StartProgram()启动目标程序。QSYM 在插桩阶段会重点做两件事指令级追踪分析每条指令的语义如 analysis_instruction.cpp 中的指令建模判断其是否依赖符号数据污点式内存建模通过 memory.cpp 维护一个页表级的内存抽象精确记录符号数据在内存中的分布避免对整个地址空间做符号化从而控制性能开销。这张图展示了在开发环境中通过调试器挂载 PIN 插桩工具的场景——QSYM 的插桩层就是以这样的方式附着在目标进程之上的。第二层符号表达式构建把数据变成数学拿到执行轨迹后QSYM 需要把影响分支的数据抽象成符号表达式这一层对应 expr.h 和 expr_builder.cpp。你可以把符号表达式想象成带未知数的算式程序读入的输入被当作符号变量而所有运算加、减、乘、移位、位运算、比较等都被翻译成对应的符号操作节点。例如x input[0] 1会被建模为一个Add(Read(0), 1)的表达式树。这一层有两个值得关注的设计细节表达式缓存expr_cache.cpp负责复用结构相同的子表达式避免重复构建显著降低内存与时间开销约束剪枝PruneExprBuilder会利用 LLVM 的区间分析见 third_party/llvm/range.cpp提前判断约束是否可能满足把明显无解的分支直接丢弃减少无效求解。正是因为有了表达式复用与区间剪枝QSYM 才能在保持较高覆盖能力的同时把单次执行的开销压到接近原生运行水平。第三层Z3 约束求解反推出新输入当程序执行到条件跳转JCC时QSYM 会收集当前的路径约束并尝试反向求解这部分核心逻辑在 solver.cpp 中求解器本身采用微软的Z3仓库 third_party/z3/。求解流程大致如下判断兴趣分支通过isInterestingJcc()判断当前分支是否值得求解结合 AFL 位图判断该分支是否带来新的覆盖率收集并同步约束syncConstraints()会把当前路径上积累的符号约束统一加入 Z3 求解器取反路径条件negatePath()将分支条件取反迫使求解器生成一条与当前执行方向不同的新输入求值并落盘solveOne()调用 Z3 得到具体解后通过saveValues()把新输入写入 QSYM 的测试用例目录等待 AFL 拾取。为了进一步提速QSYM 对约束做了大量轻量化处理能通过区间分析直接得出结果的就不调用 Z3同时支持求解结果缓存避免同一约束反复求解。第四层与 AFL 的混合协作跑出 112架构的最后一层是 QSYM 与 AFL 的协同机制这也是混合模糊测试名称的由来。协同的关键在于 afl_trace_map.cppQSYM 会直接读取并更新 AFL 的覆盖率位图。当 QSYM 通过符号执行发现新的覆盖路径时它会同步更新位图让 AFL 认为找到了新兴趣从而把注意力引导到这些新区域反过来AFL 产生的新种子又会成为 QSYM 符号执行的输入形成双向互补。在运行层面仓库根目录的 qsym/afl.py 与bin/run_qsym_afl.py脚本负责编排整个流程启动一个 AFL master、一个 AFL slave 和一个 QSYM 进程让它们共享同一个输出目录QSYM 生成的测试用例会进入 AFL 的队列等待变异复用。上图演示的是调试器附加 PIN 进程的参数设置在实际运行中run_qsym_afl.py正是通过类似的参数把 PIN 插桩工具附加到目标二进制上。环境搭建与快速上手QSYM 基于较老的 PIN 版本构建官方推荐在 Ubuntu 14.04/16.04 64 位环境中使用。如果你希望快速体验最简单的方式是使用仓库自带的 Docker 配置Dockerfilegit clone https://gitcode.com/gh_mirrors/qs/qsym cd qsym echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope docker build -t qsym ./ docker run --cap-addSYS_PTRACE -it qsym /bin/bash注意由于 PIN 依赖ptrace运行前必须关闭系统的ptrace_scope限制否则插桩无法附加到目标进程。总结一套值得借鉴的混合执行设计回顾整个架构QSYM 的每一个设计决策都围绕实用化展开用 PIN 插桩解决源码不可得的问题用污点内存建模和区间剪枝控制符号化开销用 Z3 提供精确求解能力再用 AFL 位图打通与模糊测试的协作通道。对于安全研究人员而言QSYM 的价值不仅在于它本身是一款高效的混合模糊测试引擎更在于它的架构为如何把符号执行落地到真实漏洞挖掘提供了完整范本——从插桩到求解的每一层都值得深入研读。【免费下载链接】qsymQSYM: A Practical Concolic Execution Engine Tailored for Hybrid Fuzzing项目地址: https://gitcode.com/gh_mirrors/qs/qsym创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考