Skip to content

Commit

Permalink
add a KnownRecordTypeReverser to parse known types and constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
trolldbois committed Oct 22, 2015
1 parent 86daa0d commit 85b9442
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 1 deletion.
4 changes: 4 additions & 0 deletions haystack/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@
class NotValid(Exception):
pass


class LoadException(Exception):
pass


class Model(object):

def __init__(self, memory_handler):
Expand Down Expand Up @@ -154,6 +156,7 @@ def get_imported_module(self, name):
"""
return self.__modules[name]


def copy_generated_classes(src_module, dst_module):
"""Copies the ctypes Records of a module into another module.
Is equivalent to "from src import *" but with less clutter.
Expand Down Expand Up @@ -182,6 +185,7 @@ def copy_generated_classes(src_module, dst_module):
src_module.__name__))
return


def import_module_for_target_ctypes(module_name, target_ctypes):
"""
Import the python ctypes module for a specific ctypes platform.
Expand Down
4 changes: 3 additions & 1 deletion haystack/reverse/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import numpy
import os

from haystack import dump_loader
from haystack import model
from haystack.abc import interfaces
from haystack.reverse import utils
from haystack.reverse import config
Expand All @@ -31,6 +31,8 @@ def __init__(self, memory_handler):
self.memory_handler.get_heap_finder().get_heap_mappings()
self.__contextes = {}
self.__reversed_types = {}
# see bug #17 self.__model = model.Model(self.memory_handler)
# no need for that
# create the cache folder then
self.reset_cache_folder()

Expand Down
44 changes: 44 additions & 0 deletions haystack/reverse/heuristics/reversers.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,50 @@ def reverse_record(self, _context, _record):
return


class KnownRecordTypeReverser(model.AbstractReverser):
"""
Use the list of record type name provided to try to identify know records.
The ProcessContext model must have been loaded with the appropriate ctypes module
memory_handler.get_reverse_context().get_model().import_module(*args)
then any ctypes.Structure or Union of these module can be searched for.
This reverser should be use as a second step in the reverse process.
"""

REVERSE_LEVEL = 2

def __init__(self, _memory_handler, record_names, record_constraints):
super(KnownRecordTypeReverser, self).__init__(_memory_handler)
self._process_context = self._memory_handler.get_reverse_context()
self.__record_names = record_names
self.__constraints = record_constraints
self.__search_results = {}
self.__constraints = []

def _iterate_records(self, _context):
for x in self.__record_names:
yield x

def reverse_record(self, _context, record_name):
"""
_record is actually a record_type_name
"""
from haystack.search import api
modulename, sep, classname = record_name.rpartition('.')
module = self._memory_handler.get_model().import_module(modulename)
record_type = getattr(module, classname)
# now launch the search
results = api.search_record(self._memory_handler, record_type, self.__constraints, False)

addresses = [addr for _, addr in results]
self.__search_results[record_name] = addresses
return

def get_search_results(self):
return self.__search_results


class DoubleLinkedListReverser(model.AbstractReverser):
"""
Identify double Linked list. ( list, vector, ... )
Expand Down
3 changes: 3 additions & 0 deletions haystack/search/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@

log = logging.getLogger('api')


class HaystackError(Exception):
pass


def search_record(memory_handler, struct_type, search_constraints=None, extended_search=False):
"""
Search a record in the memory dump of a process represented
Expand All @@ -36,6 +38,7 @@ def search_record(memory_handler, struct_type, search_constraints=None, extended
my_searcher = searcher.RecordSearcher(memory_handler, search_constraints)
return my_searcher.search(struct_type)


#FIXME TODO change for results == ctypes
def output_to_string(memory_handler, results):
"""
Expand Down
2 changes: 2 additions & 0 deletions haystack/search/searcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

log = logging.getLogger('searcher')


class RecordSearcher(object):
"""
Generic record type searcher.
Expand Down Expand Up @@ -150,6 +151,7 @@ def _load_at(self, mem_map, address, struct_type, depth=99):
validated = False
return instance, validated


class RecordLoader(RecordSearcher):
"""
Generic record loader.
Expand Down
41 changes: 41 additions & 0 deletions test/haystack/reverse/heuristics/test_reversers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import sys

from haystack import dump_loader
from haystack import constraints
from haystack.reverse import config
from haystack.reverse import context
from haystack.reverse.heuristics import dsa
Expand All @@ -20,10 +21,50 @@
from test.testfiles import ssh_1_i386_linux
from test.testfiles import zeus_856_svchost_exe
from test.haystack import SrcTests
from test.src import ctypes6

log = logging.getLogger("test_reversers")


class TestKnownRecordTypeReverser(SrcTests):

def setUp(self):
dumpname = 'test/src/test-ctypes6.64.dump'
self.memory_handler = dump_loader.load(dumpname)
process_context = self.memory_handler.get_reverse_context()
process_context.reset_cache_folder()
# load TU values
self._load_offsets_values(self.memory_handler.get_name())
##

def tearDown(self):
self.memory_handler.reset_mappings()
self.memory_handler = None
self.dllr = None
#config.remove_cache_folder(cls.dumpname)

def test_preload(self):
sys.path.append('test/src/')

my_model = self.memory_handler.get_model()
ctypes6_gen64 = my_model.import_module("ctypes6_gen64")

handler = constraints.ConstraintsConfigHandler()
my_constraints = handler.read('test/src/ctypes6.constraints')

x64_validator = ctypes6.CTypes6Validator(self.memory_handler, my_constraints, ctypes6_gen64)

record_names = ['ctypes6_gen64.%s' % n for n in ctypes6_gen64.__all__]

krtr = reversers.KnownRecordTypeReverser(self.memory_handler, record_names, my_constraints)
krtr.reverse()
## TODO enforce better constraints, and a dynamic Contraints engine
results = krtr.get_search_results()
for record_name, addresses in results.items():
print record_name, len(addresses)
pass


class TestDoubleLinkedReverser(SrcTests):

def setUp(self):
Expand Down
1 change: 1 addition & 0 deletions test/haystack/test_listmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from test.src import ctypes6
from test.haystack import SrcTests


class TestListStructTest6(SrcTests):
"""
"""
Expand Down

0 comments on commit 85b9442

Please sign in to comment.