def test_subtype(self): start = self.offsets['start_list'][0] _record = structure.AnonymousRecord(self.memory_handler, start, 40) word_size = self._target.get_word_size() f1 = fieldtypes.Field('f1', 0 * word_size, fieldtypes.ZEROES, word_size, False) f4 = fieldtypes.Field('f2', 3 * word_size, fieldtypes.ZEROES, word_size, False) # offset in the substruct fs2 = fieldtypes.PointerField('Back', 0, word_size) fs2.value = start fs3 = fieldtypes.PointerField('Next', 1 * word_size, word_size) fs3.value = start # the new field sub record new_field = fieldtypes.RecordField(_record, 1 * word_size, 'list', 'LIST_ENTRY', [fs2, fs3]) # fieldtypes.FieldType.makeStructField(_record, 1*word_size, 'LIST_ENTRY', [fs2, fs3], 'list') # add them fields = [f1, new_field, f4] #_record.add_fields(fields) _record_type = structure.RecordType('struct_text', 40, fields) _record.set_record_type(_record_type) self.assertEqual(len(_record), 40) f1, f2, f3 = _record.get_fields() self.assertEqual(len(f1), word_size) self.assertEqual(len(f2), word_size * 2) self.assertEqual(len(f3), word_size) self.assertEqual(f2.name, 'list') self.assertIsInstance(f2.field_type, fieldtypes.FieldTypeStruct) self.assertEqual(f2.field_type.name, 'LIST_ENTRY') print _record.to_string()
def test_save_record_type(self): process_context = self.memory_handler.get_reverse_context() _record = structure.AnonymousRecord(self.memory_handler, 0xdeadbeef, 40) word_size = self.my_target.get_word_size() f1 = fieldtypes.Field('f1', 0 * word_size, fieldtypes.ZEROES, word_size, False) f2 = fieldtypes.Field('f2', 1 * word_size, fieldtypes.ZEROES, word_size, False) fields = [f1, f2] _record_type = fieldtypes.RecordType('struct_test', 2 * word_size, fields) _record.set_record_type(_record_type) # same fields self.assertEqual(f1, _record.get_fields()[0].type) self.assertEqual(f1, _record.get_field('f1').type) # Check get_fields return a new list of fields x = _record.get_fields() self.assertEqual(x, _record.get_fields()) x.pop(0) self.assertNotEqual(x, _record.get_fields()) process_context.add_reversed_type(_record_type, [1, 2, 3]) r_types = list(process_context.list_reversed_types()) self.assertEqual(r_types[0].type_name, 'struct_test')
def setUpClass(cls): from haystack import dump_loader cls.memory_handler = dump_loader.load(zeus_856_svchost_exe.dumpname) cls.context = context.get_context_for_address(cls.memory_handler, 0x90000) cls.target = cls.memory_handler.get_target_platform() cls.zeroes = dsa.ZeroFields(cls.memory_handler) cls.utf16 = dsa.UTF16Fields(cls.memory_handler) cls.ascii = dsa.PrintableAsciiFields(cls.memory_handler) cls.ints = dsa.IntegerFields(cls.memory_handler) # new test from real case zeus.856 @0xb2e38 cls.real = '\xc81\x0b\x00\xa8*\x0b\x00\x01\x00\x00\x00\x00\x00\x00\x00f \x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\xe0\xa9`\x9dz3\xd0\x11\xbd\x88\x00\x00\xc0\x82\xe6\x9a\xed\x03\x00\x00\x01\x00\x00\x00\xc8\xfc\xbe\x02p\x0c\x00\x00\x08\x00\x00\x00\x1d\x00\x02\x00L\xfd\xbe\x02\xd8\x91\x1b\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x00S\x00V\x00P\x00 \x00T\x00C\x00P\x00 \x00S\x00e\x00r\x00v\x00i\x00c\x00e\x00 \x00P\x00r\x00o\x00v\x00i\x00d\x00e\x00r\x00\x00\x00f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\xe9\x90|\xf2\x94\x80|\x00P\xfd\x7f\x00\x00\x1c\x00\x08\x00\x00\x00\x00\x00\x00\x00t\xfc\xbe\x02\\\r\x91|\x00\x00\x1c\x00\x00\x00\xc3\x00\x00\x00\x00\x00\x88\xb0\xd2\x01\\\r\x91|\x00\x00\x1c\x00\x91\x0e\x91|\x08\x06\x1c\x00m\x05\x91|h^\xd0\x01\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\xc3\x00\x01\x00\x00\x000\x02\x1c\x00\x02\x00\x00\x00\x90\xb0\xd2\x01\x03\x00\x00\x00\x02\x00\x00\x00h^\xd0\x010\x02\x1c\x00\xd8>\xd4\x010\xf0\xfc\x00\xb8\x02\x1c\x00\xe8?\xd4\x01\xd8\x01\x1c\x00\x00\x00\x00\x00\x10\x00\x00\x00\xe8?\xd4\x01\x0c\x00\x00\x00\x05\x00\x00\x00\xf0\x06\x91|\xe0\x01\x1c\x00\x18\x00\x00\x00\xe0>\xd4\x01\x00\x00\x1c\x00\x01\x00\x00\x00\x08\x00\x00\x00\xe0\x01\x1c\x00@\x00\x00\x00\xf0?\xd4\x01\xa8\x04\x1c\x00\x00\x00\x1c\x00Om\x01\x01\x84^\xd0\x01`\x00\x00\x00\xb8\x02\x1c\x00\x00\x00\x00\x00\xd8>\xd4\x01\x88\xfc\xbe\x02F\x0f\x91|\r\x00\x00\x00\xd8>\xd4\x01\x00\x00\x1c\x00\x10<\xd4\x01\x00\x00\x00\x00\\\xfd\xbe\x02\\\r\x91|\x00\x00\x1c\x00\x91\x0e\x91|\x08\x06\x1c\x00m\x05\x91|`\xab\xf0\x00\x00\x00\x00\x00\xec<\xca\x02\x00\x00\xc3\x00\x0c\x00\x00\x00\x10<\xd4\x01\x00\x00\x00\x00\x00\x00\x00\x00\xd0\x0c\x00\x00\x00\x00\x00\x00\x18<\xd4\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\x0c\x00\x00(\xfd\xbe\x02\xa8\x04\x1c\x00\xd0\x0c\x00\x00@\x00\x00\x00\x03\x00\x00\x00\x18<\xd4\x01\xa8\x04\x1c\x00`\xab\xf0\x00\xc8\x02\x00\x00\xec<\xca\x02\x0c\x00\x0e\x00<V_u\x00\x00\x00\x00\xf8\xfc\xbe\x02\xec<\xca\x02\x00\x00\x00\x00`\xab\xf0\x00P\xfd\xbe\x02l\xfb\x90|q\xfb\x90|`\xab\xf0\x00\x00\x00\x00\x00\xec<\xca\x02,\xfd\xbe\x02%SystemRoot%\\system32\\rsvpsp.dll\x00\x003\x00B\x006\x004\x00B\x007\x00}\x00\x00\x00\xbe\x02\x05\x00\x00\x00\xe6-\xfd\x7f\x96\x15\x91|\xeb\x06\x91|\xa4\xfd\xbe\x02 8\xd4\x01\x10\x00\x00\x00\t\x04\x00\x00\x00\x01\x00\x00\xdc\xfa\xbe\x02\x00\x00\x00\x00\x96\x15\x91|\xeb\x06\x91|\x01\x00\x00\x00\xa4\xfd\xbe\x02\x04\x00\x00\x00\xaf\x9f\xd4w\xdc\xfa\xbe\x02\x05\x00\x00\x00\x96\x15\x91|\xeb\x06\x91|\x01\x00\x00\x00\xa4\xfd\xbe\x02\x96\x15\x91|\xeb\x06\x91|\x00\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\xeb\x06\x91|\x01\x00\x00\x00\xa4\xfd\xbe\x02\x01\x00\x00\x00\xff\xff\xff\xff\xd8\xa2\x92w\x08\xa3\x92w\xdc\xfa\xbe\x02\xd8\xfa\xbe\x02\x02\x00\x00\x80\x9c\xfa\xbe\x02\x90\x01\x1c\x00\xb0\x01\x00\x00\xe4\xfa\xbe\x02\xff\xff\xff\xff\xe0\xfc\xbe\x02\xab\xa5\x92wh^\xd0\x01\xdc\xfa\xbe\x02\x88\x01\x1c\x00\x00\x00\xc3\x00\x01\x00\x00\x00\x96\x15\x91|\x00\x00\x00\x00' cls.test1 = structure.AnonymousRecord(cls.memory_handler, 0xb2e38, 904, prefix=None) cls.test2 = structure.AnonymousRecord(cls.memory_handler, 0xb2e38 + 636, 100, prefix=None) pass
def test_utf_16_le_null_terminated_3(self): ''' null terminated ''' # in putty.7124.dump vaddr = 0x657488 size = 88 st = structure.AnonymousRecord(self.memory_handler, vaddr, size) self.dsa.reverse_record(self.context, st) # print repr(st.bytes) log.debug(st.to_string()) fields = st.get_fields() self.assertEquals(len([_ for _ in fields]), 2) # should be 3 Lt0? self.assertEquals(fields[0].field_type, fieldtypes.STRING16) self.assertTrue(fields[0].is_string())
def test_ascii_null_terminated_2(self): """ null terminated """ # struct_64f328 in putty.7124.dump vaddr = 0x64f328 size = 72 st = structure.AnonymousRecord(self.memory_handler, vaddr, size) self.dsa.reverse_record(self.context, st) # print repr(st.bytes) log.debug(st.to_string()) fields = st.get_fields() self.assertEquals(len([_ for _ in fields]), 5) self.assertEquals(fields[3].field_type, fieldtypes.STRINGNULL) self.assertTrue(fields[3].is_string())
def test_utf_16_le_non_null_terminated(self): """ non-null terminated """ # struct_691ed8 in putty.7124.dump vaddr = 0x691ed8 size = 256 st = structure.AnonymousRecord(self.memory_handler, vaddr, size) self.dsa.reverse_record(self.context, st) # print repr(st.bytes) log.debug(st.to_string()) fields = st.get_fields() self.assertEquals(len([_ for _ in fields]), 2) self.assertEquals(fields[1].field_type, fieldtypes.STRING16) self.assertTrue(fields[1].is_string())
def test_big_block_2(self): # in putty.7124.dump # its garbage anyway vaddr = 0x675b30 size = 8184 st = structure.AnonymousRecord(self.memory_handler, vaddr, size) self.dsa.reverse_record(self.context, st) # print repr(st.bytes) log.debug(st.to_string()) fields = st.get_fields() self.assertLess(len([_ for _ in fields]), 890) #self.assertEquals( fields[35].field_type.name, fieldtypes.STRINGNULL) #self.assertTrue( fields[35].isString()) fields = [f for f in st.get_fields() if f.is_string()]
def reverse_record(self, _context, _record): i, (ptr_value, size) = _record if ptr_value in self._done_records: sys.stdout.write('.') sys.stdout.flush() return self._loaded += 1 if size < 0: log.error("Negative allocation size") mystruct = structure.AnonymousRecord(_context.memory_handler, ptr_value, size) _context._structures[ptr_value] = mystruct # cache to disk mystruct.saveme(_context) return
def test_uuid(self): ''' null terminated ''' # in putty.7124.dump vaddr = 0x63aa68 size = 120 st = structure.AnonymousRecord(self.memory_handler, vaddr, size) self.dsa.reverse_record(self.context, st) # print repr(st.bytes) log.debug(st.to_string()) fields = st.get_fields() self.assertEquals(len([_ for _ in fields]), 3) self.assertEquals(fields[1].field_type, fieldtypes.STRING16) self.assertTrue(fields[1].is_string()) pass
def test_equals(self): start = self.offsets['start_list'][0] _record = structure.AnonymousRecord(self.memory_handler, start, 40) word_size = self._target.get_word_size() f1 = fieldtypes.Field('f1', 0 * word_size, fieldtypes.ZEROES, word_size, False) f2 = fieldtypes.Field('f2', 1 * word_size, fieldtypes.ZEROES, word_size, False) fields = [f1, f2] _record_type = structure.RecordType('struct_text', 2 * word_size, fields) _record.set_record_type(_record_type) self.assertEqual(f1, _record.get_fields()[0]) self.assertEqual(f1, _record.get_field('f1'))
def test_utf_16_le_null_terminated(self): # struct_682638 in putty.7124.dump vaddr = 0x682638 size = 184 st = structure.AnonymousRecord(self.memory_handler, vaddr, size) self.dsa.reverse_record(self.context, st) # print repr(st.bytes) log.debug(st.to_string()) fields = st.get_fields() self.assertEquals(len([_ for _ in fields]), 5) # TODO should be 6 fields lllttp self.assertEquals(fields[2].field_type, fieldtypes.STRING16) self.assertTrue(fields[2].is_string()) # TODO fields[3] should start at offset 12, not 10. self.assertEquals(fields[3].field_type, fieldtypes.STRING16) self.assertTrue(fields[3].is_string())
def test_big_block(self): ''' null terminated ''' # in putty.7124.dump vaddr = 0x63d4c8 # + 1968 size = 4088 # 128 st = structure.AnonymousRecord(self.memory_handler, vaddr, size) self.dsa.reverse_record(self.context, st) # print repr(st.bytes) log.debug(st.to_string()) fields = st.get_fields() self.assertLess(len([_ for _ in fields]), 879) #self.assertEquals( fields[35].field_type.name, fieldtypes.STRINGNULL) #self.assertTrue( fields[35].isString()) strfields = [f for f in st.get_fields() if f.is_string()] # for f in strfields: # print f.toString(), self.assertGreater(len(strfields), 30)
def test_get_fields(self): _record = structure.AnonymousRecord(self.memory_handler, 0xdeadbeef, 40) word_size = self.target.get_word_size() f1 = fieldtypes.Field('f1', 0*word_size, fieldtypes.ZEROES, word_size, False) f2 = fieldtypes.Field('f2', 1*word_size, fieldtypes.ZEROES, word_size, False) fields = [f1, f2] _record_type = fieldtypes.RecordType('struct_test', 2 * word_size, fields) _record.set_record_type(_record_type) # same fields self.assertEqual(f1, _record.get_fields()[0].type) self.assertEqual(f1, _record.get_field('f1').type) # get_fields return a new list of fields x = _record.get_fields() self.assertEqual(x, _record.get_fields()) x.pop(0) self.assertNotEqual(x, _record.get_fields())
def verify(self, _record_type, members): records = [] lines = [] # try to apply the fields template to all members of the list for list_item_addr in members: _context = self.__process_context.get_context_for_address( list_item_addr) _item = _context.get_record_for_address(list_item_addr) new_record = structure.AnonymousRecord(self.__memory_handler, _item.address, len(_item), name=None) new_record.set_record_type(_record_type, True) records.append(new_record) lines.append('# instances: [%s]' % (','.join(['0x%x' % addr for addr in members]))) # check fields values for i, field_decl in enumerate(_record_type.get_fields()): if field_decl.is_record(): # we ignore the subrecord. is too complicated to show. continue values = [] for record in records: # get the field instance field_instance = record.get_field(field_decl.name) val = field_instance.value if field_decl.is_pointer(): values.append(hex(val)) else: values.append(val) if field_decl.is_zeroes() and len(values) == 1: values = [0] # ignore the field in that case. continue counter = Counter(values) # print 'field: %s values: %s' % (field.name, counter) lines.append('# field: %s values: %s' % (field_decl.name, counter)) return lines
def verify(self, _record_type, members): records = [] lines = [] # try to apply the fields template to all members of the list for list_item_addr in members: heap = self.__memory_handler.get_mapping_for_address( list_item_addr) _context = self.__process_context.get_context_for_heap(heap) _item = _context.get_record_for_address(list_item_addr) new_record = structure.AnonymousRecord(self.__memory_handler, _item.address, len(_item), prefix=None) new_record.set_record_type(_record_type, True) records.append(new_record) # check fields values for i, field in enumerate(_record_type.get_fields()): if field.is_record(): # we ignore the subrecord. is too complicated to show. continue values = [] for _item in records: val = _item.get_value_for_field(field) if field.is_pointer(): values.append(hex(val)) else: values.append(val) if field.is_zeroes() and len(values) == 1: values = [0] # ignore the field in that case. continue counter = Counter(values) # print 'field: %s values: %s' % (field.name, counter) lines.append('# field: %s values: %s' % (field.name, counter)) return lines