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 reverse_record(self, _context, _record): if not _record.resolvedPointers: raise ValueError('I should be resolved') _record._dirty = True _record._fields.sort() myfields = [] signature = _record.get_type_signature() pencoder = pattern.PatternEncoder(signature, minGroupSize=2) patterns = pencoder.makePattern() txt = _record.get_type_signature(text=True) p = pattern.findPatternText(txt, 1, 2) log.debug('substruct typeSig: %s' % txt) log.debug('substruct findPatterntext: %s' % p) log.debug('substruct came up with pattern %s' % patterns) # pattern is made on FieldType, # so we need to dequeue _record.fields at the same time to enqueue in # myfields for nb, fieldTypes in patterns: if nb == 1: field = _record._fields.pop(0) myfields.append(field) # single el # log.debug('simple field:%s '%(field) ) elif len(fieldTypes) > 1: # array of subtructure DEBUG XXX TODO log.debug('fieldTypes:%s' % fieldTypes) log.debug('substructure with sig %s', ''.join([ft.sig[0] for ft in fieldTypes])) myelements = [] for i in range(nb): fields = [ _record._fields.pop(0) for i in range(len(fieldTypes)) ] # nb-1 left # otherFields = [ _record.fields.pop(0) for i in range((nb-1)*len(fieldTypesAndSizes)) ] # need global ref to compare substructure signature to # other anonstructure firstField = fieldtypes.RecordField( _record, fields[0].offset, 'unk', 'typename', fields) myelements.append(firstField) array = fieldtypes.ArrayField(myelements) myfields.append(array) # log.debug('array of structure %s'%(array)) # make array of elements obase on same base type elif len(fieldTypes) == 1: log.debug('found array of %s', _record._fields[0].typename.basename) fields = [_record._fields.pop(0) for i in range(nb)] array = fieldtypes.ArrayField(fields) myfields.append(array) # log.debug('array of elements %s'%(array)) else: # TODO DEBUG internal struct raise ValueError('fields patterns len is incorrect %d' % (len(fieldTypes))) log.debug('done with findSubstructure') _record._fields = myfields # print 'final', _record.fields return
def get_fields(self): """ Return the reversed fields for this record :return: list(Field) """ # we have to check for RecordField # return [f for f in self.__record_type.get_fields()] from haystack.reverse import fieldtypes _fields = [] for f in self.__record_type.get_fields(): if f.is_record(): _fields.append(fieldtypes.RecordField(self, f.offset, f.name, f.field_type.name, f.get_fields())) else: _fields.append(f) return _fields
def reverse_record(self, _context, _record): """ Aggregate fields of similar type into arrays in the record. """ if _record.get_reverse_level() < 30: raise ValueError('The record reverse level needs to be >30') log.debug('0x%x: %s', _record.address, _record.get_signature_text()) _record._dirty = True _record._fields.sort() myfields = [] signature = _record.get_signature() pencoder = pattern.PatternEncoder(signature, minGroupSize=3) patterns = pencoder.makePattern() #txt = self.getSignature(text=True) #log.warning('signature of len():%d, %s'%(len(txt),txt)) #p = pattern.findPatternText(txt, 2, 3) # log.debug(p) #log.debug('aggregateFields came up with pattern %s'%(patterns)) # pattern is made on FieldType, # so we need to dequeue self.fields at the same time to enqueue in # myfields for nb, fieldTypesAndSizes in patterns: # print 'fieldTypesAndSizes:',fieldTypesAndSizes if nb == 1: fieldType = fieldTypesAndSizes[0] # its a tuple field = _record._fields.pop(0) myfields.append(field) # single el #log.debug('simple field:%s '%(field) ) # array of subtructure DEBUG XXX TODO elif len(fieldTypesAndSizes) > 1: log.debug('substructure with sig %s' % (fieldTypesAndSizes)) myelements = [] for i in range(nb): fields = [ _record._fields.pop(0) for i in range(len(fieldTypesAndSizes)) ] # nb-1 left #otherFields = [ self.fields.pop(0) for i in range((nb-1)*len(fieldTypesAndSizes)) ] # need global ref to compare substructure signature to # other anonstructure firstField = fieldtypes.RecordField( _record, fields[0].offset, 'unk', 'typename', fields) myelements.append(firstField) array = fieldtypes.ArrayField(myelements) myfields.append(array) #log.debug('array of structure %s'%(array)) elif len(fieldTypesAndSizes) == 1: # make array of elements or log.debug("found array of %s", _record._fields[0].typename.basename) fields = [_record._fields.pop(0) for i in range(nb)] array = fieldtypes.ArrayField(fields) myfields.append(array) #log.debug('array of elements %s'%(array)) else: # TODO DEBUG internal struct raise ValueError("fields patterns len is incorrect %d" % len(fieldTypesAndSizes)) log.debug('done with aggregateFields') _record.reset() # _record.add_fields(myfields) _record_type = structure.RecordType('struct_%x' % _record.address, len(_record), myfields) _record.set_record_type(_record_type) _record.set_reverse_level(self._reverse_level) # print 'final', self.fields log.debug('0x%x: %s', _record.address, _record.get_signature_text()) return
def rename_record_type(self, _members, offset): """ Change the type of the 2 pointers to a substructure. Rename the field to reflect this . Rename the _record ? :param _context: :param _members: :param offset: :param head_addr: :return: """ # we look at each item and get the most common signature between all items best_member = self.find_common_type_signature(_members) # use member[1] instead of head, so that we have a better chance for field types. # in head, back pointer is probably a zero value, not a pointer field type. _context = self._process_context.get_context_for_address(best_member) _record = _context.get_record_for_address(best_member) # we need two pointer fields to create a substructure. ## Check if field at offset is a pointer, If so change it name, otherwise split old_next = _record.get_field_at_offset(offset) old_back = _record.get_field_at_offset(offset + self._word_size) # next_field = fieldtypes.PointerField('Next', 0, self._word_size) back_field = fieldtypes.PointerField('Back', self._word_size, self._word_size) sub_fields = [next_field, back_field] # make a substructure new_field = fieldtypes.RecordField(_record, offset, 'list', 'LIST_ENTRY', sub_fields) fields = [x for x in _record.get_fields()] fields.remove(old_next) if old_next == old_back: # its probably a LIST_ENTRY btw. log.debug("old_next == old_back, aborting") return _record.record_type fields.remove(old_back) fields.append(new_field) fields.sort() # create a new type head_addr = _members[0] _record_type = structure.RecordType('list_%x' % head_addr, len(_record), fields) log.debug("Created Record Type %s", _record_type.to_string()) # 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) ### KEEP THIS if len(_item) != len(_record): log.warning("x2 linked reverser: len(_item) != len(_record)") else: _item.set_record_type(_record_type, True) # push the LIST_ENTRY type into the context/memory_handler rev_context = self._memory_handler.get_reverse_context() rev_context.add_reversed_type(_record_type, _members) # change the list_head name back _context = self._process_context.get_context_for_address(head_addr) _context.get_record_for_address(head_addr).set_name('list_head') return _record_type