Skip to main content
Register operations are fundamental to ROP chain building. Angrop provides powerful methods to set registers to specific values and move data between registers.

Setting Registers: set_regs()

The set_regs() method sets one or more registers to specific values.

Method Signature

Parameters:
  • **registers: Keyword arguments mapping register names to values (integers or symbolic values)
  • preserve_regs: Set of register names that should not be modified during chain generation
Returns: A RopChain object that sets the specified registers

Basic Examples

1

Set a single register

Output:
2

Set multiple registers

Output:
Angrop automatically finds the best gadgets to set your registers, preferring gadgets with minimal stack changes and side effects.

Preserving Register Values

Use preserve_regs to ensure certain registers aren’t modified during chain generation:

Real-World Example: Preserving Function Arguments

This example from angrop’s kernel test suite shows preserving registers across function calls:
Always use preserve_regs when you need to maintain register values across multiple operations, especially when passing return values or setting up complex function arguments.

Moving Registers: move_regs()

The move_regs() method copies data from one register to another.

Method Signature

Parameters:
  • **moves: Keyword arguments mapping destination register to source register name (as string)
  • preserve_regs: Set of register names that should not be modified
Returns: A RopChain object that performs the register moves

Basic Examples

Output:

Moving Multiple Registers

Angrop searches for direct move gadgets like mov rax, rdx; ret. If direct moves aren’t available, it may chain multiple gadgets or use push/pop sequences to accomplish the move.

Advanced Register Operations

Using Return Values from Functions

When calling functions, the return value is typically in rax (on x64) or eax (on x86). Use move_regs() to preserve it:

Combining Set and Move Operations

Architecture-Specific Registers

Angrop supports register operations across different architectures:

x86_64 Registers

x86 (32-bit) Registers

ARM Registers

Register Setting with Badbytes

When badbytes are configured, angrop automatically avoids values containing them:
When values contain badbytes, angrop uses arithmetic operations to construct them. For example, it might set a register to 0x0a0a0a0b and then subtract 1, rather than directly loading 0x0a0a0a0a.

How Register Setting Works Internally

Angrop uses several strategies to set registers:
  1. Direct pop gadgets - pop rax; ret - Most efficient
  2. Register arithmetic - If value contains badbytes, construct it via add/sub/xor
  3. Register moves - Chain register moves when direct pops aren’t available
  4. Complex gadget chains - Combine multiple gadgets when needed

Example: Register Arithmetic for Badbytes

From the source code (reg_setter.py:699-725):

Symbolic Register Values

You can also set registers to symbolic values for advanced use cases:

Troubleshooting

”Couldn’t set registers” Error

If you see this error, it means angrop couldn’t find gadgets to set the requested registers:
Solutions:
  • Ensure find_gadgets(optimize=True) was called
  • Try using move_regs() from a register that can be set
  • Check if your badbytes are too restrictive
  • Verify the register name is correct for your architecture

Best Practices

  1. Minimize register operations - Set multiple registers in one call when possible
  2. Use preserve_regs strategically - Only preserve registers when necessary
  3. Chain efficiently - Combine operations with + instead of making separate calls
  4. Verify your chains - Use chain.pp() to inspect the generated gadgets

Examples from Different Architectures

x86_64 Function Call Setup

ARM Function Call Setup

Next Steps