Target-agnostic arm64 binary analysis helpers — disassembly window, branch/ADRP xref scanner, and a six-step RE methodology.
re-toolkit provides two practical arm64 analysis tools and a structured
methodology doc:
| Component | What it gives you |
|---|---|
re_toolkit.disasm |
Disassemble a configurable window of instructions from any raw binary — useful for quickly inspecting a function without loading a full IDA/Ghidra project. |
re_toolkit.xref |
Pure-stdlib scanner that finds B/BL/B.cond branch targets and ADRP+ADD/ADRP+LDR address-materialisation pairs across an entire segment in one pass. |
docs/METHODOLOGY.md |
A six-step RE pipeline (discover → hypothesize → instrument → verify → harden → document) with version-drift resilience patterns, checksum gates, and three-layer verification doctrine. |
All tools operate on raw binary bytes — no ELF/Mach-O parsing required — which makes them usable on carved-out regions, firmware dumps, or in-memory captures as easily as on file-backed binaries.
- Python 3.10+
uv(recommended) or pip
# Clone
git clone https://github.com/convenientlymike/re-toolkit.git
cd re-toolkit
# Install with uv (creates an isolated venv automatically; --extra dev installs pytest)
uv sync --extra dev
# Disassemble the bundled sample blob
uv run python -m re_toolkit.disasm examples/sample.bin --offset 0 --load-address 0x1000
# Scan the same blob for branch and ADRP xrefs
uv run python -m re_toolkit.xref examples/sample.bin --load-address 0x1000
# Run the end-to-end demo (both tools together)
uv run python examples/run_demo.py
# Run the test suite
uv run pytestpip install -e ".[dev]"
python -m re_toolkit.disasm examples/sample.bin --offset 0 --load-address 0x1000
pytest# examples/sample.bin offset=0x0 (12 instructions)
0x0000000000001000 00 00 00 b0 adrp x0, #0x2000
0x0000000000001004 00 40 00 91 add x0, x0, #0x10
0x0000000000001008 1f 20 03 d5 nop
0x000000000000100c 05 00 00 94 bl #0x1020
0x0000000000001010 e1 dd 97 d2 mov x1, #0xbeef
0x0000000000001014 04 00 00 14 b #0x1024
0x0000000000001018 1f 20 03 d5 nop
...
# examples/sample.bin offset=0x0 found 2 branches, 1 ADRP pairs
BL 0x000000000000100c → 0x0000000000001020
B 0x0000000000001014 → 0x0000000000001024
ADRP+ADD 0x0000000000001000 → materialized=0x0000000000002010
from re_toolkit.disasm import disasm_window
from re_toolkit.xref import scan_xrefs
data = open("target.bin", "rb").read()
# Disassemble 20 instructions starting at file offset 0x1234.
# load_address is the VA of data[0] (the image base); the first reported
# instruction address will be 0x100000000 + 0x1234 = 0x100001234.
for insn in disasm_window(data, offset=0x1234, count=20, load_address=0x100000000):
print(insn)
# Find all branch targets and ADRP-materialized addresses in a segment.
result = scan_xrefs(data, offset=0, load_address=0x100000000)
for xref in result:
print(xref)re-toolkit/
├── src/re_toolkit/
│ ├── disasm.py Capstone-backed disassembly window (CLI + library)
│ ├── xref.py Pure-stdlib arm64 branch + ADRP scanner (CLI + library)
│ └── __main__.py Top-level dispatcher (python -m re_toolkit <sub>)
├── tests/
│ └── test_disasm.py 21 tests across disasm + xref + blob integrity
├── examples/
│ ├── sample.bin 48-byte hand-crafted arm64 blob (12 instructions)
│ └── run_demo.py Self-contained end-to-end demo
└── docs/
└── METHODOLOGY.md Six-step RE pipeline with version-drift doctrine
Capstone for disassembly, stdlib for scanning. Capstone is the industry standard arm64 decode engine — correct, well-maintained, and used by every major RE tool. The xref scanner, however, only needs to recognise a handful of fixed-width encodings, so a pure-Python bit-field extractor is faster and has zero dependencies.
disasm_window not disasm_all. The public API is intentionally
windowed. Disassembling a large binary in one call produces noise; disassembling a
targeted 16–32 instruction window around a known offset produces signal. The
caller decides how wide the window needs to be.
Immutable Instruction dataclass. The Instruction type is frozen so
it can be safely stored in sets, used as dict keys, and passed between
threads without defensive copying.
Load-address separation. The load_address parameter is distinct from
offset because the two concepts are genuinely different: offset is where
in the file the bytes come from, load_address is the virtual address at
which the target maps those bytes. Making them the same parameter by default
would be convenient but wrong for any binary that isn't mapped at offset 0.
re-toolkit/
├── src/
│ └── re_toolkit/
│ ├── __init__.py
│ ├── __main__.py
│ ├── disasm.py
│ └── xref.py
├── tests/
│ ├── __init__.py
│ └── test_disasm.py
├── examples/
│ ├── README.md
│ ├── run_demo.py
│ └── sample.bin
├── docs/
│ └── METHODOLOGY.md
├── .gitignore
├── LICENSE
├── pyproject.toml
└── README.md
uv run pytest # all tests
uv run pytest -v # verbose
uv run pytest -k "xref" # xref tests only (no capstone needed)
uv run pytest --co -q # list tests without runningThe test suite is split into two groups:
- Xref and blob-integrity tests — pure stdlib, run with zero extra dependencies.
- Disassembly tests — require Capstone; automatically skipped if
Capstone is not installed (
pytest.mark.skipif).
This toolkit is intended for authorized binary analysis — security
research, CTF challenges, software you own, or work performed under an
explicit authorization agreement. The methodology in docs/METHODOLOGY.md
is written for exactly this context and includes an explicit authorized-use
framing in its preamble.
Clean-room demo built to showcase low-level arm64 binary analysis depth — Capstone integration, pure-Python bit-field decoding, and structured RE methodology documentation.