Skip to main content
The RopChain class represents a complete ROP exploit chain. It holds gadgets, stack values, constraints, and provides methods for chain composition, execution, and payload generation.

Class Definition

class RopChain
Holds ROP chains returned by chain building methods such as rop.set_regs().

Constructor

RopChain(project, builder, state=None, badbytes=None)
project
angr.Project
required
The angr project instance.
builder
ChainBuilder
required
The ChainBuilder instance that created this chain.
state
angr.SimState | None
Optional symbolic state to use. If None, a blank symbolic state is created.
badbytes
list[int] | None
List of bad bytes to avoid. Defaults to empty list.
You typically don’t instantiate RopChain directly. Chain building methods like rop.set_regs() return RopChain instances.

Attributes

payload_len
int
Length of the ROP chain payload in bytes.
badbytes
list[int]
List of bytes to avoid in the payload.

Chain Composition

Addition Operator

chain1 + chain2 -> RopChain
Combines two ROP chains into a single chain. The second chain is appended after the first. Example:
chain1 = rop.set_regs(rax=0x1234)
chain2 = rop.set_regs(rbx=0x5678)
full_chain = chain1 + chain2
Returns: A new RopChain combining both chains.
Chains with conflicting symbolic constraints cannot be combined. An exception is raised if constraints are unsatisfiable.

Value and Gadget Management

add_value

add_value(value)
Adds a value to the chain’s stack.
value
int | RopValue
required
Value to add to the chain.

add_gadget

add_gadget(gadget)
Adds a gadget to the chain.
gadget
RopGadget
required
The gadget to add.

set_gadgets

set_gadgets(gadgets)
Sets the complete list of gadgets for the chain.
gadgets
list[RopGadget]
required
List of gadgets.

add_constraint

add_constraint(cons)
Adds a symbolic constraint to the chain. Useful when the chain contains symbolic values.
cons
claripy.ast.Bool
required
Constraint to add.

Payload Generation

payload_str

payload_str(constraints=None, base_addr=None, timeout=None) -> bytes
Generates the concrete byte string payload for the ROP chain.
constraints
list | claripy.ast.Bool | None
Additional constraints to apply when concretizing symbolic values.
base_addr
int | None
Base address of the binary. Defaults to the main object’s mapped base.
timeout
int | None
Timeout in seconds for solving constraints.
Returns: Raw bytes of the ROP payload. Example:
chain = rop.set_regs(rax=0x1234)
payload = chain.payload_str()
with open('payload.bin', 'wb') as f:
    f.write(payload)

payload_code

payload_code(constraints=None, print_instructions=True, timeout=None) -> str
Generates Python code that constructs the ROP payload.
constraints
list | claripy.ast.Bool | None
Additional constraints for concretization.
print_instructions
bool
default:"True"
Whether to include gadget instructions as comments.
timeout
int | None
Timeout in seconds.
Returns: Python code string using p32()/p64() functions. Example:
chain = rop.set_regs(rax=0x1234, rbx=0x5678)
print(chain.payload_code())
Output:
chain = b""
chain += p64(0x400123)  # pop rax; ret
chain += p64(0x1234)
chain += p64(0x400456)  # pop rbx; ret
chain += p64(0x5678)
print_payload_code(constraints=None, print_instructions=True)
Prints the Python code for the payload to stdout.
constraints
list | claripy.ast.Bool | None
Additional constraints.
print_instructions
bool
default:"True"
Whether to include instruction comments.

payload_bv

payload_bv() -> claripy.ast.BV
Generates a symbolic bitvector representation of the payload. Returns: Claripy bitvector of the entire payload.

Display Methods

dstr

dstr() -> str
Generates a detailed string representation of the chain showing gadgets and values. Returns: Human-readable string representation. Example Output:
0x400123: pop rax; ret
          0x1234
0x400456: pop rbx; ret
          0x5678

pp

pp()
Pretty-prints the chain using dstr(). Outputs to stdout. Example:
chain = rop.set_regs(rax=0x1234)
chain.pp()

__str__

__str__() -> str
String representation returns the payload code. Returns: Same as payload_code().

Execution Methods

exec

exec(timeout=None, stop_at_pivot=False) -> angr.SimState
Symbolically executes the ROP chain and returns the final state.
timeout
int | None
Timeout for execution in seconds.
stop_at_pivot
bool
default:"False"
Whether to stop execution at a stack pivot.
Returns: The final angr SimState after executing the chain. Example:
chain = rop.set_regs(rax=0x1234, rbx=0x5678)
final_state = chain.exec()
print(f"RAX = {final_state.regs.rax}")

sim_exec_til_syscall

sim_exec_til_syscall() -> angr.SimState
Symbolically executes the chain until a syscall is encountered. Returns: The state at the syscall.

concrete_exec_til_addr

concrete_exec_til_addr(target_addr) -> angr.SimState
Concretely executes the chain until reaching a specific address.
target_addr
int
required
Address to execute until.
Returns: The state at the target address.

Utility Methods

copy

copy() -> RopChain
Creates a deep copy of the chain. Returns: A new RopChain instance with copied gadgets and values.

set_timeout

set_timeout(timeout)
Sets the timeout for this chain instance.
timeout
int
required
Timeout in seconds.

set_cls_timeout (class method)

RopChain.set_cls_timeout(timeout)
Sets the default timeout for all new RopChain instances.
timeout
int
required
Default timeout in seconds.

next_pc_idx

next_pc_idx() -> int | None
Finds the index of the next PC value in the chain. Some gadgets (like pop pc, r1) have the PC not as the last value. Returns: Index of the next PC symbolic value, or None if the chain doesn’t return.

find_symbol

find_symbol(addr) -> str | None
Finds the symbol name for an address.
addr
int
required
Address to look up.
Returns: Symbol name (with @plt suffix if PLT stub) or None.

set_project

set_project(project)
Updates the project reference for the chain and all its gadgets.
project
angr.Project
required
New project instance.

set_builder

set_builder(builder)
Updates the chain builder reference.
builder
ChainBuilder
required
New builder instance.

Complete Example

import angr

# Load binary and find gadgets
project = angr.Project('/bin/ls')
rop = project.analyses.ROP()
rop.find_gadgets()
rop.set_badbytes([0x00, 0x0a])

# Build individual chains
chain1 = rop.set_regs(rax=0x3b)  # execve syscall number
chain2 = rop.write_to_mem(0x8048000, b'/bin/sh\x00')
chain3 = rop.set_regs(rdi=0x8048000, rsi=0, rdx=0)
chain4 = rop.do_syscall(0x3b, [0x8048000, 0, 0])

# Combine into full exploit chain
exploit = chain1 + chain2 + chain3 + chain4

# Generate payload
payload = exploit.payload_str()
print(f"Payload size: {len(payload)} bytes")

# Display the chain
exploit.pp()

# Generate Python code
exploit.print_payload_code()

# Test execution symbolically
final_state = exploit.exec()
print(f"Final state: {final_state}")

Build docs developers (and LLMs) love