Source code for angr.exploration_techniques.driller_core

import logging
from itertools import islice

from . import ExplorationTechnique


l = logging.getLogger(name=__name__)


[docs]class DrillerCore(ExplorationTechnique): """ An exploration technique that symbolically follows an input looking for new state transitions. It has to be used with Tracer exploration technique. Results are put in 'diverted' stash. """
[docs] def __init__(self, trace, fuzz_bitmap=None): """ :param trace : The basic block trace. :param fuzz_bitmap: AFL's bitmap of state transitions. Defaults to saying every transition is worth satisfying. """ super().__init__() self.trace = trace self.fuzz_bitmap = fuzz_bitmap or b"\xff" * 65536 # Set of encountered basic block transitions. self.encounters = set()
[docs] def setup(self, simgr): self.project = simgr._project # Update encounters with known state transitions. self.encounters.update(zip(self.trace, islice(self.trace, 1, None)))
[docs] def step(self, simgr, stash="active", **kwargs): simgr.step(stash=stash, **kwargs) # Mimic AFL's indexing scheme. if "missed" in simgr.stashes and simgr.missed: # A bit ugly, might be replaced by tracer.predecessors[-1] or crash_monitor.last_state. prev_addr = simgr.one_missed.history.bbl_addrs[-1] prev_loc = prev_addr prev_loc = (prev_loc >> 4) ^ (prev_loc << 8) prev_loc &= len(self.fuzz_bitmap) - 1 prev_loc = prev_loc >> 1 for state in simgr.missed: cur_loc = state.addr cur_loc = (cur_loc >> 4) ^ (cur_loc << 8) cur_loc &= len(self.fuzz_bitmap) - 1 hit = bool(self.fuzz_bitmap[cur_loc ^ prev_loc] ^ 0xFF) transition = (prev_addr, state.addr) mapped_to = self.project.loader.find_object_containing(state.addr).binary l.debug("Found %#x -> %#x transition.", transition[0], transition[1]) if ( not hit and transition not in self.encounters and not self._has_false(state) and mapped_to != "cle##externs" ): state.preconstrainer.remove_preconstraints() if state.satisfiable(): # A completely new state transition. l.debug("Found a completely new transition, putting into 'diverted' stash.") simgr.stashes["diverted"].append(state) self.encounters.add(transition) else: l.debug("State at %#x is not satisfiable.", transition[1]) elif self._has_false(state): l.debug("State at %#x is not satisfiable even remove preconstraints.", transition[1]) else: l.debug("%#x -> %#x transition has already been encountered.", transition[0], transition[1]) return simgr
# # Private methods # @staticmethod def _has_false(state): # Check if the state is unsat even if we remove preconstraints. claripy_false = state.solver.false if state.scratch.guard.cache_key == claripy_false.cache_key: return True for c in state.solver.constraints: if c.cache_key == claripy_false.cache_key: return True return False