Skip to main content
The RegSetter class is responsible for building ROP chains that set registers to specific values. It uses graph search algorithms and optimization techniques to find the most efficient gadget combinations.

Overview

Accessed through the ROP instance as rop.set_regs(), RegSetter automatically:
  • Finds optimal gadgets to set registers
  • Handles badbytes in register values
  • Uses register moves when direct pops aren’t available
  • Constructs values using arithmetic when needed

Class Definition

Located in angrop/chain_builder/reg_setter.py

Public Methods

run

Builds a ROP chain that sets the specified registers.
tuple | None
default:"None"
Range of memory addresses that can be modified (start, end). Used for gadgets that require memory access.
set | None
default:"None"
Set of register names that must not be modified during chain generation.
bool
default:"True"
Whether to log warnings if register setting fails.
Keyword arguments mapping register names to values (int, RopValue, or symbolic).
Returns: A RopChain that sets all specified registers. Raises: RopException if registers cannot be set.

can_set_reg

Checks if a register can be set to arbitrary values.
str
required
Register name to check.
Returns: True if the register can be set, False otherwise.

verify

Verifies that a chain correctly sets registers without clobbering preserved ones.
RopChain
required
The chain to verify.
set
required
Registers that should not be modified.
dict
required
Target register values.
Returns: True if verification passes, False otherwise.

ROP Instance Method

When you call rop.set_regs(), it invokes RegSetter.run() internally:

Implementation Details

Graph Search Algorithm

RegSetter uses a sophisticated graph-based approach:
  1. Node representation: Each node represents a state where certain registers are correctly set
  2. Edge creation: Edges represent gadgets that can transition between states
  3. Path finding: Uses NetworkX to find shortest paths from initial state to target state
From source code (reg_setter.py:474-612):

Handling Hard Registers

Registers that can’t be directly popped are handled specially:
  1. Badbytes in values: Uses arithmetic gadgets to construct the value
  2. No pop gadgets: Uses concrete value gadgets or register moves
  3. Arithmetic chains: Combines setter + changer gadgets
From source code (reg_setter.py:699-725):

Optimization Strategies

RegSetter includes two optimization passes:

1. Register Move Optimization

Finds opportunities to set hard registers by moving from settable ones. Example: If r15 can’t be popped but rax can:

2. Gadget Normalization

Normalizes complex gadgets to enable new register setting capabilities.

Usage Examples

Basic Register Setting

Output:

Setting Multiple Registers

Preserving Register Values

Setting Registers with Badbytes

Kernel Mode Example

From angrop’s kernel test suite:

Symbolic Register Values

Internal Components

RegSetter uses several helper builders:

ConcreteRegSetter

Finds gadgets that set registers to specific concrete values. Example gadgets:

ConcreteRegChanger

Finds gadgets that modify register values using arithmetic. Example gadgets:

Error Handling

Common Errors

”Couldn’t set registers :(”

Raised when no valid gadget chain can be found. Solutions:
  1. Run find_gadgets(optimize=True)
  2. Try using move_regs() from a register that can be set
  3. Check if badbytes are too restrictive
  4. Verify register names are correct for your architecture

”unknown registers”

Raised when invalid register names are provided. Solution: Use valid register names for your architecture (e.g., rax not eax on x64).

“too many registers contain bad bytes”

Raised when multiple register values contain badbytes. Solution: Currently only one register with badbytes is supported at a time.

Performance Considerations

  • Graph search is limited to paths of length ≤ 6 to avoid exponential complexity
  • Only top 5 gadgets per edge are considered after reduction
  • Gadget filtering removes duplicates with same effect
  • Optimization passes may take time but significantly improve capabilities

Architecture Support

RegSetter works across all architectures supported by angrop:
  • x86/x86_64: Full support for all GPRs
  • ARM/ARM64: Support for r0-r15, x0-x30
  • MIPS: Support for t0−t0-t9, s0−s0-s7, etc.
  • PowerPC: Support for r0-r31

See Also