Overview
angrop’s chain builder automatically assembles ROP gadgets into functional exploit chains. Rather than manually selecting and linking gadgets, you specify high-level goals (“set rax to 0x1234”, “write data to memory”, “call execve”) and angrop finds the optimal gadget sequence.Architecture
The chain builder consists of specialized modules, each responsible for different types of operations:Core Modules
Fromchain_builder/__init__.py:42-53:
- Bootstraps by analyzing available gadgets and building internal data structures
- Optimizes by finding better gadget combinations
- Generates chains on demand using graph search and constraint solving
The RegSetter Module
The most fundamental module. Sets registers to arbitrary values using graph search.Graph Search Algorithm
Fromreg_setter.py:474-612, RegSetter builds a directed graph where:
- Nodes: States representing which registers have been set to target values
- Edges: Gadgets that transition between states
rax=0x1234 and rbx=0x5678:
pop rax; ret- Sets raxpop rbx; pop r12; ret- Sets rbx (and r12)pop rax; pop rbx; ret- Sets both at once
Register Setting Strategy
Fromreg_setter.py:749-777:
- Registers containing badbytes: Use arithmetic gadgets to construct the value
- Unpoppable registers: Use register moves or memory reads
Concrete Value Crafting
When a register can’t be popped directly, angrop crafts the value using arithmetic: Fromreg_setter.py:699-725:
rax = 0x41424344 (contains null bytes):
pop rax; retwith value0x41424300add rax, 0x44; ret- Result:
rax = 0x41424344(no null bytes in payload)
The MemWriter Module
Writes arbitrary data to memory addresses.Basic Memory Writing
Frommem_writer.py:464-492:
- Self-contained
- Exactly one memory write
- Address and data independently controllable
- No symbolic memory reads
Handling Badbytes
When data contains badbytes, angrop uses memory modification gadgets: Frommem_writer.py:631-661:
\x00\x41\x42\x43 with \x00 as badbyte:
- Write
\x01\x41\x42\x43(no badbytes) - Execute
xor dword [rax], 0x00000001 - Result:
\x00\x41\x42\x43
The MemChanger Module
Modifies memory in-place using arithmetic/logical operations. Supported operations:mem_add(addr, value)-[addr] += valuemem_xor(addr, value)-[addr] ^= valuemem_or(addr, value)-[addr] |= valuemem_and(addr, value)-[addr] &= value
The FuncCaller Module
Invokes functions with specified arguments, handling calling conventions. From the ChainBuilder API:The SysCaller Module
Builds syscall invocation chains. Fromchain_builder/__init__.py:138-152:
execve chains
Chain Composition
Chains are built incrementally and can be combined:RopChain Objects
From usage:RopBlock Normalization
Complex gadgets are wrapped in RopBlocks that encapsulate:- The gadget sequence
- Required stack values
- Symbolic constraints
- Register preservation requirements
builder.py:879-956:
Optimization
The chain builder optimizes iteratively: Fromchain_builder/__init__.py:232-244:
- Register moves: Find ways to set hard registers by moving from easy ones
- Gadget normalization: Make non-self-contained gadgets usable
- Chain shortening: Replace long chains with shorter equivalent ones
Constraint Solving
The chain builder uses symbolic execution and constraint solving throughout:Building Reg Setting Chains
Frombuilder.py:362-556:
Rebalancing Constraints
When gadgets transform values, angrop “rebalances” constraints: Frombuilder.py:245-359:
pop rax; add rax, 0x10; ret transparently.
Example: Building a Complete Chain
- Gadget selection and ordering
- Register allocation and preservation
- Constraint solving for stack values
- Calling convention adherence
- Badbyte avoidance