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 _aligned_gaps(self, _record, endoffset, nextoffset, gaps): """ if nextoffset is aligned add a gap to gaps, or if nextoffset is not aligned add (padding + gap) to gaps """ if nextoffset % self._word_size == 0: gap = fieldtypes.Field('gap_%d' % nextoffset, nextoffset, fieldtypes.UNKNOWN, endoffset - nextoffset, False) log.debug('_make_gaps: adding field at offset %d:%d', gap.offset, gap.offset + len(gap)) gaps.append(gap) else: # we need a field of endoffset - nextoffset bytes. # unaligned field should be splitted size = endoffset - nextoffset if size < self._word_size: s1 = size else: s1 = size - size % self._word_size gap1 = fieldtypes.Field('gap_%d' % nextoffset, nextoffset, fieldtypes.UNKNOWN, s1, True) log.debug('_make_gaps: Unaligned field at offset %d:%d', gap1.offset, gap1.offset + len(gap1)) gaps.append(gap1) if nextoffset + s1 < endoffset: gap2 = fieldtypes.Field('gap_%d' % (nextoffset + s1), nextoffset + s1, fieldtypes.UNKNOWN, endoffset - nextoffset - s1, True) log.debug('_make_gaps: adding field at offset %d:%d', gap2.offset, gap2.offset + len(gap2)) gaps.append(gap2) return
def make_fields(self, _record, offset, size): # vaddr and offset should be aligned assert (offset % self._word_size == 0) # log.debug('checking String') fields = [] _bytes = _record.bytes while size >= self._word_size: # print 're_string.find_ascii(bytes, %d, %d)'%(offset,size) index, ssize = re_string.find_ascii(_bytes, offset, size) if index == 0: _offset = offset + index if (ssize < size) and _bytes[offset + index + ssize] == '\x00': # space for a \x00 ssize += 1 f = fieldtypes.Field('strnull_%d' % _offset, _offset, fieldtypes.STRINGNULL, ssize, False) else: f = fieldtypes.Field('str_%d' % _offset, _offset, fieldtypes.STRING, ssize, False) # print repr(structure.bytes[f.offset:f.offset+f.size]) fields.append(f) size -= ssize # reduce unknown field offset += ssize if ssize % self._word_size: rest = self._word_size - ssize % self._word_size size -= rest # goto next aligned offset += rest else: size -= self._word_size # reduce unkown field offset += self._word_size # look in head return fields
def test_gaps(self): g1 = fieldtypes.Field('gap_0', 0, fieldtypes.UNKNOWN, 1, False) self.assertEqual(len(g1), 1) self.assertTrue(g1.is_gap()) print g1.to_string('\x00\x00\x00\x00') self.assertIn('ctypes.c_ubyte*1 )', g1.to_string('\x00\x00\x00\x00')) g2 = fieldtypes.Field('gap_0', 0, fieldtypes.UNKNOWN, 2, False) self.assertEqual(len(g2), 2) self.assertIn('ctypes.c_ubyte*2 )', g2.to_string('\x00\x00\x00\x00'))
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 _make_gaps(self, _record, fields): fields.sort() gaps = [] nextoffset = 0 for i, f in enumerate(fields): if f.offset > nextoffset: # add temp padding field self._aligned_gaps(_record, f.offset, nextoffset, gaps) elif f.offset < nextoffset: log.debug(_record) log.debug(f) log.debug('%s < %s ' % (f.offset, nextoffset)) log.debug(fields[i + 1]) log.error("need to TU the fields gap with utf8 text") assert False # f.offset < nextoffset # No overlaps authorised # fields.remove(f) # do next field nextoffset = f.offset + len(f) # conclude on QUEUE insertion lastfield_size = len(_record) - nextoffset if lastfield_size > 0: if lastfield_size < self._word_size: gap = fieldtypes.Field('gap_%d' % nextoffset, nextoffset, fieldtypes.UNKNOWN, lastfield_size, True) log.debug('_make_gaps: adding last field at offset %d:%d', gap.offset, gap.offset + len(gap)) gaps.append(gap) else: self._aligned_gaps(_record, len(_record), nextoffset, gaps) return gaps
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 check_small_integers(self, my_bytes, offset, endianess='<'): """ check for small value in signed and unsigned forms """ data = my_bytes[offset:offset + self._word_size] val = self._target.get_target_ctypes_utils().unpackWord( data, endianess) # print endianess, val if val < 0xffff: field = fieldtypes.Field('small_int_%d' % offset, offset, fieldtypes.SMALLINT, self._word_size, False) # FIXME field.value = val field.endianess = endianess return field # check signed int elif (2**(self._word_size * 8) - 0xffff) < val: _name = 'small_signed_int_%d' % offset field = fieldtypes.Field(_name, offset, fieldtypes.SIGNED_SMALLINT, self._word_size, False) # FIXME field.value = val field.endianess = endianess return field return None
def make_fields(self, _record, offset, size): assert (offset % self._word_size == 0 ) # vaddr and offset should be aligned # log.debug('checking String') fields = [] _bytes = _record.bytes while size > self._word_size: # print 're_string.rfind_utf16(bytes, %d, %d)'%(offset,size) # we force aligned results only. otherwise er have overlaps index = re_string.rfind_utf16(_bytes, offset, size, False, self._word_size) if index > -1: _offset = offset + index f = fieldtypes.Field('utf16_%d' % _offset, _offset, fieldtypes.STRING16, size - index, False) # print repr(structure.bytes[f.offset:f.offset+f.size]) fields.append(f) size = index # reduce unknown field in prefix else: size -= self._word_size # reduce unkown field # look in head return fields
def _analyze(self, _record): slen = len(_record) offset = 0 # call on analyzers fields = [] nb = -1 gaps = [ fieldtypes.Field('unknown_0', 0, fieldtypes.UNKNOWN, len(_record), False) ] _record.set_reverse_level(10) # find zeroes # find strings # find smallints # find pointers for analyser in [ self.zero_a, self.utf16_a, self.ascii_a, self.int_a, self.ptr_a ]: log.debug("analyzing with %s", analyser) for field in gaps: if field.padding: fields.append(field) continue log.debug('Using %s on %d:%d', analyser.__class__.__name__, field.offset, field.offset + len(field)) new_fields = analyser.make_fields(_record, field.offset, len(field)) fields.extend(new_fields) for f1 in new_fields: log.debug('new_field %s', f1) # print fields if len(fields) != nb: # no change in fields, keep gaps nb = len(fields) gaps = self._make_gaps(_record, fields) if len(gaps) == 0: return fields, gaps return fields, gaps