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 = structure.RecordType('struct_test', 2 * word_size, fields) _record.set_record_type(_record_type) # same fields self.assertEqual(f1, _record.get_fields()[0]) self.assertEqual(f1, _record.get_field('f1')) # 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 = process_context.list_reversed_types() self.assertEqual(r_types[0].name, 'struct_test')
def __init__(self, parent, offset, field_name, field_type, fields): size = sum([len(f) for f in fields]) _address = parent.address + offset structure.AnonymousRecord.__init__(self, parent._memory_handler, _address, size, prefix=None) Field.__init__(self, field_name, offset, FieldTypeStruct(field_type), size, False) structure.AnonymousRecord.set_name(self, field_name) #structure.AnonymousRecord.add_fields(self, fields) _record_type = structure.RecordType(field_type, size,fields) self.set_record_type(_record_type) return
def reverse_record(self, _context, _record): _record.reset() fields, gaps = self._analyze(_record) # _record.add_fields(fields) # _record.add_fields(gaps) # , fieldtypes.UNKNOWN _record_type = structure.RecordType('struct_%x' % _record.address, len(_record), fields + gaps) _record.set_record_type(_record_type) _record.set_reverse_level(self._reverse_level) return _record
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_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 = structure.RecordType('struct_test', 2*word_size, fields) _record.set_record_type(_record_type) # same fields self.assertEqual(f1, _record.get_fields()[0]) self.assertEqual(f1, _record.get_field('f1')) # 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 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