Skip to main content
The SysCaller class builds ROP chains that invoke system calls, automatically handling syscall numbers and arguments according to the platform’s syscall convention.

Overview

Accessed through the ROP instance as rop.do_syscall() and rop.execve(), SysCaller automatically:
  • Sets syscall number register (rax on x64, eax on x86, r7 on ARM)
  • Sets argument registers according to syscall convention
  • Handles both returning and non-returning syscalls
  • Finds optimal syscall gadgets
  • Supports execve convenience method

Class Definition

Inherits from FuncCaller and extends it with syscall-specific functionality. Located in angrop/chain_builder/sys_caller.py

Public Methods

do_syscall

Builds a ROP chain that invokes a system call.
int
required
System call number. Examples:
  • Linux x64: execve=59, read=0, write=1, open=2
  • Linux x86: execve=11, read=3, write=4, open=5
list
required
List of syscall arguments. Number and meaning depend on the specific syscall.
bool
default:"True"
Whether control flow should continue after the syscall. Set to False for syscalls like execve that don’t return.
set | None
default:"None"
Set of register names that should not be modified.
Returns: A RopChain that invokes the syscall. Raises: RopException if syscall cannot be invoked.

execve

Convenience method to invoke execve syscall with /bin/sh.
bytes | None
default:"b'/bin/sh\\\\x00'"
Command to execute. Must be null-terminated.
int | None
default:"None"
Address to write the path string. If None, automatically finds writable memory.
Returns: A complete ROP chain that spawns a shell. Raises: RopException if execve cannot be invoked.

verify

Verifies that a syscall chain correctly sets registers.
RopChain
required
Chain to verify.
dict
required
Target register values.
set
required
Registers that should not be modified.
Returns: True if verification passes, False otherwise.

ROP Instance Methods

Implementation Details

Syscall Convention Detection

SysCaller uses angr’s syscall calling convention: From source code (sys_caller.py:42):

Syscall Conventions by Architecture

x86_64 Linux

x86 (32-bit) Linux

ARM Linux

Gadget Filtering

From source code (sys_caller.py:80-84):
Gadgets are sorted by:
  1. Can return (preferred)
  2. Fewer symbolic memory accesses
  3. Smaller stack change
  4. Fewer instructions

Per-Request Gadget Filtering

SysCaller optimizes gadget selection per syscall: From source code (sys_caller.py:140-175):

Usage Examples

Basic Syscall

Execve Shell

Read Syscall

Write Syscall

Open Syscall

Non-Returning Syscall

Complete File Read Example

Chaining Syscalls

Preserving Registers Across Syscalls

Execve Implementation

From source code (sys_caller.py:86-131):

Syscall Verification

From source code (sys_caller.py:51-78):

Common Syscall Numbers

Linux x86_64

Linux x86 (32-bit)

Linux ARM

Error Handling

”target does not contain syscall gadget!”

Raised when no syscall gadgets are found. Solutions:
  1. Binary may not have syscall instructions
  2. Try using function calls instead: rop.func_call("syscall", [...])
  3. Check if binary is statically linked

”Fail to invoke syscall with arguments: !”

Raised when syscall chain cannot be built. Solutions:
  1. Run find_gadgets(optimize=True)
  2. Try needs_return=False for simpler chain
  3. Check if arguments are valid for the syscall
  4. Verify syscall number is correct for the architecture

”Fail to invoke execve!”

Raised when execve cannot be invoked. Solutions:
  1. Provide explicit path_addr to writable memory
  2. Check badbytes configuration
  3. Try rop.do_syscall(execve_num, [...]) directly

Platform Support

Operating Systems

From source code (sys_caller.py:45-46):
Supported:
  • Linux (all architectures)
  • BSD variants
  • Other Unix-like systems
Not supported:
  • Windows (uses different syscall mechanism)

Best Practices

  1. Use execve() for shells - Simplest and most reliable
  2. Set needs_return=False - For syscalls that don’t return (execve, exit)
  3. Preserve return values - Move rax to another register if needed
  4. Verify syscall numbers - They differ across architectures
  5. Handle file descriptors - Save fd from open for read/write

Performance Considerations

  • Gadget filtering reduces search space significantly
  • Concrete value matching optimizes gadget selection
  • Verification adds overhead but ensures correctness
  • Non-returning syscalls generate shorter chains

See Also