Debug variable resolution#
angr now support resolve source level variable (debug variable) in binary with debug information. This article will introduce you how to use it.
Setting up#
To use it you need binary that is compiled with dwarf debuging
information (ex: gcc -g
) and load in angr with the option
load_debug_info
. After that you need to run
project.kb.dvars.load_from_dwarf()
to set up the feature and we’re
set.
Overall it looks like this:
# compile your binary with debug information
gcc -g -o debug_var debug_var.c
>>> import angr
>>> project = angr.Project('./examples/debug_var/simple_var', load_debug_info = True)
>>> project.kb.dvars.load_from_dwarf()
Core feature#
With things now set up you can view the value in the angr memory view of
the debug variable within a state with:
state.dvars['variable_name'].mem
or the value that it point to if it
is a pointer with: state.dvars['pointer_name'].deref.mem
. Here are
some example:
Given the source code in examples/debug_var/simple_var.c
#include<stdio.h>
int global_var = 100;
int main(void){
int a = 10;
int* b = &a;
printf("%d\n", *b);
{
int a = 24;
*b = *b + a;
int c[] = {5, 6, 7, 8};
printf("%d\n", a);
}
return 0;
}
# Get a state before executing printf(%d\n", *b) (line 7)
# the addr to line 7 is 0x401193 you can search for it with
>>> project.loader.main_object.addr_to_line
{...}
>>> addr = 0x401193
# Create an simulation manager and run to that addr
>>> simgr = project.factory.simgr()
>>> simgr.explore(find = addr)
<SimulationManager with 1 found>
>>> state = simgr.found[0]
# Resolve 'a' in state
>>> state.dvars['a'].mem
<int (32 bits) <BV32 0xa> at 0x7fffffffffeff30>
# Dereference pointer b
>>> state.dvars['b'].deref.mem
<int (32 bits) <BV32 0xa> at 0x7fffffffffeff30>
# It works as expected when resolving the value of b gives the address of a
>>> state.dvars['b'].mem
<reg64_t <BV64 0x7fffffffffeff30> at 0x7fffffffffeff38>
Side-note: For string type you can use .string
instead of .mem
to resolve it. For struct type you can resolve its member by
.member("member_name").mem
. For array type you can use
.array(index).mem
to access the element in array.
Variable visibility#
If you have many variable with the same name but in different scope,
calling state.dvars['var_name']
would resolve the variable with the
nearest scope.
Example:
# Find the addr before executing printf("%d\n", a) (line 12)
# with the same method to find addr
>>> addr = 0x4011e0
# Explore until find state
>>> simgr.move(from_stash='found', to_stash='active')
<SimulationManager with 1 active>
>>> simgr.explore(find = addr)
<SimulationManager with 1 found>
>>> state = simgr.found[0]
# Resolve 'a' in state before execute line 10
>>> state.dvars['a'].mem
<int (32 bits) <BV32 0x18> at 0x7fffffffffeff34>
Congratulation, you’ve now know how to resolve debug variable using angr, for more info check out the api-doc.