class AutoREView(idaapi.PluginForm): ADDR_ROLE = QtCore.Qt.UserRole + 1 def __init__(self, data): super(AutoREView, self).__init__() self._data = data self.tv = None self._model = None def Show(self): return idaapi.PluginForm.Show(self, 'AutoRE', options=idaapi.PluginForm.FORM_PERSIST) def OnCreate(self, form): if HAS_PYSIDE: self.parent = self.FormToPySideWidget(form) else: self.parent = self.FormToPyQtWidget(form) self._idp_hooks = AutoReIDPHooks(self) if not self._idp_hooks.hook(): print 'IDP_Hooks.hook() failed' self.tv = QTreeView() self.tv.setExpandsOnDoubleClick(False) root_layout = QVBoxLayout(self.parent) # self.le_filter = QLineEdit(self.parent) # root_layout.addWidget(self.le_filter) root_layout.addWidget(self.tv) self.parent.setLayout(root_layout) self._model = QtGui.QStandardItemModel() self._init_model() self.tv.setModel(self._model) self.tv.setColumnWidth(0, 200) self.tv.setColumnWidth(1, 300) self.tv.header().setStretchLastSection(True) self.tv.expandAll() self.tv.doubleClicked.connect(self.on_navigate_to_method_requested) # self.le_filter.textChanged.connect(self.on_filter_text_changed) self.tv.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.tv.customContextMenuRequested.connect(self._tree_customContextMenuRequesssted) rename_action = QAction('Rename...', self.tv) rename_action.setShortcut('n') rename_action.triggered.connect(self._tv_rename_action_triggered) self.tv.addAction(rename_action) # def __event_filter(self, source, event): # if event.type() == QtCore.QEvent. def _tree_customContextMenuRequesssted(self, pos): idx = self.tv.indexAt(pos) if not idx.isValid(): return addr = idx.data(role=self.ADDR_ROLE) if not addr: return name_idx = idx.sibling(idx.row(), 1) old_name = name_idx.data() menu = QMenu() rename_action = menu.addAction('Rename `%s`...' % old_name) rename_action.setShortcut('n') action = menu.exec_(self.tv.mapToGlobal(pos)) if action == rename_action: return self._rename_ea_requested(addr, name_idx) def _tv_rename_action_triggered(self): selected = self.tv.selectionModel().selectedIndexes() if not selected: return idx = selected[0] if not idx.isValid(): return addr = idx.data(role=self.ADDR_ROLE) if not addr: return name_idx = idx.sibling(idx.row(), 1) if not name_idx.isValid(): return return self._rename_ea_requested(addr, name_idx) def _rename_ea_requested(self, addr, name_idx): old_name = name_idx.data() if idaapi.IDA_SDK_VERSION >= 700: new_name = idaapi.ask_str(str(old_name), 0, 'New name:') else: new_name = idaapi.askstr(0, str(old_name), 'New name:') if new_name is None: return self._rename(addr, new_name) renamed_name = idaapi.get_ea_name(addr) name_idx.model().setData(name_idx, renamed_name) @classmethod def _rename(cls, ea, new_name): if not ea or ea == idaapi.BADADDR: return if idaapi.IDA_SDK_VERSION >= 700: return idaapi.force_name(ea, new_name, idaapi.SN_NOCHECK) return idaapi.do_name_anyway(ea, new_name, 0) def OnClose(self, form): if self._idp_hooks: self._idp_hooks.unhook() def _tv_init_header(self, model): item_header = QtGui.QStandardItem("EA") item_header.setToolTip("Address") model.setHorizontalHeaderItem(0, item_header) item_header = QtGui.QStandardItem("Function name") model.setHorizontalHeaderItem(1, item_header) item_header = QtGui.QStandardItem("API called") model.setHorizontalHeaderItem(2, item_header) # noinspection PyMethodMayBeStatic def _tv_make_tag_item(self, name): rv = QtGui.QStandardItem(name) rv.setEditable(False) return [rv, QtGui.QStandardItem(), QtGui.QStandardItem()] def _tv_make_ref_item(self, tag, ref): ea_item = QtGui.QStandardItem(('%0' + get_addr_width() + 'X') % ref['ea']) ea_item.setEditable(False) ea_item.setData(ref['ea'], self.ADDR_ROLE) name_item = QtGui.QStandardItem(ref['name']) name_item.setEditable(False) name_item.setData(ref['ea'], self.ADDR_ROLE) apis = ', '.join(ref['tags'][tag]) api_name = QtGui.QStandardItem(apis) api_name.setEditable(False) api_name.setData(ref['ea'], self.ADDR_ROLE) api_name.setToolTip(apis) return [ea_item, name_item, api_name] def _init_model(self): self._model.clear() root_node = self._model.invisibleRootItem() self._tv_init_header(self._model) for tag, refs in self._data.items(): item_tag_list = self._tv_make_tag_item(tag) item_tag = item_tag_list[0] root_node.appendRow(item_tag_list) for ref in refs: ref_item_list = self._tv_make_ref_item(tag, ref) item_tag.appendRow(ref_item_list) def on_navigate_to_method_requested(self, index): addr = index.data(role=self.ADDR_ROLE) if addr is not None: idaapi.jumpto(addr)
class AutoREView(idaapi.PluginForm): ADDR_ROLE = QtCore.Qt.UserRole + 1 def __init__(self, data): super(AutoREView, self).__init__() self._data = data def Show(self): return idaapi.PluginForm.Show(self, 'AutoRE', options=idaapi.PluginForm.FORM_PERSIST) def OnCreate(self, form): # if HAS_PYSIDE: # self.parent = self.FormToPySideWidget(form) # else: self.parent = self.FormToPyQtWidget(form) self.tv = QTreeView() self.tv.setExpandsOnDoubleClick(False) root_layout = QVBoxLayout(self.parent) # self.le_filter = QLineEdit(self.parent) # root_layout.addWidget(self.le_filter) root_layout.addWidget(self.tv) self.parent.setLayout(root_layout) self._model = QtGui.QStandardItemModel() self._init_model() self.tv.setModel(self._model) self.tv.setColumnWidth(0, 200) self.tv.setColumnWidth(1, 300) self.tv.header().setStretchLastSection(True) self.tv.expandAll() self.tv.doubleClicked.connect(self.on_navigate_to_method_requested) # self.le_filter.textChanged.connect(self.on_filter_text_changed) def OnClose(self, form): # print 'TODO: OnClose(): clear the pointer to form in the plugin' pass def _tv_init_header(self, model): item_header = QtGui.QStandardItem("EA") item_header.setToolTip("Address") model.setHorizontalHeaderItem(0, item_header) item_header = QtGui.QStandardItem("Function name") model.setHorizontalHeaderItem(1, item_header) item_header = QtGui.QStandardItem("API called") model.setHorizontalHeaderItem(2, item_header) def _tv_make_tag_item(self, name): rv = QtGui.QStandardItem(name) rv.setEditable(False) return [rv, QtGui.QStandardItem(), QtGui.QStandardItem()] def _tv_make_ref_item(self, tag, ref): ea_item = QtGui.QStandardItem( ('%0' + get_addr_width() + 'X') % ref['ea']) ea_item.setEditable(False) ea_item.setData(ref['ea'], self.ADDR_ROLE) name_item = QtGui.QStandardItem(ref['name']) name_item.setEditable(False) name_item.setData(ref['ea'], self.ADDR_ROLE) apis = ', '.join(ref['tags'][tag]) api_name = QtGui.QStandardItem(apis) api_name.setEditable(False) api_name.setData(ref['ea'], self.ADDR_ROLE) api_name.setToolTip(apis) return [ea_item, name_item, api_name] def _init_model(self): self._model.clear() root_node = self._model.invisibleRootItem() self._tv_init_header(self._model) for tag, refs in self._data.items(): item_tag_list = self._tv_make_tag_item(tag) item_tag = item_tag_list[0] root_node.appendRow(item_tag_list) for ref in refs: ref_item_list = self._tv_make_ref_item(tag, ref) item_tag.appendRow(ref_item_list) def on_navigate_to_method_requested(self, index): addr = index.data(role=self.ADDR_ROLE) if addr is not None: idaapi.jumpto(addr)