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:
argskeyword argument a list of argument storage locations
ret_valkeyword argument the location where the return value should be stored
func_tykeyword argument a SymType for the function prototype.
ret_valparameters, use instances of the
SimStackArgclasses. You can find them in the factory -
b.factory.cc.Sim*Arg. Register arguments should be instantiated with the name of the register you're storing the value in, and the size of the register in bytes. Stack arguments should be instantiated with the offset from the stack pointer at the time of entry into the function and the size of the storage location, in bytes.
myfunc = b.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.
SimCC, to tell where to put the arguments and where to get the return value. By default, it uses 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.
PointerWrapperobject, available as
b.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!