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
Holds ROP chains returned by chain building methods such as rop.set_regs().
Constructor
RopChain(project, builder, state=None, badbytes=None)
The angr project instance.
The ChainBuilder instance that created this chain.
Optional symbolic state to use. If None, a blank symbolic state is created.
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
Length of the ROP chain payload in bytes.
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
Adds a value to the chain’s stack.
Value to add to the chain.
add_gadget
Adds a gadget to the chain.
set_gadgets
Sets the complete list of gadgets for the chain.
add_constraint
Adds a symbolic constraint to the chain. Useful when the chain contains symbolic values.
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 address of the binary. Defaults to the main object’s mapped base.
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.
Whether to include gadget instructions as comments.
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
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.
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
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
Pretty-prints the chain using dstr(). Outputs to stdout.
Example:
chain = rop.set_regs(rax=0x1234)
chain.pp()
__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 for execution in seconds.
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.
Address to execute until.
Returns: The state at the target address.
Utility Methods
copy
Creates a deep copy of the chain.
Returns: A new RopChain instance with copied gadgets and values.
set_timeout
Sets the timeout for this chain instance.
set_cls_timeout (class method)
RopChain.set_cls_timeout(timeout)
Sets the default timeout for all new RopChain instances.
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.
Returns: Symbol name (with @plt suffix if PLT stub) or None.
set_project
Updates the project reference for the chain and all its gadgets.
set_builder
Updates the chain builder reference.
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}")