def reload_odb(self): if self.sjob.reloaded: return # ensure we only do this once self.sjob.reloaded = True self.sjob.save() logger.info('Reloading odb for job %s' % self.name) orig_binary_file = self.oda_master.odb_file.binary # get the procdump file f = api.get_procdump(self.sjob.server, self.sjob.task_id) f.name = self.oda_master.odb_file.binary.name binary_file = BinaryFile.create(f) binary_file.save() bfm = BinaryFileModel(binary_file.id) options = orig_binary_file.options # TODO: set the target to a new target type called 'cuckoo' or something and add support in ofd options.target = 'lime' bfm.options = options odb_file = OdbFile(bfm) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) self.oda_master.odb_file = odb_file self.oda_master.save()
def test_total_lines(self): odb_file = OdbFile(BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) dasm = Disassembler(odb_file) total_lines = dasm.total_lines() self.assertEquals(41614, total_lines)
def test_add_bad_vma_fails(self): odb_file = OdbFile() op1 = CreateFunctionOperation(TEST_VMA, TEST_NAME, sym_type='U') odb_file.execute(op1) op2 = CreateFunctionOperation(TEST_VMA, TEST_NAME2, sym_type='U') self.assertRaises(ValidationError, odb_file.execute, op2)
def test_load_string_arm(self): s = '01 20 40 E2 02 20 61 E0 01 30 D1 E4 00 00 53 E3 02 30 C1 E7 FB FF FF 1A 1E FF 2F E1' odb_file = OdbFile(BinaryString(s, 'arm')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) self.assertEqual(1, len(odb_file.get_structure_list(Branch)))
def test_decompile_by_addr_nonexistent(self): odb_file = OdbFile( BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) decompiler = OdaDecompiler(odb_file) with self.assertRaises(OdaDecompilerException): decompiler.decompile(0x306b26)
def undo_not_last_fails(self): odb_file = OdbFile() op1 = CreateFunctionOperation(TEST_VMA, TEST_NAME, sym_type='U') odb_file.execute(op1) op2 = CreateFunctionOperation(TEST_VMA2, TEST_NAME2, sym_type='U') odb_file.execute(op2) self.assertRaises(Exception, op1.undo, odb_file)
def test_serialize(self): odb_file = OdbFile( BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) serialized = DefaultOdbSerializer().dumps(odb_file) loaded_odb_file = DefaultOdbSerializer().load(serialized) self.assertEqual(len(odb_file.get_structure_list(Function)), len(loaded_odb_file.get_structure_list(Function)))
def test_add(self): odb_file = OdbFile() odb_file.execute(CreateFunctionOperation(TEST_VMA, TEST_NAME)) self.assertEquals(1, len(odb_file.get_structure_list(Function))) f = odb_file.get_structure_list(Function)[0] self.assertEquals(TEST_NAME, f.name) odb_file.operations[-1].undo(odb_file) self.assertEquals(0, len(odb_file.get_structure_list(Function)))
def test_decompile_by_addr_good(self): odb_file = OdbFile( BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) decompiler = OdaDecompiler(odb_file) results = decompiler.decompile(0x406b26) self.assertEquals(0x4067A0, results.start) self.assertEquals(0x406BC0, results.end) self.assertNotEquals("", results.source)
def test_basic_scan(self): odb_file = OdbFile( BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) self.assertEqual(215, len(odb_file.get_structure_list(Function))) for f in odb_file.get_structure_list(Function): print(f.name) self.assertEqual(2814, len(odb_file.get_structure_list(Branch)))
def test_load_and_get(self): s = '01 20 40 E2 02 20 61 E0 01 30 D1 E4 00 00 53 E3 02 30 C1 E7 FB FF FF 1A 1E FF 2F E1' odb = OdbFile(BinaryString(s, 'arm')) odb.execute(LoadOperation()) binary = odb.get_binary() options = binary.options self.assertEquals("arm", options.architecture) self.assertEquals(0, options.base_address) self.assertEquals('binary', options.target)
def test_basic_binary_loader(self): odb_file = OdbFile( BinaryFile(self.get_test_bin_path('ls.bin.x86-64'), 'binary', 'i386:x86-64')) odb_file.execute(LoadOperation()) self.assertEquals(1, len(odb_file.get_structure_list(Section))) self.assertEquals(0, len(odb_file.get_structure_list(Symbol))) self.assertEquals(0, len(odb_file.get_structure_list(Function))) self.assertEquals(857, len(odb_file.get_structure_list(DataString)))
def test_load_string(self): s = '55 31 D2 89 E5 8B 45 08 56 8B 75 0C 53 8D 58 FF 0F B6 0C 16 88 4C 13 01 83 C2 01 84 C9 75 F1 5B 5E 5D C3' odb_file = OdbFile(BinaryString(s, 'i386')) odb_file.execute(LoadOperation()) passive_scan_operation = PassiveScanOperation() odb_file.execute(passive_scan_operation) self.assertEqual(1, len(odb_file.get_structure_list(Branch))) self.assertEqual(1, len(odb_file.get_structure_list(Parcel))) self.assertEqual(0, odb_file.get_structure_list(Parcel)[0].vma_start) self.assertEqual(35, odb_file.get_structure_list(Parcel)[0].vma_end)
def test_analyzer_output(self): odb_file = OdbFile(BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) dasm = Disassembler(odb_file) # Disassemble at a provided vma units = dasm.display(0x4095e0, 200, False) # The provided address should be the first instruction self.assertEquals(0x4095e0, units[0].vma) self.assertEquals("mov", units[0].opcode) # Another random instruction self.assertEquals("test", units[18].opcode) self.assertEquals("al,al", units[18].operands) # Disassemble at a provided negative vma units = dasm.display(0x4095e0, -10, False) # The provided address should be the last instruction self.assertEquals(0x4095e0, units[9].vma) self.assertEquals("mov", units[9].opcode) # IDA finds this one through a function pointer in data section # self.assertEquals(True, units[9].isFunction) # 9 instructions earlier self.assertEquals(0x4095BB, units[0].vma) self.assertEquals("call", units[0].opcode) # Disassemble a function units = dasm.display(0x40BEE0, 10, False) self.assertEquals(True, units[0].isFunction) # Cross Parcel Boundaries units = dasm.display(0x412BF4, -10, False) self.assertEquals(0x412BF4, units[9].vma) self.assertEquals("ret", units[9].opcode) self.assertEquals(".fini", units[9].section_name) self.assertEquals(0x412BE1, units[2].vma) self.assertEquals("jmp", units[2].opcode) self.assertEquals(".text", units[2].section_name) # Cross Code/Data Boundaries units = dasm.display(0x412BF4, 10, False) self.assertEquals(0x412BF4, units[0].vma) self.assertEquals(0x412C00, units[1].vma) self.assertEquals(1, units[1].dataSize)
def test_multiple_add(self): odb_file = OdbFile() op1 = CreateFunctionOperation(TEST_VMA, TEST_NAME, sym_type='U') odb_file.execute(op1) op2 = CreateFunctionOperation(TEST_VMA2, TEST_NAME2, sym_type='U') odb_file.execute(op2) self.assertEquals(2, len(odb_file.get_structure_list(Function))) op2.undo(odb_file) self.assertEquals(1, len(odb_file.get_structure_list(Function))) self.assertEquals(TEST_NAME, odb_file.get_structure_list(Function)[ 0].name) op1.undo(odb_file) self.assertEquals(0, len(odb_file.get_structure_list(Function)))
def test_basic_graph_nodes(self): # we load this ELF as a raw binary, because it has an invalid opcode fairly early on odb_file = OdbFile( BinaryFile(self.get_test_bin_path('mkdir'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) bgv = BranchGraphView(odb_file, 0x401980) expectedNodes = [ BranchGraphNode(0x401980, 0x401990, 0x12, 0x4019dd, 0x401992), BranchGraphNode(0x401992, 0x4019b0, 0x20, 0x4019d6, 0x4019b2), BranchGraphNode(0x4019b2, 0x4019b2, 0x06, 0x4019b8, None), BranchGraphNode(0x4019b8, 0x4019d4, 0x1e, 0x4019b8, 0x4019d6), BranchGraphNode(0x4019d6, 0x4019d6, 0x07, 0x4019dd, None), BranchGraphNode(0x4019dd, 0x4019e4, 0x13, None, None), ] self.assertCountEqual(expectedNodes, bgv._nodes.values())
def test_basic_loader(self): odb_file = OdbFile( BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) self.assertEquals(26, len(odb_file.get_structure_list(Section))) self.assertEquals(120, len(odb_file.get_structure_list(Symbol))) self.assertEquals(2, len(odb_file.get_structure_list(Function))) self.assertEquals( 1, len([ x for x in odb_file.get_structure_list(Function) if x.name == '_init' ])) self.assertEquals( 1, len([ x for x in odb_file.get_structure_list(Function) if x.name == '_fini' ])) self.assertEquals(1304, len(odb_file.get_structure_list(DataString))) self.assertEquals( 1, len([ s for s in odb_file.get_structure_list(DataString) if s.value == 'hide-control-chars' ])) self.assertEquals( 1, len([ s for s in odb_file.get_structure_list(DataString) if s.value == 'error initializing month strings' ]))
def partial_update(self, request, pk): oda_master = OdaMaster.objects.get( short_name=request.data['short_name'], revision=request.data['revision']) previous_odb = oda_master.odb_file try: odb_file = OdbFile( BinaryString(request.data['binary_string'], previous_odb.get_binary().options.architecture)) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) except (TypeError, UnicodeDecodeError, UnicodeEncodeError): return HttpResponseNotAllowed('Invalid hex digits') oda_master.odb_file = odb_file oda_master.save() logger.info("updating...") return Response({'binary_string': request.data['binary_string']})
def test_add(self): odb_file = OdbFile() item = odb_file.execute(CreateCStructOperation('simpleStruct', True)) builtin = BuiltinTypeFactory('uint8_t') item.append_field( BuiltinField(name='Field1',oda_type=builtin) ) item.append_field( BuiltinField(name='Field2',oda_type=builtin) ) item.append_field( BuiltinField(name='Field3',oda_type=builtin) ) self.assertEquals(3, item.size) self.assertEquals(1, len(odb_file.get_structure_list(CStruct)))
def load_examples(owner=None): EXAMPLES_DIR = os.path.join( os.path.dirname(oda.apps.odaweb.examples.__file__), 'examples') for example in Examples: short_name = example['short_name'] valid_file_storage_id = True if OdaMaster.objects.filter(short_name=short_name).exists(): print('Example %s already exists in the database' % short_name) oda_master = OdaMaster.objects.filter( short_name=short_name).first() else: oda_master = OdaMaster( short_name=short_name, project_name=example['project_name'], owner=owner, default_permission=OdaMasterPermissionLevel.read.value) print('Adding example %s to database' % short_name) if 'data' in example: example_data = ''.join(example['data'].split()) odb_file = OdbFile( BinaryString(example_data, example['options']['architecture'])) elif 'file_name' in example: odb_file = OdbFile( BinaryFile(os.path.join(EXAMPLES_DIR, example['file_name']), example['options']['target'], example['options']['architecture'])) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) if 'comments' in example: for vma, msg in example['comments']: odb_file.execute(CreateCommentOperation(vma, msg)) print("Adding Comment %s To %s" % (msg, str(odb_file))) if 'labels' in example: for vma, label in example['labels']: odb_file.execute(CreateLabelOperation(vma, label)) print("Saving label %s To %s" % (label, str(odb_file))) oda_master.odb_file = odb_file oda_master.save()
def failing_test_follow_jmps_i386(self): odb_file = OdbFile( BinaryFile( self.get_test_bin_path( 'active_scan_follow_jmps/active_scan_follow_jmps.bin'), 'binary', 'i386')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) parcels_before = ParcelList(odb_file.get_structure_list(Parcel)) # number of parcels before the split self.assertEquals(1, len(parcels_before)) # execute the active scan operation odb_file.execute(ActiveScanOperation(0x0)) # number of parcels after the split parcels_after = ParcelList(odb_file.get_structure_list(Parcel)) self.assertEquals(11, len(parcels_after))
def helper_import_idb(self, fname, arch, target): # django configuration requires input file to be in /tmp, so copy there idb_path = NamedTemporaryFile(dir=settings.MEDIA_ROOT, delete=False).name copy(self.get_test_bin_path('idb/%s' % fname), idb_path) # verify we have a valid .idb file idbImport = IdbImport(open(idb_path, "rb")) self.assertTrue(idbImport.is_idb()) # guess the architecture correctly actual_arch, actual_target = idbImport.guess_arch() self.assertEqual(arch, actual_arch) self.assertEqual(target, actual_target) # reconstruct as ELF elfPath = idbImport.reconstruct_elf() self.assertIsNotNone(elfPath) # create the binary file binary_file = BinaryFile.create_from_idb(File(open(idb_path, "rb"))) binary_file.binary_options.architecture = arch binary_file.binary_options.target = target binary_file.binary_options.save() binary_file.save() # create the ODB file odb_file = OdbFile(BinaryFileModel(binary_file.id)) odb_file.binary.set_the_file(File(open(elfPath, "rb"))) odb_file.execute(IdbImportOperation()) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) return odb_file
def partial_update(self, request, pk): oda_master = OdaMaster.objects.get( short_name=request.data['short_name'], revision=request.data['revision']) arch = request.data.get('architecture') ba = request.data.get('base_address', 0) base_address = hex(ba) if ba else 0 endian = request.data.get('endian') selected_opts = request.data.get('selected_opts') logger.info("updating binary options ..." + str(oda_master)) odb_file = oda_master.odb_file odb_file.execute( ModifySettingsFactory.set_values({ 'architecture': arch, 'base_address': base_address, 'endian': endian, 'selected_opts': selected_opts })) odb_file = OdbFile(odb_file.binary) if odb_file.binary.idb_file(): idbImport = IdbImport(File(odb_file.binary.idb_file())) path = idbImport.reconstruct_elf() odb_file.binary.set_the_file(File(open(path, "rb"))) odb_file.execute(IdbImportOperation()) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) oda_master.odb_file = odb_file oda_master.save() return Response({'status': 'ok'})
def test_basic_active_scan(self): # we load this ELF as a raw binary, because it has an invalid opcode fairly early on odb_file = OdbFile( BinaryFile(self.get_test_bin_path('mkdir'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) parcels_before = ParcelList(odb_file.get_structure_list(Parcel)) p = parcels_before.find_parcel_by_vma(0x4002ce) gnu_hash_lda_before = parcels_before.vma_to_lda(0x4002cd) dynsym_lda_before = parcels_before.vma_to_lda(0x4002e0) dynstr_lda_before = parcels_before.vma_to_lda(0x400a18) # number of parcels before the split self.assertEquals(24, len(parcels_before)) # execute the split operation odb_file.execute(ActiveScanOperation(0x4002ce)) # number of parcels after the split parcels_after = ParcelList(odb_file.get_structure_list(Parcel)) self.assertEquals(26, len(parcels_after)) # get the three parcels p1 = parcels_after.find_parcel_by_vma(0x400298) p2 = parcels_after.find_parcel_by_vma(0x4002ce) p3 = parcels_after.find_parcel_by_vma(0x4002d5) # make sure they are all unique self.assertNotEqual(p1, p2) self.assertNotEqual(p1, p3) self.assertNotEqual(p2, p3) # check num_ldas in p1 (54 bytes) self.assertEquals(54, p1.num_ldas) # check num_ldas in p2 (3 instructions) self.assertEquals(3, p2.num_ldas) # check num_ldas in p3 (7 bytes) self.assertEquals(7, p3.num_ldas) # make sure vmas line up self.assertEquals(0x400298, p1.vma_start) self.assertEquals(0x4002ce, p1.vma_end) self.assertEquals(0x4002ce, p2.vma_start) self.assertEquals(0x4002d5, p2.vma_end) self.assertEquals(0x4002d5, p3.vma_start) self.assertEquals(0x4002dc, p3.vma_end) # # make sure vma->lda mappings line up # # these shouldn't have changed self.assertEquals(gnu_hash_lda_before, parcels_after.vma_to_lda(0x4002cd)) self.assertEquals(gnu_hash_lda_before + 1, parcels_after.vma_to_lda(0x4002ce)) self.assertEquals(False, p1.is_code) self.assertEquals(False, p3.is_code) # these changed self.assertEquals(gnu_hash_lda_before + 2, parcels_after.vma_to_lda(0x4002d0)) self.assertEquals(gnu_hash_lda_before + 3, parcels_after.vma_to_lda(0x4002d2)) self.assertEquals(gnu_hash_lda_before + 4, parcels_after.vma_to_lda(0x4002d5)) self.assertEquals(gnu_hash_lda_before + 5, parcels_after.vma_to_lda(0x4002d6)) self.assertEquals(gnu_hash_lda_before + 6, parcels_after.vma_to_lda(0x4002d7)) self.assertEquals(gnu_hash_lda_before + 7, parcels_after.vma_to_lda(0x4002d8)) self.assertEquals(gnu_hash_lda_before + 8, parcels_after.vma_to_lda(0x4002d9)) self.assertEquals(gnu_hash_lda_before + 9, parcels_after.vma_to_lda(0x4002da)) self.assertEquals(gnu_hash_lda_before + 10, parcels_after.vma_to_lda(0x4002db)) self.assertEquals(True, p2.is_code) # 7 bytes turned into 3 instructions, so it shifted the following parcels by -4 ldas self.assertEquals(dynsym_lda_before - 4, parcels_after.vma_to_lda(0x4002e0)) self.assertEquals(dynstr_lda_before - 4, parcels_after.vma_to_lda(0x400a18)) # # make sure lda->vma mappings line up # # these shouldn't have changed self.assertEquals(0x4002cd, parcels_after.lda_to_vma(gnu_hash_lda_before)) self.assertEquals(0x4002ce, parcels_after.lda_to_vma(gnu_hash_lda_before + 1)) # these changed self.assertEquals(0x4002d0, parcels_after.lda_to_vma(gnu_hash_lda_before + 2)) self.assertEquals(0x4002d2, parcels_after.lda_to_vma(gnu_hash_lda_before + 3)) self.assertEquals(0x4002d5, parcels_after.lda_to_vma(gnu_hash_lda_before + 4)) self.assertEquals(0x4002d6, parcels_after.lda_to_vma(gnu_hash_lda_before + 5)) self.assertEquals(0x4002d7, parcels_after.lda_to_vma(gnu_hash_lda_before + 6)) self.assertEquals(0x4002d8, parcels_after.lda_to_vma(gnu_hash_lda_before + 7)) self.assertEquals(0x4002d9, parcels_after.lda_to_vma(gnu_hash_lda_before + 8)) self.assertEquals(0x4002da, parcels_after.lda_to_vma(gnu_hash_lda_before + 9)) self.assertEquals(0x4002db, parcels_after.lda_to_vma(gnu_hash_lda_before + 10)) # 7 bytes turned into 3 instructions, so it shifted the following parcels by -4 ldas self.assertEquals(0x4002e0, parcels_after.lda_to_vma(dynsym_lda_before - 4)) self.assertEquals(0x400a18, parcels_after.lda_to_vma(dynstr_lda_before - 4))
def test_split_to_data_at_start_of_parcel(self): odb_file = OdbFile(BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) parcels_before = ParcelList(odb_file.get_structure_list(Parcel)) # start of .fini section p = parcels_before.find_parcel_by_vma(0x412bec) num_p1_ldas_before = p.num_ldas fini_lda_before = parcels_before.vma_to_lda(0x412bec) # number of parcels before the split self.assertEquals(25, len(parcels_before)) # execute the split operation odb_file.execute(SplitParcelOperation(0x412bec)) # number of parcels after the split (should only add one more) parcels_after = ParcelList(odb_file.get_structure_list(Parcel)) self.assertEquals(26, len(parcels_after)) # get the two parcels p1 = parcels_after.find_parcel_by_vma(0x412bec) p2 = parcels_after.find_parcel_by_vma(0x412bf0) # make sure they are unique self.assertNotEqual(p1, p2) # check num_ldas in p1 (4 data bytes) self.assertEquals(4, p1.num_ldas) # check num_ldas in p2 self.assertEquals(2, p2.num_ldas) # make sure vmas line up self.assertEquals(0x412bec, p1.vma_start) self.assertEquals(0x412bf0, p1.vma_end) self.assertEquals(0x412bf0, p2.vma_start) self.assertEquals(0x412bf5, p2.vma_end) # # make sure vma->lda mappings line up # # these shouldn't have changed self.assertEquals(fini_lda_before, parcels_after.vma_to_lda(0x412bec)) self.assertEquals(True, p2.is_code) # these changed self.assertEquals(fini_lda_before+1, parcels_after.vma_to_lda(0x412bed)) self.assertEquals(fini_lda_before+2, parcels_after.vma_to_lda(0x412bee)) self.assertEquals(fini_lda_before+3, parcels_after.vma_to_lda(0x412bef)) self.assertEquals(fini_lda_before+4, parcels_after.vma_to_lda(0x412bf0)) self.assertEquals(fini_lda_before+5, parcels_after.vma_to_lda(0x412bf4)) self.assertEquals(False, p1.is_code) # # make sure lda->vma mappings line up # # these shouldn't have changed self.assertEquals(0x412bec, parcels_after.lda_to_vma(fini_lda_before)) # these changed self.assertEquals(0x412bed, parcels_after.lda_to_vma(fini_lda_before+1)) self.assertEquals(0x412bee, parcels_after.lda_to_vma(fini_lda_before+2)) self.assertEquals(0x412bef, parcels_after.lda_to_vma(fini_lda_before+3)) self.assertEquals(0x412bf0, parcels_after.lda_to_vma(fini_lda_before+4)) self.assertEquals(0x412bf4, parcels_after.lda_to_vma(fini_lda_before+5))
def handle(self, *args, **options): binary_file = BinaryFile(args[0], args[1], args[2]) odb_file = OdbFile(binary_file) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation())
def test_split_to_data_single_inst_in_parcel(self): odb_file = OdbFile(BinaryFile( self.get_test_bin_path('code_split_single_instruction/split_parcel_single'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) parcels_before = ParcelList(odb_file.get_structure_list(Parcel)) # only one instruction in .single p = parcels_before.find_parcel_by_vma(0x400598) p_text = parcels_before.find_parcel_by_vma(0x400597) p_fini = parcels_before.find_parcel_by_vma(0x4005a0) p_got = parcels_before.find_parcel_by_vma(0x600fe0) num_ldas_before = p.num_ldas num_text_ldas_before = p_text.num_ldas num_fini_ldas_before = p_fini.num_ldas single_lda_before = p.lda_start fini_lda_before = p_fini.lda_start text_lda_before = p_text.lda_start got_lda_before = p_got.lda_start # number of parcels before the split self.assertEquals(25, len(parcels_before)) # execute the split operation odb_file.execute(SplitParcelOperation(0x400598)) # number of parcels after the split (should not have changed) parcels_after = ParcelList(odb_file.get_structure_list(Parcel)) self.assertEquals(25, len(parcels_after)) # get the parcels p = parcels_after.find_parcel_by_vma(0x400598) p_text = parcels_after.find_parcel_by_vma(0x400597) p_fini = parcels_after.find_parcel_by_vma(0x4005a0) # make sure they are all unique self.assertNotEqual(p, p_text) self.assertNotEqual(p, p_fini) self.assertNotEqual(p_text, p_fini) # check num_ldas in p (1 instruction become 7 data bytes) self.assertEquals(7, p.num_ldas) # check num_ldas in text didn't change self.assertEquals(num_text_ldas_before, p_text.num_ldas) # check num_ldas in fini didn't change self.assertEquals(num_fini_ldas_before, p_fini.num_ldas) # make sure vmas line up self.assertEquals(0x4003d0, p_text.vma_start) self.assertEquals(0x400598, p_text.vma_end) self.assertEquals(0x400598, p.vma_start) self.assertEquals(0x40059f, p.vma_end) self.assertEquals(0x4005a0, p_fini.vma_start) self.assertEquals(0x4005ae, p_fini.vma_end) # # make sure vma->lda mappings line up # # these shouldn't have changed self.assertEquals(text_lda_before, parcels_after.vma_to_lda(0x4003d0)) self.assertEquals(text_lda_before+num_text_ldas_before-1, parcels_after.vma_to_lda(0x400597)) self.assertEquals(single_lda_before, parcels_after.vma_to_lda(0x400598)) self.assertEquals(True, p_text.is_code) self.assertEquals(True, p_fini.is_code) # these changed self.assertEquals(single_lda_before+1, parcels_after.vma_to_lda(0x400599)) self.assertEquals(single_lda_before+2, parcels_after.vma_to_lda(0x40059a)) self.assertEquals(single_lda_before+3, parcels_after.vma_to_lda(0x40059b)) self.assertEquals(single_lda_before+4, parcels_after.vma_to_lda(0x40059c)) self.assertEquals(single_lda_before+5, parcels_after.vma_to_lda(0x40059d)) self.assertEquals(single_lda_before+6, parcels_after.vma_to_lda(0x40059e)) self.assertEquals(False, p.is_code) # 1 instruction turned into 7 data bytes, so it shifted the following parcels by 6 ldas self.assertEquals(fini_lda_before+6, parcels_after.vma_to_lda(0x4005a0)) self.assertEquals(got_lda_before+6, parcels_after.vma_to_lda(0x600fe0)) # # make sure lda->vma mappings line up # self.assertEquals(text_lda_before, parcels_after.vma_to_lda(0x4003d0)) self.assertEquals(text_lda_before+num_text_ldas_before-1, parcels_after.vma_to_lda(0x400597)) self.assertEquals(single_lda_before, parcels_after.vma_to_lda(0x400598)) # these shouldn't have changed self.assertEquals(0x4003d0, parcels_after.lda_to_vma(text_lda_before)) self.assertEquals(0x400597, parcels_after.lda_to_vma(text_lda_before+num_text_ldas_before-1)) self.assertEquals(0x400598, parcels_after.lda_to_vma(single_lda_before)) # these changed self.assertEquals(0x400599, parcels_after.lda_to_vma(single_lda_before+1)) self.assertEquals(0x40059a, parcels_after.lda_to_vma(single_lda_before+2)) self.assertEquals(0x40059b, parcels_after.lda_to_vma(single_lda_before+3)) self.assertEquals(0x40059c, parcels_after.lda_to_vma(single_lda_before+4)) self.assertEquals(0x40059d, parcels_after.lda_to_vma(single_lda_before+5)) self.assertEquals(0x40059e, parcels_after.lda_to_vma(single_lda_before+6)) # 1 instruction turned into 7 data bytes, so it shifted the following parcels by 6 ldas self.assertEquals(0x4005a0, parcels_after.lda_to_vma(fini_lda_before+6)) self.assertEquals(0x600fe0, parcels_after.lda_to_vma(got_lda_before+6))
def test_split_to_data_at_end_of_parcel(self): odb_file = OdbFile(BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) parcels_before = ParcelList(odb_file.get_structure_list(Parcel)) # last instruction in .plt p = parcels_before.find_parcel_by_vma(0x4029bb) p3 = parcels_before.find_parcel_by_vma(0x4029c0) num_p1_ldas_before = p.num_ldas num_p3_ldas_before = p3.num_ldas plt_lda_before = parcels_before.vma_to_lda(0x402320) text_lda_before = parcels_before.vma_to_lda(0x4029c0) # number of parcels before the split self.assertEquals(25, len(parcels_before)) # execute the split operation odb_file.execute(SplitParcelOperation(0x4029bb)) # number of parcels after the split (should only add one more) parcels_after = ParcelList(odb_file.get_structure_list(Parcel)) self.assertEquals(26, len(parcels_after)) # get the two parcels (plus the .text one following) p1 = parcels_after.find_parcel_by_vma(0x402320) p2 = parcels_after.find_parcel_by_vma(0x4029bb) p3 = parcels_after.find_parcel_by_vma(0x4029c0) # make sure they are all unique self.assertNotEqual(p1, p2) self.assertNotEqual(p1, p3) self.assertNotEqual(p2, p3) # check num_ldas in p1 (5 instructions) self.assertEquals(num_p1_ldas_before - 1, p1.num_ldas) # check num_ldas in p2 (this one instruction has now become 5 data bytes) self.assertEquals(5, p2.num_ldas) # check num_ldas in p3 (should not have changed) self.assertEquals(num_p3_ldas_before, p3.num_ldas) # make sure vmas line up self.assertEquals(0x402320, p1.vma_start) self.assertEquals(0x4029bb, p1.vma_end) self.assertEquals(0x4029bb, p2.vma_start) self.assertEquals(0x4029c0, p2.vma_end) self.assertEquals(0x4029c0, p3.vma_start) self.assertEquals(0x412bec, p3.vma_end) # # make sure vma->lda mappings line up # # these shouldn't have changed self.assertEquals(plt_lda_before, parcels_after.vma_to_lda(0x402320)) self.assertEquals(plt_lda_before+num_p1_ldas_before-2, parcels_after.vma_to_lda(0x4029b6)) self.assertEquals(plt_lda_before+num_p1_ldas_before-1, parcels_after.vma_to_lda(0x4029bb)) self.assertEquals(True, p1.is_code) self.assertEquals(True, p3.is_code) # these changed self.assertEquals(plt_lda_before+num_p1_ldas_before, parcels_after.vma_to_lda(0x4029bc)) self.assertEquals(plt_lda_before+num_p1_ldas_before+1, parcels_after.vma_to_lda(0x4029bd)) self.assertEquals(plt_lda_before+num_p1_ldas_before+2, parcels_after.vma_to_lda(0x4029be)) self.assertEquals(plt_lda_before+num_p1_ldas_before+3, parcels_after.vma_to_lda(0x4029bf)) self.assertEquals(plt_lda_before+num_p1_ldas_before+4, parcels_after.vma_to_lda(0x4029c0)) self.assertEquals(False, p2.is_code) # 1 instruction turned into 5 data bytes, so it shifted the following parcels by 4 ldas self.assertEquals(text_lda_before+4, parcels_after.vma_to_lda(0x4029c0)) # # make sure lda->vma mappings line up # # these shouldn't have changed self.assertEquals(0x402320, parcels_after.lda_to_vma(plt_lda_before)) self.assertEquals(0x4029b6, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before-2)) self.assertEquals(0x4029bb, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before-1)) # these changed self.assertEquals(0x4029bc, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before)) self.assertEquals(0x4029bd, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before+1)) self.assertEquals(0x4029be, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before+2)) self.assertEquals(0x4029bf, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before+3)) self.assertEquals(0x4029c0, parcels_after.lda_to_vma(plt_lda_before+num_p1_ldas_before+4)) # 1 instruction turned into 5 data bytes, so it shifted the following parcels by 4 ldas self.assertEquals(0x4029c0, parcels_after.lda_to_vma(text_lda_before+4))
def test_split_to_data_basic(self): odb_file = OdbFile(BinaryFile(self.get_test_bin_path('ls'), 'elf64-x86-64', 'i386:x86-64')) odb_file.execute(LoadOperation()) odb_file.execute(PassiveScanOperation()) parcels_before = ParcelList(odb_file.get_structure_list(Parcel)) p = parcels_before.find_parcel_by_vma(0x4029c0) num_p1_ldas_before = p.num_ldas text_lda_before = parcels_before.vma_to_lda(0x4029c0) fini_lda_before = parcels_before.vma_to_lda(0x412bec) # number of parcels before the split self.assertEquals(25, len(parcels_before)) # execute the split operation odb_file.execute(SplitParcelOperation(0x4029d5)) # number of parcels after the split parcels_after = ParcelList(odb_file.get_structure_list(Parcel)) self.assertEquals(27, len(parcels_after)) # get the three parcels p1 = parcels_after.find_parcel_by_vma(0x4029c0) p2 = parcels_after.find_parcel_by_vma(0x4029d5) p3 = parcels_after.find_parcel_by_vma(0x4029da) # make sure they are all unique self.assertNotEqual(p1, p2) self.assertNotEqual(p1, p3) self.assertNotEqual(p2, p3) # check num_ldas in p1 (5 instructions) self.assertEquals(5, p1.num_ldas) # check num_ldas in p2 (this one instruction has now become 5 data bytes) self.assertEquals(5, p2.num_ldas) # check num_ldas in p3 (less 5 from p1 and less 1 from p2 - remember it used to only be 1 lda before the split) self.assertEquals(num_p1_ldas_before - 5 - 1, p3.num_ldas) # make sure vmas line up self.assertEquals(0x4029c0, p1.vma_start) self.assertEquals(0x4029d5, p1.vma_end) self.assertEquals(0x4029d5, p2.vma_start) self.assertEquals(0x4029da, p2.vma_end) self.assertEquals(0x4029da, p3.vma_start) self.assertEquals(0x412bec, p3.vma_end) # # make sure vma->lda mappings line up # # these shouldn't have changed self.assertEquals(text_lda_before, parcels_after.vma_to_lda(0x4029c0)) self.assertEquals(text_lda_before+5, parcels_after.vma_to_lda(0x4029d5)) self.assertEquals(True, p1.is_code) self.assertEquals(True, p3.is_code) # these changed self.assertEquals(text_lda_before+6, parcels_after.vma_to_lda(0x4029d6)) self.assertEquals(text_lda_before+7, parcels_after.vma_to_lda(0x4029d7)) self.assertEquals(text_lda_before+8, parcels_after.vma_to_lda(0x4029d8)) self.assertEquals(text_lda_before+9, parcels_after.vma_to_lda(0x4029d9)) self.assertEquals(text_lda_before+10, parcels_after.vma_to_lda(0x4029da)) self.assertEquals(text_lda_before+11, parcels_after.vma_to_lda(0x4029db)) self.assertEquals(False, p2.is_code) # 1 instruction turned into 5 data bytes, so it shifted the following parcels by 4 ldas self.assertEquals(fini_lda_before+4, parcels_after.vma_to_lda(0x412bec)) # # make sure lda->vma mappings line up # # these shouldn't have changed self.assertEquals(0x4029c0, parcels_after.lda_to_vma(text_lda_before)) self.assertEquals(0x4029d5, parcels_after.lda_to_vma(text_lda_before+5)) # these changed self.assertEquals(0x4029d6, parcels_after.lda_to_vma(text_lda_before+6)) self.assertEquals(0x4029d7, parcels_after.lda_to_vma(text_lda_before+7)) self.assertEquals(0x4029d8, parcels_after.lda_to_vma(text_lda_before+8)) self.assertEquals(0x4029d9, parcels_after.lda_to_vma(text_lda_before+9)) self.assertEquals(0x4029da, parcels_after.lda_to_vma(text_lda_before+10)) self.assertEquals(0x4029db, parcels_after.lda_to_vma(text_lda_before+11)) # 1 instruction turned into 5 data bytes, so it shifted the following parcels by 4 ldas self.assertEquals(0x412bec, parcels_after.lda_to_vma(fini_lda_before+4))