cozy.concolic.exploration

Module Contents

Classes

ConcolicSim

This class implements concolic execution without using an external emulator

_ExploreMode

Create a collection of name/value pairs.

JointConcolicSim

Jointly runs two SimulationManager objects by concretizing symbols, then running the left and right simulations

class cozy.concolic.exploration.ConcolicSim(concrete_init: dict[claripy.BVS, claripy.BVV] | set[claripy.BVS] | frozenset[claripy.BVS], deferred_stash='deferred', check_only_recent_constraints=True)

Bases: angr.ExplorationTechnique

This class implements concolic execution without using an external emulator like QEMU or Unicorn. This class functions by storing a concrete assignment for each symbolic variable. When the state branches, the assignment is substituted into both children’s constraints. If the substitution results in the constraints evaluating to false, that child is placed in the deferred stash. By querying the simulation manager’s active stash length, we can tell when the concrete execution ends. When concrete execution ends, we can either choose a new concrete substitution ourselves and set it with the ConcolicDeferred.set_concrete() method. Alternatively we can take one of the deferred states and generate and autogenerate a new concrete substitution by finding a satisfying assignment for that state’s constraints.

ConcolicSim constructor

Parameters:
  • concrete_init (dict[claripy.BVS, claripy.BVV] | set[claripy.BVS] | frozenset[claripy.BVS]) – Used to initialize the concrete value. If this value is a substitution dictionary, then that dictionary is used as our concrete input. If this value is a set or frozenset, then a substituting dictionary is autogenerated, subject to the initial state’s constraints.

  • deferred_stash (string) – The name of the deferred stash

  • check_only_recent_constraints (bool) – If this value is true, then whenever child states are created, only the new constraints are checked with respect to the concrete substitution. Here we assume that the parent of the child already satisfied the concrete input on a previous iteration, so it’s safe to only check with respect to the new constraints.

setup(simgr)

Perform any initialization on this manager you might need to do.

Parameters:

simgr (angr.SimulationManager) – The simulation manager to which you have just been added

is_satisfied(constraints: list[claripy.ast.bool]) bool

Substitutes the current concrete input into the constraints, and returns True if the constraints are True after the substitution is made.

Parameters:

constraints (list[claripy.ast.bool]) – The constraints in which the concrete solution will be substituted.

Return type:

bool

Returns:

If the constraints are True after substitution, then True is returned. Otherwise returns False.

_set_replacement_dict(concrete)
set_concrete(simgr, concrete: dict[claripy.BVS | claripy.FPS, claripy.BVV | claripy.FPV])

Sets the concrete input via a substitution dictionary. All the symbols used by the program should have concrete values provided for them. The active and deferred stash will be mutated to ensure that only states which are satisfied by the concrete substitution are active.

Parameters:

concrete (dict[claripy.BVS, claripy.BVV]) – A dictionary mapping each symbol to its concrete value.

_generate_concrete(simgr: angr.SimulationManager, from_stash: list[angr.SimState], symbols: set[claripy.BVS] | frozenset[claripy.BVS], candidate_heuristic: collections.abc.Callable[[list[angr.SimState]], angr.SimState] | None = None)
generate_concrete(simgr: angr.SimulationManager, symbols: set[claripy.BVS] | frozenset[claripy.BVS], candidate_heuristic: collections.abc.Callable[[list[angr.SimState]], angr.SimState] | None = None)

Autogenerates a new concrete input by choosing a deferred state and finding a satisfying assignment with respect to that state’s constraints. The symbols provided will be used to internally generate a substitution dictionary. The candidate_heuristic is used to choose a state from the current stash of deferred states. If no heuristic is provided, the last state in the deferred stash will be chosen next. If there are any active states in the simulation manager, a ValueError will be thrown.

Parameters:
  • simgr (angr.SimulationManager) – The simulation manager

  • symbols (set[claripy.BVS] | frozenset[claripy.BVS]) – The symbols that we will generate a substitution for.

  • candidate_heuristic (Callable[[list[angr.SimState]], angr.SimState] | None) – The heuristic that should be used to choose the deferred state that should be explored further. Note that this function should mutate its input list (ie, remove the desired state), and return that desired state.

filter(simgr, state, **kwargs)

Perform filtering on which stash a state should be inserted into.

If the state should be filtered, return the name of the stash to move the state to. If you want to modify the state before filtering it, return a tuple of the stash to move the state to and the modified state. To defer to the original categorization procedure, return the result of simgr.filter(state, **kwargs)

