一个用于跨多种架构反汇编、汇编和分析机器码的二进制分析库。基于 LLVM 21 构建。
功能:
Function,或单个展平的 IGNIL 块(无需 CFG),提升为 LLVM IR,并在其上运行优化流水线(mem2reg/instcombine/GVN/DCE).pat 签名数据库识别已知函数LoadedImage:节区和 ELF PT_LOAD 段位于其虚拟地址并带有 R/W/X 权限,入口点、映像基址、带导入/导出标志的符号,以及从头部自动检测的架构(无需指定)。loader::disassembleImage 一次调用即可从文件得到填充好的 Graph。基于 LLVM 的 llvm::object 构建,因此无需额外依赖disassembler CLI —— 一个加载 ELF 或 PE 二进制并转储反汇编的命令行工具,适用于快速检查和脚本编写dragon_c.h)和 Python API(cffi),覆盖上述大部分功能集(少数仅限 C++ 的部分——模式匹配 DSL 模板、架构特定的指令分类辅助函数等——已在 docs/cpp_api.md 中如此说明)带标签的发布版在 GitHub Releases 页面上为每个平台提供自包含的 SDK 归档
(dragon-<version>-{linux-x64,macos-arm64,windows-x64}.{tar.gz,zip})。LLVM 已静态链接进
库中,因此使用它们无需系统安装 LLVM;Z3 也一并捆绑。
每个归档包含:
lib/ libdragon + libdragon_c (shared) and the bundled Z3 runtime
bin/ the `disassembler` CLI (plus the DLLs on Windows)
include/ the C++ headers (dragon/...) and the C-shim header (dragon/dragon_c.h)
share/dragon/python/dragon.py the Python API
将 Python API 指向随附的库,使用
DRAGON_C_LIB=/path/to/lib/libdragon_c.so(根据情况使用 .dylib/.dll)。
若要从源码构建:
mkdir build && cd build
cmake ..
cmake --build .
运行测试:
ctest --output-on-failure
少数 x86 语义往返测试开销很大:它们会对提升后的 IR 进行 JIT 编译,并在 Unicorn 下针对大量边界情况输入的交叉组合(每个测试包含数千次往返)模拟原始字节。它们被标记为 [.][expensive],这会使其在默认的 ctest 运行中被隐藏,从而保持运行速度。请显式运行它们——通常在性能更强的机器上或 CI 中——使用:
./build/bin/dragon_tests "[expensive]"
在 Windows 上,CMakeLists.txt 中的依赖查找需要一些提示,
因为它是为 Linux 的软件包布局编写的:Z3 通过 LLVM 自带的
FindZ3.cmake 模块定位,而 Unicorn 通过 pkg-config 定位。
这两种机制都不知道 vcpkg 将内容安装在哪里,并且 LLVM 是通过
LLVM_DIR 而不是系统路径找到的。提供三个提示即可解决所有问题。
先决条件
C:\llvm-21(预构建的
clang+llvm-*-x86_64-pc-windows-msvc 发行版可用)1. 使用 vcpkg 安装这些库(x64-windows 三元组;pkgconf
提供 Unicorn 查找所需的 pkg-config 可执行文件):
vcpkg install z3:x64-windows unicorn:x64-windows pkgconf:x64-windows
2. CMake 所需的三个提示
| 提示 | 用途 | 示例值 |
|---|---|---|
LLVM_DIR | 定位 LLVM 21 | C:/llvm-21/lib/cmake/llvm |
CMAKE_PREFIX_PATH | 让 FindZ3 看到 vcpkg 目录树 | C:/vcpkg/installed/x64-windows |
PKG_CONFIG_EXECUTABLE + PKG_CONFIG_PATH | 让 Unicorn 通过 pkg-config 被找到 | .../tools/pkgconf/pkgconf.exe 和 .../installed/x64-windows/lib/pkgconfig |
3a. 配置并构建(单条命令)
$env:PKG_CONFIG_PATH = "C:/vcpkg/installed/x64-windows/lib/pkgconfig"
cmake -S . -B build `
-DLLVM_DIR=C:/llvm-21/lib/cmake/llvm `
-DCMAKE_PREFIX_PATH=C:/vcpkg/installed/x64-windows `
-DPKG_CONFIG_EXECUTABLE=C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe `
-DDRAGON_USE_Z3=ON -DDRAGON_USE_UNICORN=ON
cmake --build build --config Release
配置成功后会输出:
-- Found LLVM 21.1.8 at C:/llvm-21/lib/cmake/llvm
-- Found Z3 5.0.0 at C:/vcpkg/installed/x64-windows/lib/libz3.lib
-- Found Unicorn 2.1.4
3b. 或使用预设(推荐)
将设置一次性保存在 CMakeLists.txt 旁边的 CMakeUserPresets.json 中,
然后使用单个标志进行配置。此文件包含特定于机器的路径,因此
请勿将其纳入版本控制(它已被 git 忽略)。
{
"version": 3,
"configurePresets": [
{
"name": "win-vcpkg",
"generator": "Visual Studio 17 2022",
"architecture": "x64",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"LLVM_DIR": "C:/llvm-21/lib/cmake/llvm",
"CMAKE_PREFIX_PATH": "C:/vcpkg/installed/x64-windows",
"PKG_CONFIG_EXECUTABLE": "C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe",
"DRAGON_USE_Z3": "ON",
"DRAGON_USE_UNICORN": "ON"
},
"environment": {
"PKG_CONFIG_PATH": "C:/vcpkg/installed/x64-windows/lib/pkgconfig"
}
}
],
"buildPresets": [
{ "name": "win-vcpkg", "configurePreset": "win-vcpkg", "configuration": "Release" }
]
}
cmake --preset win-vcpkg
cmake --build build --config Release
说明
请根据你的机器调整路径。如果 vcpkg 位于其他位置,请相应设置
%VCPKG_ROOT%;如果你将 LLVM 解压到了其他位置,请将 LLVM_DIR
指向该目录树下的 lib/cmake/llvm。
请不要在此处传入 vcpkg 的工具链文件
(-DCMAKE_TOOLCHAIN_FILE=.../vcpkg.cmake)。它会限制包搜索,
并阻止 CMake 找到位于 vcpkg 之外的 LLVM,而后者正是本项目的
常见配置方式。
Unicorn 是可选的:如果没有可用的 pkg-config,它会被直接禁用,
并且只会跳过 tests/semantic/ 的往返测试。相比之下,只要
DRAGON_USE_Z3=ON,Z3 就是必需的。
始终构建 Release 配置。 预构建的
clang+llvm-*-windows-msvc 包只附带 Release 库,这些库使用
动态发布版 CRT(/MD)。当未指定 --config 时,Visual Studio
生成器默认使用 Debug(/MDd),而将 Debug 项目代码与 Release
版 LLVM 链接会因数百处 LNK2038 运行时库 /
_ITERATOR_DEBUG_LEVEL 不匹配而失败,最终以 LNK1319 结束。请在每次
cmake --build 时传入 --config Release(或使用同样为 /MD 的
RelWithDebInfo):
cmake --build build --config Release -j
include/ C++ public headers (dragon/)
lib/ C++ implementation
c_shim/ C API (dragon_c.h + libdragon_c.so)
python/ Python API (cffi, wraps the C shim)
tool/ CLI tools (disassembler, opcode_audit)
tests/ Catch2 test suite
docs/ API documentation, examples, and the manual
公共头文件位于 include/dragon/ 下,按领域分组(disassembler/、lifters/、analysis/、loader/、sigs/)。完整接口请参阅下方的 API 文档。
每个 API 层的完整示例都在 docs/ 中:
docs/cpp_api.md — C++ APIdocs/c_api.md — C shim APIdocs/python_api.md — Python APIIGNIL.md — IGNIL 设计与实现指南按任务而非按类组织的实操演练位于 docs/manual/ —— 从原始字节,经过 IGNIL 和 LLVM IR,一直到符号执行。
C++
#include <dragon/disassembler/Disassembler.hpp>
dragon::Configuration config;
dragon::Disassembler dis(dragon::Architecture::X86_64, config);
auto instructions = dis.disassemble(bytes, base_address);
for (const auto& insn : instructions)
std::cout << std::hex << insn.address() << " " << insn.disassembly() << "\n";
Python
import sys
sys.path.insert(0, 'python')
import dragon
cfg = dragon.Configuration()
dis = dragon.Disassembler(dragon.Architecture.X86_64, cfg)
graph = dis.disassemble(b'\x90\xC3', base_address=0x1000)
for insn in graph.instructions():
print(hex(insn.address), insn.disassembly)
后向切片(C++)
#include <dragon/analysis/BackwardSlicer.hpp>
#include <dragon/lifters/ignil/x86/x86IGNILRegs.hpp>
// graph must be populated by Disassembler::disassemble(bytes, base_addr, graph)
// so IGNIL blocks exist
dragon::BackwardSlicer slicer;
auto expr = slicer.slice(dragon::x86::ZF, block_addr, graph);
std::cout << dragon::slice::toString(expr) << "\n";
// e.g. EQ(SUB(RAX:i64, RBX:i64), 0x0:i64)
后向切片(Python)
with dragon.BackwardSlicer() as slicer:
with slicer.slice_reg(graph, block_addr, *dragon.x86.ZF) as expr:
print(expr.to_string()) # EQ(SUB(RAX:i64, RBX:i64), 0x0:i64)