Skip to main content

ropinator

ROP gadget finder with constraint-based semantic search.

Finds gadgets in ELF, PE, Mach-O, and raw binaries across x86, ARM, MIPS, PowerPC, and RISC-V. Includes a Z3-backed symbolic execution engine for searching gadgets by behavior rather than text patterns.

Install

pip install ropinator

Requires Python 3.13+.

Usage

Running ropinator with no arguments launches the interactive TUI, where you load binaries and search for gadgets — no flags required:

ropinator

Optionally preload a binary on startup:

ropinator -f binary.elf

Set search depth (max instructions per gadget, default 3):

ropinator -f binary.elf -d 5

Custom base address:

ropinator -f binary.elf -b 0x400000

Export gadgets to a file non-interactively (find, write, exit — the only batch mode):

ropinator -f binary.elf -o gadgets.txt

Preload previously exported gadgets into the TUI:

ropinator -f binary.elf -g gadgets.txt

Load gadgets without the original binary (requires --arch):

ropinator --arch x86_64 -g gadgets.txt

Override architecture detection:

ropinator -f binary.raw --arch arm -b 0x10000

Expand all gadget addresses:

ropinator -f binary.elf -a

Interactive TUI

Launch the full-screen TUI and do everything from there — load a binary, search by behavior, inspect, and export. No commands to memorize: you pick a search from a sidebar, fill in a small form, and read the results in a table.

ropinator

With no binary loaded you land on a load screen: enter a file path, optionally pick an architecture (defaults to auto-detect), depth, and base, then load. As you type a path, a dropdown lists the matching files and folders (native Windows paths included) — arrow keys or click to choose, and selecting a folder descends into it. A second tab loads a previously exported gadgets file. (ropinator -f binary.elf preloads and drops you straight into the workspace.)

The workspace has four parts:

  • a sidebar of searches, grouped Structural / Semantic / Plan (semantic and plan searches are greyed out on architectures without a solver),
  • a form that changes to match the selected search — register fields autocomplete from the loaded architecture,
  • a results table (address · effect · instructions · notes), and
  • a detail panel showing the full symbolic register state of the highlighted result.
Key Action
↑/↓ or click Pick a search in the sidebar
Enter / Run search Run the current search
↑/↓ in the table Highlight a result → its register state fills the detail panel
↑/↓, Enter/Tab, click (path fields) Choose from the file dropdown; picking a folder descends into it
a Toggle showing unchanged registers in the detail panel
F2 Command palette — jump straight to any search or action
F3 Load another binary
F4 Re-scan the current binary at a new depth (deeper = more, longer gadgets)
F6 Export the current results to a file
F7 Show the architecture's registers
Ctrl-C Quit

The hotkeys are function keys (plus Ctrl-C) chosen so nothing collides with VS Code's default shortcuts when you run ropinator in its integrated terminal — and because function keys reach the app even while a text field is focused.

While a search or a re-scan is running, a status box keeps you informed. Re-scan (F4) re-runs gadget finding on the loaded binary with a new depth, so you can start shallow (fast) and go deeper when you need longer gadgets.

Searches

Search Fields Finds
Text search pattern, regex Raw instruction-text matches
Control transfer kind (syscall/call/jmp/any) Gadgets that fire the chain
Set constant dst, value dst = value
Pop / controllable set dst Controllable setters (pop reg ; ret)
Move register dst, src dst = src
Load from memory dst, addr reg/literal, offset dst = [src + offset]
Store to memory addr reg, src, offset Write-what-where (mov [addr+off], src)
Arithmetic dst, op (add/sub), src1, src2 dst = src1 op src2
Stack pivot src, max offset rsp = src + constant
Plan register goals goals (rdi=0x404000 rsi=0) Every gadget needed to set a group of registers
Plan a call abi, target, args Argument-register setters + a control transfer

Text search and Control transfer are structural (no symbolic execution) and work on every supported architecture. The semantic and plan searches require the constraint solver (x86-64, x86, ARM64).

The two Plan searches don't return a result table — they render a requirements bundle: for each register, the direct constant setters, the controllable (pop) setters, and one-level move fallbacks, plus the control transfer for a call. Nothing is ordered or emitted — it's the raw material for building a chain.

Stack-pivot offsets

For pivots, the offset is the signed difference rsp_final = src + offset. For a clean x64 pivot (mov rsp, rcx ; ret) the offset is +0x8 because ret consumes one return address from the newly-pivoted stack — place your fake ROP stack starting at [rcx]. Memory pivots (mov rsp, [rax+0x10]) show up under Load from memory with dst = rsp.

MCP Server

Ropinator ships an MCP server so AI agents (Claude, Cursor, etc.) can search gadgets programmatically without a human at the shell.

Setup

