angr.types- an instance of any of these classes represents a type. Many of the types are incomplete unless they are supplamented with a SimState - their size depends on the architecture you're running under. You may do this with
ty.with_arch(arch), which returns a copy of itself, with the architecture specified.
pycparser, which is a C parser. This helps with getting instances of type objects:
state.meminterface! Any type that's registered with the types module can be used to extract data from memory.
derefproperty to return a SimMemView at the address present in memory.
.array(n)to view the data as an array of n elements.
.resolvedwill return bitvector values, while
.concretewill return integer, string, array, etc values, whatever best represents the data.
x = s.mem[...].prop; x = valwill NOT work, you must say
s.mem[...].prop = val.
register_types(parse_type(struct_expr)), you can access it here as a type:
p.factory.cc(...). This will give a calling convention which is guessed based your guest architecture and OS. If angr guesses wrong, you can explicitly pick one of the calling conventions in the
angr.calling_conventions.SimCCUsercall. This will ask you to specify locations for the arguments and the return value. To do this, use instances of the
SimStackArgclasses. You can find them in the factory -
myfunc = p.factory.callable(addr), and then call it!
result = myfunc(args, ...)When you call the callable, angr will set up a
call_stateat the given address, dump the given arguments into memory, and run a
path_groupbased on this state until all the paths have exited from the function. Then, it merges all the result states together, pulls the return value out of that state, and returns it.
SimTypeFunction, to tell where to put the arguments and where to get the return value. It will try to use a sane default for the architecture, but if you'd like to customize it, you can pass a
SimCCobject in the
cckeyword argument when constructing the callable. The
SimTypeFunctionis required - you must pass the
prototypeparameter. If you pass a string to this parameter it will be parsed as a function declaration.
PointerWrapperobject, available as
p.factory.callable.PointerWrapper. The exact semantics of how pointer-wrapping work are a little confusing, but they can be boiled down to "unless you specify it with a PointerWrapper or a specific SimArrayType, nothing will be wrapped in a pointer automatically unless it gets to the end and it hasn't yet been wrapped in a pointer yet and the original type is a string, array, or tuple." The relevant code is actually in SimCC - it's the
func.perform_call(arg, ...), and then the properties
func.result_path_groupwill be populated. They will actually be populated even if you call the callable normally, but you probably care about them more in this case!