def find_disass_view(self): widget = idaapi.find_widget('IDA View-%s' % dbg.registers.pc) if widget: return widget for c in map(chr, range(65, 75)): widget = idaapi.find_widget('IDA View-%s' % c) if widget: return widget return None
def run(self, arg): plg = Hyara() plg.Show("Hyara") widget_a = find_widget("IDA View-A") widget_Hyara = find_widget("Hyara") widget_OW = find_widget("Output window") if widget_Hyara and widget_a: set_dock_pos("Hyara", "IDA View-A", DP_RIGHT) if widget_OW: set_dock_pos("Output window", "Functions window", DP_BOTTOM)
def activate(self, ctx): if self.widget_title == REGS_WIDGET_TITLE: if idaapi.find_widget(self.widget_title) is None: w = RegsFlagsViewer() w.Show(REGS_WIDGET_TITLE) w.set_window_position() elif self.widget_title == STACK_WIDGET_TITLE: if idaapi.find_widget(self.widget_title) is None: w = StackViewer() w.Create(STACK_WIDGET_TITLE) w.Show() w.set_window_position() return 1
def set_window_position(self): stack_view = idaapi.find_widget("Stack view") if stack_view: idaapi.set_dock_pos(STACK_WIDGET_TITLE, "Stack view", idaapi.DP_INSIDE) idaapi.close_widget(stack_view, 0) else: idaapi.set_dock_pos(STACK_WIDGET_TITLE, REGS_WIDGET_TITLE, idaapi.DP_BOTTOM)
def show_dockable(self, dockable_name): try: make_dockable = self._dockable_factory[dockable_name] except KeyError: return False parent, dctx = None, None # not used for IDA's integration widget = make_dockable(dockable_name, parent, dctx) # get the original twidget, so we can use it with the IDA API's #twidget = idaapi.TWidget__from_ptrval__(widget) NOTE: IDA 7.2+ only... twidget = self._dockable_widgets.pop(dockable_name) if not twidget: self.warning( "Could not open dockable window, because its reference is gone?!?" ) return # show the dockable widget flags = idaapi.PluginForm.WOPN_TAB | idaapi.PluginForm.WOPN_RESTORE | idaapi.PluginForm.WOPN_PERSIST idaapi.display_widget(twidget, flags) widget.visible = True # attempt to 'dock' the widget in a reasonable location for target in ["IDA View-A", "Pseudocode-A"]: dwidget = idaapi.find_widget(target) if dwidget: idaapi.set_dock_pos(dockable_name, 'IDA View-A', idaapi.DP_RIGHT) break
def get_selected_funcs(): """ Return the list of function names selected in the Functions window. """ import sip twidget = idaapi.find_widget("Functions window") widget = sip.wrapinstance(int(twidget), QtWidgets.QWidget) # TODO: test this if not widget: idaapi.warning("Unable to find 'Functions window'") return # # locate the table widget within the Functions window that actually holds # all the visible function metadata # table = widget.findChild(QtWidgets.QTableView) # # scrape the selected function names from the Functions window table # selected_funcs = [str(s.data()) for s in table.selectionModel().selectedRows()] # # re-map the scraped names as they appear in the function table, to their true # names as they are saved in the IDB. See the match_funcs(...) function # comment for more details # return match_funcs(selected_funcs)
def _get_selected_funcs(self): """ Return the list of function names selected in the Functions window. Warning: It's possible that we don't get the correct name for a function lookup. In that case, this function will fail. See: https://github.com/gaasedelen/prefix/blob/master/plugin/ida_prefix.py#L567 """ twidget = idaapi.find_widget("Functions window") widget = sip.wrapinstance(int(twidget), QWidget) if not widget: idaapi.warning("Unable to find 'Functions window'") return # # locate the table widget within the Functions window that actually holds # all the visible function metadata # table: QTableView = widget.findChild(QTableView) # # scrape the selected function names from the Functions window table # selected_funcs = [ str(s.data()) for s in table.selectionModel().selectedRows() ] return selected_funcs
def _touch_ida_window(self, target): """ Touch a window/widget/form to ensure it gets drawn by IDA. XXX/HACK: We need to ensure that widget we will analyze actually gets drawn so that there are colors for us to steal. To do this, we switch to it, and switch back. I tried a few different ways to trigger this from Qt, but could only trigger the full painting by going through the IDA routines. """ # get the currently active widget/form title (the form itself seems transient...) twidget = idaapi.get_current_widget() title = idaapi.get_widget_title(twidget) # touch the target window by switching to it idaapi.activate_widget(target, True) flush_qt_events() # locate our previous selection previous_twidget = idaapi.find_widget(title) # return us to our previous selection idaapi.activate_widget(previous_twidget, True) flush_qt_events()
def highlight_symbol_in_DISASM(): """ Select a symbol in the DECOMP view, highlight the corresponding symbols in IDA DISASM view. """ # print("GhIDA:: [DEBUG] highlight_symbol_in_DISASM called") disasm_widget = idaapi.find_widget('IDA View-A') symbol = None ret = ida_kernwin.get_highlight(ida_kernwin.get_current_viewer()) if ret and ret[1]: symbol = ret[0] if not symbol: # TODO improve it # Highlight a non-existing symbole idaapi.set_highlight(disasm_widget, 'aaabbbccc', 1) return True converted_symbol = from_ghidra_to_ida_syntax_conversion(symbol) if converted_symbol: # Update IDA DISASM view idaapi.set_highlight(disasm_widget, converted_symbol, 1) else: # TODO improve it # Highlight a non-existing symbole idaapi.set_highlight(disasm_widget, 'aaabbbccc', 1) return True
def get_ida_bg_color_ida7(): """ Get the background color of an IDA disassembly view. (IDA 7+) """ names = ["Enums", "Structures"] names += ["Hex View-%u" % i for i in range(5)] names += ["IDA View-%c" % chr(ord('A') + i) for i in range(5)] # find a form (eg, IDA view) to analyze colors from for window_name in names: twidget = idaapi.find_widget(window_name) if twidget: break else: raise RuntimeError("Failed to find donor view") # touch the target form so we know it is populated touch_window(twidget) # locate the Qt Widget for a form and take 1px image slice of it import sip widget = sip.wrapinstance(long(twidget), QtWidgets.QWidget) pixmap = widget.grab(QtCore.QRect(0, 10, widget.width(), 1)) # convert the raw pixmap into an image (easier to interface with) image = QtGui.QImage(pixmap.toImage()) # return the predicted background color return QtGui.QColor(predict_bg_color(image))
def dbg_bpt(self, tid, ea): Registers = StartHandler(REGS_WIDGET_TITLE) Registers.activate(None) Stack = StartHandler(STACK_WIDGET_TITLE) Stack.activate(None) idaapi.activate_widget(idaapi.find_widget("IDA View-EIP"), True) return 0
def _get_ida_bg_color_from_view(self): """ Get the background color of the IDA disassembly views via widget inspection. """ logger.debug( "Attempting to get IDA disassembly background color from view...") names = ["Enums", "Structures"] names += ["Hex View-%u" % i for i in range(5)] names += ["IDA View-%c" % chr(ord('A') + i) for i in range(5)] # find a form (eg, IDA view) to analyze colors from for window_name in names: twidget = idaapi.find_widget(window_name) if twidget: break else: logger.debug(" - Failed to find donor view...") return None # touch the target form so we know it is populated self._touch_ida_window(twidget) # locate the Qt Widget for a form and take 1px image slice of it import sip widget = sip.wrapinstance(int(twidget), QtWidgets.QWidget) pixmap = widget.grab(QtCore.QRect(0, 10, widget.width(), 1)) # convert the raw pixmap into an image (easier to interface with) image = QtGui.QImage(pixmap.toImage()) # return the predicted background color return QtGui.QColor(predict_bg_color(image))
def get_widget(title): """Get the Qt widget of the IDA window with the given title.""" tform = idaapi.find_widget(title) if not tform: raise exceptions.FormNotFound( "No form titled {!r} found.".format(title)) return idaapi.PluginForm.FormToPyQtWidget(tform)
def activate(self, ctx): tform = idaapi.find_widget('Classes') if not tform: class_viewer = ClassViewer(classes.ProxyModel(), classes.TreeModel()) class_viewer.Show() else: idaapi.activate_widget(tform, True)
def init(): """It colors the database, loads capa explorer (running its analysis) and reactivate the `IDA View-A` view. Call this method after IDA initial autoanalysis has been finished.""" color.apply() ida_loader.load_and_run_plugin("capa_explorer", 1) # 1 = analyze widget = idaapi.find_widget("IDA View-A") if widget: idaapi.activate_widget(widget, True) print("ANA: Initialization finished")
def open_control_panel(self): """ Open the control panel view and attach it to IDA View-A or Pseudocode-A. """ wrapper = ControlPanelViewWrapper(controller) if not wrapper.twidget: l.info( "BinSync is unable to find a widget to attach to. You are likely running headlessly" ) return None flags = idaapi.PluginForm.WOPN_TAB | idaapi.PluginForm.WOPN_RESTORE | idaapi.PluginForm.WOPN_PERSIST idaapi.display_widget(wrapper.twidget, flags) wrapper.widget.visible = True # casually open a pseudocode window, this prevents magic sync from spawning pseudocode windows # in weird locations upon an initial run func_addr = next(idautils.Functions()) ida_hexrays.open_pseudocode( func_addr, ida_hexrays.OPF_NO_WAIT | ida_hexrays.OPF_REUSE) # then attempt to flip back to IDA View-A twidget = idaapi.find_widget("IDA View-A") if twidget is not None: ida_kernwin.activate_widget(twidget, True) target = "Functions" fwidget = idaapi.find_widget(target) if not fwidget: # prioritize attaching the binsync panel to a decompilation window target = "Pseudocode-A" dwidget = idaapi.find_widget(target) if not dwidget: target = "IDA View-A" if target == "Functions": idaapi.set_dock_pos(ControlPanelViewWrapper.NAME, target, idaapi.DP_INSIDE) else: # attach the panel to the found target idaapi.set_dock_pos(ControlPanelViewWrapper.NAME, target, idaapi.DP_RIGHT)
def refresh_pseudocode_view(): """ Refresh the pseudocode view in IDA. """ names = ['Pseudocode-%c' % chr(ord('A') + i) for i in range(5)] for name in names: widget = idaapi.find_widget(name) if widget: vu = idaapi.get_widget_vdui(widget) vu.refresh_view(True)
def get_window(): """Get IDA's top level window.""" tform = idaapi.get_current_widget() # Required sometimes when closing IDBs and not IDA. if not tform: tform = idaapi.find_widget("Output window") widget = idaapi.PluginForm.FormToPyQtWidget(tform) window = widget.window() return window
def __init__(self, title): columns = [["Caller", 20 | 327680], ["Function", 30 | 327680], ["NumOfArgs", 8], ["Risk", 8]] # columns += [[i, 8] for i in ARG_NAMES] Choose2.__init__(self, title, columns) self.items = [] twidget = idaapi.find_widget("Functions window") self.widget = sip.wrapinstance(long(twidget), QtWidgets.QWidget) # NOTE: LOL self.table = self.widget.findChild(QtWidgets.QTableView) self.table.selectionModel().selectionChanged.connect(self.my_event)
def set_window_position(self): ref_widgets = [("Modules", idaapi.DP_TOP), ("Threads", idaapi.DP_TOP), ("IDA View-EIP", idaapi.DP_RIGHT), ("Stack view", idaapi.DP_TOP)] plug_window_name = "Registers - %s" % PLUGIN_NAME regs_widget = idaapi.find_widget("General registers") if regs_widget: idaapi.set_dock_pos(REGS_WIDGET_TITLE, "General registers", idaapi.DP_INSIDE) idaapi.close_widget(regs_widget, 0) else: found = False for wname, pos in ref_widgets: if idaapi.find_widget(wname): idaapi.set_dock_pos(REGS_WIDGET_TITLE, wname, pos) found = True break if not found: idaapi.set_dock_pos(REGS_WIDGET_TITLE, None, idaapi.DP_FLOATING)
def register_actions_and_handlers_decompile_view(): """ Attach the following actions in the pop-up menu of the decompiled view. """ # Load a custom icon icon_path = gl.plugin_resource("ghida.png") icon_data = str(open(icon_path, "rb").read()) icon_ghida = idaapi.load_custom_icon(data=icon_data) decompiler_widget = idaapi.find_widget('Decompiled Function') # TODO alternative # decompiler_widget = idaapi.get_current_tform() # Add Rename to the pop-up action_renamecustviewer = idaapi.action_desc_t( 'my:renamecustviewerhandler', 'Rename', RenameCustViewerHandler(DECOMP_VIEW), None, None, icon_ghida) decompiler_widget = idaapi.find_widget('Decompiled Function') idaapi.register_action(action_renamecustviewer) idaapi.attach_action_to_popup(decompiler_widget, None, "my:renamecustviewerhandler", None) # Add add-comment to the pop-up action_addcommentcustviewer = idaapi.action_desc_t( 'my:addcommentcustviewer', 'Add comment', AddCommentCustViewerHandler(DECOMP_VIEW), None, None, icon_ghida) idaapi.register_action(action_addcommentcustviewer) idaapi.attach_action_to_popup(decompiler_widget, None, "my:addcommentcustviewer", None) # Add goto to the pop-up action_gotocustviewerhandler = idaapi.action_desc_t( 'my:gotocustviewerhandler', 'Goto', GoToCustViewerHandler(DECOMP_VIEW), None, None, icon_ghida) idaapi.register_action(action_gotocustviewerhandler) idaapi.attach_action_to_popup(decompiler_widget, None, "my:gotocustviewerhandler", None) return
def touch_window(target): """ Touch a window/widget/form to ensure it gets drawn by IDA. XXX/HACK: We need to ensure that widget we will analyze actually gets drawn so that there are colors for us to steal. To do this, we switch to it, and switch back. I tried a few different ways to trigger this from Qt, but could only trigger the full painting by going through the IDA routines. """ # get the currently active widget/form title (the form itself seems transient...) if using_ida7api: twidget = idaapi.get_current_widget() title = idaapi.get_widget_title(twidget) else: form = idaapi.get_current_tform() title = idaapi.get_tform_title(form) # touch/draw the widget by playing musical chairs if using_ida7api: # touch the target window by switching to it idaapi.activate_widget(target, True) flush_ida_sync_requests() # locate our previous selection previous_twidget = idaapi.find_widget(title) # return us to our previous selection idaapi.activate_widget(previous_twidget, True) flush_ida_sync_requests() else: # touch the target window by switching to it idaapi.switchto_tform(target, True) flush_ida_sync_requests() # locate our previous selection previous_form = idaapi.find_tform(title) # lookup our original form and switch back to it idaapi.switchto_tform(previous_form, True) flush_ida_sync_requests()
def eventFilter(self, source, event): # # hook the destroy event of the coverage overview widget so that we can # cleanup after ourselves in the interest of stability # if int(event.type() ) == 16: # NOTE/COMPAT: QtCore.QEvent.Destroy not in IDA7? self._target.terminate() # # this is an unknown event, but it seems to fire when the widget is # being saved/restored by a QMainWidget. we use this to try and ensure # the Coverage Overview stays docked when flipping between Reversing # and Debugging states in IDA. # # See issue #16 on github for more information. # if int(event.type()) == 2002 and disassembler.NAME == "IDA": import idaapi # # if the general registers IDA View exists, we make the assumption # that the user has probably started debugging. # # NOTE / COMPAT: if disassembler.USING_IDA7API: debug_mode = bool(idaapi.find_widget("General registers")) else: debug_mode = bool(idaapi.find_tform("General registers")) # # if this is the first time the user has started debugging, dock # the coverage overview in the debug QMainWidget workspace. its # dock status / position should persist future debugger launches. # global debugger_docked if debug_mode and not debugger_docked: idaapi.set_dock_pos(self._target._title, "Structures", idaapi.DP_TAB) debugger_docked = True return False
def highlight_symbol_in_DECOMP(): """ Select a symbol in the IDA DISASM view, highlight the corresponding symbol in DECOMP view. """ # print("GhIDA:: [DEBUG] highlight_symbol_in_DECOMP called") symbol = idaapi.get_highlighted_identifier() if not symbol: return converted_symbol = from_ida_to_ghidra_syntax_conversion(symbol) decompiler_widget = idaapi.find_widget('Decompiled Function') if converted_symbol: # Update IDA DECOMP view idaapi.set_highlight(decompiler_widget, converted_symbol, 1) else: idaapi.set_highlight(decompiler_widget, 'aaabbbccc', 1) return
def _make_unique_title(self, title): """Make the title unique. Adds a counter to the title to prevent duplicates. Prior to IDA 6.8, two graphs with the same title could crash IDA. This has been fixed (https://www.hex-rays.com/products/ida/6.8/index.shtml). The code will not change for support of older versions and as it is more usable this way. """ unique_title = title for counter in itertools.count(): unique_title = "{}-{}".format(title, counter) if not idaapi.find_widget(unique_title): break return unique_title
def open_control_panel(self): """ Open the control panel view and attach it to IDA View-A or Pseudocode-A. """ wrapper = InfoPanelViewWrapper(controller) if not wrapper.twidget: raise RuntimeError("Unexpected: twidget does not exist.") flags = idaapi.PluginForm.WOPN_TAB | idaapi.PluginForm.WOPN_RESTORE | idaapi.PluginForm.WOPN_PERSIST idaapi.display_widget(wrapper.twidget, flags) wrapper.widget.visible = True # Dock it for target in ["IDA View-A", "Pseudocode-A"]: dwidget = idaapi.find_widget(target) if dwidget: idaapi.set_dock_pos(InfoPanelViewWrapper.NAME, target, idaapi.DP_RIGHT) break
def arrange_widgets(self): if self.arranging: return self.arranging = True try: wlist = [] for ch in range(ord("A"), ord("Z")): wname = "Pseudocode-" + chr(ch) if idaapi.find_widget(wname): wlist.append(wname) if len(wlist) > 0: idaapi.set_dock_pos(wlist[0], "IDA View-A", idaapi.DP_RIGHT) for i in range(1, len(wlist)): idaapi.set_dock_pos(wlist[i], wlist[i - 1], idaapi.DP_TAB) finally: self.arranging = False
def retrieve_function_callback(self, __, ea=None): func_ea = idaapi.get_screen_ea() if ea is None else ea func_name = idaapi.get_func_name(func_ea) widget_title = "{} - {}".format(self.name, func_name) widget = idaapi.find_widget(widget_title) if widget: idaapi.activate_widget(widget, True) return targets = self.retrieve_function(func_ea, self.cfg['topk']) if targets is None: print("[{}] {} is skipped because get function feature error".format(self.name, func_name)) return cv = SourceCodeViewer(func_name, targets) cv.Create(widget_title) cv.refresh() # CDVF_STATUSBAR 0x04, keep the status bar in the custom viewer cv = idaapi.create_code_viewer(cv.GetWidget(), 0x4) idaapi.set_code_viewer_is_source(cv) idaapi.display_widget(cv, idaapi.PluginForm.WOPN_DP_TAB | idaapi.PluginForm.WOPN_RESTORE) ida_kernwin.refresh_navband(True)
def ida_get_cfg_raw(existing_cfg=None): if "idaapi" not in sys.modules: print("ERROR: idaapi not loaded") return None import idaapi tw = idaapi.find_widget("IDAgrap") if tw is not None: import idagrap # Get CFG from existing loaded IDAgrap w = idaapi.PluginForm.FormToPyQtWidget(tw) pgw = w.findChild( idagrap.ui.widgets.PatternGenerationWidget.PatternGenerationWidget) cfg = pgw.cc.PatternGenerator.graph return cfg, True else: # If necessary, load grap and creates new CFG object if existing_cfg is None: fp, pathname, description = imp.find_module("grap") _mod = imp.load_module("grap", fp, pathname, description) cfg = _mod.CFG() return cfg, False return existing_cfg, False
def get_disas_bg_color_ida7(): """ Get the background color of an IDA disassembly view. (IDA 7+) """ import sip # find a widget (eg, IDA view) to steal a pixel from for i in xrange(5): twidget = idaapi.find_widget("IDA View-%c" % chr(ord('A') + i)) if twidget: break else: raise RuntimeError("Failed to find donor IDA View") # take 2px tall screenshot of the widget widget = sip.wrapinstance(long(twidget), QtWidgets.QWidget) # NOTE: LOL pixmap = widget.grab(QtCore.QRect(0, 0, widget.width(), 2)) # extract 1 pixel like a pleb (hopefully a background pixel :|) img = QtGui.QImage(pixmap.toImage()) color = QtGui.QColor(img.pixel(img.width() / 2, 1)) # return the color of the pixel we extracted return color