diff --git a/ghida.py b/ghida.py index 8878392..29b56f4 100644 --- a/ghida.py +++ b/ghida.py @@ -623,14 +623,14 @@ def update(self, ctx): class DisasmsHooks(idaapi.UI_Hooks): - def finish_populating_tform_popup(self, form, popup): + def finish_populating_widget_popup(self, form, popup): # TODO - Attach to the functions view. - # if idaapi.get_tform_type(form) == idaapi.BWN_FUNCS: + # if idaapi.get_widget_type(form) == idaapi.BWN_FUNCS: # idaapi.attach_action_to_popup( # form, popup, "my:disasmsaction", None) # Attach to the disassembler view only - if idaapi.get_tform_type(form) == idaapi.BWN_DISASMS: + if idaapi.get_widget_type(form) == idaapi.BWN_DISASMS: idaapi.attach_action_to_popup( form, popup, "my:disasmsaction", None) idaapi.attach_action_to_popup( @@ -647,7 +647,7 @@ def register_handlers(): # Load a custom icon icon_path = gl.plugin_resource("ghida.png") - icon_data = str(open(icon_path, "rb").read()) + icon_data = open(icon_path, "rb").read() icon_ghida = idaapi.load_custom_icon(data=icon_data) idaapi.register_action(idaapi.action_desc_t( @@ -728,7 +728,7 @@ def load_configuration(): print("GHIDA_CONF.load_save_cached_comments", GHIDA_CONF.load_save_cached_comments) - md5 = idautils.GetInputFileMD5() + md5 = idautils.GetInputFileMD5().hex() # Initalize the cache (and load cached objects) DECOMPILED_CACHE = gl.DecompiledCache( @@ -752,7 +752,7 @@ def register_actions_and_handlers_decompile_view(): """ # Load a custom icon icon_path = gl.plugin_resource("ghida.png") - icon_data = str(open(icon_path, "rb").read()) + icon_data = open(icon_path, "rb").read() icon_ghida = idaapi.load_custom_icon(data=icon_data) decompiler_widget = idaapi.find_widget('Decompiled Function') @@ -893,7 +893,8 @@ def decompile_function_wrapper(cache_only=False, do_show=True): # Check if the program has been rebased if GHIDA_CONF.image_base != image_base: print( - "GhIDA:: [DEBUG] program has been rebased. Invalidating caches.") + "GhIDA:: [DEBUG] program has been rebased. " + "Invalidating caches.") DECOMPILED_CACHE.invalidate_cache() COMMENTS_CACHE.invalidate_cache() gl.force_export_XML_file() @@ -976,11 +977,11 @@ def decompile_function_wrapper(cache_only=False, do_show=True): print("GhIDA:: [!] Decompilation wrapper error") idaapi.warning("GhIDA decompilation wrapper error") - # ------------------------------------------------------------ # GHIDRA DECOMPILER PLUGIN # ------------------------------------------------------------ + class GhIDADecompiler_t(idaapi.plugin_t): comment = "GhIDA Decompiler for IDA Pro" help = "GhIDA Decompiler shortcut key is Ctrl-Alt-D" diff --git a/ghida_plugin/__init__.py b/ghida_plugin/__init__.py index 55b71c1..1566422 100644 --- a/ghida_plugin/__init__.py +++ b/ghida_plugin/__init__.py @@ -23,13 +23,13 @@ ghida_vv = "0.1" -from comments_cache import * -from config import * -from constants import * -from decompiled_cache import * -from idaxml import SYMBLE_TABLE_DICT -from lib import * -from ui import * -from utility import * +from .comments_cache import * +from .config import * +from .constants import * +from .decompiled_cache import * +from .idaxml import SYMBLE_TABLE_DICT +from .lib import * +from .ui import * +from .utility import * SYMBLE_TABLE_DICT = dict() diff --git a/ghida_plugin/idaxml.py b/ghida_plugin/idaxml.py index 03c6120..dbb5879 100644 --- a/ghida_plugin/idaxml.py +++ b/ghida_plugin/idaxml.py @@ -40,7 +40,9 @@ import idc import datetime import os +import sys import time + from xml.etree import cElementTree @@ -242,7 +244,7 @@ def __init__(self, arg): self.inf = ida_idaapi.get_inf_structure() self.min_ea = self.inf.min_ea self.max_ea = self.inf.max_ea - self.cbsize = (ida_idp.ph_get_cnbits() + 7) / 8 + self.cbsize = int((ida_idp.ph_get_cnbits() + 7) / 8) self.processor = str.upper(ida_idp.get_idp_name()) self.batch = ida_kernwin.cvar.batch @@ -266,7 +268,7 @@ def export_xml(self, filename): idc.msg("\n------------------------------------------------" + "-----------") idc.msg("\nExporting XML document ....") - begin = time.clock() + begin = time.time() self.write_xml_declaration() ret_val = self.export_program() @@ -462,7 +464,7 @@ def display_cpu_time(self, start): Args: start: Floating-point value representing start time in seconds. """ - idc.msg('CPU time: %6.4f' % (time.clock() - start)) + idc.msg('CPU time: %6.4f' % (time.time() - start)) def end_element(self, tag, newline=True): """ @@ -510,7 +512,7 @@ def export_bookmarks(self): Exports marked location descriptions as BOOKMARK elements. """ found = False - timer = time.clock() + timer = time.time() for slot in range(0, 1025): address = idc.get_bookmark(slot) description = idc.get_bookmark_desc(slot) @@ -571,7 +573,7 @@ def export_code(self): if (addr == BADADDR): return self.update_status(CODE) - timer = time.clock() + timer = time.time() data = ida_bytes.next_that(addr, self.max_ea, idc.is_data) unknown = ida_bytes.next_unknown(addr, self.max_ea) self.start_element(CODE, True) @@ -641,7 +643,7 @@ def export_comments(self): if (addr == BADADDR): return self.update_status(COMMENTS) - timer = time.clock() + timer = time.time() self.start_element(COMMENTS, True) while (addr != BADADDR): cmt = idc.get_cmt(addr, False) @@ -677,7 +679,7 @@ def export_data(self): addr = ida_bytes.next_that(addr, self.max_ea, idc.is_data) if (addr == BADADDR): return - timer = time.clock() + timer = time.time() self.update_status(DATA) self.start_element(DATA, True) while (addr != BADADDR): @@ -730,7 +732,7 @@ def export_datatypes(self): if idc.get_struc_qty() == 0: return self.update_status(DATATYPES) - timer = time.clock() + timer = time.time() self.start_element(DATATYPES, True) self.export_structures() self.export_enums() @@ -927,7 +929,7 @@ def export_functions(self): if functions == None: return self.update_status(FUNCTIONS) - timer = time.clock() + timer = time.time() self.start_element(FUNCTIONS, True) for addr in functions: function = ida_funcs.get_func(addr) @@ -1013,7 +1015,7 @@ def export_markup(self): and manual instructions and operands. """ self.update_status(MARKUP) - timer = time.clock() + timer = time.time() self.start_element(MARKUP, True) addr = self.min_ea while addr != BADADDR: @@ -1124,6 +1126,7 @@ def export_memory_contents(self, binfilename, binfile, start, end): if ((has_val == False) or (next_address != addr + 1) or (next_address == end)): if length > 0: + length = int(length) offset = binfile.tell() ida_loader.base2file(binfile.get_fp(), offset, startaddr, startaddr + length) @@ -1147,7 +1150,7 @@ def export_memory_map(self): if (nsegs == 0): return self.update_status(MEMORY_MAP) - timer = time.clock() + timer = time.time() binfilename = '' if (self.options.MemoryContent.checked == True): (binfilename, ext) = os.path.splitext(self.filename) @@ -1178,9 +1181,9 @@ def export_memory_reference(self, addr, op): elif idc.is_code(f) == True: insn = ida_ua.insn_t() ida_ua.decode_insn(insn, addr) - target = insn.ops[op].value - ri.tdelta + ri.base + target = (insn.ops[op].value - ri.tdelta + ri.base) & ((1 << 64) - 1) elif idc.is_data(f) == True: - target = self.get_data_value(addr) - ri.tdelta + ri.base + target = (self.get_data_value(addr) - ri.tdelta + ri.base) & ((1 << 64) - 1) else: return else: @@ -1221,6 +1224,8 @@ def export_memory_section(self, seg, binfilename): self.write_attribute(NAME, segname) self.write_address_attribute(START_ADDR, seg.start_ea) length = (seg.end_ea - seg.start_ea) * self.cbsize + + length = int(length) self.write_numeric_attribute(LENGTH, length) perms = "" if (seg.perm != 0): @@ -1247,7 +1252,7 @@ def export_program(self): """ # output the PROGRAM element self.update_status(PROGRAM) - timer = time.clock() + timer = time.time() self.start_element(PROGRAM) self.write_attribute(NAME, idc.get_root_filename()) self.write_attribute(EXE_PATH, idc.get_input_file_path()) @@ -1257,7 +1262,7 @@ def export_program(self): # check for presence of INPUT_MD5 netnode md5 = ida_netnode.netnode(INPUT_MD5) if md5 == BADNODE: - input_md5 = idc.retrieve_input_file_md5() + input_md5 = idc.retrieve_input_file_md5().hex() else: input_md5 = md5.supval(ida_nalt.RIDX_MD5) if input_md5 != None: @@ -1390,7 +1395,7 @@ def export_program_entry_points(self): if (nepts == 0): return self.update_status(PROGRAM_ENTRY_POINTS) - timer = time.clock() + timer = time.time() self.start_element(PROGRAM_ENTRY_POINTS, True) for i in range(nepts): self.start_element(PROGRAM_ENTRY_POINT) @@ -1415,7 +1420,7 @@ def export_register_values(self): if has_segregareas == False: return self.update_status(REGISTER_VALUES) - timer = time.clock() + timer = time.time() self.start_element(REGISTER_VALUES, True) sr = ida_segregs.sreg_range_t() for j in range(first, last): @@ -1651,7 +1656,7 @@ def export_symbol_table(self): return self.update_status(SYMBOL_TABLE) self.start_element(SYMBOL_TABLE, True) - timer = time.clock() + timer = time.time() while addr != BADADDR: # only export meaningful names (user and auto) f = idc.get_full_flags(addr) @@ -1680,8 +1685,9 @@ def export_typeinfo_cmt(self, cmt): cmt: String containing type info. """ # older versions of IDAPython returned a '\n' at end of cmt - while cmt[-1] == '\n': - cmt = cmt[:-1] + if(len(cmt) > 0): + while cmt[-1] == '\n': + cmt = cmt[:-1] self.write_comment_element(TYPEINFO_CMT, cmt) def export_user_memory_reference(self, addr): @@ -2307,13 +2313,13 @@ def import_xml(self): if event in self.callbacks: if element.tag in self.callbacks[event]: if event == 'start': - self.timers[element.tag] = time.clock() + self.timers[element.tag] = time.time() self.callbacks[event][element.tag](element) if event == 'end': element.clear() if event == 'end': n += 1 - end = time.clock() + end = time.time() ida_kernwin.hide_wait_box() self.display_summary('Import' if self.plugin else "Load") idc.msg('\nXML Elements parsed: ' + str(n) + '\n\n') @@ -2391,7 +2397,7 @@ def display_timer(self, element): return if element.tag in self.timers: idc.msg('elapsed time: %.4f' % - (time.clock() - self.timers[element.tag])) + (time.time() - self.timers[element.tag])) def display_total_time(self, element): """ @@ -2402,7 +2408,7 @@ def display_total_time(self, element): """ TOTAL = 'Total ' idc.msg('\n%35selapsed time: %.4f' % - (TOTAL, time.clock() - self.timers[PROGRAM])) + (TOTAL, time.time() - self.timers[PROGRAM])) def get_address(self, element, attr): """ @@ -2473,7 +2479,7 @@ def get_cbsize(self): Integer representing the number of 8-bit bytes in an addressable codebyte. """ - return (ida_idp.ph_get_cnbits() + 7) / 8 + return int((ida_idp.ph_get_cnbits() + 7) / 8) def get_datatype_flags(self, datatype, size): """ @@ -2675,7 +2681,9 @@ def import_bookmark(self, bookmark): break except: msg = "** Exception occurred in import_bookmark **" - print("\n" + msg + "\n", sys.exc_type, sys.exc_value) + print(msg) + excinfo = sys.exc_info() + print(excinfo) def import_cmts(self, element, sid, typ): """ @@ -3003,7 +3011,9 @@ def import_function(self, function): self.import_register_var(register_var, func) except: msg = "** Exception occurred in import_function **" - print("\n" + msg + "\n", sys.exc_type, sys.exc_value) + print(msg) + excinfo = sys.exc_info() + print(excinfo) def import_function_def(self, function_def): # import_function_def: NOT IMPLEMENTED @@ -3466,7 +3476,7 @@ def import_structure(self, structure): if self.has_attribute(structure, NAMESPACE) == False: return namespace = self.get_attribute(structure, NAMESPACE) - name = namspace + '__' + name + name = namespace + '__' + name name.replace('/', '_') name.replace('.', '_') dtyp = idc.get_struc_id(name) @@ -3535,7 +3545,7 @@ def import_union(self, union): if self.has_attribute(union, NAMESPACE) == False: return namespace = self.get_attribute(union, NAMESPACE) - name = namspace + '__' + name + name = namespace + '__' + name name.replace('/', '_') name.replace('.', '_') dtyp = idc.get_struc_id(name) @@ -3703,4 +3713,4 @@ def update_import(self, element): USER_DEFINED = 'USER_DEFINED' VALUE = 'VALUE' VARIABLE_LENGTH = 'VARIABLE_LENGTH' -ZERO_PAD = 'ZERO_PAD' +ZERO_PAD = 'ZERO_PAD' \ No newline at end of file diff --git a/ghida_plugin/lib.py b/ghida_plugin/lib.py index b301876..4eda580 100644 --- a/ghida_plugin/lib.py +++ b/ghida_plugin/lib.py @@ -28,7 +28,7 @@ import tempfile import time -import Queue +import queue as Queue import random import requests import string @@ -41,8 +41,8 @@ import idautils import idc -from idaxml import Cancelled -from idaxml import XmlExporter +from .idaxml import Cancelled +from .idaxml import XmlExporter # This value can be changed TIMEOUT = 300 @@ -72,7 +72,8 @@ def create_random_filename(): if not GLOBAL_FILENAME: letters = [random.choice(string.ascii_letters) for i in range(5)] random_string = ''.join(letters) - GLOBAL_FILENAME = "%s_%s" % (idautils.GetInputFileMD5(), random_string) + GLOBAL_FILENAME = "%s_%s" % ( + idautils.GetInputFileMD5().hex(), random_string) return GLOBAL_FILENAME @@ -133,7 +134,9 @@ def export_ida_project_to_xml(): except Exception: ida_kernwin.hide_wait_box() msg = "GhIDA:: [!] Exception occurred: XML Exporter failed!" - print("\n" + msg + "\n", sys.exc_type, sys.exc_value) + print(msg) + excinfo = sys.exc_info() + print(excinfo) idc.warning(msg) finally: xml.cleanup() @@ -225,6 +228,7 @@ def ghidra_headless(address, "Temp", "-import", xml_file_path, + '-readOnly', '-scriptPath', ghidra_plugins_path, '-postScript', @@ -247,7 +251,7 @@ def ghidra_headless(address, p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, + stderr=subprocess.PIPE, **kwargs) stop = False @@ -260,14 +264,17 @@ def ghidra_headless(address, counter += 1 subprocess.Popen.poll(p) + print(p.returncode) + # Process terminated if p.returncode is not None: + print("GhIDA:: [DEBUG] ", str(p.stdout.read(), 'utf-8')) stop = True print("GhIDA:: [INFO] Ghidra analysis completed!") continue # User terminated action - if idaapi.wasBreak(): + if idaapi.user_cancelled(): # Termiante the process! terminate_process(p.pid) stop = True @@ -364,7 +371,7 @@ def ghidraaas_checkin(bin_file_path, filename, ghidra_server_url): """ idaapi.show_wait_box("Connecting to Ghidraaas. Sending bytes file...") try: - md5_hash = idautils.GetInputFileMD5() + md5_hash = idautils.GetInputFileMD5().hex() queue = Queue.Queue() my_args = (bin_file_path, filename, ghidra_server_url, md5_hash, queue) @@ -380,7 +387,7 @@ def ghidraaas_checkin(bin_file_path, filename, ghidra_server_url): counter += 1 # User terminated action - if idaapi.wasBreak(): + if idaapi.user_cancelled(): stop = True print("GhIDA:: [!] Check-in interrupted.") continue @@ -445,7 +452,7 @@ def ghidraaas_checkout(ghidra_server_url): idaapi.show_wait_box( "Connecting to Ghidraaas. Removing temporary files...") try: - md5_hash = idautils.GetInputFileMD5() + md5_hash = idautils.GetInputFileMD5().hex() aargs = (md5_hash, ghidra_server_url) t1 = threading.Thread(target=ghidraaas_checkout_thread, @@ -459,7 +466,7 @@ def ghidraaas_checkout(ghidra_server_url): time.sleep(SLEEP_LENGTH) counter += 1 - if idaapi.wasBreak(): + if idaapi.user_cancelled(): print("GhIDA:: [!] Check-out interrupted.") stop = True continue @@ -564,7 +571,7 @@ def ghidraaas_decompile(address, "Connecting to Ghidraaas. Decompiling function %s" % address) try: - md5_hash = idautils.GetInputFileMD5() + md5_hash = idautils.GetInputFileMD5().hex() queue = Queue.Queue() aargs = (address, xml_file_path, bin_file_path, @@ -580,7 +587,7 @@ def ghidraaas_decompile(address, time.sleep(SLEEP_LENGTH) counter += 1 - if idaapi.wasBreak(): + if idaapi.user_cancelled(): print("GhIDA:: [!] decompilation interrupted.") stop = True continue diff --git a/ghida_plugin/ui.py b/ghida_plugin/ui.py index 201358f..0dc1513 100644 --- a/ghida_plugin/ui.py +++ b/ghida_plugin/ui.py @@ -24,13 +24,13 @@ import ida_kernwin import idaapi -from constants import COMMENT_FORM_TEXT -from constants import RENAME_FORM_TEXT -from constants import SETTINGS_FORM_TEXT +from .constants import COMMENT_FORM_TEXT +from .constants import RENAME_FORM_TEXT +from .constants import SETTINGS_FORM_TEXT # from utility import get_address_for_symbol -from utility import from_ghidra_to_ida_syntax_conversion -from utility import from_ida_to_ghidra_syntax_conversion +from .utility import from_ghidra_to_ida_syntax_conversion +from .utility import from_ida_to_ghidra_syntax_conversion USE_GHIDRAAAS_OPTION_CONST = 11 diff --git a/ghida_plugin/utility.py b/ghida_plugin/utility.py index ae95ee7..051006f 100644 --- a/ghida_plugin/utility.py +++ b/ghida_plugin/utility.py @@ -27,7 +27,7 @@ import idaapi import idc -from idaxml import SYMBLE_TABLE_DICT +from .idaxml import SYMBLE_TABLE_DICT PLUGIN_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__))) @@ -262,8 +262,8 @@ def get_current_address(): return None # Get function start address - ea = func.startEA - ea = hex(ea).strip("0x").strip("L") + ea = func.start_ea + ea = hex(ea).replace("0x", "").strip("L") return ea @@ -278,7 +278,7 @@ def convert_address(ca): return None # Get function start address - ea = func.startEA + ea = func.start_ea ea = hex(ea).strip("0x").strip("L") return ea