def test_disasm_against_objdump(objdump_path, binary_path): # TODO: code repetition from test_disasm_standalone, encapsulate inner functionality. start_time = time.time() total_inst = 0 match_inst = 0 print(('Processing file:', binary_path)) elf_file = ELFFile(open(binary_path, 'rb')) if elf_file.num_segments() == 0: print('There are no program headers in this file.') return objdump = ObjdumpWrapper(objdump_path) disasm = HexagonDisassembler(objdump_compatible=True) for segment in elf_file.iter_segments(): if segment['p_flags'] & P_FLAGS.PF_X: print("Offset: {:x}".format(segment['p_offset'])) print("VirtAddr: {:x}".format(segment['p_vaddr'])) print("FileSiz: {:x}".format(segment['p_filesz'])) segment_data = segment.data() data_pos = 0 while data_pos + INST_SIZE <= len(segment_data): addr = segment['p_vaddr'] + data_pos inst_as_int = struct.unpack( '<I', segment_data[data_pos:data_pos + 4])[0] disasm_output = disasm.disasm_one_inst(inst_as_int, addr).text.strip() objdump_output = objdump.disasm_packet_raw( segment_data[data_pos:min(data_pos + 4 * 4, segment_data)], addr).strip() if (objdump_output != disasm_output): print("[{:08x}] {:s}".format(addr, objdump_output)) print("[{:08x}] {:s}".format(addr, disasm_output)) print() else: match_inst += 1 data_pos += 4 total_inst += 1 elapsed_time = time.time() - start_time print("Elapsed time: {0:.2f}".format(elapsed_time)) print('Match: {0:.2f}%'.format(match_inst / total_inst * 100))
def test_disasm_against_objdump(objdump_path, binary_path): # TODO: code repetition from test_disasm_standalone, encapsulate inner functionality. start_time = time.time() total_inst = 0 match_inst = 0 print(('Processing file:', binary_path)) elf_file = ELFFile(open(binary_path, 'rb')) if elf_file.num_segments() == 0: print('There are no program headers in this file.') return objdump = ObjdumpWrapper(objdump_path) disasm = HexagonDisassembler(objdump_compatible=True) for segment in elf_file.iter_segments(): if segment['p_flags'] & P_FLAGS.PF_X: print("Offset: {:x}".format(segment['p_offset'])) print("VirtAddr: {:x}".format(segment['p_vaddr'])) print("FileSiz: {:x}".format(segment['p_filesz'])) segment_data = segment.data() data_pos = 0 while data_pos + INST_SIZE <= len(segment_data): addr = segment['p_vaddr'] + data_pos inst_as_int = struct.unpack('<I', segment_data[data_pos: data_pos + 4])[0] disasm_output = disasm.disasm_one_inst(inst_as_int, addr).text.strip() objdump_output = objdump.disasm_packet_raw( segment_data[data_pos: min(data_pos + 4 * 4, segment_data)], addr).strip() if (objdump_output != disasm_output): print("[{:08x}] {:s}".format(addr, objdump_output)) print("[{:08x}] {:s}".format(addr, disasm_output)) print() else: match_inst += 1 data_pos += 4 total_inst += 1 elapsed_time = time.time() - start_time print("Elapsed time: {0:.2f}".format(elapsed_time)) print('Match: {0:.2f}%'.format(match_inst / total_inst * 100))
def test_disasm_standalone(binary_path, timeout=None): profile = cProfile.Profile() profile.enable() start_time = time.time() print(('Processing file:', binary_path)) elf_file = ELFFile(open(binary_path, 'rb')) if elf_file.num_segments() == 0: print('There are no program headers in this file.') return disasm = HexagonDisassembler() total_inst = 0 for segment in elf_file.iter_segments(): if segment['p_flags'] & P_FLAGS.PF_X: print("Offset: {:x}".format(segment['p_offset'])) print("VirtAddr: {:x}".format(segment['p_vaddr'])) print("FileSiz: {:x}".format(segment['p_filesz'])) segment_data = segment.data() data_pos = 0 while data_pos + INST_SIZE <= len(segment_data): addr = segment['p_vaddr'] + data_pos inst_as_int = struct.unpack( '<I', segment_data[data_pos:data_pos + 4])[0] dis = disasm.disasm_one_inst(inst_as_int, addr) print("[{:08x}] {:s}".format(addr, dis.text)) data_pos += 4 total_inst += 1 if timeout and (time.time() - start_time) > timeout: break profile.disable() prof_stats = pstats.Stats(profile) prof_stats.strip_dirs().sort_stats('cumulative').print_stats(20) print("Total instructions: " + str(total_inst)) elapsed_time = time.time() - start_time print("Elapsed time: " + str(elapsed_time))
def test_disasm_standalone(binary_path, timeout = None): profile = cProfile.Profile() profile.enable() start_time = time.time() print(('Processing file:', binary_path)) elf_file = ELFFile(open(binary_path, 'rb')) if elf_file.num_segments() == 0: print('There are no program headers in this file.') return disasm = HexagonDisassembler() total_inst = 0 for segment in elf_file.iter_segments(): if segment['p_flags'] & P_FLAGS.PF_X: print("Offset: {:x}".format(segment['p_offset'])) print("VirtAddr: {:x}".format(segment['p_vaddr'])) print("FileSiz: {:x}".format(segment['p_filesz'])) segment_data = segment.data() data_pos = 0 while data_pos + INST_SIZE <= len(segment_data): addr = segment['p_vaddr'] + data_pos inst_as_int = struct.unpack('<I', segment_data[data_pos: data_pos + 4])[0] dis = disasm.disasm_one_inst(inst_as_int, addr) print("[{:08x}] {:s}".format(addr, dis.text)) data_pos += 4 total_inst += 1 if timeout and (time.time() - start_time) > timeout: break profile.disable() prof_stats = pstats.Stats(profile) prof_stats.strip_dirs().sort_stats('cumulative').print_stats(20) print("Total instructions: " + str(total_inst)) elapsed_time = time.time() - start_time print("Elapsed time: " + str(elapsed_time))
def generate_function(org_func_name, org_func, symtab, base_elf, metadata, func_symtab): """ generates a helper function to call the original version of an overwritten firmware function :param org_func_name: name of the new function :param org_func: original function name, the one we replaced :param symtab: symbol table :param base_elf: base firmware ELF file :param metadata: base firmware metadata :param func_symtab: table of new symbols needed by generated functions """ addr_str, ret_type, param_str = resolve_symbol_all(org_func, symtab) if (addr_str == '"unknown"'): print "error: trying to generate fw_org function for a function with unknown location" exit(1) address = int(addr_str, 0) # read first 5 instruction of destination function # we have to read 5 instructions in case the first packet contains only 1 instruction, # then the we have to relocate 2 packages (with up to 5 instructions in total) elf_pos, elf_blob = get_offset_in_elf(metadata, address) base_elf.seek(elf_pos) data = struct.unpack("<IIIII", base_elf.read(20)) disasm = HexagonDisassembler(objdump_compatible=True) disasm0 = HexagonDisassembler(objdump_compatible=True) next_prefix = "" # generate function start text function_decl = "%s %s(%s)" % (ret_type, org_func_name, param_str) function_def = "%s {\n\tasm(\n" % function_decl function_decl += ";" # iterate over the four instructions fetched reloc_size = 0 for pos in range(0, 5): reloc_size += 1 # disassemble instruction with correct position hi = disasm.disasm_one_inst(data[pos], address + pos * 4) # disassemble instruction again with position 0 to check for PC relative immediates hi0 = disasm0.disasm_one_inst(data[pos], pos * 4) if (hi.immext is not None): if (hi.start_packet): next_prefix = "{ " continue disasm_output = hi.text.strip() disasm_output_hi0 = hi0.text.strip() # if we have a realtive immediate if (disasm_output != disasm_output_hi0): # loop over all immediates for pos_imm, imm in enumerate(hi.imm_ops): imm0 = hi0.imm_ops[pos_imm] # check for difference -> PC relative immediate if (imm0 != imm): # generate a dummy symbol at the destination address # and write our target relative to this, by this we # force the compiler to generate a relocation for # the immediate for us dest_address = address + imm0.value symbol = "sym_0x%X" % dest_address func_symtab[symbol] = dest_address rel_adr = "%s" % symbol disasm_output = disasm_output.replace( ("0x%X" % imm.value).lower(), rel_adr) function_def += '\t\t"%s%s\\n\\t" \n' % (next_prefix, disasm_output) next_prefix = "" if ((pos != 0) & (hi.end_packet)): break # generate a jump instruction to the start of remaining original function org_func_start = (address + (reloc_size << 2)) symbol = "sym_0x%X" % org_func_start func_symtab[symbol] = org_func_start function_def += '\t\t"{ jump %s }"\n' % symbol function_def += "\t);\n}" return function_decl, function_def, func_symtab