/bin/true
for these examples.archinfo.Arch
object for whichever architecture the program is compiled, in this case little-endian amd64. It contains a ton of clerical data about the CPU it runs on, which you can peruse at your leisure. The common ones you care about are arch.bits
, arch.bytes
(that one is a @property
declaration on the main Arch
class), arch.name
, and arch.memory_endness
..loader
property. We'll get into detail on how to use this soon, but for now just know that you can use it to see the shared libraries that angr loaded alongside your program and perform basic queries about the loaded address space.project.factory
, which has several convenient constructors for common objects you'll want to use frequently.project.factory.block()
, which is used to extract a basic block of code from a given address. This is an important fact - angr analyzes code in units of basic blocks. You will get back a Block object, which can tell you lots of fun things about the block of code:Project
object only represents an "initialization image" for the program. When you're performing execution with angr, you are working with a specific object representing a simulated program state - a SimState
. Let's grab one right now!state.regs
and state.mem
to access the registers and memory of this state:.length
property describing how wide it is in bits.mem
interface is a little confusing at first, since it's using some pretty hefty Python magic. The short version of how to use it is:.<type>
to specify that the memory should be interpreted as <type> (common values: char, short, int, long, size_t, uint8_t, uint16_t...).resolved
to get the value as a bitvector.concrete
to get the value as a Python intactive
, is initialized with the state we passed in. We could look at simgr.active[0]
to look at our state some more, if we haven't had enough!/bin/true
isn't a very good example for describing how to do interesting things with symbolic execution, so we'll stop here for now.