If the user provided a filter_func in their step or run command, it will appear here.

Parameters:
  • simgr (angr.SimulationManager) –

  • state (angr.SimState) –

class cozy.concolic.exploration._ExploreMode(*args, **kwds)

Bases: enum.Enum

Create a collection of name/value pairs.

Example enumeration:

>>> class Color(Enum):
...     RED = 1
...     BLUE = 2
...     GREEN = 3

Access them by:

  • attribute access:

>>> Color.RED
<Color.RED: 1>
  • value lookup:

>>> Color(1)
<Color.RED: 1>
  • name lookup:

>>> Color['RED']
<Color.RED: 1>

Enumerations can be iterated over, and know how many members they have:

>>> len(Color)
3
>>> list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

Methods can be added to enumerations, and members can have their own attributes – see the documentation for details.

EXPLORE_LEFT = 0
EXPLORE_RIGHT = 1
class cozy.concolic.exploration.JointConcolicSim(simgr_left: angr.SimulationManager, simgr_right: angr.SimulationManager, symbols: set[claripy.BVS] | frozenset[claripy.BVS], left_explorer: ConcolicSim, right_explorer: ConcolicSim, candidate_heuristic_left: collections.abc.Callable[[list[angr.SimState]], angr.SimState] | None = None, candidate_heuristic_right: collections.abc.Callable[[list[angr.SimState]], angr.SimState] | None = None)

Jointly runs two SimulationManager objects by concretizing symbols, then running the left and right simulations with the same concrete input. This joint simulator alternates between the left and right simulations when generating new concrete inputs.

Parameters:
  • simgr_left (SimulationManager) – The first simulation manager to run in concolic execution

  • simgr_right (SimulationManager) – The second simulation manager to run in concolic execution.

  • left_explorer (ConcolicSim) – The first exploration method to use for concolic execution. Note that this exploration technique will be attached to the left simulation manager.

  • right_explorer (ConcolicSim) – The second exploration method to use for concolic execution. Note that this exploration technique will be attached to the right simulation manager.

  • candidate_heuristic_left (Callable[[list[angr.SimState]], angr.SimState] | None) – The heuristic that should be used to choose the deferred state that should be explored further. Note that this function should mutate its input list (ie, remove the desired state), and return that desired state. Note that some pre-made candidate heuristic techniques can be found in the cozy.concolic.heuristics module.

  • candidate_heuristic_right (Callable[[list[angr.SimState]], angr.SimState] | None) – The heuristic that should be used to choose the deferred state that should be explored further. Note that this function should mutate its input list (ie, remove the desired state), and return that desired state. Note that some pre-made candidate heuristic techniques can be found in the cozy.concolic.heuristics module.

_swap_explore_mode()
_generate_concrete(from_stash_left, from_stash_right)
explore(explore_fun_left: collections.abc.Callable[[angr.SimulationManager], None] | None = None, explore_fun_right: collections.abc.Callable[[angr.SimulationManager], None] | None = None, termination_fun_left: collections.abc.Callable[[angr.SimulationManager], bool] | None = None, termination_fun_right: collections.abc.Callable[[angr.SimulationManager], bool] | None = None) None

Explores the simulations given in the left and right simulation manager.

Parameters:
  • explore_fun_left (Callable[[SimulationManager], None] | None) – If this parameter is not None, then instead of SimulationManager.explore() being called to do the exploration, we call explore_fun_left instead.

  • explore_fun_right (Callable[[SimulationManager], None] | None) – If this parameter is not None, then instead of SimulationManager.explore() being called to do the exploration, we call explore_fun_right instead.

  • termination_fun_left (Callable[[SimulationManager], bool] | None) – Every time we finish exploring one concrete input, this function is called to determine if the exploration should terminate. If both termination functions return True, then exploration is halted and this function returns. If this parameter is None, then the left simulation manager will terminate only when no further exploration is possible (ie, execution is complete). Pre-made termination functions can be found in the cozy.concolic.heuristics module.

  • termination_fun_right (Callable[[SimulationManager], bool] | None) – Every time we finish exploring one concrete input, this function is called to determine if the exploration should terminate. If both termination functions return True, then exploration is halted and this function returns. If this parameter is None, then the right simulation manager will terminate only when no further exploration is possible (ie, execution is complete). Pre-made termination functions can be found in the cozy.concolic.heuristics module.

Returns:

None

Return type:

None