Shifter class builds ROP chains that shift the stack pointer by specific byte amounts, enabling precise stack manipulation and ret-sled construction.
Overview
Accessed through the ROP instance asrop.shift() and rop.retsled(), Shifter automatically:
- Finds pop chains that shift SP by exact amounts
- Constructs ret-sleds of arbitrary length
- Manages stack value placement
- Supports custom next PC positioning
- Verifies stack shifts
Class Definition
angrop/chain_builder/shifter.py
Public Methods
shift
int
required
Number of bytes to shift the stack (must be word-aligned).
set | None
default:"None"
Set of register names that should not be modified.
int
default:"-1"
Index (in words) where the next PC should be placed. Supports negative indexing.
-1: Next PC at end (default)0: Next PC at start- Positive: Absolute position
RopChain that shifts the stack.
Raises: RopException if shift cannot be performed.
retsled
int
required
Total size in bytes for the ret-sled (must be word-aligned).
set | None
default:"None"
Set of register names that should not be modified.
RopChain consisting only of ret gadgets.
Raises: RopException if ret-sled cannot be built.
verify_shift
RopChain
required
Chain to verify.
int
required
Expected shift amount.
set
required
Registers that should not be modified.
verify_retsled
RopChain
required
Chain to verify.
int
required
Expected size in bytes.
set
required
Registers that should not be modified.
ROP Instance Methods
Implementation Details
Shift Gadget Dictionary
Shifter maintains a dictionary mapping stack changes to gadgets: From source code (shifter.py:140-159):Shift Implementation
From source code (shifter.py:62-110):Retsled Implementation
From source code (shifter.py:112-130):Usage Examples
Basic Stack Shift
Shift with Custom Next PC Position
Stack Arguments for Function Calls
Used internally by FuncCaller for stack arguments: From source code context:Ret-Sled
NOP Sled Equivalent
Preserving Registers During Shift
Stack Cleanup After Function
Shift Gadget Patterns
Common Patterns by Stack Change
8 bytes (1 word)
16 bytes (2 words)
24 bytes (3 words)
32 bytes (4 words)
PC Offset Importance
Thepc_offset determines where ret pops from:
Verification
From source code (shifter.py:26-42):Effect and Comparison Tuples
From source code (shifter.py:132-138):- Gadgets grouped by stack_change and pc_offset
- Within groups, prefer fewer register changes
- Then prefer smaller stack changes
- Then simpler transit types
- Finally fewer instructions
Error Handling
”Currently, we do not support shifting misaligned sp change”
Raised when length is not word-aligned. Solution: Use multiples of word size:“Encounter a shifting request that requires chaining multiple shifting gadgets”
Raised when exact shift amount isn’t available. Solutions:- Try a different shift amount
- Use
fast_mode=Falsefor more gadgets - Manually chain multiple shifts:
“the size of a retsled must be word aligned”
Raised when retsled size is not aligned. Solution: Use word-aligned sizes.”fail to find a ret-equivalent gadget”
Raised when no simple ret gadget exists. Solution: Very rare; binary likely has unusual structure.Performance Considerations
- Gadget dictionary is pre-built during bootstrap
- Shifts are fast (single gadget)
- Retsleds may be long but simple
- Verification adds small overhead
Architecture Support
- x86/x86_64: Full support, many pop patterns
- ARM/ARM64: Full support
- MIPS: Full support
- PowerPC: Basic support
Advanced Techniques
Precise Stack Control
Custom Stack Layouts
Ret-Sled for Alignment
Best Practices
- Use for exact amounts: When you need precise stack shifts
- Prefer simpler shifts: Fewer words = fewer clobbered registers
- Check alignment: Always use word-aligned values
- Verify shifts: Use
chain.pp()to inspect - Consider alternatives: Sometimes
pivot()is better
See Also
- Pivot - Stack pivoting to arbitrary locations
- FuncCaller - Uses shift for stack arguments
- ChainBuilder - Main chain building interface