Use this file to discover all available pages before exploring further.
SimProcedure is a powerful abstraction for creating symbolic function summaries. Instead of executing actual binary code, you can replace functions with Python implementations that manipulate the state symbolically.Detailed documentation: https://docs.angr.io/extending-angr/simprocedures
Receives arguments extracted from the state based on calling convention and prototype. Return value is automatically handled unless you explicitly call self.ret().
Example: Simple SimProcedure
import angrfrom angr import SimProcedureimport claripyclass MyStrlen(SimProcedure): def run(self, s): # s is automatically extracted based on calling convention # Find null terminator length = claripy.BVV(0, self.state.arch.bits) idx = 0 while True: char = self.state.memory.load(s + idx, 1) if self.state.solver.is_true(char == 0): break idx += 1 if idx > 1000: # prevent infinite loops break return claripy.BVV(idx, self.state.arch.bits)# Hook strlenproject.hook_symbol('strlen', MyStrlen())
Keyword arguments passed to procedure constructor as sim_kwargs
Returns the executed procedure instance with ret_expr set.
Example: Inline Call
class WrapperFunction(SimProcedure): def run(self, s): # Call strlen inline strlen_result = self.inline_call( MyStrlen, s ) length = strlen_result.ret_expr # Use the length if self.state.solver.eval(length) > 100: self.ret(1) # String too long else: self.ret(0) # OK
Specific index to extract. If None, extracts next variadic arg
Use for functions with variable arguments like printf.
Example: Variadic Arguments
class MyPrintf(SimProcedure): def run(self, fmt): # fmt is the first argument # Additional arguments are variadic # Read format string fmt_str = self.state.mem[fmt].string.concrete # Count %d specifiers num_ints = fmt_str.count(b'%d') # Extract variadic arguments args = [] for i in range(num_ints): arg = self.va_arg('int') args.append(arg) # Format and write to stdout # (simplified - real implementation more complex) output = fmt_str % tuple(args) self.state.posix.write(1, output, len(output)) self.ret(len(output))
import angrimport claripyclass MyMalloc(angr.SimProcedure): def run(self, size): # Get allocation size size_int = self.state.solver.eval(size) # Allocate from heap addr = self.state.heap.allocate(size_int) # Mark memory as allocated self.state.memory.store(addr, claripy.BVV(0, size_int * 8)) # Return pointer return addrclass MyFree(angr.SimProcedure): def run(self, ptr): # angr doesn't really need free for symbolic execution # Just mark the memory as freed if you want passproject = angr.Project('/bin/example')project.hook_symbol('malloc', MyMalloc())project.hook_symbol('free', MyFree())
Example: System Call
class MyWrite(angr.SimProcedure): NO_RET = False def run(self, fd, buf, count): # Read data from buffer data = self.state.memory.load(buf, count) # Write to file descriptor written = self.state.posix.write(fd, data, count) # Return bytes written return written# Hook write syscallproject.simos.syscall_library.add('write', MyWrite, number=1)
Example: Stub with Symbolic Return
class UnknownFunction(angr.SimProcedure): def run(self, arg1, arg2): # Create symbolic return value ret_val = self.state.solver.BVS( 'unknown_func_ret', self.arch.bits ) # Add constraints if known # For example, assume non-negative self.state.add_constraints(ret_val >= 0) return ret_valproject.hook_symbol('unknown_function', UnknownFunction())
Example: No Return Function
class MyExit(angr.SimProcedure): NO_RET = True # This function never returns def run(self, code): # Terminate execution self.exit(code)project.hook_symbol('exit', MyExit())