Skip to main content

Utility Functions

angrop provides a comprehensive set of utility functions in rop_utils.py for working with symbolic execution, gadget analysis, and ROP chain construction.

Address and Assembly

addr_to_asmstring

Converts an address to a human-readable assembly string.
angr.Project
required
The project containing the binary
int
required
The address to disassemble
Returns: String of semicolon-separated instructions (e.g., "pop rax; pop rbx; ret") Example:

AST Dependency Analysis

get_ast_dependency

Identifies which registers affect a symbolic AST expression.
claripy.ast.BV
required
The AST to analyze. Must be created from a symbolic state where registers are named "sreg_REG-"
Returns: Set of register names that affect the AST value Algorithm:
  • Extracts all variables starting with "sreg_"
  • Returns the register name portion (e.g., "sreg_rax-123" → "rax")
  • Returns empty set if any non-register variables are found
Example:

get_ast_controllers

Identifies which registers can fully control (unconstrain) an AST expression.
angr.SimState
required
The symbolic state
claripy.ast.BV
required
The AST to analyze
set
required
Set of register dependencies (from get_ast_dependency)
Returns: Set of register names that can make the AST take arbitrary values Algorithm:
  1. For each dependent register, set all other registers to a test value
  2. Check if the resulting AST is unconstrained using fast_unconstrained_check
  3. Return registers that allow arbitrary values
Example:

get_ast_const_offset

Extracts the constant offset from a memory access expression.
angr.SimState
required
The symbolic state
claripy.ast.BV
required
The memory address AST
set
required
Register dependencies
Returns: The constant offset value Example:

Constraint Checking

unconstrained_check

Checks if an AST is completely unconstrained (can take any value). Returns: True if the AST has no constraints in the solver

fast_unconstrained_check

Quickly checks if an AST is probably unconstrained using heuristics. Heuristics:
  1. Allowed operations: Extract, BVS, add, sub, xor, Reverse, BVV, ZeroExt, SignExt
  2. Disallowed patterns:
    • Bitwise AND with non-all-ones constant
    • Bitwise OR with non-zero constant
    • Shifts by non-zero amount
    • Operations like x + x (constrained)
  3. Byte-level check: Each byte must be unconstrained
  4. Fallback: Uses loose_constrained_check if heuristics pass
Example:

loose_constrained_check

Checks if an AST can take at least 3 out of 5 test values. Test values:
  1. 0x0
  2. 0xFFFFFFFF... (all ones)
  3. 0xAAAAAAAA... (alternating)
  4. 0x55555555... (alternating)
  5. 0x9ABC... (mixed pattern)
Returns: True if at most 2 test values are unsatisfiable

Register Utilities

get_reg_name

Finds the register name for a given offset in the register file.
angrop.arch.Arch
required
Architecture instance
int
required
Byte offset in the register file
Returns: Register name Raises: RegNotFoundException if no register found at offset Example:

State Creation

make_initial_state

Creates an optimized initial state for ROP analysis. Features:
  • Custom memory plugin (SpecialMem) for faster uninitialized memory
  • Symbolic stack of size stack_gsize * arch.bytes
  • Optimized angr options for gadget analysis
  • 1-second solver timeout
Options enabled:
  • CONSERVATIVE_READ_STRATEGY
  • AVOID_MULTIVALUED_WRITES
  • NO_SYMBOLIC_JUMP_RESOLUTION
  • TRACK_ACTION_HISTORY
  • TRACK_REGISTER_ACTIONS
  • TRACK_MEMORY_ACTIONS
Options disabled:
  • AVOID_MULTIVALUED_READS
  • SUPPORT_FLOATING_POINT
  • All resilience and simplification options

make_symbolic_state

Creates a symbolic state with specified registers symbolized.
angr.Project
required
The angr project
set
required
Registers to symbolize (named "sreg_REG-")
int
required
Symbolic stack size in pointer-sized elements
set | None
default:"None"
Additional registers to symbolize (named "esreg_REG-")
bool
default:"False"
Symbolize the GOT table (for non-FULL RELRO binaries)
Example:

Execution Control

step_one_inst

Steps a state forward by exactly one instruction. Handles:
  • Kernel execution (steps through if not stop_at_syscall)
  • Hooked addresses (steps through)

step_to_unconstrained_successor

Steps until reaching an unconstrained successor or syscall.
int
default:"2"
Maximum steps to take
Returns: State at unconstrained successor or syscall Raises: RopException if cannot reach unconstrained state

step_to_syscall

Steps state forward until just before a syscall instruction. Returns: State at syscall instruction Raises: RuntimeError if unable to reach syscall

Address Checking

is_kernel_addr

Checks if an address is in kernel space. Returns: True if the address belongs to the kernel object (cle##kernel)

is_in_kernel

Checks if a state’s instruction pointer is in kernel space.

Timeout Decorator

timeout

Decorator that raises RopTimeoutException if function exceeds time limit. Features:
  • Uses SIGALRM signal
  • Handles nested timeouts (respects shortest timeout)
  • Delays timeout during __del__ methods to avoid exceptions during cleanup
Example:

Value Conversion

cast_rop_value

Converts a value to a RopValue instance and performs rebase analysis.

bits_extended

Returns the number of bits added by ZeroExt or SignExt operations. Example:

Error Classes

angrop defines custom exceptions in errors.py for fine-grained error handling.

RegNotFoundException

Raised when a register cannot be found at a specified offset. Example:

RopException

Base exception for general ROP analysis errors. Common scenarios:
  • Gadget does not reach unconstrained state
  • Cannot get to single successor
  • SP change is symbolic or uncontrolled
  • Memory access with no dependencies
Example:

RopTimeoutException

Raised when gadget analysis exceeds the timeout limit. Usage with timeout decorator:

Common Patterns

Custom Gadget Analysis

Memory Access Validation