Skip to content

Commit

Permalink
fix some haystack api changes
Browse files Browse the repository at this point in the history
  • Loading branch information
trolldbois committed Jul 18, 2017
1 parent 0553b07 commit 0197c69
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 56 deletions.
12 changes: 6 additions & 6 deletions haystack/reverse/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

def show_hex(args):
""" Show the Hex values for the record at that address. """
memory_handler = cli.get_memory_handler(args)
memory_handler = cli.make_memory_handler(args)
process_context = memory_handler.get_reverse_context()
ctx = process_context.get_context_for_address(args.address)
try:
Expand All @@ -35,10 +35,10 @@ def show_hex(args):
def show_predecessors_cmdline(args):
"""
Show the predecessors that point to a record at a particular address.
:param opt:
:param args: cmdline args
:return:
"""
memory_handler = cli.get_memory_handler(args)
memory_handler = cli.make_memory_handler(args)
process_context = memory_handler.get_reverse_context()
ctx = process_context.get_context_for_address(args.address)
try:
Expand All @@ -58,7 +58,7 @@ def show_predecessors_cmdline(args):

def reverse_show_cmdline(args):
""" Show the record at a specific address. """
memory_handler = cli.get_memory_handler(args)
memory_handler = cli.make_memory_handler(args)
process_context = memory_handler.get_reverse_context()
ctx = process_context.get_context_for_address(args.address)
try:
Expand All @@ -73,7 +73,7 @@ def reverse_cmdline(args):
""" Reverse """
from haystack.reverse import api as rapi
# get the memory handler adequate for the type requested
memory_handler = cli.get_memory_handler(args)
memory_handler = cli.make_memory_handler(args)
# do the search
rapi.reverse_instances(memory_handler)
return
Expand Down Expand Up @@ -111,7 +111,7 @@ def reverse_parents():
desc = REVERSE_PARENT_DESC
rootparser = cli.base_argparser(program_name=os.path.basename(sys.argv[0]), description=desc)
rootparser.add_argument('address', type=argparse_utils.int16, action='store', default=None,
help='Hex address of the child structure')
help='Hex address of the child structure')
rootparser.set_defaults(func=show_predecessors_cmdline)
opts = rootparser.parse_args(argv)
# apply verbosity
Expand Down
3 changes: 3 additions & 0 deletions haystack/reverse/heuristics/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@


