A Graph-Based ROP Gadget Finder for RISC-V architectures
Project description
LCSAJdump
LCSAJDump: A Graph-Based Framework for Automated Gadget Discovery in RISC-V Environments.
Table of Contents
Overview
LCSAJdump is a static analysis framework designed to discover Return-Oriented Programming (ROP) and Jump-Oriented Programming (JOP) gadgets within RISC-V binaries.
Traditional ROP scanners typically employ a linear, sliding-window approach over raw executable bytes. While effective for standard instruction sequences, this method fails to identify Shadow Gadgets—executable chains that span non-contiguous memory blocks connected by unconditional jumps or conditional branches.
LCSAJdump overcomes this limitation by reconstructing the Control-Flow Graph (CFG) through Linear Code Sequence and Jump (LCSAJ) analysis. By modeling the binary as a directed graph of basic blocks, the tool identifies:
- Contiguous Gadgets: Standard linear sequences terminating in a control-flow transfer.
- Non-Contiguous (Shadow) Gadgets: Complex chains traversing multiple basic blocks, effectively bypassing "bad bytes" (e.g., null bytes) and utilizing instructions that would otherwise be unreachable by linear scanning.
Features
- Comprehensive Architecture Support: Full support for RISC-V 64-bit (RV64) and Compressed (C) extensions. Handling 16-bit compressed instructions is critical for maximizing gadget coverage in modern RISC-V binaries.
- Graph-Based Reconstruction: The engine segments the
.textsection into basic blocks based on control-flow transfers (jumps, branches, returns) and reconstructs edges for both fallthrough and direct targets using NetworkX. - Heuristic Backward Search: Implements a specialized backward Breadth-First Search (BFS) algorithm starting from control-flow sinks (
ret,jr,jalr) to reconstruct valid execution paths in reverse. - Hybrid Discovery: Capable of identifying both standard linear gadgets and complex, multi-block trampoline gadgets in a single pass.
- Scoring and Classification: Includes a heuristic scoring system that prioritizes gadgets involving critical registers (
ra,a0,sp) and classifies results into functional categories (Linear, Trampoline, Conditional, Fallthrough). - Optimized Performance: Features configurable pruning parameters ("Darkness" factor) to limit the search depth and node visitation, balancing analysis speed with coverage depth.
Project Structure
The repository is organized into modular components responsible for binary loading, graph generation, and algorithmic search.
LCSAJdump/
├── loader.py # ELF parsing and Capstone disassembly wrapper
├── graph.py # LCSAJ basic block decomposition and DiGraph construction
├── rainbowBFS.py # Backward search algorithm, scoring, and classification logic
├── LCSAJdump.py # Main entry point and CLI argument parsing
└── utils.py # Helper functions for formatting and logging
Project Index
loader.py: Utilizespyelftoolsto extract executable sections andCapstoneto disassemble RV64GC instructions into a linear stream.graph.py: Converts the linear instruction stream into a directed graph. Nodes represent basic blocks (LCSAJs), and edges represent control flow (jumps, branches, and fallthroughs).rainbowBFS.py: The core analysis engine. It traverses the reverse graph from leaf nodes (returns) to find executable paths, applying heuristic scoring to filter non-viable chains.LCSAJdump.py: Orchestrates the analysis pipeline, handling user input, parameter tuning, and output generation.
Getting Started
Prerequisites
All of them listed in requirements.txt:
- Python 3.8 or higher
capstone(Disassembly engine)networkx(Graph algorithms)pyelftools(ELF file parsing)
Installation
GitHub
Clone the repository and install the required dependencies:
git clone [https://github.com/Chris1sFlaggin/LCSAJdump.git](https://github.com/Chris1sFlaggin/LCSAJdump.git)
cd LCSAJdump
pip install -r requirements.txt
Pip
pip install lcsajdump
Usage
Basic Scan Run the tool on a target binary using default parameters:
python LCSAJdump.py <path_to_binary>
Advanced Configuration Users can tune the search depth and pruning thresholds to handle larger binaries or deeper gadget chains:
python LCSAJdump.py -d 15 -k 100 -l 20 --verbose <path_to_binary>
CLI Options:
-d, --depth: Maximum search depth (in blocks) for the BFS algorithm.-k, --darkness: Pruning threshold (maximum visits per node) to prevent infinite loops in cyclic graphs.-l, --limit: Maximum number of top-ranked gadgets to display.-s, --min-score: Minimum heuristic score threshold for reporting.-v, --verbose: Enable detailed output of instruction decoding.
Testing
To verify the integrity of the graph reconstruction and gadget finding logic, run the unit tests provided in the tests/ directory:
python -m pytest unitTest/*
Output Example
❯ time python LCSAJdump/LCSAJdump.py testCTFs/rop/vuln
[*] Analisi Target: testCTFs/rop/vuln
[*] Caricamento binario: testCTFs/rop/vuln
[*] Sezione .text trovata.
Dimensione: 258236 bytes
Indirizzo Base: 0x10250
[*] Avvio disassemblaggio con Capstone...
Disassembling [████████████████████████████████████████████████████████████] 100.0%
[*] Disassemblaggio completato. 89354 istruzioni estratte.
[*] Costruzione Nodi LCSAJ...
Building Graph [████████████████████████████████████████████████████████████] 100.0%
[*] Configurazione Rainbow: Depth=12, Darkness=30
[*] Pruning effettuato: 0 rami tagliati.
============================================================
--- TOP 10 SEQUENTIAL GADGETS ---
============================================================
0x39ffe: c.ldsp ra, 0x48(sp); c.ldsp a0, 0x38(sp); c.addi16sp sp, 0x50; c.jr ra
0x4078c: c.ldsp a0, 0x20(sp); c.ldsp ra, 0x58(sp); c.addi16sp sp, 0x60; c.jr ra
0x45d2e: c.ld a0, 0x10(a5); c.ldsp ra, 0x38(sp); c.addi16sp sp, 0x40; c.jr ra
0x460b8: c.ldsp ra, 0x38(sp); c.ldsp a0, 0x20(sp); c.addi16sp sp, 0x40; c.jr ra
0x460e6: c.ldsp ra, 0x38(sp); c.ldsp a0, 0x20(sp); c.addi16sp sp, 0x40; c.jr ra
0x4618c: c.ldsp ra, 0x28(sp); c.ldsp a0, 0x10(sp); c.addi16sp sp, 0x30; c.jr ra
0x461b6: c.ldsp ra, 0x28(sp); c.ldsp a0, 0x10(sp); c.addi16sp sp, 0x30; c.jr ra
0x46386: c.ldsp a0, 0(sp); c.ldsp ra, 0x18(sp); c.addi16sp sp, 0x20; c.jr ra
0x4aa1a: c.ldsp a0, 0x18(sp); c.ldsp ra, 0x28(sp); c.addi16sp sp, 0x30; c.jr ra
0x113be: c.ldsp a0, 8(sp); c.ldsp ra, 0x18(sp); c.sw s0, 0x70(a0); c.ldsp s0, 0x10(sp); c.addi16sp sp, 0x20; c.jr ra
============================================================
--- TOP 10 JUMP-BASED GADGETS ---
============================================================
0x4060a: c.ld a0, 0x18(s0); jal -0x27b12; c.ldsp a1, 8(sp); addi a7, zero, 0x87; c.li a0, 2; c.li a2, 0; c.li a3, 8; ecall ; c.ldsp ra, 0x18(sp); c.addi16sp sp, 0x20; c.jr ra
0x46fc0: ld s8, -0x500(s0); ld a0, -0x480(s0); ld a6, -0x4f8(s0); beq a0, s8, 0x10; sd a6, -0x4c8(s0); jal -0x2e4da; c.sd a4, 0x28(a5); c.ldsp ra, 0x78(sp); c.ldsp s8, 0x30(sp); c.addi16sp sp, 0x80; c.jr ra
0x2b9f4: auipc a3, 0x4e; ld a3, 0x504(a3); addi a2, sp, 0x4e0; c.mv a1, a2; c.add a3, tp; c.ld a0, 0(a3); jal 0x13ace; c.lw a4, 0(a5); c.andi a4, -0x11; c.sw a4, 0(a5); c.ldsp ra, 0x18(sp); c.addi16sp sp, 0x20; c.jr ra
0x4146a: ld a0, 8(s10); jal -0x28974; c.mv a0, t3; bltz t3, 0x22e; c.ldsp s0, 0x50(sp); c.ldsp s1, 0x48(sp); c.ldsp s3, 0x38(sp); c.ldsp ra, 0x58(sp); c.ldsp s2, 0x40(sp); c.ldsp s4, 0x30(sp); c.ldsp s5, 0x28(sp); c.addi16sp sp, 0x60; c.jr ra
0x46224: c.addi16sp sp, -0x30; c.sdsp a0, 0(sp); auipc a0, 0x34; ld a0, -0x328(a0); c.sdsp ra, 0x28(sp); c.sdsp s0, 0x20(sp); c.sdsp a1, 8(sp); c.sdsp ra, 0x10(sp); jal -0x16152; c.ldsp ra, 0x18(sp); c.ldsp s0, 0x10(sp); c.li a0, -1; c.addi16sp sp, 0x20; c.jr ra
0x35a06: ld a0, 0x360(s1); c.li a5, -1; beq a0, a5, 8; jal -0x1cf16; c.ld a2, 0x58(s0); c.lw a1, 0x60(s0); auipc a0, 0x34; addi a0, a0, -0x1a; addi s0, s0, 0x80; jal 0x1b864; c.ldsp ra, 0x88(sp); c.ldsp s0, 0x80(sp); c.ldsp s1, 0x78(sp); c.addi16sp sp, 0x90; c.jr ra
0x46366: c.ld a0, 0x10(a0); c.sdsp a5, 8(sp); c.sdsp a4, 0(sp); jal -0x1245a; add a4, a2, a1; c.lw a3, 0(a5); c.sd a2, 0x18(a5); c.sd a4, 8(a5); c.andi a3, -0x11; c.sd a4, 0x10(a5); c.sd a0, 0x90(a5); c.sw a3, 0(a5); c.ldsp ra, 0x28(sp); c.mv a0, a1; c.addi16sp sp, 0x30; c.jr ra
0x1db48: c.ld a0, 8(s0); c.ldsp s0, 0x10(sp); c.ld a1, 8(s1); c.ldsp ra, 0x18(sp); c.ldsp s1, 8(sp); c.addi16sp sp, 0x20; j 0x141fe; c.lw a4, 0(a5); c.ld a3, 8(a5); andi a4, a4, 0x100; c.bnez a4, 0xe; c.ld a5, 0x18(a5); c.lw a0, 0x10(a0); sub a5, a3, a5; c.subw a0, a5; c.jr ra
0x4145e: lw a5, 0(s6); andi a5, a5, 0x40; bnez a5, 0x2c0; ld a0, 8(s10); jal -0x28974; c.mv a0, t3; bltz t3, 0x22e; c.ldsp s0, 0x50(sp); c.ldsp s1, 0x48(sp); c.ldsp s3, 0x38(sp); c.ldsp ra, 0x58(sp); c.ldsp s2, 0x40(sp); c.ldsp s4, 0x30(sp); c.ldsp s5, 0x28(sp); c.addi16sp sp, 0x60; c.jr ra
0x2bd72: c.mv a2, s8; addi a1, zero, 0x20; c.mv a0, s0; jal 0x109e8; slli a0, a4, 5; c.addi a0, 0x10; c.addi a4, 1; c.add a0, a2; c.sd a4, 8(a2); ld a5, 0xa0(gp); c.li a4, 1; c.ldsp ra, 0x18(sp); c.sd a4, 0(a0); c.add a5, a4; sd a5, 0xa0(gp); c.addi16sp sp, 0x20; c.jr ra
[+] Report salvato in: gadgets_found.txt (Trovati 4637 gadget)
python LCSAJdump/LCSAJdump.py testCTFs/rop/vuln 1,67s user 0,27s system 99% cpu 1,936 total
Contributing
Contributions to improve the search algorithm or extend architecture support are welcome. Please ensure that any pull requests include relevant test cases and adhere to the existing coding standards.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lcsajdump-1.0.1.tar.gz.
File metadata
- Download URL: lcsajdump-1.0.1.tar.gz
- Upload date:
- Size: 11.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4187211bd1cfe2767b8e5d4319408d4e21503cdcaf1a538f988b5a9eb9b97158
|
|
| MD5 |
5bff51f88b5cf36fc5dc9a6aa3e9c590
|
|
| BLAKE2b-256 |
438de52333da23245a3027f75a4123976d1f8ff6331962ffd74a9e4645fb570a
|
File details
Details for the file lcsajdump-1.0.1-py3-none-any.whl.
File metadata
- Download URL: lcsajdump-1.0.1-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9a5ebf56f07ff738afca101df2337d4dc54d020c3ba5219bcb223a86e9c9ed8e
|
|
| MD5 |
d45b7dba664cd316bd4b014e67e48120
|
|
| BLAKE2b-256 |
87ea3bc997b53f8d5e1b9b5f749e6d481cbb3de688d6cdfca18fd593aab3fd13
|