Skip to main content

Overview

angrop is built on top of angr’s symbolic execution engine. Instead of executing instructions with concrete values, symbolic execution treats program inputs as symbolic variables and tracks all possible states through constraints. This allows angrop to:
  1. Analyze gadget effects - Understand what a gadget does to registers and memory
  2. Find gadget capabilities - Determine which registers can be controlled
  3. Generate chains - Solve constraints to build working ROP payloads
  4. Verify correctness - Ensure generated chains achieve their goals

Symbolic Execution in angr

From the README:
“angrop uses symbolic execution to understand the effects of gadgets and uses constraint solving and graph search for generating chains.”

Key Concepts

Symbolic State: Represents program state where values can be symbolic (unknown) rather than concrete. Constraints: Logical conditions that must be satisfied (e.g., rax + rbx == 0x1234). Constraint Solver: Uses SMT solvers (Z3) to find values satisfying all constraints. Unconstrained State: A state where the instruction pointer is symbolic, indicating a controlled jump.

Analyzing Gadget Effects

Creating Symbolic States

From builder.py:47-55:
This creates a state where:
  • All GP registers are symbolic: rax = sreg_rax_0, rbx = sreg_rbx_0, etc.
  • Stack slots are symbolic: [rsp+0] = symbolic_stack_0, [rsp+8] = symbolic_stack_1, etc.
  • We can track how the gadget transforms these symbols

Stepping Through Gadgets

From builder.py:419-437:
What this does:
  1. Execute each instruction symbolically
  2. Track all possible execution paths
  3. Apply constraints from branches
  4. Reach the final state where pc is symbolic (return)

Extracting Effects

After stepping through a gadget, angrop analyzes the final state: Register effects:
Memory effects:

Constraint Solving for Chain Generation

The Core Algorithm

From builder.py:362-420, the chain building process:

Example: Setting RAX to 0x1234

Let’s trace through finding a chain to set rax = 0x1234: Gadget: pop rax; ret at 0x401000

Advanced Constraint Solving

Rebalancing ASTs

When gadgets transform values, we need to invert the operations: From builder.py:245-359:
Example: Gadget pop rax; add rax, 0x10; ret

Handling Symbolic Memory Accesses

From builder.py:472-492:
Example: Gadget mov [rax+0x10], rbx; ret

Verification

After generating a chain, angrop verifies it works: From reg_setter.py:161-200:
This ensures:
  1. No unintended register modifications
  2. No out-of-bounds memory accesses
  3. All target registers reach desired values
  4. Control flow remains in our hands

Symbolic State Management

State Copying and Constraints

angr’s symbolic states are copied when exploring multiple paths:
angrop uses this for:
  • Exploring conditional gadgets: Try both branches
  • Preserving states: Keep original state while constraining copies
  • Parallel chain attempts: Try multiple gadget combinations

Constraint Satisfiability

Before building chains, check if constraints are satisfiable:
This avoids wasting time on impossible chains.

Performance Considerations

Constraint Complexity

From builder.py:361:
Symbolic execution can be slow when:
  • Many gadgets in a chain (exponential state explosion)
  • Complex arithmetic operations (hard for SMT solver)
  • Many symbolic memory accesses
angrop mitigates this by:
  1. Filtering gadgets early
  2. Limiting chain length
  3. Using timeouts
  4. Caching results

Caching Symbolic Results

From mem_writer.py:494-515:
This allows writing to multiple addresses efficiently without re-solving constraints.

Integration with Chain Building

Symbolic execution enables the entire chain building pipeline:
  1. Gadget Discovery: Symbolically execute candidate gadgets to analyze effects
  2. Capability Analysis: Determine which registers/memory each gadget can control
  3. Graph Construction: Build state-transition graph based on symbolic effects
  4. Path Finding: Search graph for paths that achieve goals
  5. Constraint Solving: Solve for concrete stack values that satisfy all constraints
  6. Verification: Symbolically re-execute to confirm correctness
From the README:
“angrop uses symbolic execution to understand the effects of gadgets and uses constraint solving and graph search for generating chains.”
This combination of techniques allows angrop to automatically build complex ROP chains that would take humans hours to construct manually.