Let's look at a basic usage example for Haystack.
First we have a program which allocates structures on the HEAP:
In [ ]:
!cat ../test/src/test-ctypes3.c
Then, using ctypeslib, we have generated python ctypes records for the same structures.
In [ ]:
!clang2py ../test/src/test-ctypes3.c #-o ../test/src/clang3_gen64.py
We have run the compiled C program, and dumped its memory mappings to files:
In [4]:
!ls -hsw 1 ../test/src/test-ctypes3.64.dump/
print ''
!cat ../test/src/test-ctypes3.64.stdout
Let's load that memory dump in haystack.
In [5]:
import haystack
memdumpname = '../test/src/test-ctypes3.64.dump'
# we need a memory dump loader
from haystack import dump_loader
memory_handler = dump_loader.load(memdumpname)
print memory_handler
Now the first feature of haystack is to search a specific structure in memory.
In [6]:
# we need to add our test path to the env
import sys
sys.path.append('../test/src/')
py_modulename = 'ctypes3_gen64'
# load this module with haystack
my_model = memory_handler.get_model()
test3 = my_model.import_module("ctypes3_gen64")
print test3.__dict__.keys()
Now we can search for the structure in memory.
In [7]:
py_class = test3.struct_test3
results = haystack.search_record(memory_handler, py_class)
print results
The output is a list of ctypes records and their memory offset. We can also get a better formatted string output:
In [8]:
out = haystack.output_to_string(memory_handler, results)
print out
Or even a translation of these records to plain old python dynamically generated objects.
In [9]:
out = haystack.output_to_python(memory_handler, results)
print out
In [10]:
for x in out:
print "@0x%x val1: 0x%x , val1b: 0x%x "%(x[1], x[0].val1, x[0].val1b)
There should only be 3 of struct_test3. The true instance are at 0x202a030, 0x202a070 and 0x202a0b0
oh-oh, there is a bit too many chunks in memory which could be possible struct_test3.
Let's apply more constraints to the search
In [11]:
!cat ../test/src/ctypes3.constraints
Here we say that val1 and val1b fields should both be 0xdeadbeef. Let's apply these constraints to the search.
In [12]:
from haystack import constraints
handler = constraints.ConstraintsConfigHandler()
my_constraints = handler.read('../test/src/ctypes3.constraints')
# now use them
results = haystack.search_record(memory_handler, py_class, my_constraints)
print haystack.output_to_string(memory_handler, results)
In [13]:
for x in results:
print "@0x%x val1: 0x%x , val1b: 0x%x "%(x[1], x[0].val1, x[0].val1b)
The constraints did reduce the number of results, and haystack only returns allocated chunks of memory that match these constraints.
In [ ]: