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

Find gadgets:

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 to file:

ropinator -f binary.elf -o gadgets.txt

Load previously exported gadgets:

ropinator -f binary.elf -g gadgets.txt --start-solver

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

ropinator --arch x86_64 -g gadgets.txt --start-solver

Override architecture detection:

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

Expand all gadget addresses:

ropinator -f binary.elf -a

Constraint Solver

Launch the interactive solver to search gadgets by semantic behavior:

ropinator -f binary.elf --start-solver

Commands

Command Description
pivot [src] [--max-offset N] [--max N] Find stack-pivot gadgets
move [dst] [src] Find register-to-register moves
const <dst> <value> Find gadgets that load a constant
load <dst> <src> [offset] Find memory read gadgets
store <addr_reg> [src] [offset] Find write-what-where gadgets (mov [addr+off], src)
setreg [dst] Find controllable setters (pop reg ; ret)
arith <dst> add|sub <src1> [src2] Find arithmetic gadgets
search <pattern> [--regex] Raw instruction-text search (all architectures)
branch [syscall|call|jmp] Find control-transfer gadgets (fire the chain)
setregs reg=val ... Bundle: all gadgets needed to set several registers
plan_call [--abi A] [--target T] arg... Bundle: gadgets to call a function/syscall with args
show <index> [--all] Inspect symbolic register state
export <file> Export results to file
registers List available registers

search and branch are structural (no symbolic execution) and work on every supported architecture. The semantic commands (move, const, load, store, setreg, arith, pivot) require the constraint solver (x86-64, x86, ARM64).

Examples

Stack pivots

rop> pivot rcx
Found 3 pivot gadget(s) (rsp <- rcx):

  [0] 0x0000000000401000  rsp <- rcx + 0x8   mov rsp, rcx ; ret            [clobbers: none]
  [1] 0x0000000000401010  rsp <- rcx + 0x8   xchg rsp, rcx ; ret           [clobbers: rcx]
  [2] 0x0000000000401020  rsp <- rcx + 0x18  lea rsp, [rcx + 0x10] ; ret   [clobbers: none]

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].

Search all registers for any pivot:

rop> pivot

Limit to pivots that land within 0x10 bytes of the source:

rop> pivot rcx --max-offset 0x10

Memory pivots (mov rsp, [rax+0x10]) are found with the load command:

rop> load rsp rax 0x10

Register moves

rop> move rax rbx
Found 3 move gadget(s):

  [0] 0x0000000000401000: rax <- rbx | mov rax, rbx ; ret
  [1] 0x0000000000401020: rax <- rbx | push rbx ; pop rax ; ret
  [2] 0x0000000000401040: rax <- rbx | xchg rax, rbx ; xchg rax, rbx ; mov rax, rbx ; ret

Constant loads

rop> const rax 0xdeadbeef
Found 1 constant-loading gadget(s):

  [0] 0x0000000000401234: rax = 0xdeadbeef | pop rax ; ret

Memory reads

rop> load rax rbx 0x10
Found 2 load gadget(s):

  [0] 0x0000000000402000: rax <- [rbx + 0x10] | mov rax, qword ptr [rbx + 0x10] ; ret
  [1] 0x0000000000402030: rax <- [rbx + 0x10] | lea rcx, [rbx + 0x10] ; mov rax, qword ptr [rcx] ; ret

Inspecting results

show prints only the registers changed by the gadget. Add --all to see the full register file:

rop> show 0
Result [0]
  Address:      0x0000000000401000
  Instructions: mov rsp, rcx ; ret
  Effect:       rsp <- rcx + 0x8

  Changed registers:
    rsp    = rcx + 0x8

  (15 registers unchanged — use 'show 0 --all' to see them)

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

-f, --file FILE           Binary to analyze (required unless --arch and -g are used)
-b, --base ADDR           Override base address
-d, --depth N             Max gadget depth (default: 3)
-a, --all                 Expand all gadget addresses
-o, --output FILE         Export gadgets to file
-g, --gadgets-file FILE   Load gadgets from exported file instead of searching
--arch ARCH               Override architecture detection (see below)
--start-solver            Launch constraint solver shell

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
  • cmd2 - interactive shell 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.2.0.tar.gz (55.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.2.0-py3-none-any.whl (68.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ropinator-0.2.0.tar.gz
  • Upload date:
  • Size: 55.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.2.0.tar.gz
Algorithm Hash digest
SHA256 fb3ad86eb108d28eeed6bf68534abd1988f82db72c1f861aa87b477994274c59
MD5 329bdbc45bd88c7fdaba896db78a0ba7
BLAKE2b-256 92f8a8ab6f655b47fcdc7a1fd8955b596c7b1a769a94ad2b0fe6bb9dea3b8dd1

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ropinator-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 68.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.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 294f6a2ccdf1202b1ab85cf1f7c76a4821357c9e5e323789afbe9a0b6497d768
MD5 ebe8b6455a6a521f6acbd11ee8041b64
BLAKE2b-256 de4047440e3cb29e6f76909763d35a23c7e17bf2e31b881e128f8a75b43f5da0

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

0.3.0

2 files

This release

0.2.0 This release

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