
dragon-tales
a binary analysis library, cross-architecture, built on LLVM. Disassemble, assemble, lift to an architecture-independent IL, and slice — from C++, from Python, from C.
Some tales tell of heroes. This one tells of older things — the archaic tongues machines have spoken to each other since long before anyone thought to read them back. We call it assembly: dense, irregular, one dialect per silicon lineage — x86's guttural muttering, ARM's disciplined verse, RISC-V's still-forming grammar.
dragon-tales was built to read them. To decode the runes byte by byte, trace their lineage through blocks and functions, and set them down in a single shared tongue — IGNIL — so a story once told only in x86, or only in ARM, can finally be read, optimized, and understood as one.
what it does
Disassembly
Linear sweep and recursive traversal, across six architectures, built on LLVM's MC layer.
CFG & function recovery
Turns a flat instruction stream into basic blocks, functions, and a control-flow graph.
IGNIL
A lightweight, architecture-independent intermediate language every backend lifts into.
LLVM IR
Move from IGNIL into optimizable LLVM IR for further analysis or transformation.
Backward slicer
Propagates values through IGNIL CFGs without crossing join nodes — trace a flag or register back to its source.
C++, C, Python
A C++ core, an opaque-pointer C shim, and cffi-based Python bindings over the same API shape.
What is dragon-tales?
dragon-tales is a binary analysis library for disassembling, assembling, and analyzing machine code across multiple architectures. It’s built on LLVM 21, so decoding is as accurate as LLVM’s own MC layer, and every architecture LLVM knows about is a realistic target for dragon-tales to grow into.
Everything is object-based, top to bottom. A Configuration object — syntax,
disassembly strategy, target CPU, target features — is constructed once and
handed to a Disassembler or Assembler. There’s no free-function API to
half-remember; the same shape shows up whether you’re in C++, calling the
C shim directly, or using the Python bindings that wrap it.
Three layers, one API shape
- C++ core (
include/dragon/,lib/) — the real implementation:Configuration,Disassembler,Assembler,Graph,BasicBlock,Function,Instruction. - C shim (
c_shim/dragon_c.h) — an opaque-pointer C API wrapping the C++ layer, for anything that needs a stable C ABI. - Python (
python/dragon.py) —cffibindings over the C shim, so the Python API mirrors the C++ one almost 1:1.
From bytes to IR
The pipeline goes further than “print the disassembly.” Once instructions are recovered, dragon-tales reconstructs basic blocks and functions into a control-flow graph, lifts that graph into IGNIL — a small architecture-independent intermediate language — and can move IGNIL into optimizable LLVM IR for further analysis or transformation. A backward slicer walks IGNIL CFGs to answer questions like “where did this flag actually come from?” without crossing block joins.
Where reading the code stops being enough, a symbolic executor runs IGNIL
over Z3 bitvectors: seed registers and memory concretely or symbolically, run
a block, then ask the solver for an input that makes a check pass, a proof
that some obfuscated arithmetic is really just a + b, or the concrete set of
addresses a computed jump can reach.
Where to go next
The manual walks through the whole pipeline hands-on, one running
example (a small ARM64/x86-64 function) all the way from raw bytes to LLVM IR,
and ends by asking the solver questions the
code alone doesn’t answer.
For reference material organized by class and function instead, see
docs/cpp_api.md,
docs/c_api.md, and
docs/python_api.md
in the repository.
the theory behind dragon-tales
dragon-tales is a project of
.
The theory this library is built on — disassembly, function and CFG
recovery, semantic ILs, lowering to LLVM IR, emulation and symbolic
execution — is taught end to end in the following trainings, all with
in-browser labs and no local setup:

Wyvern — Building an ARM Disassembler & IL From Scratch
Assemble and decode AArch64 through LLVM’s MC layer, recover functions and basic blocks from a flat instruction stream, build the control-flow graph, then design WVIL — a semantic IL — and lift instructions into it. The same ground dragon-tales covers from raw bytes to an architecture-independent IL.
fuzzsociety.org →
Wyvern Advanced — From AArch64 Machine Code to LLVM IR & Program Analysis
The full pipeline: disassembly, function discovery, basic-block recovery, CFG construction, the WVIL semantic IL, then lowering to LLVM IR, optimizing it and analysing the result — backward slicing, jump-table recovery, a C API and Python bindings over cffi, closing on ARM32/Thumb.
fuzzsociety.org →
Program Analysis Bundle — Wyvern Advanced + Emulation & Symbolic Execution
Wyvern Advanced together with Emulators & Symbolic Execution Engines: the three ways of reading a binary — static lifting to an IR, concrete execution under emulation, and symbolic reasoning over constraints — which is exactly the combination the VMProtect write-up leans on.
fuzzsociety.org →