Techniques for controlling symbolic execution exploration in angr
Exploration techniques are hooks for a simulation manager that assist in implementing new symbolic exploration strategies. They allow you to customize how states are selected, stepped, and categorized during execution.
All hook methods are optional to override. Each receives the simulation manager and should call the corresponding simgr.* method to delegate to the default behavior.
Returns a dict mapping stash names to lists of successor states. Use None as stash name to apply default categorization.Takes precedence over the filter hook - filter only applies to states in the None stash.To work with SimSuccessors directly: simgr.successors(state, **kwargs)
Returns a SimSuccessors object. Defer to default with simgr.successors(state, **kwargs).If user provided successor_func in step/run command, it appears here.
Returns True if SimulationManager.run() should halt, False otherwise.Important: Do NOT call simgr.complete - make your own decision. Each technique’s completion checker is called and results are combined with simgr.completion_mode.
class Spiller(ExplorationTechnique): def __init__(self, min_states: int = 10, max_states: int = 100, staging_min: int = 5, staging_max: int = 10, priority_key=None)
from angr.exploration_techniques import ExplorationTechniqueclass AvoidStrings(ExplorationTechnique): """Avoid states that print specific strings""" def __init__(self, avoid_strings): super().__init__() self.avoid_strings = avoid_strings def filter(self, simgr, state, **kwargs): # Check stdout for avoided strings output = state.posix.dumps(1) for avoid_str in self.avoid_strings: if avoid_str in output: return 'avoided' # Defer to default filtering return simgr.filter(state, **kwargs)# Use custom techniquesimgr.use_technique(AvoidStrings([b'error', b'fatal']))simgr.run()
Example: Priority-Based Exploration
class PriorityExplorer(ExplorationTechnique): """Select states based on priority function""" def __init__(self, priority_func): super().__init__() self.priority_func = priority_func def step(self, simgr, stash='active', **kwargs): # Sort states by priority if stash in simgr.stashes and simgr.stashes[stash]: simgr.stashes[stash].sort( key=self.priority_func, reverse=True ) # Step normally return simgr.step(stash=stash, **kwargs)# Prioritize states closer to targetdef distance_priority(state): target = 0x400800 return -abs(state.addr - target)simgr.use_technique(PriorityExplorer(distance_priority))