class ConstraintsReverser(object):
# TODO: ConstraintsReverser need to work on RecordInstance and not RecordType
# so that value of fields can be evaluated.
def __init__(self, memory_handler):
self.__memory_handler = memory_handler
self.__process_context = memory_handler.get_reverse_context()
Expand Down Expand Up @@ -50,6 +52,7 @@ def verify(self, _record_type, members):
continue
values = []
for _item in records:
# BUG AttributeError: 'AnonymousRecord' object has no attribute 'get_value_for_field'
val = _item.get_value_for_field(field)
if field.is_pointer():
values.append(hex(val))
Expand Down
39 changes: 20 additions & 19 deletions haystack/reverse/heuristics/pointertypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,18 @@ def reverse_record(self, _context, _record):
"""
# If you want to cache resolved infos, it still should be decided by
# the caller
pointer_fields = [field for field in _record.record_type.get_fields() if field.is_pointer()]
pointer_fields = [field for field in _record.get_fields() if field.type.is_pointer()]
log.debug('got %d pointer fields', len(pointer_fields))
for field in pointer_fields:
#value = field.value
value = field.value
# get the FieldInstance, and its value.
# FIXME This is messed up, this set_pointee_addr method should be in FieldInstance
value = _record.get_field(field.name).value
field.set_pointee_addr(value) # default
# ? FIX ME This is messed up, this set_pointee_addr method should be in FieldInstance
#value = _record.get_field(field.name).value
#field.set_pointee_addr(value) # default
# FIXME field.set_resolved() # What ?
# + if value is unaligned, mark it as cheesy
if value % self._target.get_word_size():
field.comment = 'Unaligned pointer value'
field.type.comment = 'Unaligned pointer value'
# + ask _memory_handler for the context for that value
try:
ctx = context.get_context_for_address(self._memory_handler, value) # no error expected.
Expand All @@ -60,10 +60,10 @@ def reverse_record(self, _context, _record):
# value is a pointer, but not to a heap.
m = self._memory_handler.get_mapping_for_address(value)
# field.set_child_desc('ext_lib @%0.8x %s' % (m.start, m.pathname))
field.set_pointer_to_ext_lib()
field.set_pointee_ctype('void')
field.type.set_pointer_to_ext_lib()
field.type.set_pointee_ctype('void')
# TODO: Function pointer ?
field.name = 'ptr_ext_lib_%d' % field.offset
field.name = 'ptr_ext_lib_%d' % field.type.offset
# if value in self.__functions_pointers:
# size, bbs, name = self.__functions_pointers[value]
# field.name = 'func_ptr_%s_%d' % (name, field.offset)
Expand All @@ -75,35 +75,36 @@ def reverse_record(self, _context, _record):
# there is no child structure member at pointed value.
except (IndexError, ValueError) as e:
log.debug('there is no child structure enclosing pointed value %0.8x - %s', value, e)
field.set_pointee_desc('MemoryHandler management space')
field.set_pointee_ctype('void')
field.name = 'ptr_void_%d' % field.offset
field.type.set_pointee_desc('MemoryHandler management space')
field.type.set_pointee_ctype('void')
field.name = 'ptr_void_%d' % field.type.offset
continue
# structure found
## log.debug('Looking at child id:0x%x str:%s', tgt.address, tgt.to_string())
# we always point on structure, not field
field.set_pointee_addr(tgt.address)
# FIXME this is really a meta pointer instance thing
field.type.set_pointee_addr(tgt.address)
offset = value - tgt.address
try:
tgt_field = tgt.get_field_at_offset(offset) # @throws IndexError
except IndexError as e:
# there is no field right there
log.debug('there is no field at pointed value %0.8x. May need splitting byte field - %s', value, e)
field.set_pointee_desc('Badly reversed field')
field.set_pointee_ctype('void')
field.name = 'ptr_void_%d' % field.offset
field.type.set_pointee_desc('Badly reversed field')
field.type.set_pointee_ctype('void')
field.name = 'ptr_void_%d' % field.type.offset
continue
# do not put exception for field 0. structure name should appears
# anyway.
field.set_pointee_desc('%s.%s' % (tgt.name, tgt_field.name))
field.type.set_pointee_desc('%s.%s' % (tgt.name, tgt_field.name))
# TODO:
# do not complexify code by handling target field type,
# lets start with simple structure type pointer,
# later we would need to use tgt_field.ctypes depending on field
# offset
field.set_pointee_ctype(tgt.name)
field.type.set_pointee_ctype(tgt.name)
# field.name = '%s_%s_%d' % (tgt.name, tgt_field.name, field.offset)
field.name = 'ptr_%s_%d' % (tgt.name, field.offset)
field.name = 'ptr_%s_%d' % (tgt.name, field.type.offset)
# all

_record.set_reverse_level(self._reverse_level)
Expand Down
12 changes: 6 additions & 6 deletions haystack/reverse/heuristics/reversers.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,9 +474,9 @@ def reverse_record(self, heap_context, _record):
# for child in struct.getPointerFields()) #target_struct_addr
# target_struct_addr

pointer_fields = [f for f in _record.get_fields() if f.is_pointer()]
pointer_fields = [f for f in _record.get_fields() if f.type.is_pointer()]
for f in pointer_fields:
pointee_addr = f._child_addr
pointee_addr = f.value # f._child_addr
# we always feed these two
# TODO: if a Node is out of heap/segment, replace it by a virtual node & color representing
# the foreign heap/segment
Expand Down Expand Up @@ -675,8 +675,8 @@ def reverse_context(self, _context):

def reverse_record(self, _context, _record):
for field in _record.get_fields():
addr = _record.address + field.offset
if field.is_string():
maxlen = len(field)
value = _record.get_value_for_field(field, maxlen+10)
addr = _record.address + field.type.offset
if field.type.is_string():
maxlen = len(field.type)
value = field.get_value_for_field(maxlen+10)
self.fout.write("0x%x,%d,%s\n" % (addr, maxlen, value))
3 changes: 2 additions & 1 deletion haystack/reverse/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ class %s(ctypes.Structure): # %s


# FIXME maybe instances field and record should have no name.
# __str__ should combinae type.name with @address
# __str__ should combine type.name with @address
class FieldInstance(object):
"""
The instance of a Field
Expand All @@ -571,6 +571,7 @@ def type(self):
return self._field_decl

def get_value_for_field(self, max_len=120):
# call the .value property instead
my_bytes = self.__get_value_for_field_inner(max_len)
if isinstance(my_bytes, str):
bl = len(str(my_bytes))
Expand Down
24 changes: 0 additions & 24 deletions scripts/haystack-gui

This file was deleted.

59 changes: 59 additions & 0 deletions test/haystack/reverse/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from __future__ import print_function

import logging
import unittest
import sys
try:
from unittest import mock
except ImportError:
import mock

from haystack.reverse import cli
from haystack.reverse import config

log = logging.getLogger("test_reverse_cli")


class TestReverseBasic(unittest.TestCase):

def setUp(self):
self.dumpname = 'dmp://./test/dumps/minidump/cmd.dmp'
config.remove_cache_folder(self.dumpname)

def tearDown(self):
config.remove_cache_folder(self.dumpname)

def test_reverse(self):
testargs = ["haystack-reverse", self.dumpname]
with mock.patch.object(sys, 'argv', testargs):
# no exception
cli.reverse()
# test cache/headers_values.py
# test cache/graph.gexf
# test cache/graph.heaps.gexf
# test cache/*.strings

def test_reverse_hex(self):
testargs = ["haystack-reverse-hex", self.dumpname, '0x543f60']
# TODO, make a hexdump like output ?
with mock.patch.object(sys, 'argv', testargs):
cli.reverse_hex()
# output is
# b'USERPROFILE=C:\\Documents and Settings\\UserName\x00\x00'

def test_reverse_parent(self):
testargs = ["haystack-reverse-parents", self.dumpname, '0x543f60']
with mock.patch.object(sys, 'argv', testargs):
cli.reverse_parents()
# not exception

def test_reverse_show(self):
testargs = ["haystack-reverse-show", self.dumpname, '0x543f60']
with mock.patch.object(sys, 'argv', testargs):
cli.reverse_show()
# not exception


if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
unittest.main(verbosity=2)

0 comments on commit 0197c69

Please sign in to comment.