Add to your MCP client config (e.g. Claude Code's .claude/settings.json):

{
  "mcpServers": {
    "ropinator": {
      "command": "ropinator-mcp"
    }
  }
}

Or if running from the repo with uv:

{
  "mcpServers": {
    "ropinator": {
      "command": "uv",
      "args": ["run", "--project", "/path/to/ropinator", "ropinator-mcp"]
    }
  }
}

Tools

Search tools return JSON so agents can parse results directly. Each result has address, instructions, type, effect, and (where relevant) clobbers or control kind/target fields.

Tool Description
load_binary Load a binary and scan for gadgets
load_gadgets_file Load gadgets from a previously exported file
search_gadgets Raw instruction-text search — the generic finder (all arches)
find_pivots Find stack-pivot gadgets (src_reg, max_offset)
find_moves Find register-to-register move gadgets
find_loads Find memory-read gadgets (also covers memory pivots)
find_const Find constant-loading gadgets
find_stores Find write-what-where gadgets (mov [addr+off], src)
find_setreg Find controllable setters (pop reg ; ret)
find_arith Find arithmetic gadgets (add/sub)
find_control Find control-transfer gadgets (syscall / call reg / jmp reg)
plan_registers Bundle: all gadgets needed to set several registers to values
plan_call Bundle: all gadgets needed to call a function/syscall with args
show_result Full register state for a result index (JSON)
get_registers List GP registers for the loaded architecture
session_status Summary of the loaded binary and cached results

Workflow

The server is stateful: call load_binary once, then run as many searches as needed. Results from the most recent search are cached so show_result(index) always works after any find_*/search_gadgets call.

load_binary(file_path="target.exe")
find_pivots(src_reg="rcx", max_offset="0x40")
show_result(0)
find_moves(dst_reg="rdi", src_reg="rax")

Getting all gadgets for a chain

plan_registers and plan_call return a requirements bundle: every gadget an agent needs to reach a goal, annotated with clobbers. The bundle gathers candidates but does not order them or emit a payload — the agent composes the chain from the returned options.

# Set up a Linux execve/mprotect-style syscall (SysV ABI: rdi, rsi, rdx, ...)
plan_call(args="0x404000 0 7", abi="sysv64", target="syscall")

# Or drive individual register goals directly:
plan_registers(goals="rdi=0x404000 rsi=0 rdx=7")

Each register entry lists controllable (pop-style — supply the value on the fake stack), direct (constant setters), and a one-level via_move fallback, plus a control section with syscall/call/jmp gadgets to fire the chain.

Supported Formats

Format Description
ELF Linux, BSD, embedded
PE Windows executables and DLLs
Mach-O macOS, iOS
Raw Flat binaries (use with -b to set base address)

Supported Architectures

Gadget finding: x86 (16/32/64-bit), ARM (32/64/Thumb), MIPS (32/64), PowerPC (32/64), RISC-V (32/64).

Constraint solver: x86-64. Other architectures planned.

Options

All options are optional. With none, ropinator launches the TUI; the flags below just preload a binary/gadgets (or, with -o, run a one-shot export).

-f, --file FILE           Binary to preload into the TUI
-b, --base ADDR           Override base address
-d, --depth N             Max gadget depth (default: 3)
-a, --all                 Expand all gadget addresses (in the -o export)
-o, --output FILE         Non-interactive: find gadgets, export to file, and exit
-g, --gadgets-file FILE   Preload gadgets from an exported file
--arch ARCH               Override architecture detection (see below)

Architecture names for --arch:

Name Aliases
x86_64 x86-64, x64
x86 i386
ARM64 aarch64
ARM32 arm
ThumbBE thumb-be
MIPS32 mips
MIPS64
PowerPC32 ppc, ppc32
PowerPC64 ppc64
RISCV64 riscv

Dependencies

Installed automatically via pip:

  • Capstone - disassembly engine
  • Keystone - assembler engine (for gadget file loading)
  • z3-solver - symbolic execution backend
  • Textual - interactive TUI framework

License

GPL-3.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ropinator-0.3.0.tar.gz (65.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ropinator-0.3.0-py3-none-any.whl (80.1 kB view details)

Uploaded Python 3

File details

Details for the file ropinator-0.3.0.tar.gz.

File metadata

  • Download URL: ropinator-0.3.0.tar.gz
  • Upload date:
  • Size: 65.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ropinator-0.3.0.tar.gz
Algorithm Hash digest
SHA256 d9e7a737617c713112b2afe68bd1a8751505025e1a9eeb5df4ff537a71d0be70
MD5 27921428e60bd6fa9315feadcfff28fb
BLAKE2b-256 6ae8e9ae99f319d65ef575804c24d324f66693ad06f2c8309e653fe0e670978f

See more details on using hashes here.

File details

Details for the file ropinator-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: ropinator-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 80.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for ropinator-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2f0ba138831400461bf24111836320d092fd1e8ca2827db5c3c2b5a8ebc6b84b
MD5 873595108b7587e731a93dd1b95a5981
BLAKE2b-256 c7842780ff0ab26a8df0504d8a83dd872a08269f9c52b708ff2d6da3d1c92995

See more details on using hashes here.

Release history Release notifications | RSS feed

0.6.0

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page