simuvex, which was responsible for analyzing the effects of a single piece of code (whether a basic block or a SimProcedure) on a program state, and
angr, which aggregated analyses of these basic blocks into program-level analysis such as control-flow recovery, symbolic execution, and so forth. In theory, this would encourage for the encapsulation of block-level analyses, and allow other program analysis frameworks to build upon
simuvexfor their needs. In practice, no one (to our knowledge) used
angr, and the separation introduced frustrating limitations (such as not being able to reference the history of a state from a SimInspect breakpoint) and duplication of code (such as the need to synchronize data from
simuvex.SimProcedureshas been renamed to
angr.SIM_PROCEDURES, since it is a global variable and not a class. There have been some other changes to its semantics, see the section on SimProcedures for details.
state.history. Since the path would now simply point to the state, we got rid of it. The mapping of concepts is roughly as follows:
path.recent_actions- actions are no longer tracked by default. If you would like them to be tracked again, please add
angr.options.refsto your state.
erroredstash of a path group. Now, error resilience is handled at the simulation manager level, and any state that throws an error during stepping will be wrapped in an ErrorRecord object, which is not a subclass of SimState, and put into the
erroredlist attribute of the simulation manager, which is not a stash.
.state(the initial state that caused the error),
.error(the error that was thrown), and
.traceback(the traceback from the error). To debug these errors you can call
SimProcedures['libc.so.6']has been split up between
SIM_PROCEDURES['glibc'], depending on what specifications each function conforms to. This allows us to reuse the
msvcrt.dlland the MUSL libc, for example.
angr.procedures.definitions. Each SimLibrary object stores information about a single shared library, and can contain SimProcedure implementations, calling convention information, and type information. SimLibraries are scraped from the filesystem at import time, just like SimProcedures, and placed into
SimProceduresdict in order to change which SimProcedures would be used to hook over library functions by default, this will no longer work. Instead of
SimProcedures[lib][func_name] = proc, you now need to say
SIM_LIBRARIES[lib].add(func_name, proc). But really you should just be using
Hookclass is gone. Instead, we now can hook with individual instances of SimProcedure objects, as opposed to just the classes. A shallow copy of the SimProcedure will be made at runtime to preserve thread safety.
project.hook(addr, Hook(proc, ...))or
project.hook(addr, proc), you can now do
project.hook(addr, proc(...)). In order to use simple functions as hooks, you can either say
project.hook(addr, func)or decorate the declaration of your function with
self.call(...)SimProcedure continuation system. It is no longer required to set
IS_FUNCTION = Trueif you intend to use
self.call()while writing a SimProcedure, and each call-return target you use will have a unique address associated with it. These addresses will be allocated lazily, which does have the side effect of making address allocation nondeterministic, sometimes based on dictionary-iteration order.
hook_symbolmethod will no longer attempt to redo relocations for the given symbol, instead just hooking directly over the address of the symbol in whatever library it comes from. This speeds up loading substancially and ensures more consistent behavior for when mixing and matching native library code and SimProcedure summaries.
state.solver(if you're still referring to it as
state.seyou should stop) and simplified it into a cleaner interface:
solver.eval(expression)will give you one possible solution to the given expression.
solver.eval_one(expression)will give you the solution to the given expression, or throw an error if more than one solution is possible.
solver.eval_upto(expression, n)will give you up to n solutions to the given expression, returning fewer than n if fewer than n are possible.
solver.eval_atleast(expression, n)will give you n solutions to the given expression, throwing an error if fewer than n are possible.
solver.eval_exact(expression, n)will give you n solutions to the given expression, throwing an error if fewer or more than are possible.
solver.min(expression)will give you the minimum possible solution to the given expression.
solver.max(expression)will give you the maximum possible solution to the given expression.
extra_constraintscan be passed as a tuple of constraints.
cast_tocan be passed a data type to cast the result to.
str, which will cause the method to return the byte representation of the underlying data.
state.solver.eval(state.solver.BVV(0x41424344, 32, cast_to=str)will return