lcsajdump 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ Copyright 2026 Chris1sflaggin🅭
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,21 @@
1
+ include README.md
2
+ include LICENSE
3
+ include requirements.txt
4
+
5
+ graft lcsajdump
6
+
7
+ prune testCTFs
8
+ prune unitTest
9
+ prune _images
10
+
11
+ prune build
12
+ prune lcsajdump.egg-info
13
+
14
+ prune lcsajdump/venv
15
+
16
+ global-exclude *.pyc
17
+ global-exclude __pycache__
18
+ global-exclude *.so
19
+ global-exclude .DS_Store
20
+ global-exclude gadgets_found.txt
21
+ global-exclude PAPER.md
@@ -0,0 +1,230 @@
1
+ Metadata-Version: 2.4
2
+ Name: lcsajdump
3
+ Version: 1.0.0
4
+ Summary: A Graph-Based ROP Gadget Finder for RISC-V architectures
5
+ Home-page: https://chris1sflaggin.it/LCSAJdump/
6
+ Author: Chris1sFlaggin
7
+ Author-email: lcsajdump@chris1sflaggin.it
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Topic :: Security
12
+ Classifier: Environment :: Console
13
+ Requires-Python: >=3.6
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: capstone
17
+ Requires-Dist: pyelftools
18
+ Requires-Dist: networkx
19
+ Requires-Dist: click
20
+ Dynamic: author
21
+ Dynamic: author-email
22
+ Dynamic: classifier
23
+ Dynamic: description
24
+ Dynamic: description-content-type
25
+ Dynamic: home-page
26
+ Dynamic: license-file
27
+ Dynamic: requires-dist
28
+ Dynamic: requires-python
29
+ Dynamic: summary
30
+
31
+ <div id="top">
32
+
33
+ <div align="center">
34
+
35
+ <img src="_images/LOGO.png" width="60%" style="position: relative; top: 0; right: 0;" alt="Project Logo"/>
36
+
37
+ # LCSAJdump
38
+
39
+ <em>LCSAJDump: A Graph-Based Framework for Automated Gadget Discovery in RISC-V Environments.</em>
40
+
41
+ <img src="https://img.shields.io/badge/status-Thesis_Prototype-orange?style=for-the-badge" alt="Status">
42
+
43
+ ---
44
+
45
+ ## Table of Contents
46
+
47
+ - [Overview](#overview)
48
+ - [Features](#features)
49
+ - [Project Structure](#project-structure)
50
+ - [Project Index](#project-index)
51
+ - [Getting Started](#getting-started)
52
+ - [Prerequisites](#prerequisites)
53
+ - [Installation](#installation)
54
+ - [Usage](#usage)
55
+ - [Testing](#testing)
56
+ - [Roadmap](#roadmap)
57
+ - [Contributing](#contributing)
58
+ - [License](#license)
59
+
60
+ ---
61
+
62
+ ## Overview
63
+
64
+ LCSAJdump is a static analysis framework designed to discover Return-Oriented Programming (ROP) and Jump-Oriented Programming (JOP) gadgets within RISC-V binaries.
65
+
66
+ 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.
67
+
68
+ 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:
69
+
70
+ 1. **Contiguous Gadgets:** Standard linear sequences terminating in a control-flow transfer.
71
+ 2. **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.
72
+
73
+ ## Features
74
+
75
+ * **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.
76
+ * **Graph-Based Reconstruction:** The engine segments the `.text` section into basic blocks based on control-flow transfers (jumps, branches, returns) and reconstructs edges for both fallthrough and direct targets using NetworkX.
77
+ * **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.
78
+ * **Hybrid Discovery:** Capable of identifying both standard linear gadgets and complex, multi-block trampoline gadgets in a single pass.
79
+ * **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).
80
+ * **Optimized Performance:** Features configurable pruning parameters ("Darkness" factor) to limit the search depth and node visitation, balancing analysis speed with coverage depth.
81
+
82
+ ## Project Structure
83
+
84
+ The repository is organized into modular components responsible for binary loading, graph generation, and algorithmic search.
85
+
86
+ ```text
87
+ LCSAJdump/
88
+ ├── loader.py # ELF parsing and Capstone disassembly wrapper
89
+ ├── graph.py # LCSAJ basic block decomposition and DiGraph construction
90
+ ├── rainbowBFS.py # Backward search algorithm, scoring, and classification logic
91
+ ├── LCSAJdump.py # Main entry point and CLI argument parsing
92
+ └── utils.py # Helper functions for formatting and logging
93
+
94
+ ```
95
+
96
+ ### Project Index
97
+
98
+ * **`loader.py`**: Utilizes `pyelftools` to extract executable sections and `Capstone` to disassemble RV64GC instructions into a linear stream.
99
+ * **`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).
100
+ * **`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.
101
+ * **`LCSAJdump.py`**: Orchestrates the analysis pipeline, handling user input, parameter tuning, and output generation.
102
+
103
+ ## Getting Started
104
+
105
+ ### Prerequisites
106
+
107
+ All of them listed in `requirements.txt`:
108
+ * Python 3.8 or higher
109
+ * `capstone` (Disassembly engine)
110
+ * `networkx` (Graph algorithms)
111
+ * `pyelftools` (ELF file parsing)
112
+
113
+ ### Installation
114
+
115
+ #### GitHub
116
+
117
+ Clone the repository and install the required dependencies:
118
+
119
+ ```bash
120
+ git clone [https://github.com/Chris1sFlaggin/LCSAJdump.git](https://github.com/Chris1sFlaggin/LCSAJdump.git)
121
+ cd LCSAJdump
122
+ pip install -r requirements.txt
123
+
124
+ ```
125
+
126
+ #### Pip
127
+
128
+ ```zsh
129
+ pip install lcsajdump
130
+ ```
131
+
132
+ ### Usage
133
+
134
+ **Basic Scan**
135
+ Run the tool on a target binary using default parameters:
136
+
137
+ ```bash
138
+ python LCSAJdump.py <path_to_binary>
139
+
140
+ ```
141
+
142
+ **Advanced Configuration**
143
+ Users can tune the search depth and pruning thresholds to handle larger binaries or deeper gadget chains:
144
+
145
+ ```bash
146
+ python LCSAJdump.py -d 15 -k 100 -l 20 --verbose <path_to_binary>
147
+
148
+ ```
149
+
150
+ **CLI Options:**
151
+
152
+ * `-d, --depth`: Maximum search depth (in blocks) for the BFS algorithm.
153
+ * `-k, --darkness`: Pruning threshold (maximum visits per node) to prevent infinite loops in cyclic graphs.
154
+ * `-l, --limit`: Maximum number of top-ranked gadgets to display.
155
+ * `-s, --min-score`: Minimum heuristic score threshold for reporting.
156
+ * `-v, --verbose`: Enable detailed output of instruction decoding.
157
+
158
+ ### Testing
159
+
160
+ To verify the integrity of the graph reconstruction and gadget finding logic, run the unit tests provided in the `tests/` directory:
161
+
162
+ ```bash
163
+ python -m pytest unitTest/*
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Output Example
169
+
170
+ ```text
171
+ ❯ time python LCSAJdump/LCSAJdump.py testCTFs/rop/vuln
172
+ [*] Analisi Target: testCTFs/rop/vuln
173
+ [*] Caricamento binario: testCTFs/rop/vuln
174
+ [*] Sezione .text trovata.
175
+ Dimensione: 258236 bytes
176
+ Indirizzo Base: 0x10250
177
+
178
+ [*] Avvio disassemblaggio con Capstone...
179
+ Disassembling [████████████████████████████████████████████████████████████] 100.0%
180
+ [*] Disassemblaggio completato. 89354 istruzioni estratte.
181
+
182
+ [*] Costruzione Nodi LCSAJ...
183
+ Building Graph [████████████████████████████████████████████████████████████] 100.0%
184
+
185
+ [*] Configurazione Rainbow: Depth=12, Darkness=30
186
+ [*] Pruning effettuato: 0 rami tagliati.
187
+
188
+ ============================================================
189
+ --- TOP 10 SEQUENTIAL GADGETS ---
190
+ ============================================================
191
+ 0x39ffe: c.ldsp ra, 0x48(sp); c.ldsp a0, 0x38(sp); c.addi16sp sp, 0x50; c.jr ra
192
+ 0x4078c: c.ldsp a0, 0x20(sp); c.ldsp ra, 0x58(sp); c.addi16sp sp, 0x60; c.jr ra
193
+ 0x45d2e: c.ld a0, 0x10(a5); c.ldsp ra, 0x38(sp); c.addi16sp sp, 0x40; c.jr ra
194
+ 0x460b8: c.ldsp ra, 0x38(sp); c.ldsp a0, 0x20(sp); c.addi16sp sp, 0x40; c.jr ra
195
+ 0x460e6: c.ldsp ra, 0x38(sp); c.ldsp a0, 0x20(sp); c.addi16sp sp, 0x40; c.jr ra
196
+ 0x4618c: c.ldsp ra, 0x28(sp); c.ldsp a0, 0x10(sp); c.addi16sp sp, 0x30; c.jr ra
197
+ 0x461b6: c.ldsp ra, 0x28(sp); c.ldsp a0, 0x10(sp); c.addi16sp sp, 0x30; c.jr ra
198
+ 0x46386: c.ldsp a0, 0(sp); c.ldsp ra, 0x18(sp); c.addi16sp sp, 0x20; c.jr ra
199
+ 0x4aa1a: c.ldsp a0, 0x18(sp); c.ldsp ra, 0x28(sp); c.addi16sp sp, 0x30; c.jr ra
200
+ 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
201
+
202
+ ============================================================
203
+ --- TOP 10 JUMP-BASED GADGETS ---
204
+ ============================================================
205
+ 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
206
+ 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
207
+ 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
208
+ 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
209
+ 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
210
+ 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
211
+ 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
212
+ 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
213
+ 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
214
+ 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
215
+
216
+ [+] Report salvato in: gadgets_found.txt (Trovati 4637 gadget)
217
+ python LCSAJdump/LCSAJdump.py testCTFs/rop/vuln 1,67s user 0,27s system 99% cpu 1,936 total
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Contributing
223
+
224
+ 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.
225
+
226
+ ---
227
+
228
+ ## License
229
+
230
+ This project is licensed under the MIT License. See the [LICENSE](https://www.google.com/search?q=LICENSE) file for details.
@@ -0,0 +1,200 @@
1
+ <div id="top">
2
+
3
+ <div align="center">
4
+
5
+ <img src="_images/LOGO.png" width="60%" style="position: relative; top: 0; right: 0;" alt="Project Logo"/>
6
+
7
+ # LCSAJdump
8
+
9
+ <em>LCSAJDump: A Graph-Based Framework for Automated Gadget Discovery in RISC-V Environments.</em>
10
+
11
+ <img src="https://img.shields.io/badge/status-Thesis_Prototype-orange?style=for-the-badge" alt="Status">
12
+
13
+ ---
14
+
15
+ ## Table of Contents
16
+
17
+ - [Overview](#overview)
18
+ - [Features](#features)
19
+ - [Project Structure](#project-structure)
20
+ - [Project Index](#project-index)
21
+ - [Getting Started](#getting-started)
22
+ - [Prerequisites](#prerequisites)
23
+ - [Installation](#installation)
24
+ - [Usage](#usage)
25
+ - [Testing](#testing)
26
+ - [Roadmap](#roadmap)
27
+ - [Contributing](#contributing)
28
+ - [License](#license)
29
+
30
+ ---
31
+
32
+ ## Overview
33
+
34
+ LCSAJdump is a static analysis framework designed to discover Return-Oriented Programming (ROP) and Jump-Oriented Programming (JOP) gadgets within RISC-V binaries.
35
+
36
+ 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.
37
+
38
+ 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:
39
+
40
+ 1. **Contiguous Gadgets:** Standard linear sequences terminating in a control-flow transfer.
41
+ 2. **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.
42
+
43
+ ## Features
44
+
45
+ * **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.
46
+ * **Graph-Based Reconstruction:** The engine segments the `.text` section into basic blocks based on control-flow transfers (jumps, branches, returns) and reconstructs edges for both fallthrough and direct targets using NetworkX.
47
+ * **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.
48
+ * **Hybrid Discovery:** Capable of identifying both standard linear gadgets and complex, multi-block trampoline gadgets in a single pass.
49
+ * **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).
50
+ * **Optimized Performance:** Features configurable pruning parameters ("Darkness" factor) to limit the search depth and node visitation, balancing analysis speed with coverage depth.
51
+
52
+ ## Project Structure
53
+
54
+ The repository is organized into modular components responsible for binary loading, graph generation, and algorithmic search.
55
+
56
+ ```text
57
+ LCSAJdump/
58
+ ├── loader.py # ELF parsing and Capstone disassembly wrapper
59
+ ├── graph.py # LCSAJ basic block decomposition and DiGraph construction
60
+ ├── rainbowBFS.py # Backward search algorithm, scoring, and classification logic
61
+ ├── LCSAJdump.py # Main entry point and CLI argument parsing
62
+ └── utils.py # Helper functions for formatting and logging
63
+
64
+ ```
65
+
66
+ ### Project Index
67
+
68
+ * **`loader.py`**: Utilizes `pyelftools` to extract executable sections and `Capstone` to disassemble RV64GC instructions into a linear stream.
69
+ * **`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).
70
+ * **`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.
71
+ * **`LCSAJdump.py`**: Orchestrates the analysis pipeline, handling user input, parameter tuning, and output generation.
72
+
73
+ ## Getting Started
74
+
75
+ ### Prerequisites
76
+
77
+ All of them listed in `requirements.txt`:
78
+ * Python 3.8 or higher
79
+ * `capstone` (Disassembly engine)
80
+ * `networkx` (Graph algorithms)
81
+ * `pyelftools` (ELF file parsing)
82
+
83
+ ### Installation
84
+
85
+ #### GitHub
86
+
87
+ Clone the repository and install the required dependencies:
88
+
89
+ ```bash
90
+ git clone [https://github.com/Chris1sFlaggin/LCSAJdump.git](https://github.com/Chris1sFlaggin/LCSAJdump.git)
91
+ cd LCSAJdump
92
+ pip install -r requirements.txt
93
+
94
+ ```
95
+
96
+ #### Pip
97
+
98
+ ```zsh
99
+ pip install lcsajdump
100
+ ```
101
+
102
+ ### Usage
103
+
104
+ **Basic Scan**
105
+ Run the tool on a target binary using default parameters:
106
+
107
+ ```bash
108
+ python LCSAJdump.py <path_to_binary>
109
+
110
+ ```
111
+
112
+ **Advanced Configuration**
113
+ Users can tune the search depth and pruning thresholds to handle larger binaries or deeper gadget chains:
114
+
115
+ ```bash
116
+ python LCSAJdump.py -d 15 -k 100 -l 20 --verbose <path_to_binary>
117
+
118
+ ```
119
+
120
+ **CLI Options:**
121
+
122
+ * `-d, --depth`: Maximum search depth (in blocks) for the BFS algorithm.
123
+ * `-k, --darkness`: Pruning threshold (maximum visits per node) to prevent infinite loops in cyclic graphs.
124
+ * `-l, --limit`: Maximum number of top-ranked gadgets to display.
125
+ * `-s, --min-score`: Minimum heuristic score threshold for reporting.
126
+ * `-v, --verbose`: Enable detailed output of instruction decoding.
127
+
128
+ ### Testing
129
+
130
+ To verify the integrity of the graph reconstruction and gadget finding logic, run the unit tests provided in the `tests/` directory:
131
+
132
+ ```bash
133
+ python -m pytest unitTest/*
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Output Example
139
+
140
+ ```text
141
+ ❯ time python LCSAJdump/LCSAJdump.py testCTFs/rop/vuln
142
+ [*] Analisi Target: testCTFs/rop/vuln
143
+ [*] Caricamento binario: testCTFs/rop/vuln
144
+ [*] Sezione .text trovata.
145
+ Dimensione: 258236 bytes
146
+ Indirizzo Base: 0x10250
147
+
148
+ [*] Avvio disassemblaggio con Capstone...
149
+ Disassembling [████████████████████████████████████████████████████████████] 100.0%
150
+ [*] Disassemblaggio completato. 89354 istruzioni estratte.
151
+
152
+ [*] Costruzione Nodi LCSAJ...
153
+ Building Graph [████████████████████████████████████████████████████████████] 100.0%
154
+
155
+ [*] Configurazione Rainbow: Depth=12, Darkness=30
156
+ [*] Pruning effettuato: 0 rami tagliati.
157
+
158
+ ============================================================
159
+ --- TOP 10 SEQUENTIAL GADGETS ---
160
+ ============================================================
161
+ 0x39ffe: c.ldsp ra, 0x48(sp); c.ldsp a0, 0x38(sp); c.addi16sp sp, 0x50; c.jr ra
162
+ 0x4078c: c.ldsp a0, 0x20(sp); c.ldsp ra, 0x58(sp); c.addi16sp sp, 0x60; c.jr ra
163
+ 0x45d2e: c.ld a0, 0x10(a5); c.ldsp ra, 0x38(sp); c.addi16sp sp, 0x40; c.jr ra
164
+ 0x460b8: c.ldsp ra, 0x38(sp); c.ldsp a0, 0x20(sp); c.addi16sp sp, 0x40; c.jr ra
165
+ 0x460e6: c.ldsp ra, 0x38(sp); c.ldsp a0, 0x20(sp); c.addi16sp sp, 0x40; c.jr ra
166
+ 0x4618c: c.ldsp ra, 0x28(sp); c.ldsp a0, 0x10(sp); c.addi16sp sp, 0x30; c.jr ra
167
+ 0x461b6: c.ldsp ra, 0x28(sp); c.ldsp a0, 0x10(sp); c.addi16sp sp, 0x30; c.jr ra
168
+ 0x46386: c.ldsp a0, 0(sp); c.ldsp ra, 0x18(sp); c.addi16sp sp, 0x20; c.jr ra
169
+ 0x4aa1a: c.ldsp a0, 0x18(sp); c.ldsp ra, 0x28(sp); c.addi16sp sp, 0x30; c.jr ra
170
+ 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
171
+
172
+ ============================================================
173
+ --- TOP 10 JUMP-BASED GADGETS ---
174
+ ============================================================
175
+ 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
176
+ 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
177
+ 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
178
+ 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
179
+ 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
180
+ 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
181
+ 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
182
+ 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
183
+ 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
184
+ 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
185
+
186
+ [+] Report salvato in: gadgets_found.txt (Trovati 4637 gadget)
187
+ python LCSAJdump/LCSAJdump.py testCTFs/rop/vuln 1,67s user 0,27s system 99% cpu 1,936 total
188
+ ```
189
+
190
+ ---
191
+
192
+ ## Contributing
193
+
194
+ 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.
195
+
196
+ ---
197
+
198
+ ## License
199
+
200
+ This project is licensed under the MIT License. See the [LICENSE](https://www.google.com/search?q=LICENSE) file for details.
File without changes
@@ -0,0 +1,57 @@
1
+ import click
2
+ import sys
3
+ from .core.loader import BinaryLoader
4
+ from .core.graph import LCSAJGraph
5
+ from .core.rainbowBFS import RainbowFinder
6
+
7
+ @click.command()
8
+ @click.argument('binary_path', type=click.Path(exists=True))
9
+ @click.option('--depth', '-d', default=12, help='Profondità massima di ricerca (blocchi LCSAJ).')
10
+ @click.option('--darkness', '-k', default=30, help='Soglia di pruning (Max visite per nodo).')
11
+ @click.option('--limit', '-l', default=10, help='Numero di gadget da mostrare a video.')
12
+ @click.option('--min-score', '-s', default=0, help='Punteggio minimo per mostrare un gadget.')
13
+ @click.option('--verbose', '-v', is_flag=True, help='Mostra dettagli extra sui gadget trovati.')
14
+ @click.version_option(version='1.0.0', prog_name='LCSAJdump')
15
+ def main(binary_path, depth, darkness, limit, min_score, verbose):
16
+ """
17
+ RISC-V LCSAJ ROP Finder.
18
+ Analizza un binario per trovare gadget ROP usando l'algoritmo Rainbow BFS.
19
+ """
20
+ print('\33[33m'+r"""
21
+ ██╗ ██████╗███████╗ █████╗ ██╗██████╗ ██╗ ██╗███╗ ███╗██████╗ ██╗ ██╗ ██╗ ██████╗ ██████╗
22
+ ██║ ██╔════╝██╔════╝██╔══██╗ ██║██╔══██╗██║ ██║████╗ ████║██╔══██╗ ██║ ██║███║ ██╔═████╗ ██╔═████╗
23
+ ██║ ██║ ███████╗███████║ ██║██║ ██║██║ ██║██╔████╔██║██████╔╝ █████╗ ██║ ██║╚██║ ██║██╔██║ ██║██╔██║
24
+ ██║ ██║ ╚════██║██╔══██║██ ██║██║ ██║██║ ██║██║╚██╔╝██║██╔═══╝ ╚════╝ ╚██╗ ██╔╝ ██║ ████╔╝██║ ████╔╝██║
25
+ ███████╗╚██████╗███████║██║ ██║╚█████╔╝██████╔╝╚██████╔╝██║ ╚═╝ ██║██║ ╚████╔╝ ██║██╗╚██████╔╝▄█╗╚██████╔╝
26
+ ╚══════╝ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═════╝
27
+ """+'\33[0m')
28
+
29
+ print(f"[*] Analizing Target: {binary_path}")
30
+
31
+ loader = BinaryLoader(binary_path)
32
+ insns = loader.disassemble()
33
+
34
+ gb = LCSAJGraph(insns)
35
+ gb.build()
36
+
37
+ finder = RainbowFinder(gb, max_depth=depth, max_darkness=darkness)
38
+ gadgets = finder.search()
39
+
40
+ # Output a video filtrato
41
+ finder.print_gadgets(limit=limit, min_score=min_score, verbose=verbose)
42
+
43
+ # Output su file
44
+ output_file = "gadgets_found.txt"
45
+ try:
46
+ with open(output_file, "w") as f:
47
+ sys.stdout = f
48
+ print(f"REPORT GADGET - Depth:{depth} Darkness:{darkness}\n")
49
+ finder.print_gadgets(limit=len(gadgets), min_score=min_score)
50
+ sys.stdout = sys.__stdout__
51
+ print(f"\n[+] Report saved in: {output_file} (Found {len(gadgets)} gadgets)")
52
+ except Exception as e:
53
+ sys.stdout = sys.__stdout__
54
+ print(f"[!] Errore while saving file: {e}")
55
+
56
+ if __name__ == '__main__':
57
+ main()
File without changes
@@ -0,0 +1,82 @@
1
+ import networkx as nx
2
+ from .loader import draw_progress
3
+
4
+ class LCSAJGraph:
5
+ def __init__(self, instructions):
6
+ self.instructions = instructions
7
+ self.graph = nx.DiGraph()
8
+ self.addr_to_node = {} # Inizio blocco -> Dati blocco
9
+ self.insn_to_block_start = {} # Indirizzo istruzione -> Inizio blocco di appartenenza
10
+ self.reverse_graph = {}
11
+ self.nodes = []
12
+
13
+ def build(self):
14
+ self._create_nodes()
15
+ self._build_edges()
16
+
17
+ def _create_nodes(self):
18
+ if not self.instructions: return
19
+
20
+ print("[*] Building LCSAJ Nodes...")
21
+
22
+ total_insns = len(self.instructions)
23
+ current_block_insns = []
24
+ block_start = self.instructions[0].address
25
+
26
+ for idx, insn in enumerate(self.instructions):
27
+
28
+ if idx % 1000 == 0:
29
+ draw_progress(idx, total_insns, "Building Graph")
30
+
31
+ current_block_insns.append(insn)
32
+ mnem = insn.mnemonic.lower()
33
+
34
+ is_jump = mnem in ['ret', 'c.jr', 'c.jalr', 'jr', 'jalr'] or \
35
+ mnem in ['j', 'jal', 'c.j', 'c.jal'] or \
36
+ mnem.startswith('b') or mnem.startswith('c.b')
37
+
38
+ if is_jump:
39
+ self._add_node(block_start, current_block_insns)
40
+ current_block_insns = []
41
+ if idx + 1 < total_insns:
42
+ block_start = self.instructions[idx+1].address
43
+
44
+ if current_block_insns:
45
+ self._add_node(block_start, current_block_insns)
46
+
47
+ draw_progress(total_insns, total_insns, "Building Graph")
48
+
49
+ def _add_node(self, start, insns):
50
+ node = {'start': start, 'end': insns[-1].address, 'insns': insns, 'last_insn': insns[-1]}
51
+ self.nodes.append(node)
52
+ self.addr_to_node[start] = node
53
+ for i in insns:
54
+ self.insn_to_block_start[i.address] = start
55
+
56
+ def _build_edges(self):
57
+ for node in self.nodes:
58
+ last = node['last_insn']
59
+ mnem = last.mnemonic.lower()
60
+ targets = []
61
+
62
+ if mnem not in ['j', 'jal', 'c.j', 'c.jal', 'ret', 'jr', 'c.jr']:
63
+ next_addr = last.address + last.size
64
+ if next_addr in self.insn_to_block_start:
65
+ targets.append(self.insn_to_block_start[next_addr])
66
+
67
+ if mnem.startswith('b') or mnem in ['jal', 'j', 'c.j', 'c.jal']:
68
+ try:
69
+ import re
70
+ hex_match = re.findall(r'0x[0-9a-fA-F]+', last.op_str)
71
+ if hex_match:
72
+ addr = int(hex_match[-1], 16)
73
+ if addr in self.insn_to_block_start:
74
+ targets.append(self.insn_to_block_start[addr])
75
+ except: pass
76
+
77
+ for t in set(targets):
78
+ if t not in self.reverse_graph: self.reverse_graph[t] = []
79
+ self.reverse_graph[t].append(node['start'])
80
+
81
+ def get_gadget_tails(self):
82
+ return [n for n in self.nodes if n['last_insn'].mnemonic.lower() in ['ret', 'c.jr', 'jr', 'jalr']]
@@ -0,0 +1,100 @@
1
+ import capstone
2
+ from elftools.elf.elffile import ELFFile
3
+ import sys
4
+
5
+ def draw_progress(current, total, label=""):
6
+ percent = float(current) / float(total) * 100
7
+ bar_length = 60
8
+ filled_length = int(bar_length * current // total)
9
+
10
+ bar = '█' * filled_length + '░' * (bar_length - filled_length)
11
+
12
+ sys.stdout.write(f"\r{label:15} \033[32m[{bar}]\033[0m {percent:>5.1f}%")
13
+ sys.stdout.flush()
14
+
15
+ if current == total:
16
+ print()
17
+
18
+ class BinaryLoader:
19
+ def __init__(self, path):
20
+ self.path = path
21
+ self.code_bytes = None
22
+ self.base_addr = 0
23
+
24
+ # --- CONFIGURAZIONE CAPSTONE ---
25
+ # CS_ARCH_RISCV: Architettura principale
26
+ # CS_MODE_RISCV64: Modalità a 64-bit
27
+ # CS_MODE_RISCVC: Abilita le istruzioni "Compressed" (16-bit).
28
+ self.md = capstone.Cs(capstone.CS_ARCH_RISCV,
29
+ capstone.CS_MODE_RISCV64 | capstone.CS_MODE_RISCVC)
30
+
31
+ # Abilitiamo i dettagli per poter analizzare gli operandi (registri, imm) dopo
32
+ self.md.detail = True
33
+
34
+ def load(self):
35
+ """
36
+ Apre il file ELF, cerca la sezione .text (codice eseguibile)
37
+ e la carica in memoria.
38
+ """
39
+ print(f"[*] Loadaing binary: {self.path}")
40
+ try:
41
+ with open(self.path, 'rb') as f:
42
+ elf = ELFFile(f)
43
+ text_section = elf.get_section_by_name('.text')
44
+
45
+ if not text_section:
46
+ raise ValueError("Error: Section .text not found in binary!")
47
+
48
+ self.code_bytes = text_section.data()
49
+ self.base_addr = text_section['sh_addr']
50
+
51
+ print(f"[*] Section .text found.")
52
+ print(f" Dimension: {len(self.code_bytes)} bytes")
53
+ print(f" Start Address: {hex(self.base_addr)}\n")
54
+
55
+ except FileNotFoundError:
56
+ print(f"[!] Errore: File {self.path} non trovato.")
57
+ sys.exit(1)
58
+ except Exception as e:
59
+ print(f"[!] Errore nel parsing ELF: {e}")
60
+ sys.exit(1)
61
+
62
+ def disassemble(self):
63
+ if self.code_bytes is None:
64
+ self.load()
65
+
66
+ print("[*] Capstone is disassembling...")
67
+
68
+ instructions = []
69
+ total_bytes = len(self.code_bytes)
70
+ ptr = 0
71
+
72
+ while ptr < total_bytes:
73
+ curr_addr = self.base_addr + ptr
74
+
75
+ # v6 OTTIMIZZAZIONE: Invece di chiederne 1 alla volta,
76
+ try:
77
+ # Slicing (solo con buco nel codice)
78
+ chunk = self.code_bytes[ptr:]
79
+ disasm_iter = self.md.disasm(chunk, curr_addr)
80
+
81
+ count = 0
82
+ for insn in disasm_iter:
83
+ instructions.append(insn)
84
+ ptr += insn.size
85
+ count += 1
86
+
87
+ if len(instructions) % 5000 == 0:
88
+ draw_progress(ptr, total_bytes, "Disassembling")
89
+
90
+ # Se count == 0, significa che Capstone si è bloccato SUBITO.
91
+ # Quindi il byte a 'ptr' è sporco.
92
+ if count == 0:
93
+ ptr += 2
94
+
95
+ except Exception:
96
+ ptr += 2
97
+
98
+ draw_progress(total_bytes, total_bytes, "Disassembling")
99
+ print(f"[*] Disassembling complete. {len(instructions)} instructions estracted.\n")
100
+ return instructions
@@ -0,0 +1,115 @@
1
+ import collections
2
+
3
+ class RainbowFinder:
4
+ jump_mnemonics = ['j', 'c.j', 'jal', 'c.jal']
5
+
6
+ def __init__(self, graph_manager, max_depth, max_darkness):
7
+ self.gm = graph_manager
8
+ self.gadgets = []
9
+
10
+ self.MAX_DEPTH = max_depth
11
+ self.MAX_DARKNESS = max_darkness
12
+
13
+ def score_gadget(self, path):
14
+ score = 100
15
+ full_insns = []
16
+ for addr in path:
17
+ if addr in self.gm.addr_to_node:
18
+ full_insns.extend(self.gm.addr_to_node[addr]['insns'])
19
+
20
+ # v4 fix: togliere anche (len(path) * 10) era troppo penalizzante per gadget LCSAJ
21
+ score -= (len(full_insns) * 2)
22
+
23
+ has_ra = any('ra' in i.op_str and 'ld' in i.mnemonic for i in full_insns)
24
+ has_a0 = any('a0' in i.op_str and 'ld' in i.mnemonic for i in full_insns)
25
+ # v4 fix: premiare i salti trampolino
26
+ has_J = any(i.mnemonic in self.jump_mnemonics for i in full_insns)
27
+
28
+ if has_ra: score += 50
29
+ if has_a0: score += 40
30
+ if has_J: score += 30
31
+
32
+ # Penalità JOP (Salti a registro non-ra)
33
+ if full_insns:
34
+ last = full_insns[-1]
35
+ if last.mnemonic in ['jr', 'jalr', 'c.jr', 'c.jalr'] and 'ra' not in last.op_str:
36
+ score -= 20
37
+
38
+ return score
39
+
40
+ def search(self):
41
+ print(f"\n[*] RainbowBFS config: Depth={self.MAX_DEPTH}, Darkness={self.MAX_DARKNESS}")
42
+ tails = self.gm.get_gadget_tails()
43
+ queue = collections.deque([([t['start']], {t['start']}) for t in tails])
44
+ node_darkness = collections.defaultdict(int)
45
+ pruned = 0
46
+
47
+ while queue:
48
+ path, visited = queue.popleft()
49
+ head = path[0]
50
+ # V4 fix: '>' was blocking sequential gadgets
51
+ if len(path) >= 1: self.gadgets.append(path)
52
+ if len(path) >= self.MAX_DEPTH: continue
53
+
54
+ for parent in self.gm.reverse_graph.get(head, []):
55
+ if parent in visited: continue
56
+ if node_darkness[parent] >= self.MAX_DARKNESS:
57
+ pruned += 1
58
+ continue
59
+ node_darkness[parent] += 1
60
+ queue.append(([parent] + path, visited | {parent}))
61
+
62
+ print(f"[*] Pruning: {pruned} pruned branches.")
63
+ return self.gadgets
64
+
65
+ def _classify_gadget(self, path):
66
+ """Ritorna una etichetta e una categoria per il gadget"""
67
+ if len(path) == 1:
68
+ return "LINEAR", "Sequential"
69
+
70
+ # Analizziamo il tipo di salto
71
+ first_node = self.gm.addr_to_node[path[0]]
72
+ last_insn = first_node['last_insn']
73
+ mnem = last_insn.mnemonic.lower()
74
+
75
+ if mnem in ['j', 'c.j', 'jal', 'c.jal']:
76
+ return "TRAMPOLINE", "Jump-Based" # Salta sopra ostacoli
77
+ elif mnem.startswith('b') or mnem.startswith('c.b'):
78
+ return "CONDITIONAL", "Jump-Based" # Logica if/else
79
+ else:
80
+ return "FALLTHROUGH", "Jump-Based" # Discontinuità di memoria
81
+
82
+ def print_gadgets(self, limit, min_score, verbose=False):
83
+ categories = {'Sequential': [], 'Jump-Based': []}
84
+
85
+ for g in self.gadgets:
86
+ s = self.score_gadget(g)
87
+ if s < min_score: continue
88
+
89
+ tag, cat = self._classify_gadget(g)
90
+ categories[cat].append((s, g, tag))
91
+
92
+ for cat_name in ['Sequential', 'Jump-Based']:
93
+ gadgets = categories[cat_name]
94
+ gadgets.sort(key=lambda x: x[0], reverse=True)
95
+
96
+ print(f"\033[33m\n{'='*60}\033[0m")
97
+ print(f"\033[33m--- TOP {limit} {cat_name.upper()} GADGETS ---\033[0m")
98
+ print(f"\033[33m{'='*60}\033[0m")
99
+
100
+ for i, (s, p, tag) in enumerate(gadgets[:limit]):
101
+ if verbose:
102
+ print(f"\nRANK #{i+1} | SCORE: {s} | TYPE: {tag}")
103
+ for addr in p:
104
+ node = self.gm.addr_to_node[addr]
105
+ for insn in node['insns']:
106
+ print(f" \033[33m{hex(insn.address)}\033[0m: {insn.mnemonic} {insn.op_str}")
107
+ else:
108
+ full_gadget_str = []
109
+ for addr in p:
110
+ node = self.gm.addr_to_node[addr]
111
+ for insn in node['insns']:
112
+ full_gadget_str.append(f"{insn.mnemonic} {insn.op_str}")
113
+
114
+ start_addr = hex(p[0])
115
+ print(f"\033[33m{start_addr}\033[0m: {'; '.join(full_gadget_str)}")
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ requirements.txt
5
+ setup.py
6
+ lcsajdump/__init__.py
7
+ lcsajdump/cli.py
8
+ lcsajdump/core/__init__.py
9
+ lcsajdump/core/graph.py
10
+ lcsajdump/core/loader.py
11
+ lcsajdump/core/rainbowBFS.py
@@ -0,0 +1,4 @@
1
+ capstone>=5.0.0
2
+ pyelftools>=0.29
3
+ networkx>=3.0
4
+ click>=8.0
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,45 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ with open("README.md", "r", encoding="utf-8") as fh:
4
+ long_description = fh.read()
5
+
6
+ setup(
7
+ name="lcsajdump",
8
+ version="1.0.0",
9
+ author="Chris1sFlaggin",
10
+ author_email="lcsajdump@chris1sflaggin.it",
11
+ description="A Graph-Based ROP Gadget Finder for RISC-V architectures",
12
+ long_description=long_description,
13
+ long_description_content_type="text/markdown",
14
+ url="https://chris1sflaggin.it/LCSAJdump/",
15
+
16
+ packages=find_packages(exclude=[
17
+ "testCTFs*",
18
+ "unitTest*",
19
+ "_images*",
20
+ "build*",
21
+ "dist*",
22
+ "venv*",
23
+ "lcsajdump.venv*"
24
+ ]),
25
+
26
+ classifiers=[
27
+ "Programming Language :: Python :: 3",
28
+ "License :: OSI Approved :: MIT License",
29
+ "Operating System :: OS Independent",
30
+ "Topic :: Security",
31
+ "Environment :: Console",
32
+ ],
33
+ python_requires='>=3.6',
34
+ install_requires=[
35
+ "capstone",
36
+ "pyelftools",
37
+ "networkx",
38
+ "click",
39
+ ],
40
+ entry_points={
41
+ 'console_scripts': [
42
+ 'lcsajdump=lcsajdump.cli:main',
43
+ ],
44
+ },
45
+ )