Library / SDK
JonathanSalwan/ROPgadget avatar
JonathanSalwan/ROPgadget

ROPgadget: Finding ROP Gadgets in ELF, PE and Mach-O Binaries

This tool lets you search your gadgets on your binaries to facilitate your ROP exploitation. ROPgadget supports ELF, PE and Mach-O format on x86, x64, ARM, ARM64, PowerPC, SPARC, MIPS, RISC-V 64, and RISC-V Compressed architectures.

4,484 stars579 forksPythonNOASSERTION

At a glance

What is it?
ROPgadget scans executables for the short instruction sequences that return-oriented programming chains are built from. It covers nine architectures and four container formats, and it ships a chain generator that only works on a subset of them.
Who is it for?
ROPgadget fits exploit developers and CTF players who need to enumerate gadgets in a local binary across an unusual architecture, and it is the practical choice when the target is MIPS or SPARC, where the dedicated --mipsrop finder has no equivalent in most other tools. Do not adopt it expecting a portable chain builder: --ropchain is documented for x86 and x86-64 only, and the README's own contribution list still asks for system gadgets on PPC, SPARC and ARM64.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 99 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What ROPgadget searches for, and who needs it

Return-oriented programming builds an exploit out of code that is already in the target binary. Instead of writing new instructions, you jump to short sequences that end in a return or an indirect branch, and you chain them by controlling the stack. The hard part is finding those sequences. ROPgadget automates that search: the README describes it as a tool that "lets you search your gadgets on your binaries to facilitate your ROP exploitation."

The audience is narrow and technical. Exploit developers, CTF players and reverse engineers working on memory-corruption bugs are the people who run it. If you are auditing a web application or reviewing source code, this tool has nothing for you. It reads compiled binaries, not source, and its output is a list of instruction addresses and byte sequences that only mean something once you already know which register or stack slot you control.

What makes the tool worth a look rather than a one-off script is coverage. The README lists ELF, PE, Mach-O and raw formats, and x86, x86-64, ARM, ARM64, MIPS, PowerPC, Sparc, RISC-V 64 and RISC-V Compressed architectures. That breadth is the reason it survives next to newer gadget finders. A firmware image for a MIPS router and a Mach-O binary for macOS go through the same command.

How the search engine works: Capstone, depth and the gadget categories

ROPgadget does not pattern-match instruction bytes against a table. It disassembles the executable segments with Capstone and then walks backwards from every terminating instruction it recognises. The README states plainly that the tool "uses the Capstone disassembler for the search engine," and that dependency is the reason installation has two paths.

The --depth flag controls how far back the engine looks from a terminator. The default is 10 bytes, per the usage text. Raising it produces longer gadgets and a larger result set; lowering it to 3 or 5, as several README examples do, keeps the output to short sequences that are easier to place in a chain. This is the single parameter that changes results most, and it is worth understanding before you trust a gadget list.

The engine separates gadgets into categories that can be toggled independently: ROP, JOP and SYS. --norop and --nojop disable the first two, and --nosys disables system-call gadgets. There is also --multibr for multiple-branch gadgets and --callPreceded to keep only gadgets that are preceded by a call instruction. The contribution section of the README notes that system gadgets exist for some architectures but not all, and asks for help adding them for PPC, Sparc and ARM64. That is a direct statement that the SYS category is uneven across targets.

Deduplication is on by default and --all turns it off. If two addresses hold the same instruction sequence, the default output shows one. That keeps the list readable but hides the alternative addresses, which matter when a bad byte rules one of them out.

Installing ROPgadget from PyPI and running a first search

The README gives PyPI as the easiest route. The commands below are copied from it, including the sudo -H form, which matters on distributions where pip otherwise writes into a user directory that is not on the executable path.

bash
sudo apt install python3-pip
sudo -H python3 -m pip install ROPgadget
ROPgadget --help

After that, ROPgadget is on your PATH and --help prints the full option list shown in the README. The alternative is installing from source, which requires Capstone first:

bash
sudo apt install python3-pip
sudo -H python3 -m pip install capstone
python3 ROPgadget.py --help

The repository also ships setup.py, so `sudo -H python3 setup.py install` installs the package into site-packages, after which the ROPgadget command works from PATH. The version in setup.py is 7.7, matching the v7.7 release.

For a first real run, point it at one of the binaries in test-suite-binaries/ and limit the depth so the output stays short:

bash
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --depth 3

You should see a table of gadget addresses, the raw bytes, and the disassembled instructions. If you want only sequences that move data into a register and return, the README's --only example narrows the list:

bash
ROPgadget.py --binary ./test-suite-binaries/elf-Linux-x86 --only "mov|pop|xor|ret"

For a raw blob with no container headers, you must supply the architecture, mode and endianness yourself, since nothing in the file declares them:

bash
ROPgadget.py --binary ./test-suite-binaries/raw-x86.raw --rawArch=x86 --rawMode=32

The README does not document a rollback or uninstall procedure for any of these install paths.

Where ROPgadget stops: chain generation, bad bytes and missing SYS gadgets

