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 | None
default:"None"
Set of register names that must not be modified.
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
RopChain
required
The chain to verify.
set
required
Registers that should not be modified.
dict
required
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