RegMover class builds ROP chains that move data from one register to another. It uses graph-based path finding to chain register moves when direct moves aren’t available.
Overview
Accessed through the ROP instance asrop.move_regs(), RegMover automatically:
- Finds direct move gadgets like
mov rax, rdx; ret - Chains multiple moves when needed
- Uses push/pop sequences as fallback
- Optimizes move paths for efficiency
Class Definition
angrop/chain_builder/reg_mover.py
Public Methods
run
Set of register names that must not be modified.
**registers
Keyword arguments mapping destination register to source register name (as string).
Example:
rax='rdx' means move rdx to rax.RopChain that performs the register moves.
Raises: RopException if moves cannot be performed.
verify
The chain to verify.
Registers that should not be modified.
Target register moves.
ROP Instance Method
When you callrop.move_regs(), it invokes RegMover.run() internally:
Implementation Details
Move Graph
RegMover builds a directed graph where:- Nodes = Registers
- Edges = Move gadgets with metadata (bits, blocks)
Path Finding
Uses NetworkX to find shortest paths between registers:Gadget Types
RegMover recognizes several move gadget patterns:- Direct moves:
mov rax, rdx; ret - Exchange:
xchg rax, rbx; ret - Conditional moves:
cmov rax, rdx; ret(if enabled) - Arithmetic:
lea rax, [rdx]; ret
PushPopMover Component
A specialized component that constructs moves via push/pop chains.How It Works
Usage Examples
Basic Register Move
Moving Multiple Registers
Using Return Values
Preserving Registers During Moves
Chained Moves
If no direct move exists, RegMover chains multiple moves:Complex Move Sequences
From kernel ROP example:Optimization
RegMover includes optimization to normalize complex gadgets:Normalizing Non-Self-Contained Gadgets
From source code (reg_mover.py:211-258):Move Graph Metadata
Each edge in the move graph contains:- block: List of gadgets sorted by stack_change
- bits: Maximum bits moved (8, 16, 32, or 64)
Architecture-Specific Behavior
x86_64
Full support for all GPRs and common move patterns.ARM
Supports ARM register moves:Partial Register Moves
RegMover tracks bit width of moves:Error Handling
”Couldn’t move registers :(”
Raised when no valid move chain can be found. Solutions:- Run
find_gadgets(optimize=True)to enable push/pop moves - Use intermediate register:
rax='src'thendst='rax' - Check if registers are valid for your architecture
”There is no chain can move X to Y”
Raised when no path exists in the move graph. Solutions:- Try an intermediate register as a bridge
- Use
set_regs()instead if the value is known - Check if both registers are available on your architecture
Performance Considerations
- Move graph is built once during bootstrap
- Only shortest paths are considered to limit complexity
- Edge blocks are sorted by stack_change for efficiency
- Multiprocessing used during optimization
Verification
RegMover verifies that moves are correct: From source code (reg_mover.py:363-395):Best Practices
- Prefer direct moves - Let RegMover find the shortest path
- Chain efficiently - Combine multiple moves in one call
- Use preserve_regs - Protect values you need to keep
- Verify chains - Use
chain.pp()to inspect generated gadgets
See Also
- RegSetter - Setting registers to values
- Register Operations Guide - Usage examples
- ChainBuilder - Main chain building interface