The most overestimated flag is --ropchain. It is documented as enabling ROP chain generation, and the README's example runs it against the x86 test binary. Nothing in the README says it emits working chains for ARM, ARM64, MIPS, PowerPC, Sparc or RISC-V. Treat it as an x86 and x86-64 convenience, not a cross-architecture exploit builder. On other targets you are reading the gadget list and assembling the chain yourself.

The README's contribution list is effectively a list of gaps. It asks for system gadgets for PPC, Sparc and ARM64, for RISC-V 32-bit support, for handling bad bytes in data during ROP chain generation, and for big-endian handling in Mach-O like the ELF class already has. Each of those is a real limitation acknowledged by the project rather than discovered by a user.

Bad bytes are a good example of the friction. --badbytes lets you reject gadgets whose addresses contain particular bytes, and the README example uses a compound pattern: `--badbytes "00|01-1f|7f|42"`. That filters by address, which is what a string-copy overflow usually needs. But the contribution note about bad bytes in data during chain generation says the chain generator does not apply the same discipline to the values it writes. Filtering the gadget list and generating a valid chain are two different problems, and the tool solves the first more completely than the second.

There is also an operational cost the README does not address. A full search on a large binary at the default depth produces a long list, and --silent only suppresses printing during analysis rather than trimming the result. --range and --offset exist to scope the search, and using them is usually faster than filtering the output afterwards.

ROPgadget compared with Ropper and with architecture-specific finders

Ropper is the alternative most people encounter, and the RELATED SEARCHES data shows it surfacing next to ROPgadget repeatedly. The difference is in approach rather than in the gadget list. ROPgadget is a search and inspection tool with a chain generator bolted onto the x86 path. Ropper is built around the chain as the primary artifact, with an interactive mode and a file-type and architecture table in its own documentation. If your workflow is "give me a chain for this binary," Ropper's framing fits better. If your workflow is "show me every gadget matching this pattern across these architectures, and let me read the disassembly," ROPgadget's flag set is more direct.

For MIPS specifically, ROPgadget carries something the general tools do not. The --mipsrop flag takes a gadget type: stackfinder, system, tails, lia0 or registers. That is a curated finder for a known-hard architecture, where the useful gadgets are not simply the ones ending in a return. Nothing in the README suggests an equivalent curated finder for ARM or RISC-V.

The other boundary is that ROPgadget is a static tool. It reads a file. It does not run the target, does not resolve addresses at runtime under ASLR, and does not know about a specific libc build unless you point it at that file. Tools built around a debugger or a runtime process answer a different question, and for a live target you need one of those.

Licence, releases and what an upgrade actually costs

The repository root contains LICENSE_BSD.txt, and setup.py declares `license = "BSD"`. The README points at LICENSE_BSD.txt and at the license header on each source file rather than restating terms. The repository metadata reports the licence as NOASSERTION, which means an automated classifier could not match the file to a known SPDX identifier. If you are redistributing ROPgadget or bundling it into a product, read LICENSE_BSD.txt and the per-file headers directly instead of trusting the metadata field. This is a description of the files, not legal advice.

On maintenance, the last push was on 2026-06-24, and the most recent release is v7.7 from 2025-10-15, following v7.6 in January 2025 and v7.5 in September 2024. The cadence is roughly one release a year, with commits in between. That is a mature project moving slowly, not an abandoned one, and the version in setup.py tracks the release tag.

Upgrade cost is low and mostly invisible. The tool is a Python package with a single external dependency, Capstone, and the README's install instructions pin nothing. That means a pip upgrade can pull a newer Capstone than the one your results were produced with, and disassembly output can shift between Capstone versions. If you keep gadget lists as reference artifacts, record the ROPgadget and Capstone versions alongside them. The README does not describe a compatibility policy between ROPgadget releases and Capstone releases.

Editorial conclusion

ROPgadget fits exploit developers and CTF players who need to enumerate gadgets in a local binary across an unusual architecture, and it is the practical choice when the target is MIPS or SPARC, where the dedicated --mipsrop finder has no equivalent in most other tools. Do not adopt it expecting a portable chain builder: --ropchain is documented for x86 and x86-64 only, and the README's own contribution list still asks for system gadgets on PPC, SPARC and ARM64. Before relying on it, install it in a virtual environment, run it against a binary from test-suite-binaries/, and confirm that the gadget count you get back is stable when you re-run with --depth 10, the documented default.

Frequently asked questions

How do I install ROPgadget?

The README gives PyPI as the easiest route: install python3-pip, then run sudo -H python3 -m pip install ROPgadget, then check it with ROPgadget --help. Installing from source requires Capstone first, after which you can run python3 ROPgadget.py --help or install with setup.py.

What is a ROP gadget?

A gadget is a short instruction sequence ending in a return or branch that an exploit can chain by controlling the stack. ROPgadget searches a binary's executable segments with the Capstone disassembler and prints the gadgets it finds, with addresses, bytes and disassembly.

What is return-oriented programming (ROP)?

Return-oriented programming builds an exploit from code already present in the target binary rather than from injected instructions. ROPgadget exists to make that practical by listing the gadgets available in a given binary.

Official sources

  1. Issues
  2. JonathanSalwan/ROPgadget on GitHub
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jonathansalwan-ropgadget.svg)](https://hysenlabs.com/projects/jonathansalwan-ropgadget)