Skip to content

thebabush/xr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

61 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

xr - fast binary cross-reference extractor

xr is a standalone Rust CLI tool for ultra-fast, parallel extraction of cross-references from stripped binaries (ELF, Mach-O, PE). It emits (from_va, to_va, kind) tuples at orders-of-magnitude faster speed than traditional disassemblers.

Quick Start

cargo build --release

# Analyse a binary at the recommended depth
./target/release/xr /path/to/binary --depth paired

# Output as JSONL or CSV
./target/release/xr /path/to/binary --depth paired --format jsonl
./target/release/xr /path/to/binary --depth paired --format csv

# Filter to a specific xref kind
./target/release/xr /path/to/binary --depth paired --kind call

# Show disasm context around each xref site (like grep -A/-B)
./target/release/xr /path/to/binary --depth paired -A 3 -B 2

Performance

206 million xrefs from a 4.6 GB dyld shared cache (3240 images) in under 6 seconds:

$ xr /System/Library/dyld/dyld_shared_cache_x86_64 > /dev/null
dyld shared cache: arch=X86_64  mappings=24  images=3240  subcaches=5
xrefs: 206432528  |  5.7s  |  4620.3 MB scanned  |  24 segments

Example Output

Default text output:

$ xr binary --depth paired --limit 4
0x00000000006a268f -> 0x00000000006a2699  jump  [linear-immediate]
0x00000000006a26a1 -> 0x00000000006a25ea  call  [linear-immediate]
0x00000000006a26b7 -> 0x0000000000798345  call  [linear-immediate]
0x00000000006a26cf -> 0x00000000006a2368  data_ptr  [linear-immediate]

With disassembly context (-B 2 -A 1):

$ xr binary -k call --limit 2 -B 2 -A 1
0x00000000006a26d6 -> 0x00000000006a2393  call  [linear-immediate]
    0x00000000006a26ca  48 8d 4c 24 0c            lea rcx, [rsp+0Ch]
    0x00000000006a26cf  48 8d 15 92 fc ff ff      lea rdx, [6A2368h]
  > 0x00000000006a26d6  e8 b8 fc ff ff            call 00000000006A2393h
    0x00000000006a26db  48 83 c4 18               add rsp, 18h

With Rust string heuristics (--rust):

$ xr target/release/my_app --rust -k data_ptr
...
0x00000001002b0238 -> 0x0000000100243834  data_ptr  [byte-scan]  "STRIKETHROUGH"
0x00000001002b4b68 -> 0x00000001002744d2  data_ptr  [byte-scan]  "failed to write the buffered data"
0x00000001002b5de0 -> 0x000000010022e8b0  data_ptr  [byte-scan]  "src/arch/arm64.rs"
0x00000001002b5e10 -> 0x000000010022e8c2  data_ptr  [byte-scan]  "src/arch/x86_64.rs"

Analysis Depths

Flag Name What it does
--depth scan ByteScan Pointer-sized byte scan of data sections
--depth linear Linear Linear disasm, immediate targets + RIP-relative
--depth paired Paired ADRP+ADD/LDR pairs (ARM64) or register prop (x86-64), recommended

Accuracy

See docs/STATUS.md for architecture details and known gaps.

Supported Formats

  • ELF (x86-64, AArch64), including PIE (ET_DYN)
  • Single-arch Mach-O (x86-64, ARM64). Fat binaries require lipo -extract first
  • PE / COFF (x86-64, ARM64)
  • Apple dyld shared cache
  • Raw flat binary (treated as single executable segment)

x86-32 and ARM32 binaries are loaded but not scanned (architecture stubs only).

Options

USAGE:
    xr [OPTIONS] <BINARY>

OPTIONS:
    -d, --depth <DEPTH>         Analysis depth: scan | linear | paired [default: paired]
    -j, --workers <N>           Worker threads; 0 = all CPUs [default: 0]
    -f, --format <FORMAT>       Output format: text | jsonl | csv [default: text]
    -k, --kind <KIND>           Filter by kind: call | jump | data_read | data_write | data_ptr
        --base <VA>             Override PIE ELF load base (hex or decimal)
        --min-ref-va <VA>       Drop xrefs whose 'to' VA is below this value
        --start <VA>            Scan only 'from' addresses >= VA
        --end <VA>              Scan only 'from' addresses < VA
        --ref-start <VA>        Retain only xrefs with 'to' >= VA
        --ref-end <VA>          Retain only xrefs with 'to' < VA
        --limit <N>             Cap output at N xrefs (0 = unlimited)
    -A, --after-context <N>     Show N instructions after each xref site
    -B, --before-context <N>    Show N instructions before each xref site
        --rust                  Extract Rust string literals from data_ptr xrefs
        --rust-min-blob <N>     Min UTF-8 blob size in bytes [default: 16]
        --rust-string-max <N>   Max display width for strings (0 = unlimited) [default: 100]

Benchmarking

# Build the benchmark binary
cargo build --release --bin benchmark

# Run against a ground-truth file
./target/release/benchmark \
    --binary /path/to/binary \
    --ground-truth /path/to/binary.xrefs.json \
    --depth paired

Claude Code Skill

This project includes a Claude Code skill in .claude/skills/xrefs/ that teaches Claude how to use xr for binary reverse-engineering workflows: finding callers/callees, data references, pointer hunting, and more.

About

Fast binary cross-reference extractor for ELF, Mach-O, PE, and dyld shared caches

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors