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.mem
interface! Any type that's registered with the types module can be used to extract data from memory.deref
property to return a SimMemView at the address present in memory.state.mem.types
..array(n)
to view the data as an array of n elements..resolved
or .concrete
. .resolved
will return bitvector values, while .concrete
will return integer, string, array, etc values, whatever best represents the data.x = s.mem[...].prop; x = val
will 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
module.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 SimRegArg
or SimStackArg
classes. You can find them in the factory - p.factory.cc.Sim*Arg
.p.factory.call_state
, or...myfunc = p.factory.callable(addr)
, and then call it! result = myfunc(args, ...)
When you call the callable, angr will set up a call_state
at the given address, dump the given arguments into memory, and run a path_group
based 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
and a 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 SimCC
object in the cc
keyword argument when constructing the callable. The SimTypeFunction
is required - you must pass the prototype
parameter. If you pass a string to this parameter it will be parsed as a function declaration.PointerWrapper
object, 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 setup_callsite
function.func.perform_call(arg, ...)
, and then the properties func.result_state
and func.result_path_group
will be populated. They will actually be populated even if you call the callable normally, but you probably care about them more in this case!