def __init__(self, app): super(DataPanel, self).__init__(app) self.app = app self.data = {} self.setOrientation(Qt.Horizontal) self._key_list_model = QStandardItemModel(0, 1) self.key_lists = DwarfListView(parent=self.app) self.key_lists.setHeaderHidden(True) self.key_lists.setModel(self._key_list_model) self.key_lists.selectionModel().selectionChanged.connect( self.item_selected) self.key_lists.setContextMenuPolicy(Qt.CustomContextMenu) self.key_lists.customContextMenuRequested.connect( self._on_context_menu) self.addWidget(self.key_lists) self.editor = QPlainTextEdit() self.addWidget(self.editor) self.hex_view = HexEditor(self.app) self.hex_view.have_context_menu = False self.hex_view.setVisible(False) self.addWidget(self.hex_view) #self.setStretchFactor(0, 8) self.setStretchFactor(1, 4) self.setStretchFactor(2, 4)
def __init__(self, app, flags=None): super(QDebugPanel, self).__init__(flags) self.setDockOptions(QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks | QMainWindow.AllowTabbedDocks) self.app = app self.q_settings = app.q_settings self.functions_list = DwarfListView() self.functions_list_model = QStandardItemModel(0, 1) self.functions_list_model.setHeaderData(0, Qt.Horizontal, '') self.functions_list.setModel(self.functions_list_model) self.functions_list.setHeaderHidden(True) self.functions_list.doubleClicked.connect( self._function_double_clicked) self.dock_functions_list = QDockWidget('Functions', self) self.dock_functions_list.setObjectName('functions') self.dock_functions_list.setWidget(self.functions_list) self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_functions_list) self.resizeDocks([self.dock_functions_list], [100], Qt.Horizontal) self.app.debug_view_menu.addAction( self.dock_functions_list.toggleViewAction()) self.memory_panel_range = None self.disassembly_panel_range = None screen_size = QtWidgets.QDesktopWidget().screenGeometry(-1) m_width = screen_size.width() self.memory_panel = HexEditor(self.app) self.memory_panel.debug_panel = self self.memory_panel.dataChanged.connect(self.on_memory_modified) self.disassembly_panel = DisassemblyView(self.app) self.disassembly_panel.debug_panel = self self.dock_memory_panel = QDockWidget('Memory', self) self.dock_memory_panel.setWidget(self.memory_panel) self.dock_memory_panel.setObjectName('memory') self.dock_disassembly_panel = QDockWidget('Disassembly', self) self.dock_disassembly_panel.setWidget(self.disassembly_panel) self.dock_disassembly_panel.setObjectName('disassembly') self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_memory_panel, Qt.Horizontal) self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_disassembly_panel, Qt.Horizontal) if m_width >= 1920: self.splitDockWidget(self.dock_memory_panel, self.dock_disassembly_panel, Qt.Horizontal) else: self.tabifyDockWidget(self.dock_memory_panel, self.dock_disassembly_panel) self.restoreUiState()
def __init__(self, parent=None): super(ContextWidget, self).__init__(parent=parent) self._app_window = parent self.setAutoFillBackground(True) self._app_window.dwarf.onContextChanged.connect( self._on_context_changed) self._nativectx_model = QStandardItemModel(0, 4) self._nativectx_model.setHeaderData(0, Qt.Horizontal, 'Reg') self._nativectx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(1, Qt.Horizontal, 'Value') self._nativectx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(2, Qt.Horizontal, 'Decimal') self._nativectx_model.setHeaderData(3, Qt.Horizontal, 'Telescope') self._nativectx_list = DwarfListView() self._nativectx_list.setModel(self._nativectx_model) self._nativectx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._nativectx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._nativectx_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self._nativectx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._nativectx_list.customContextMenuRequested.connect( self._on_native_contextmenu) self._javactx_model = QStandardItemModel(0, 3) self._javactx_model.setHeaderData(0, Qt.Horizontal, 'Argument') self._javactx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._javactx_model.setHeaderData(1, Qt.Horizontal, 'Class') self._javactx_model.setHeaderData(2, Qt.Horizontal, 'Value') self._javactx_list = DwarfListView() self._javactx_list.setModel(self._javactx_model) self._javactx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._javactx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._javactx_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self._javactx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._javactx_list.customContextMenuRequested.connect( self._on_java_contextmenu) self.addTab(self._nativectx_list, 'Native') self.show_context_tab('Native')
def __init__(self, parent=None): super(WelcomeDialog, self).__init__(parent=parent) self._prefs = parent.prefs self._sub_titles = [ ['duck', 'dumb', 'doctor', 'dutch', 'dark', 'dirty', 'debugging'], ['warriors', 'wardrobes', 'waffles', 'wishes', 'worcestershire'], ['are', 'aren\'t', 'ain\'t', 'appears to be'], ['rich', 'real', 'riffle', 'retarded', 'rock'], [ 'as f**k', 'fancy', 'f****d', 'front-ended', 'falafel', 'french fries' ], ] self._update_thread = None # setup size and remove/disable titlebuttons self.desktop_geom = qApp.desktop().availableGeometry() self.setFixedSize(self.desktop_geom.width() * .45, self.desktop_geom.height() * .4) self.setGeometry( QStyle.alignedRect(Qt.LeftToRight, Qt.AlignCenter, self.size(), qApp.desktop().availableGeometry())) self.setSizeGripEnabled(False) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.setWindowFlag(Qt.WindowContextHelpButtonHint, False) self.setWindowFlag(Qt.WindowCloseButtonHint, True) self.setModal(True) self._recent_list_model = QStandardItemModel(0, 2) self._recent_list_model.setHeaderData(0, Qt.Horizontal, 'Type') self._recent_list_model.setHeaderData(1, Qt.Horizontal, 'Path') self._recent_list = DwarfListView(self) self._recent_list.setModel(self._recent_list_model) self._recent_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._recent_list.header().setSectionResizeMode(1, QHeaderView.Stretch) # setup ui elements self.setup_ui() random.seed(a=None, version=2) self.update_commits_thread = DwarfCommitsThread(parent) self.update_commits_thread.on_update_available.connect( self._on_dwarf_isupdate) self.update_commits_thread.start() # center self.setGeometry( QStyle.alignedRect(Qt.LeftToRight, Qt.AlignCenter, self.size(), qApp.desktop().availableGeometry()))
class DisassemblyPanel(QSplitter): def __init__(self, app): super(DisassemblyPanel, self).__init__() self.app = app self.functions_list = DwarfListView() self.functions_list_model = QStandardItemModel(0, 1) self.functions_list_model.setHeaderData(0, Qt.Horizontal, 'functions') self.functions_list.setModel(self.functions_list_model) self.addWidget(self.functions_list) self.functions_list.hide() self.functions_list.doubleClicked.connect(self._function_double_clicked) self.disasm_view = DisassemblyView(app) self.addWidget(self.disasm_view) self.setStretchFactor(0, 1) self.setStretchFactor(1, 5) self.update_functions() def disassemble(self, dwarf_range): self.disasm_view.disassemble(dwarf_range) def update_functions(self, functions_list=None): if functions_list is None: functions_list = {} self.functions_list_model.setRowCount(0) for module_info_base in self.app.dwarf.database.modules_info: module_info = self.app.dwarf.database.modules_info[module_info_base] if len(module_info.functions) > 0: self.functions_list.show() for function in module_info.functions: functions_list[function.name] = function.address for function_name in sorted(functions_list.keys()): function_addr = functions_list[function_name] item = QStandardItem(function_name.replace('.', '_')) item.setData(function_addr, Qt.UserRole + 2) self.functions_list_model.appendRow([item]) if self.functions_list_model.rowCount() > 0: self.functions_list.show() else: self.functions_list.hide() def _function_double_clicked(self, model_index): item = self.functions_list_model.itemFromIndex(model_index) address = item.data(Qt.UserRole + 2) self.disasm_view.read_memory(address)
def _on_ui_element_created(self, elem, widget): if elem == 'disassembly': self.disassembly_view = widget self.disassembly_view.run_default_disassembler = False self.disassembly_view.onDisassemble.connect(self._on_disassemble) r2_info = QSplitter() r2_info.setOrientation(Qt.Vertical) call_refs = DwarfListView() self.call_refs_model = QStandardItemModel(0, 3) self.call_refs_model.setHeaderData(0, Qt.Horizontal, 'call refs') self.call_refs_model.setHeaderData(1, Qt.Horizontal, '') self.call_refs_model.setHeaderData(2, Qt.Horizontal, '') call_refs.setModel(self.call_refs_model) code_xrefs = DwarfListView() self.code_xrefs_model = QStandardItemModel(0, 3) self.code_xrefs_model.setHeaderData(0, Qt.Horizontal, 'code xrefs') self.code_xrefs_model.setHeaderData(1, Qt.Horizontal, '') self.code_xrefs_model.setHeaderData(2, Qt.Horizontal, '') code_xrefs.setModel(self.code_xrefs_model) r2_info.addWidget(call_refs) r2_info.addWidget(code_xrefs) self.disassembly_view.insertWidget(0, r2_info) self.disassembly_view.setStretchFactor(0, 1) self.disassembly_view.setStretchFactor(1, 5) r2_menu = QMenu('r2') r2_menu.addAction('graph view', self.show_graph_view) r2_menu.addAction('decompile', self.show_decompiler_view) self.disassembly_view.disasm_view.menu_extra_menu.append(r2_menu)
class DataPanel(QSplitter): def __init__(self, app): super(DataPanel, self).__init__(app) self.app = app self.data = {} self.setOrientation(Qt.Horizontal) self._key_list_model = QStandardItemModel(0, 1) self.key_lists = DwarfListView(parent=self.app) self.key_lists.setHeaderHidden(True) self.key_lists.setModel(self._key_list_model) self.key_lists.doubleClicked.connect(self.list_item_double_clicked) self.key_lists.setContextMenuPolicy(Qt.CustomContextMenu) self.key_lists.customContextMenuRequested.connect( self._on_context_menu) self.addWidget(self.key_lists) self.editor = QPlainTextEdit() self.addWidget(self.editor) self.hex_view = HexEditor(self.app) self.hex_view.setVisible(False) self.addWidget(self.hex_view) #self.setStretchFactor(0, 8) self.setStretchFactor(1, 4) def clear(self): self._key_list_model.clear() self.editor.setPlainText('') self.hex_view.clear_panel() def append_data(self, data_type, key, text_data): if key not in self.data: self._key_list_model.appendRow([QStandardItem(key)]) self.data[key] = [data_type, text_data] def list_item_double_clicked(self, item): item = self._key_list_model.itemFromIndex(item) if self.data[item.text()][0] == 'plain': self.hex_view.setVisible(False) self.editor.setVisible(True) self.editor.setPlainText(self.data[item.text()][1]) else: self.editor.setVisible(False) self.hex_view.setVisible(True) self.hex_view.bytes_per_line = 16 self.hex_view.set_data(self.data[item.text()][1]) def _on_context_menu(self, pos): context_menu = QMenu(self) index = self.key_lists.indexAt(pos).row() if index != -1: context_menu.addAction('Clear', self.clear) global_pt = self.key_lists.mapToGlobal(pos) context_menu.exec(global_pt)
def __init__(self, parent=None): super(JavaInspector, self).__init__(parent) self._app_window = parent self._app_window.dwarf.onEnumerateJavaMethodsComplete.connect( self._on_method_enumeration_complete) self._app_window.dwarf.onEnumerateJavaClassesStart.connect( self._on_class_enumeration_start) self._app_window.dwarf.onEnumerateJavaClassesMatch.connect( self._on_class_enumeration_match) self._app_window.dwarf.onEnumerateJavaClassesComplete.connect( self._on_class_enumeration_complete) self._java_classes = DwarfListView(self) self._javaclass_model = QStandardItemModel(0, 1) self._javaclass_model.setHeaderData(0, Qt.Horizontal, 'Class') self._java_classes.setModel(self._javaclass_model) self._java_classes.selectionModel().selectionChanged.connect( self._class_clicked) self._java_classes.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._java_classes.setContextMenuPolicy(Qt.CustomContextMenu) self._java_classes.customContextMenuRequested.connect( self._on_class_contextmenu) self._java_classes.doubleClicked.connect(self._class_dblclicked) self._java_methods = DwarfListView(self) self._javamethod_model = QStandardItemModel(0, 1) self._javamethod_model.setHeaderData(0, Qt.Horizontal, 'Method') self._java_methods.setModel(self._javamethod_model) self._java_methods.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._java_methods.setContextMenuPolicy(Qt.CustomContextMenu) self._java_methods.customContextMenuRequested.connect( self._on_method_contextmenu) self._java_methods.doubleClicked.connect(self._method_dblclicked) h_box = QHBoxLayout() h_box.setContentsMargins(0, 0, 0, 0) h_box.addWidget(self._java_classes) h_box.addWidget(self._java_methods) self.setLayout(h_box)
def __init__(self, parent=None, file_path=None): super().__init__(parent=parent) h_box = QHBoxLayout(self) self._ident_titles = ['EI_MAG0', 'EI_MAG1', 'EI_MAG2', 'EI_MAG3', 'EI_CLASS', 'EI_DATA', 'EI_VERSION', 'EI_OSABI', 'EI_ABIVERSION', 'EI_PAD'] self.elf_info = DwarfListView(self) self.elf_info.setRootIsDecorated(True) self.elf_info.setExpandsOnDoubleClick(True) self.elf_info.setContextMenuPolicy(Qt.CustomContextMenu) self.elf_info.customContextMenuRequested.connect(self._on_context_menu) h_box.addWidget(self.elf_info) self._elf_info_mdl = QStandardItemModel(0, 2) self._elf_info_mdl.setHeaderData(0, Qt.Horizontal, 'Name') self._elf_info_mdl.setHeaderData(1, Qt.Horizontal, 'Value') self.elf_info.setModel(self._elf_info_mdl) self.elf_info.doubleClicked.connect(self._on_dblclicked) self.title = "ELF Info" self._elf_file_path = None self.setLayout(h_box) if file_path: self.set_elf_file(file_path)
def __init__(self, app): super(DisassemblyPanel, self).__init__() self.app = app self.functions_list = DwarfListView() self.functions_list_model = QStandardItemModel(0, 1) self.functions_list_model.setHeaderData(0, Qt.Horizontal, 'functions') self.functions_list.setModel(self.functions_list_model) self.addWidget(self.functions_list) self.functions_list.hide() self.functions_list.doubleClicked.connect(self._function_double_clicked) self.disasm_view = DisassemblyView(app) self.addWidget(self.disasm_view) self.setStretchFactor(0, 1) self.setStretchFactor(1, 5) self.update_functions()
def __init__(self, device, parent=None): super(SpawnsList, self).__init__(parent=parent) self.break_at_start = False self._device = device self.spawn_list = DwarfListView() model = QStandardItemModel(0, 2, parent) model.setHeaderData(0, Qt.Horizontal, "Name") model.setHeaderData(1, Qt.Horizontal, "Package") self.spawn_list.doubleClicked.connect(self._on_item_clicked) v_box = QVBoxLayout() v_box.setContentsMargins(0, 0, 0, 0) v_box.addWidget(self.spawn_list) break_spawn_start = QCheckBox('Break at spawn') break_spawn_start.stateChanged.connect(self._on_toggle_break_spawn) v_box.addWidget(break_spawn_start) self.refresh_button = QPushButton('Refresh') self.refresh_button.clicked.connect(self._on_refresh_procs) self.refresh_button.setEnabled(False) v_box.addWidget(self.refresh_button) self.setLayout(v_box) self.spawn_list.setModel(model) self.spawn_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.spaw_update_thread = SpawnsThread(self, self._device) self.spaw_update_thread.add_spawn.connect(self._on_add_proc) self.spaw_update_thread.is_error.connect(self._on_error) self.spaw_update_thread.is_finished.connect(self._on_refresh_finished) self.spaw_update_thread.device = self._device self.spaw_update_thread.start()
def __init__(self, device, parent=None): super(ProcessList, self).__init__(parent=parent) # if not isinstance(device, frida.core.Device): # print('No FridaDevice') # return self._device = device self.process_list = DwarfListView() model = QStandardItemModel(0, 2, parent) model.setHeaderData(0, Qt.Horizontal, "PID") model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) model.setHeaderData(1, Qt.Horizontal, "Name") self.process_list.doubleClicked.connect(self._on_item_clicked) v_box = QVBoxLayout() v_box.setContentsMargins(0, 0, 0, 0) v_box.addWidget(self.process_list) self.refresh_button = QPushButton('Refresh') self.refresh_button.clicked.connect(self._on_refresh_procs) self.refresh_button.setEnabled(False) v_box.addWidget(self.refresh_button) self.setLayout(v_box) self.process_list.setModel(model) self.process_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.procs_update_thread = ProcsThread(self, self._device) self.procs_update_thread.add_proc.connect(self._on_add_proc) self.procs_update_thread.is_error.connect(self._on_error) self.procs_update_thread.is_finished.connect(self._on_refresh_finished) self.procs_update_thread.device = self._device self.procs_update_thread.start()
def __init__(self, parent=None, setup_list_cb=None, setup_list_cb_args=None, double_click_to_accept=False, checkable=False): super(ListDialog, self).__init__(parent) self.right_click_handler = None layout = QVBoxLayout(self) self.list = DwarfListView() # QListWidget() self.list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) if double_click_to_accept: self.list.doubleClicked.connect(self.accept) if setup_list_cb is not None: setup_list_cb(self.list, setup_list_cb_args) layout.addWidget(self.list) if checkable: buttons = QHBoxLayout() select_all = QPushButton('select all') select_all.clicked.connect(self.select_all) buttons.addWidget(select_all) unselect_all = QPushButton('unselect all') unselect_all.clicked.connect(self.unselect_all) buttons.addWidget(unselect_all) ok = QPushButton('ok') ok.clicked.connect(self.accept) buttons.addWidget(ok) cancel = QPushButton('cancel') cancel.clicked.connect(self.close) buttons.addWidget(cancel) layout.addLayout(buttons)
def __init__(self, parent=None): # pylint: disable=too-many-statements super(BookmarksPanel, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('BookmarksPanel created before Dwarf exists') return self.bookmarks = {} self._bookmarks_list = DwarfListView() self._bookmarks_list.doubleClicked.connect(self._on_dblclicked) self._bookmarks_list.setContextMenuPolicy(Qt.CustomContextMenu) self._bookmarks_list.customContextMenuRequested.connect( self._on_contextmenu) self._bookmarks_model = QStandardItemModel(0, 2) self._bookmarks_model.setHeaderData(0, Qt.Horizontal, 'Address') self._bookmarks_model.setHeaderData(1, Qt.Horizontal, 'Notes') self._bookmarks_list.setModel(self._bookmarks_model) self._bookmarks_list.header().setStretchLastSection(False) self._bookmarks_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents | QHeaderView.Interactive) self._bookmarks_list.header().setSectionResizeMode( 1, QHeaderView.Stretch | QHeaderView.Interactive) v_box = QVBoxLayout(self) v_box.setContentsMargins(0, 0, 0, 0) v_box.addWidget(self._bookmarks_list) #header = QHeaderView(Qt.Horizontal, self) h_box = QHBoxLayout() h_box.setContentsMargins(5, 2, 5, 5) self.btn1 = QPushButton( QIcon(utils.resource_path('assets/icons/plus.svg')), '') self.btn1.setFixedSize(20, 20) self.btn1.clicked.connect(lambda: self._create_bookmark(-1)) btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')), '') btn2.setFixedSize(20, 20) btn2.clicked.connect(self.delete_items) btn3 = QPushButton( QIcon(utils.resource_path('assets/icons/trashcan.svg')), '') btn3.setFixedSize(20, 20) btn3.clicked.connect(self.clear_list) h_box.addWidget(self.btn1) h_box.addWidget(btn2) h_box.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred)) h_box.addWidget(btn3) # header.setLayout(h_box) # header.setFixedHeight(25) # v_box.addWidget(header) v_box.addLayout(h_box) self.setLayout(v_box) self._bold_font = QFont(self._bookmarks_list.font()) self._bold_font.setBold(True) shortcut_addnative = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_A), self._app_window, self._create_bookmark) shortcut_addnative.setAutoRepeat(False)
def __init__(self, parent=None): # pylint: disable=too-many-statements super(WatchersPanel, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('Watcherpanel created before Dwarf exists') return self._uppercase_hex = True self.setAutoFillBackground(True) # connect to dwarf self._app_window.dwarf.onWatcherAdded.connect(self._on_watcher_added) self._app_window.dwarf.onWatcherRemoved.connect( self._on_watcher_removed) # setup our model self._watchers_model = QStandardItemModel(0, 5) self._watchers_model.setHeaderData(0, Qt.Horizontal, 'Address') self._watchers_model.setHeaderData(1, Qt.Horizontal, 'R') self._watchers_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._watchers_model.setHeaderData(2, Qt.Horizontal, 'W') self._watchers_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._watchers_model.setHeaderData(3, Qt.Horizontal, 'X') self._watchers_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._watchers_model.setHeaderData(4, Qt.Horizontal, 'S') self._watchers_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) # setup ui v_box = QVBoxLayout(self) v_box.setContentsMargins(0, 0, 0, 0) self.list_view = DwarfListView() self.list_view.setModel(self._watchers_model) self.list_view.header().setSectionResizeMode(0, QHeaderView.Stretch) self.list_view.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setSectionResizeMode( 3, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setSectionResizeMode( 4, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setStretchLastSection(False) self.list_view.doubleClicked.connect(self._on_item_dblclick) self.list_view.setContextMenuPolicy(Qt.CustomContextMenu) self.list_view.customContextMenuRequested.connect(self._on_contextmenu) v_box.addWidget(self.list_view) #header = QHeaderView(Qt.Horizontal, self) h_box = QHBoxLayout() h_box.setContentsMargins(5, 2, 5, 5) btn1 = QPushButton(QIcon(utils.resource_path('assets/icons/plus.svg')), '') btn1.setFixedSize(20, 20) btn1.clicked.connect(self._on_additem_clicked) btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')), '') btn2.setFixedSize(20, 20) btn2.clicked.connect(self.delete_items) btn3 = QPushButton( QIcon(utils.resource_path('assets/icons/trashcan.svg')), '') btn3.setFixedSize(20, 20) btn3.clicked.connect(self.clear_list) h_box.addWidget(btn1) h_box.addWidget(btn2) h_box.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred)) h_box.addWidget(btn3) # header.setLayout(h_box) # header.setFixedHeight(25) # v_box.addWidget(header) v_box.addLayout(h_box) # create a centered dot icon _section_width = self.list_view.header().sectionSize(2) self._new_pixmap = QPixmap(_section_width, 20) self._new_pixmap.fill(Qt.transparent) painter = QPainter(self._new_pixmap) rect = QRect((_section_width * 0.5), 0, 20, 20) painter.setBrush(QColor('#666')) painter.setPen(QColor('#666')) painter.drawEllipse(rect) self._dot_icon = QIcon(self._new_pixmap) # shortcuts shortcut_add = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_W), self._app_window, self._on_additem_clicked) shortcut_add.setAutoRepeat(False) self.setLayout(v_box)
class SpawnsList(QWidget): """ ProcessListWidget wich shows running Processes on Device Includes a Refresh Button to manually start refreshthread args: device needed Signals: onProcessSelected([pid, name]) - pid(int) name(str) onRefreshError(str) """ onProcessSelected = pyqtSignal(list, name='onProcessSelected') onRefreshError = pyqtSignal(str, name='onRefreshError') def __init__(self, device, parent=None): super(SpawnsList, self).__init__(parent=parent) # if not isinstance(device, frida.core.Device): # print('No FridaDevice') # return self._device = device self.spawn_list = DwarfListView() model = QStandardItemModel(0, 2, parent) model.setHeaderData(0, Qt.Horizontal, "Name") model.setHeaderData(1, Qt.Horizontal, "Package") self.spawn_list.doubleClicked.connect(self._on_item_clicked) v_box = QVBoxLayout() v_box.setContentsMargins(0, 0, 0, 0) v_box.addWidget(self.spawn_list) self.refresh_button = QPushButton('Refresh') self.refresh_button.clicked.connect(self._on_refresh_procs) self.refresh_button.setEnabled(False) v_box.addWidget(self.refresh_button) self.setLayout(v_box) self.spawn_list.setModel(model) self.spawn_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.spaw_update_thread = SpawnsThread(self, self._device) self.spaw_update_thread.add_spawn.connect(self._on_add_proc) self.spaw_update_thread.is_error.connect(self._on_error) self.spaw_update_thread.is_finished.connect(self._on_refresh_finished) self.spaw_update_thread.device = self._device self.spaw_update_thread.start() # ************************************************************************ # **************************** Properties ******************************** # ************************************************************************ @property def device(self): """ Sets Device needs frida.core.device """ return self._device @device.setter def device(self, value): self.set_device(value) # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def clear(self): """ Clears the List """ self.spawn_list.clear() def set_device(self, device): """ Set frida Device """ if isinstance(device, frida.core.Device): self._device = device self.spaw_update_thread.device = device self._on_refresh_procs() # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_item_clicked(self, model_index): model = self.spawn_list.model() index = model.itemFromIndex(model_index).row() if index != -1: sel_pid = self.spawn_list.get_item_text(index, 0) if model_index.column() == 0: sel_name = model.data(model_index, Qt.UserRole + 2) else: sel_name = self.spawn_list.get_item_text(index, 1) self.onProcessSelected.emit([sel_pid, sel_name]) def _on_add_proc(self, item): model = self.spawn_list.model() name = QStandardItem() name.setText(item[0]) name.setData(item[1], Qt.UserRole + 2) package = QStandardItem() package.setText(item[1]) model.appendRow([name, package]) def _on_error(self, error_str): self.onRefreshError.emit(error_str) def _on_refresh_procs(self): if not self._device: return if self.spaw_update_thread.isRunning(): self.spaw_update_thread.terminate() if not self.spaw_update_thread.isRunning(): self.clear() self.refresh_button.setEnabled(False) self.spaw_update_thread.device = self._device self.spaw_update_thread.start() def _on_refresh_finished(self): self.spawn_list.resizeColumnToContents(0) self.refresh_button.setEnabled(True)
class JavaInspector(QWidget): """ Java Class/Methods Lists """ def __init__(self, parent=None): super(JavaInspector, self).__init__(parent) self._app_window = parent self._app_window.dwarf.onEnumerateJavaMethodsComplete.connect( self._on_method_enumeration_complete) self._app_window.dwarf.onEnumerateJavaClassesStart.connect( self._on_class_enumeration_start) self._app_window.dwarf.onEnumerateJavaClassesMatch.connect( self._on_class_enumeration_match) self._app_window.dwarf.onEnumerateJavaClassesComplete.connect( self._on_class_enumeration_complete) self._java_classes = DwarfListView(self) self._javaclass_model = QStandardItemModel(0, 1) self._javaclass_model.setHeaderData(0, Qt.Horizontal, 'Class') self._java_classes.setModel(self._javaclass_model) self._java_classes.selectionModel().selectionChanged.connect( self._class_clicked) self._java_classes.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._java_classes.setContextMenuPolicy(Qt.CustomContextMenu) self._java_classes.customContextMenuRequested.connect( self._on_class_contextmenu) self._java_classes.doubleClicked.connect(self._class_dblclicked) self._java_methods = DwarfListView(self) self._javamethod_model = QStandardItemModel(0, 1) self._javamethod_model.setHeaderData(0, Qt.Horizontal, 'Method') self._java_methods.setModel(self._javamethod_model) self._java_methods.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._java_methods.setContextMenuPolicy(Qt.CustomContextMenu) self._java_methods.customContextMenuRequested.connect( self._on_method_contextmenu) self._java_methods.doubleClicked.connect(self._method_dblclicked) h_box = QHBoxLayout() h_box.setContentsMargins(0, 0, 0, 0) h_box.addWidget(self._java_classes) h_box.addWidget(self._java_methods) self.setLayout(h_box) # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def update_classes(self): """ Refresh Classeslist """ self._app_window.dwarf.dwarf_api('enumerateJavaClasses') def update_methods(self, class_name): """ Refresh Methodslist """ if class_name: self._app_window.dwarf.dwarf_api('enumerateJavaMethods', class_name) # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _class_clicked(self): index = self._java_classes.selectionModel().currentIndex().row() _class = self._javaclass_model.item(index, 0) if _class is None: return self._app_window.dwarf.dwarf_api('enumerateJavaMethods', _class.text()) def _on_class_enumeration_start(self): self._java_classes.clear() def _on_class_enumeration_match(self, java_class): _class_name = QStandardItem() _class_name.setText(java_class) self._javaclass_model.appendRow(_class_name) def _on_class_enumeration_complete(self): self._java_classes.sortByColumn(0, 0) def _on_method_enumeration_complete(self, data): self._java_methods.clear() _class, methods = data for method in methods: _method_name = QStandardItem() _method_name.setText(method) self._javamethod_model.appendRow(_method_name) def _class_dblclicked(self): """ Class DoubleClicked """ index = self._java_classes.selectionModel().currentIndex().row() if index: class_item = self._javaclass_model.item(index, 0) if class_item: class_name = class_item.text() if class_name: self._hook_class(class_name) def _method_dblclicked(self): """ Function DoubleClicked """ class_index = self._java_classes.selectionModel().currentIndex().row() method_index = self._java_methods.selectionModel().currentIndex().row() if class_index and method_index: class_item = self._javaclass_model.item(class_index, 0) method_item = self._javamethod_model.item(method_index, 0) if class_item and method_item: class_name = class_item.text() method_name = method_item.text() if class_name and method_name: self._app_window.dwarf.hook_java(class_name + '.' + method_name) def _hook_class(self, class_name): if class_name: self._app_window.dwarf.hook_java(class_name) def _hook_class_functions(self, class_name): if class_name: self._app_window.dwarf.dwarf_api('hookAllJavaMethods', class_name) def _on_class_contextmenu(self, pos): """ Modules ContextMenu """ index = self._java_classes.indexAt(pos).row() glbl_pt = self._java_classes.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: context_menu.addAction( 'Hook constructor', lambda: self._hook_class( self._javaclass_model.item(index, 0).text())) context_menu.addAction( 'Hook all methods', lambda: self._hook_class_functions( self._javaclass_model.item(index, 0).text())) context_menu.addSeparator() context_menu.addAction('Refresh', self.update_classes) context_menu.exec_(glbl_pt) def _hook_method(self, method_name): class_index = self._java_classes.selectionModel().currentIndex().row() if class_index: class_item = self._javaclass_model.item(class_index, 0) if class_item: class_name = class_item.text() if class_name and method_name: self._app_window.dwarf.hook_java(class_name + '.' + method_name) def _cm_refresh_methods(self): index = self._java_classes.selectionModel().currentIndex().row() _class = self._javaclass_model.item(index, 0) if _class is None: return self.update_methods(_class.text()) def _on_method_contextmenu(self, pos): """ Modules ContextMenu """ index = self._java_methods.indexAt(pos).row() glbl_pt = self._java_methods.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: context_menu.addAction( 'Hook method', lambda: self._hook_method( self._javamethod_model.item(index, 0).text())) context_menu.addSeparator() context_menu.addAction('Refresh', self._cm_refresh_methods) context_menu.exec_(glbl_pt)
class SearchPanel(QWidget): """ SearchPanel """ def __init__(self, parent=None, show_progress_dlg=False): super(SearchPanel, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('SearchPanel created before Dwarf exists') return self._app_window.dwarf.onMemoryScanResult.connect( self._on_search_result) self._app_window.dwarf.onSetRanges.connect(self._on_setranges) self._ranges_model = None self._result_model = None self._blocking_search = show_progress_dlg self.progress = None self._pattern_length = 0 self._search_results = [] self.setContentsMargins(0, 0, 0, 0) main_wrap = QVBoxLayout() main_wrap.setContentsMargins(1, 1, 1, 1) wrapping_wdgt = QWidget() wrapping_wdgt.setContentsMargins(10, 10, 10, 10) v_box = QVBoxLayout(wrapping_wdgt) v_box.setContentsMargins(0, 0, 0, 0) self.input = QLineEdit() self.input.setPlaceholderText( 'search for a sequence of bytes in hex format: deadbeef123456aabbccddeeff...' ) v_box.addWidget(self.input) self.check_all_btn = QPushButton('check all') self.check_all_btn.clicked.connect(self._on_click_check_all) self.uncheck_all_btn = QPushButton('uncheck all') self.uncheck_all_btn.clicked.connect(self._on_click_uncheck_all) self.search_btn = QPushButton('search') self.search_btn.clicked.connect(self._on_click_search) h_box = QHBoxLayout() h_box.addWidget(self.check_all_btn) h_box.addWidget(self.uncheck_all_btn) h_box.addWidget(self.search_btn) v_box.addLayout(h_box) main_wrap.addWidget(wrapping_wdgt) self.ranges = DwarfListView(self) self.ranges.clicked.connect(self._on_show_results) self.results = DwarfListView(self) self.results.setVisible(False) h_box = QHBoxLayout() h_box.setContentsMargins(0, 0, 0, 0) h_box.addWidget(self.ranges) h_box.addWidget(self.results) main_wrap.addLayout(h_box) main_wrap.setSpacing(0) self.setLayout(main_wrap) self._setup_models() self._app_window.dwarf.dwarf_api('updateRanges') # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def _setup_models(self): self._ranges_model = QStandardItemModel(0, 7) # just replicate ranges panel model self._ranges_model.setHeaderData( 0, Qt.Horizontal, 'x' ) # TODO: replace with checkbox in header - remove checkall btns self._ranges_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._ranges_model.setHeaderData(1, Qt.Horizontal, 'Address') self._ranges_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._ranges_model.setHeaderData(2, Qt.Horizontal, 'Size') self._ranges_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._ranges_model.setHeaderData(3, Qt.Horizontal, 'Protection') self._ranges_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._ranges_model.setHeaderData(4, Qt.Horizontal, 'FileOffset') self._ranges_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._ranges_model.setHeaderData(5, Qt.Horizontal, 'FileSize') self._ranges_model.setHeaderData(5, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._ranges_model.setHeaderData(6, Qt.Horizontal, 'FilePath') self.ranges.setModel(self._ranges_model) self.ranges.header().setSectionResizeMode(0, QHeaderView.ResizeToContents) self.ranges.header().setSectionResizeMode(1, QHeaderView.ResizeToContents) self.ranges.header().setSectionResizeMode(2, QHeaderView.ResizeToContents) self.ranges.header().setSectionResizeMode(3, QHeaderView.ResizeToContents) self.ranges.header().setSectionResizeMode(4, QHeaderView.ResizeToContents) self.ranges.header().setSectionResizeMode(5, QHeaderView.ResizeToContents) self.ranges.doubleClicked.connect(self._on_range_dblclick) # setup results model self._result_model = QStandardItemModel(0, 1) self._result_model.setHeaderData(0, Qt.Horizontal, 'Address') self.results.setModel(self._result_model) self.results.doubleClicked.connect(self._on_double_clicked) def _on_setranges(self, ranges): """ Fills Rangelist with Data """ if self._ranges_model.rowCount(): return self.ranges.header().setSectionResizeMode(0, QHeaderView.Fixed) if isinstance(ranges, list): self._ranges_model.removeRows(0, self._ranges_model.rowCount()) for range_entry in ranges: if 'protection' in range_entry and isinstance( range_entry['protection'], str): if 'r' not in range_entry['protection']: # skip not readable range continue else: continue # create items to add str_frmt = '' if self.ranges._uppercase_hex: str_frmt = '0x{0:X}' else: str_frmt = '0x{0:x}' addr = QStandardItem() addr.setTextAlignment(Qt.AlignCenter) addr.setText(str_frmt.format(int(range_entry['base'], 16))) size = QStandardItem() size.setTextAlignment(Qt.AlignRight) size.setText("{0:,d}".format(int(range_entry['size']))) protection = QStandardItem() protection.setTextAlignment(Qt.AlignCenter) protection.setText(range_entry['protection']) file_path = None file_addr = None file_size = None if len(range_entry) > 3: if range_entry['file']['path']: file_path = QStandardItem() file_path.setText(range_entry['file']['path']) if range_entry['file']['offset']: file_addr = QStandardItem() file_addr.setTextAlignment(Qt.AlignCenter) file_addr.setText( str_frmt.format(range_entry['file']['offset'])) if range_entry['file']['size']: file_size = QStandardItem() file_size.setTextAlignment(Qt.AlignRight) file_size.setText("{0:,d}".format( int(range_entry['file']['size']))) checkbox = QStandardItem() checkbox.setCheckable(True) self._ranges_model.appendRow([ checkbox, addr, size, protection, file_addr, file_size, file_path ]) # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_range_dblclick(self, model_index): item = self._ranges_model.itemFromIndex(model_index) if item: if self._ranges_model.item(model_index.row(), 0).checkState() != Qt.Checked: self._ranges_model.item(model_index.row(), 0).setCheckState(Qt.Checked) else: self._ranges_model.item(model_index.row(), 0).setCheckState(Qt.Unchecked) def _on_click_check_all(self): for i in range(self._ranges_model.rowCount()): self._ranges_model.item(i, 0).setCheckState(Qt.Checked) def _on_click_uncheck_all(self): for i in range(self._ranges_model.rowCount()): self._ranges_model.item(i, 0).setCheckState(Qt.Unchecked) def _on_double_clicked(self, model_index): item = self._result_model.itemFromIndex(model_index) if item: self._app_window.jump_to_address( self._result_model.item(model_index.row(), 0).text()) def _on_click_search(self): pattern = self.input.text() if pattern == '': return 1 # check if we already provide a hex string as input try: test = pattern.replace(' ', '') int(test, 16) pattern = test except ValueError: # search for string pattern = binascii.hexlify(pattern.encode('utf8')).decode('utf8') ranges = [] self._search_results = [] for i in range(self._ranges_model.rowCount()): item = self._ranges_model.item(i, 0) if item.checkState() == Qt.Checked: addr = self._ranges_model.item(i, 1) size = self._ranges_model.item(i, 2) ranges.append([addr.text(), size.text()]) if len(ranges) == 0: return 1 status_message = 'searching...' if self._blocking_search: self.progress = utils.progress_dialog(status_message) self.progress.forceShow() self._app_window.show_progress(status_message) self.input.setEnabled(False) self.search_btn.setEnabled(False) self.check_all_btn.setEnabled(False) self.uncheck_all_btn.setEnabled(False) self._pattern_length = len(pattern) * .5 search_thread = SearchThread(self._app_window.dwarf, self) search_thread.onCmdCompleted.connect(self._on_search_complete) search_thread.onError.connect(self._on_search_error) search_thread.pattern = pattern search_thread.ranges = ranges search_thread.start() def _on_search_result(self, data): self._search_results.append(data) def _on_search_complete(self): self.input.setEnabled(True) self.search_btn.setEnabled(True) self.check_all_btn.setEnabled(True) self.uncheck_all_btn.setEnabled(True) self._app_window.hide_progress() if self._blocking_search: self.progress.cancel() self._ranges_model.removeColumns(4, 3) self._ranges_model.setHeaderData(3, Qt.Horizontal, 'Search Results') self._ranges_model.setHeaderData(3, Qt.Horizontal, None, Qt.TextAlignmentRole) results_count = 0 is_selected = False for i in range(self._ranges_model.rowCount()): item = self._ranges_model.item(i, 0) if item.checkState() == Qt.Checked: item.setCheckState(Qt.Unchecked) if not is_selected: is_selected = True self.ranges.setCurrentIndex(self._ranges_model.index(i, 0)) else: self._search_results.insert(i, None) self._ranges_model.item(i, 3).setText('') self._ranges_model.item(i, 3).setTextAlignment(Qt.AlignLeft) continue if len(self._search_results[i]): results_count += len(self._search_results[i]) self._ranges_model.item(i, 3).setText('Matches: {0}'.format( len(self._search_results[i]))) self._ranges_model.item(i, 3).setTextAlignment(Qt.AlignLeft) else: self._ranges_model.item(i, 3).setText('') self._ranges_model.item(i, 3).setTextAlignment(Qt.AlignLeft) self._app_window.set_status_text( 'Search complete: {0} matches'.format(results_count)) if results_count: for i in self._search_results: if i and len(i): self.results.setVisible(True) for result in i: self._result_model.appendRow( QStandardItem(result['address'])) break def _on_search_error(self, msg): utils.show_message_box(msg) def _on_show_results(self): if self._search_results: self.results.clear() if self._app_window.memory_panel: self._app_window.memory_panel.remove_highlights('search') selected_index = self.ranges.selectionModel().currentIndex().row() if selected_index is not None: item_txt = self._ranges_model.item(selected_index, 3).text() if item_txt == '': return for result in self._search_results[selected_index]: self._result_model.appendRow( QStandardItem(result['address'])) # TODO: fix hexview highlights performance """
def __init__(self, parent=None, show_progress_dlg=False): super(SearchPanel, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('SearchPanel created before Dwarf exists') return self._app_window.dwarf.onMemoryScanResult.connect( self._on_search_result) self._app_window.dwarf.onSetRanges.connect(self._on_setranges) self._ranges_model = None self._result_model = None self._blocking_search = show_progress_dlg self.progress = None self._pattern_length = 0 self._search_results = [] self.setContentsMargins(0, 0, 0, 0) main_wrap = QVBoxLayout() main_wrap.setContentsMargins(1, 1, 1, 1) wrapping_wdgt = QWidget() wrapping_wdgt.setContentsMargins(10, 10, 10, 10) v_box = QVBoxLayout(wrapping_wdgt) v_box.setContentsMargins(0, 0, 0, 0) self.input = QLineEdit() self.input.setPlaceholderText( 'search for a sequence of bytes in hex format: deadbeef123456aabbccddeeff...' ) v_box.addWidget(self.input) self.check_all_btn = QPushButton('check all') self.check_all_btn.clicked.connect(self._on_click_check_all) self.uncheck_all_btn = QPushButton('uncheck all') self.uncheck_all_btn.clicked.connect(self._on_click_uncheck_all) self.search_btn = QPushButton('search') self.search_btn.clicked.connect(self._on_click_search) h_box = QHBoxLayout() h_box.addWidget(self.check_all_btn) h_box.addWidget(self.uncheck_all_btn) h_box.addWidget(self.search_btn) v_box.addLayout(h_box) main_wrap.addWidget(wrapping_wdgt) self.ranges = DwarfListView(self) self.ranges.clicked.connect(self._on_show_results) self.results = DwarfListView(self) self.results.setVisible(False) h_box = QHBoxLayout() h_box.setContentsMargins(0, 0, 0, 0) h_box.addWidget(self.ranges) h_box.addWidget(self.results) main_wrap.addLayout(h_box) main_wrap.setSpacing(0) self.setLayout(main_wrap) self._setup_models() self._app_window.dwarf.dwarf_api('updateRanges')
class HooksPanel(QWidget): """ HooksPanel Signals: onShowMemoryRequest(str) - ptr onHookChanged(str) - ptr onHookRemoved(str) - ptr """ onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest') onHookChanged = pyqtSignal(str, name='onHookChanged') onHookRemoved = pyqtSignal(str, name='onHookRemoved') def __init__(self, parent=None): # pylint: disable=too-many-statements super(HooksPanel, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('HooksPanel created before Dwarf exists') return # connect to dwarf self._app_window.dwarf.onAddJavaHook.connect(self._on_add_hook) self._app_window.dwarf.onAddNativeHook.connect(self._on_add_hook) self._app_window.dwarf.onAddNativeOnLoadHook.connect(self._on_add_hook) self._app_window.dwarf.onAddJavaOnLoadHook.connect(self._on_add_hook) self._app_window.dwarf.onHitNativeOnLoad.connect( self._on_hit_native_on_load) self._app_window.dwarf.onHitJavaOnLoad.connect( self._on_hit_java_on_load) self._app_window.dwarf.onDeleteHook.connect(self._on_hook_deleted) self._hooks_list = DwarfListView() self._hooks_list.doubleClicked.connect(self._on_dblclicked) self._hooks_list.setContextMenuPolicy(Qt.CustomContextMenu) self._hooks_list.customContextMenuRequested.connect( self._on_context_menu) self._hooks_model = QStandardItemModel(0, 5) self._hooks_model.setHeaderData(0, Qt.Horizontal, 'Address') self._hooks_model.setHeaderData(1, Qt.Horizontal, 'T') self._hooks_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._hooks_model.setHeaderData(2, Qt.Horizontal, 'Input') self._hooks_model.setHeaderData(3, Qt.Horizontal, '{}') self._hooks_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._hooks_model.setHeaderData(4, Qt.Horizontal, '<>') self._hooks_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._hooks_list.setModel(self._hooks_model) self._hooks_list.header().setStretchLastSection(False) self._hooks_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents | QHeaderView.Interactive) self._hooks_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._hooks_list.header().setSectionResizeMode(2, QHeaderView.Stretch) self._hooks_list.header().setSectionResizeMode( 3, QHeaderView.ResizeToContents) self._hooks_list.header().setSectionResizeMode( 4, QHeaderView.ResizeToContents) v_box = QVBoxLayout(self) v_box.setContentsMargins(0, 0, 0, 0) v_box.addWidget(self._hooks_list) #header = QHeaderView(Qt.Horizontal, self) h_box = QHBoxLayout() h_box.setContentsMargins(5, 2, 5, 5) self.btn1 = QPushButton( QIcon(utils.resource_path('assets/icons/plus.svg')), '') self.btn1.setFixedSize(20, 20) self.btn1.clicked.connect(self._on_additem_clicked) btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')), '') btn2.setFixedSize(20, 20) btn2.clicked.connect(self.delete_items) btn3 = QPushButton( QIcon(utils.resource_path('assets/icons/trashcan.svg')), '') btn3.setFixedSize(20, 20) btn3.clicked.connect(self.clear_list) h_box.addWidget(self.btn1) h_box.addWidget(btn2) h_box.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred)) h_box.addWidget(btn3) # header.setLayout(h_box) # header.setFixedHeight(25) # v_box.addWidget(header) v_box.addLayout(h_box) self.setLayout(v_box) self._bold_font = QFont(self._hooks_list.font()) self._bold_font.setBold(True) shortcut_addnative = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_N), self._app_window, self._on_addnative) shortcut_addnative.setAutoRepeat(False) shortcut_addjava = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_J), self._app_window, self._on_addjava) shortcut_addjava.setAutoRepeat(False) shortcut_add_native_on_load = QShortcut( QKeySequence(Qt.CTRL + Qt.Key_O), self._app_window, self._on_add_native_on_load) shortcut_add_native_on_load.setAutoRepeat(False) # new menu self.new_menu = QMenu('New') self.new_menu.addAction('Native', self._on_addnative) self.new_menu.addAction('Java', self._on_addjava) self.new_menu.addAction('Module loading', self._on_add_native_on_load) # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def delete_items(self): """ Delete selected Items """ index = self._hooks_list.selectionModel().currentIndex().row() if index != -1: self._on_delete_hook(index) self._hooks_model.removeRow(index) def clear_list(self): """ Clear the List """ # go through all items and tell it gets removed for item in range(self._hooks_model.rowCount()): self._on_delete_hook(item) if self._hooks_model.rowCount() > 0: # something was wrong it should be empty self._hooks_model.removeRows(0, self._hooks_model.rowCount()) # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_add_hook(self, hook): type_ = QStandardItem() type_.setFont(self._bold_font) type_.setTextAlignment(Qt.AlignCenter) if hook.hook_type == HOOK_NATIVE: type_.setText('N') type_.setToolTip('Native hook') elif hook.hook_type == HOOK_JAVA: type_.setText('J') type_.setToolTip('Java hook') elif hook.hook_type == HOOK_ONLOAD: type_.setText('O') type_.setToolTip('On load hook') else: type_.setText('U') type_.setToolTip('Unknown Type') addr = QStandardItem() if hook.hook_type == HOOK_JAVA: parts = hook.get_input().split('.') addr.setText('.'.join(parts[:len(parts) - 1])) else: str_fmt = '0x{0:x}' if self._hooks_list.uppercase_hex: str_fmt = '0x{0:X}' # addr.setTextAlignment(Qt.AlignCenter) addr.setText(str_fmt.format(hook.get_ptr())) inp = QStandardItem() inp_text = hook.get_input() if hook.hook_type == HOOK_JAVA: parts = inp_text.split('.') inp_text = parts[len(parts) - 1] # if len(inp_text) > 15: # inp_text = inp_text[:15] + '...' # inp.setToolTip(hook.get_input()) inp.setText(inp_text) inp.setData(hook.get_input(), Qt.UserRole + 2) inp.setToolTip(hook.get_input()) logic = QStandardItem() logic.setTextAlignment(Qt.AlignCenter) logic.setFont(self._bold_font) if hook.logic and hook.logic != 'null' and hook.logic != 'undefined': logic.setText('ƒ') logic.setToolTip(hook.logic) logic.setData(hook.logic, Qt.UserRole + 2) condition = QStandardItem() condition.setTextAlignment(Qt.AlignCenter) condition.setFont(self._bold_font) if hook.condition and hook.condition != 'null' and hook.condition != 'undefined': condition.setText('ƒ') condition.setToolTip(hook.condition) condition.setData(hook.condition, Qt.UserRole + 2) self._hooks_model.appendRow([addr, type_, inp, logic, condition]) def _on_hit_native_on_load(self, data): items = self._hooks_model.findItems(data[1]['module'], Qt.MatchExactly, 2) if len(items) > 0: self._hooks_model.item(items[0].row(), 0).setText(data[1]['moduleBase']) def _on_hit_java_on_load(self, data): items = self._hooks_model.findItems(data[0], Qt.MatchExactly, 2) if len(items) > 0: pass def _on_dblclicked(self, model_index): item = self._hooks_model.itemFromIndex(model_index) if model_index.column() == 3 and item.text() == 'ƒ': self._on_modify_logic(model_index.row()) elif model_index.column() == 4 and item.text() == 'ƒ': self._on_modify_condition(model_index.row()) else: self.onShowMemoryRequest.emit( self._hooks_model.item(model_index.row(), 0).text()) def _on_context_menu(self, pos): context_menu = QMenu(self) context_menu.addMenu(self.new_menu) context_menu.addSeparator() index = self._hooks_list.indexAt(pos).row() if index != -1: context_menu.addAction( 'Copy address', lambda: utils.copy_hex_to_clipboard( self._hooks_model.item(index, 0).text())) context_menu.addAction( 'Jump to address', lambda: self._app_window.jump_to_address( self._hooks_model.item(index, 0).text())) context_menu.addSeparator() context_menu.addAction('Edit Logic', lambda: self._on_modify_logic(index)) context_menu.addAction('Edit Condition', lambda: self._on_modify_condition(index)) context_menu.addSeparator() context_menu.addAction('Delete Hook', lambda: self._on_delete_hook(index)) if self._hooks_list.search_enabled: context_menu.addSeparator() context_menu.addAction('Search', self._hooks_list._on_cm_search) # show context menu global_pt = self._hooks_list.mapToGlobal(pos) context_menu.exec(global_pt) def _on_modify_logic(self, num_row): item = self._hooks_model.item(num_row, 3) data = item.data(Qt.UserRole + 2) if data is None: data = '' ptr = self._hooks_model.item(num_row, 0).text() accept, input_ = InputMultilineDialog().input('Insert logic for %s' % ptr, input_content=data) if accept: what = utils.parse_ptr(ptr) if what == 0: what = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2) if self._app_window.dwarf.dwarf_api( 'setHookLogic', [what, input_.replace('\n', '')]): item.setData(input_, Qt.UserRole + 2) if not item.text(): item.setText('ƒ') item.setToolTip(input_) self.onHookChanged.emit(ptr) def _on_modify_condition(self, num_row): item = self._hooks_model.item(num_row, 4) data = item.data(Qt.UserRole + 2) if data is None: data = '' ptr = self._hooks_model.item(num_row, 0).text() accept, input_ = InputDialog().input(self._app_window, 'Insert condition for %s' % ptr, input_content=data) if accept: what = utils.parse_ptr(ptr) if what == 0: what = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2) if self._app_window.dwarf.dwarf_api('setHookCondition', [what, input_]): item.setData(input_, Qt.UserRole + 2) if not item.text(): item.setText('ƒ') item.setToolTip(input_) self.onHookChanged.emit(ptr) # + button def _on_additem_clicked(self): self.new_menu.exec_(QCursor.pos()) # shortcuts/menu def _on_addnative(self): self._app_window.dwarf.hook_native() def _on_addjava(self): self._app_window.dwarf.hook_java() def _on_add_native_on_load(self): self._app_window.dwarf.hook_native_on_load() def _on_add_java_on_load(self): self._app_window.dwarf.hook_java_on_load() def _on_delete_hook(self, num_row): hook_type = self._hooks_model.item(num_row, 1).text() if hook_type == 'N': ptr = self._hooks_model.item(num_row, 0).text() ptr = utils.parse_ptr(ptr) self._app_window.dwarf.dwarf_api('deleteHook', ptr) self.onHookRemoved.emit(str(ptr)) elif hook_type == 'J': input_ = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2) self._app_window.dwarf.dwarf_api('deleteHook', input_) elif hook_type == 'O': input_ = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2) self._app_window.dwarf.dwarf_api('deleteHook', input_) elif hook_type == 'U': ptr = self._hooks_model.item(num_row, 0).text() ptr = utils.parse_ptr(ptr) self._app_window.dwarf.dwarf_api('deleteHook', ptr) self.onHookRemoved.emit(str(ptr)) def _on_hook_deleted(self, parts): _msg, _type, _val = parts additional = None if _type == 'java' or _type == 'java_on_load': _val = _val.split('.') str_frmt = '.'.join(_val[:-1]) additional = _val[-1] item_index = 0 elif _type == 'native_on_load': str_frmt = _val item_index = 2 else: _ptr = utils.parse_ptr(_val) if self._hooks_list._uppercase_hex: str_frmt = '0x{0:X}'.format(_ptr) else: str_frmt = '0x{0:x}'.format(_ptr) item_index = 0 for _item in range(self._hooks_model.rowCount()): item = self._hooks_model.item(_item, item_index) if item is None: continue if str_frmt == item.text(): if additional is not None: if additional == self._hooks_model.item(_item, 2).text(): self._hooks_model.removeRow(_item) else: self._hooks_model.removeRow(_item)
def __init__(self, parent=None): # pylint: disable=too-many-statements super(HooksPanel, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('HooksPanel created before Dwarf exists') return # connect to dwarf self._app_window.dwarf.onAddJavaHook.connect(self._on_add_hook) self._app_window.dwarf.onAddNativeHook.connect(self._on_add_hook) self._app_window.dwarf.onAddNativeOnLoadHook.connect(self._on_add_hook) self._app_window.dwarf.onAddJavaOnLoadHook.connect(self._on_add_hook) self._app_window.dwarf.onHitNativeOnLoad.connect( self._on_hit_native_on_load) self._app_window.dwarf.onHitJavaOnLoad.connect( self._on_hit_java_on_load) self._app_window.dwarf.onDeleteHook.connect(self._on_hook_deleted) self._hooks_list = DwarfListView() self._hooks_list.doubleClicked.connect(self._on_dblclicked) self._hooks_list.setContextMenuPolicy(Qt.CustomContextMenu) self._hooks_list.customContextMenuRequested.connect( self._on_context_menu) self._hooks_model = QStandardItemModel(0, 5) self._hooks_model.setHeaderData(0, Qt.Horizontal, 'Address') self._hooks_model.setHeaderData(1, Qt.Horizontal, 'T') self._hooks_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._hooks_model.setHeaderData(2, Qt.Horizontal, 'Input') self._hooks_model.setHeaderData(3, Qt.Horizontal, '{}') self._hooks_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._hooks_model.setHeaderData(4, Qt.Horizontal, '<>') self._hooks_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._hooks_list.setModel(self._hooks_model) self._hooks_list.header().setStretchLastSection(False) self._hooks_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents | QHeaderView.Interactive) self._hooks_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._hooks_list.header().setSectionResizeMode(2, QHeaderView.Stretch) self._hooks_list.header().setSectionResizeMode( 3, QHeaderView.ResizeToContents) self._hooks_list.header().setSectionResizeMode( 4, QHeaderView.ResizeToContents) v_box = QVBoxLayout(self) v_box.setContentsMargins(0, 0, 0, 0) v_box.addWidget(self._hooks_list) #header = QHeaderView(Qt.Horizontal, self) h_box = QHBoxLayout() h_box.setContentsMargins(5, 2, 5, 5) self.btn1 = QPushButton( QIcon(utils.resource_path('assets/icons/plus.svg')), '') self.btn1.setFixedSize(20, 20) self.btn1.clicked.connect(self._on_additem_clicked) btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')), '') btn2.setFixedSize(20, 20) btn2.clicked.connect(self.delete_items) btn3 = QPushButton( QIcon(utils.resource_path('assets/icons/trashcan.svg')), '') btn3.setFixedSize(20, 20) btn3.clicked.connect(self.clear_list) h_box.addWidget(self.btn1) h_box.addWidget(btn2) h_box.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred)) h_box.addWidget(btn3) # header.setLayout(h_box) # header.setFixedHeight(25) # v_box.addWidget(header) v_box.addLayout(h_box) self.setLayout(v_box) self._bold_font = QFont(self._hooks_list.font()) self._bold_font.setBold(True) shortcut_addnative = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_N), self._app_window, self._on_addnative) shortcut_addnative.setAutoRepeat(False) shortcut_addjava = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_J), self._app_window, self._on_addjava) shortcut_addjava.setAutoRepeat(False) shortcut_add_native_on_load = QShortcut( QKeySequence(Qt.CTRL + Qt.Key_O), self._app_window, self._on_add_native_on_load) shortcut_add_native_on_load.setAutoRepeat(False) # new menu self.new_menu = QMenu('New') self.new_menu.addAction('Native', self._on_addnative) self.new_menu.addAction('Java', self._on_addjava) self.new_menu.addAction('Module loading', self._on_add_native_on_load)
class WatchersPanel(QWidget): """ WatcherPanel Signals: onItemSelected(addr_str) - item dblclicked onItemAddClick Constants: MEMORY_ACCESS_READ = 1 MEMORY_ACCESS_WRITE = 2 MEMORY_ACCESS_EXECUTE = 4 MEMORY_WATCH_SINGLESHOT = 8 """ MEMORY_ACCESS_READ = 1 MEMORY_ACCESS_WRITE = 2 MEMORY_ACCESS_EXECUTE = 4 MEMORY_WATCH_SINGLESHOT = 8 onItemDoubleClicked = pyqtSignal(int, name='onItemDoubleClicked') onItemAdded = pyqtSignal(int, name='onItemAdded') onItemRemoved = pyqtSignal(int, name='onItemRemoved') def __init__(self, parent=None): # pylint: disable=too-many-statements super(WatchersPanel, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('Watcherpanel created before Dwarf exists') return self._uppercase_hex = True self.setAutoFillBackground(True) # connect to dwarf self._app_window.dwarf.onWatcherAdded.connect(self._on_watcher_added) self._app_window.dwarf.onWatcherRemoved.connect( self._on_watcher_removed) # setup our model self._watchers_model = QStandardItemModel(0, 5) self._watchers_model.setHeaderData(0, Qt.Horizontal, 'Address') self._watchers_model.setHeaderData(1, Qt.Horizontal, 'R') self._watchers_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._watchers_model.setHeaderData(2, Qt.Horizontal, 'W') self._watchers_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._watchers_model.setHeaderData(3, Qt.Horizontal, 'X') self._watchers_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._watchers_model.setHeaderData(4, Qt.Horizontal, 'S') self._watchers_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) # setup ui v_box = QVBoxLayout(self) v_box.setContentsMargins(0, 0, 0, 0) self.list_view = DwarfListView() self.list_view.setModel(self._watchers_model) self.list_view.header().setSectionResizeMode(0, QHeaderView.Stretch) self.list_view.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setSectionResizeMode( 3, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setSectionResizeMode( 4, QHeaderView.ResizeToContents | QHeaderView.Fixed) self.list_view.header().setStretchLastSection(False) self.list_view.doubleClicked.connect(self._on_item_dblclick) self.list_view.setContextMenuPolicy(Qt.CustomContextMenu) self.list_view.customContextMenuRequested.connect(self._on_contextmenu) v_box.addWidget(self.list_view) #header = QHeaderView(Qt.Horizontal, self) h_box = QHBoxLayout() h_box.setContentsMargins(5, 2, 5, 5) btn1 = QPushButton(QIcon(utils.resource_path('assets/icons/plus.svg')), '') btn1.setFixedSize(20, 20) btn1.clicked.connect(self._on_additem_clicked) btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')), '') btn2.setFixedSize(20, 20) btn2.clicked.connect(self.delete_items) btn3 = QPushButton( QIcon(utils.resource_path('assets/icons/trashcan.svg')), '') btn3.setFixedSize(20, 20) btn3.clicked.connect(self.clear_list) h_box.addWidget(btn1) h_box.addWidget(btn2) h_box.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred)) h_box.addWidget(btn3) # header.setLayout(h_box) # header.setFixedHeight(25) # v_box.addWidget(header) v_box.addLayout(h_box) # create a centered dot icon _section_width = self.list_view.header().sectionSize(2) self._new_pixmap = QPixmap(_section_width, 20) self._new_pixmap.fill(Qt.transparent) painter = QPainter(self._new_pixmap) rect = QRect((_section_width * 0.5), 0, 20, 20) painter.setBrush(QColor('#666')) painter.setPen(QColor('#666')) painter.drawEllipse(rect) self._dot_icon = QIcon(self._new_pixmap) # shortcuts shortcut_add = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_W), self._app_window, self._on_additem_clicked) shortcut_add.setAutoRepeat(False) self.setLayout(v_box) # ************************************************************************ # **************************** Properties ******************************** # ************************************************************************ @property def uppercase_hex(self): """ Addresses displayed lower/upper-case """ return self._uppercase_hex @uppercase_hex.setter def uppercase_hex(self, value): """ Addresses displayed lower/upper-case value - bool or str 'upper', 'lower' """ if isinstance(value, bool): self._uppercase_hex = value elif isinstance(value, str): self._uppercase_hex = (value == 'upper') # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def do_addwatcher_dlg(self, ptr=None): # pylint: disable=too-many-branches """ Shows AddWatcherDialog """ watcher_dlg = AddWatcherDialog(self, ptr) if watcher_dlg.exec_() == QDialog.Accepted: mem_r = watcher_dlg.acc_read.isChecked() mem_w = watcher_dlg.acc_write.isChecked() mem_x = watcher_dlg.acc_execute.isChecked() mem_s = watcher_dlg.singleshot.isChecked() ptr = watcher_dlg.text_field.toPlainText() if ptr: if isinstance(ptr, str): if ptr.startswith('0x') or ptr.startswith('#'): ptr = utils.parse_ptr(ptr) else: try: ptr = int(ptr, 10) except ValueError: pass # int now? if not isinstance(ptr, int): try: ptr = int( self._app_window.dwarf.dwarf_api( 'evaluatePtr', ptr), 16) except ValueError: ptr = 0 if ptr == 0: return if not self._app_window.dwarf.dwarf_api( 'isValidPointer', ptr): return else: return mem_val = 0 if mem_r: mem_val |= self.MEMORY_ACCESS_READ if mem_w: mem_val |= self.MEMORY_ACCESS_WRITE if mem_x: mem_val |= self.MEMORY_ACCESS_EXECUTE if mem_s: mem_val |= self.MEMORY_WATCH_SINGLESHOT self.add_address(ptr, mem_val, from_api=False) # return [ptr, mem_val] def add_address(self, ptr, flags, from_api=False): """ Adds Address to display ptr - str or int flags - int """ if isinstance(ptr, str): ptr = utils.parse_ptr(ptr) if not isinstance(flags, int): try: flags = int(flags, 10) except ValueError: flags = 3 if not from_api: # function was called directly so add it to dwarf if not self._app_window.dwarf.is_address_watched(ptr): self._app_window.dwarf.dwarf_api('addWatcher', [ptr, flags]) return # show header self.list_view.setHeaderHidden(False) # create items to add if self._uppercase_hex: str_frmt = '0x{0:X}' else: str_frmt = '0x{0:x}' addr = QStandardItem() addr.setText(str_frmt.format(ptr)) read = QStandardItem() write = QStandardItem() execute = QStandardItem() singleshot = QStandardItem() if flags & self.MEMORY_ACCESS_READ: read.setIcon(self._dot_icon) if flags & self.MEMORY_ACCESS_WRITE: write.setIcon(self._dot_icon) if flags & self.MEMORY_ACCESS_EXECUTE: execute.setIcon(self._dot_icon) if flags & self.MEMORY_WATCH_SINGLESHOT: singleshot.setIcon(self._dot_icon) # add items as new row on top self._watchers_model.insertRow( 0, [addr, read, write, execute, singleshot]) def remove_address(self, ptr, from_api=False): """ Remove Address from List """ if isinstance(ptr, str): ptr = utils.parse_ptr(ptr) if not from_api: # called somewhere so remove watcher in dwarf too self._app_window.dwarf.dwarf_api('removeWatcher', ptr) return str_frmt = '' if self._uppercase_hex: str_frmt = '0x{0:X}'.format(ptr) else: str_frmt = '0x{0:x}'.format(ptr) model = self.list_view.model() for item in range(model.rowCount()): if str_frmt == model.item(item).text(): model.removeRow(item) def delete_items(self): """ Delete selected Items """ model = self.list_view.model() index = self.list_view.selectionModel().currentIndex().row() if index != -1: ptr = model.item(index, 0).text() self.remove_address(ptr) def clear_list(self): """ Clear the List """ model = self.list_view.model() # go through all items and tell it gets removed for item in range(model.rowCount()): ptr = model.item(item, 0).text() self.remove_address(ptr) if model.rowCount() > 0: # something was wrong it should be empty model.removeRows(0, model.rowCount()) # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_contextmenu(self, pos): index = self.list_view.indexAt(pos).row() glbl_pt = self.list_view.mapToGlobal(pos) context_menu = QMenu(self) context_menu.addAction('Add watcher', self._on_additem_clicked) if index != -1: context_menu.addSeparator() context_menu.addAction( 'Copy address', lambda: utils.copy_hex_to_clipboard( self._watchers_model.item(index, 0).text())) context_menu.addAction( 'Jump to address', lambda: self._app_window.jump_to_address( self._watchers_model.item(index, 0).text())) context_menu.addAction( 'Delete watcher', lambda: self.remove_address( self._watchers_model.item(index, 0).text())) context_menu.exec_(glbl_pt) def _on_item_dblclick(self, model_index): row = self._watchers_model.itemFromIndex(model_index).row() if row != -1: ptr = self._watchers_model.item(row, 0).text() self.onItemDoubleClicked.emit(ptr) def _on_additem_clicked(self): if self._app_window.dwarf.pid == 0: return self.do_addwatcher_dlg() def _on_watcher_added(self, ptr, flags): """ Callback from Dwarf after Watcher is added """ ptr = utils.parse_ptr(ptr) # add to watcherslist self.add_address(ptr, flags, from_api=True) self.onItemAdded.emit(ptr) def _on_watcher_removed(self, ptr): """ Callback from Dwarf after watcher is removed """ ptr = utils.parse_ptr(ptr) # remove from list self.remove_address(ptr, from_api=True) self.onItemRemoved.emit(ptr)
class BookmarksPanel(QWidget): onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest') def __init__(self, parent=None): # pylint: disable=too-many-statements super(BookmarksPanel, self).__init__(parent=parent) self._app_window = parent if self._app_window.dwarf is None: print('BookmarksPanel created before Dwarf exists') return self.bookmarks = {} self._bookmarks_list = DwarfListView() self._bookmarks_list.doubleClicked.connect(self._on_dblclicked) self._bookmarks_list.setContextMenuPolicy(Qt.CustomContextMenu) self._bookmarks_list.customContextMenuRequested.connect( self._on_contextmenu) self._bookmarks_model = QStandardItemModel(0, 2) self._bookmarks_model.setHeaderData(0, Qt.Horizontal, 'Address') self._bookmarks_model.setHeaderData(1, Qt.Horizontal, 'Notes') self._bookmarks_list.setModel(self._bookmarks_model) self._bookmarks_list.header().setStretchLastSection(False) self._bookmarks_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents | QHeaderView.Interactive) self._bookmarks_list.header().setSectionResizeMode( 1, QHeaderView.Stretch | QHeaderView.Interactive) v_box = QVBoxLayout(self) v_box.setContentsMargins(0, 0, 0, 0) v_box.addWidget(self._bookmarks_list) #header = QHeaderView(Qt.Horizontal, self) h_box = QHBoxLayout() h_box.setContentsMargins(5, 2, 5, 5) self.btn1 = QPushButton( QIcon(utils.resource_path('assets/icons/plus.svg')), '') self.btn1.setFixedSize(20, 20) self.btn1.clicked.connect(lambda: self._create_bookmark(-1)) btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')), '') btn2.setFixedSize(20, 20) btn2.clicked.connect(self.delete_items) btn3 = QPushButton( QIcon(utils.resource_path('assets/icons/trashcan.svg')), '') btn3.setFixedSize(20, 20) btn3.clicked.connect(self.clear_list) h_box.addWidget(self.btn1) h_box.addWidget(btn2) h_box.addSpacerItem( QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred)) h_box.addWidget(btn3) # header.setLayout(h_box) # header.setFixedHeight(25) # v_box.addWidget(header) v_box.addLayout(h_box) self.setLayout(v_box) self._bold_font = QFont(self._bookmarks_list.font()) self._bold_font.setBold(True) shortcut_addnative = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_A), self._app_window, self._create_bookmark) shortcut_addnative.setAutoRepeat(False) # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def delete_items(self): """ Delete selected Items """ index = self._bookmarks_list.selectionModel().currentIndex().row() if index != -1: self._on_delete_bookmark(index) self._bookmarks_model.removeRow(index) def clear_list(self): """ Clear the List """ # go through all items and tell it gets removed for item in range(self._bookmarks_model.rowCount()): self._on_delete_bookmark(item) if self._bookmarks_model.rowCount() > 0: # something was wrong it should be empty self._bookmarks_model.removeRows(0, self._bookmarks_model.rowCount()) # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_dblclicked(self, index): index = self._bookmarks_list.selectionModel().currentIndex().row() if index != -1: addr = self._bookmarks_model.item(index, 0).text() if addr: self.onShowMemoryRequest.emit(addr) def _on_contextmenu(self, pos): context_menu = QMenu(self) index = self._bookmarks_list.indexAt(pos).row() if index != -1: context_menu.addAction( 'Copy address', lambda: utils.copy_hex_to_clipboard( self._bookmarks_model.item(index, 0).text())) context_menu.addAction( 'Jump to address', lambda: self._app_window.jump_to_address( self._bookmarks_model.item(index, 0).text())) # todo: add hook address menu context_menu.addSeparator() context_menu.addAction('Edit', lambda: self._create_bookmark(index=index)) context_menu.addAction('Delete', lambda: self._on_delete_bookmark(index)) context_menu.addSeparator() if self._bookmarks_list.search_enabled: context_menu.addSeparator() context_menu.addAction('Search', self._bookmarks_list._on_cm_search) context_menu.addSeparator() context_menu.addAction('New', self._create_bookmark) global_pt = self._bookmarks_list.mapToGlobal(pos) context_menu.exec(global_pt) # + button def _create_bookmark(self, index=-1, ptr=''): note = '' if ptr == '': if isinstance(index, int) and index >= 0: ptr = self._bookmarks_model.item(index, 0).text() note = self._bookmarks_model.item(index, 1).text() ptr, _ = InputDialog.input_pointer(parent=self._app_window, input_content=ptr) else: if not isinstance(ptr, int): try: if ptr.startswith('0x'): ptr = int(ptr, 16) else: ptr = int(ptr) except ValueError: ptr = 0 if ptr > 0: ptr = hex(ptr) if self._bookmarks_list.uppercase_hex: ptr = ptr.upper().replace('0X', '0x') index = self._bookmarks_model.findItems(ptr, Qt.MatchExactly) if len(index) > 0: index = index[0].row() note = self._bookmarks_model.item(index, 1).text() else: index = -1 accept, note = InputDialog.input(hint='Insert notes for %s' % ptr, input_content=note) if accept: if index < 0: self.insert_bookmark(ptr, note) else: item = self._bookmarks_model.item(index, 0) item.setText(ptr) item = self._bookmarks_model.item(index, 1) item.setText(note) self.bookmarks[ptr] = note def insert_bookmark(self, ptr_as_hex, note): if self._bookmarks_list.uppercase_hex: ptr_as_hex = ptr_as_hex.upper().replace('0X', '0x') self._bookmarks_model.appendRow( [QStandardItem(ptr_as_hex), QStandardItem(note)]) self._bookmarks_list.resizeColumnToContents(0) # shortcuts/menu def _on_delete_bookmark(self, index): ptr = self._bookmarks_model.item(index, 0).text() del self.bookmarks[ptr] self._bookmarks_model.removeRow(index)
class QDebugPanel(QMainWindow): def __init__(self, app, flags=None): super(QDebugPanel, self).__init__(flags) self.setDockOptions(QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks) self.app = app self.q_settings = app.q_settings self.functions_list = DwarfListView() self.functions_list_model = QStandardItemModel(0, 1) self.functions_list_model.setHeaderData(0, Qt.Horizontal, '') self.functions_list.setModel(self.functions_list_model) self.functions_list.setHeaderHidden(True) self.functions_list.doubleClicked.connect(self._function_double_clicked) self.dock_functions_list = QDockWidget('Functions', self) self.dock_functions_list.setObjectName('functions') self.dock_functions_list.setWidget(self.functions_list) self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_functions_list) self.app.debug_view_menu.addAction(self.dock_functions_list.toggleViewAction()) self.memory_panel_range = None self.disassembly_panel_range = None screen_size = QtWidgets.QDesktopWidget().screenGeometry(-1) m_width = screen_size.width() self.memory_panel = HexEditor(self.app) self.memory_panel.debug_panel = self self.memory_panel.dataChanged.connect(self.on_memory_modified) self.disassembly_panel = DisassemblyView(self.app) self.disassembly_panel.debug_panel = self self.dock_memory_panel = QDockWidget('Memory', self) self.dock_memory_panel.setWidget(self.memory_panel) self.dock_memory_panel.setObjectName('memory') self.dock_disassembly_panel = QDockWidget('Disassembly', self) self.dock_disassembly_panel.setWidget(self.disassembly_panel) self.dock_disassembly_panel.setObjectName('disassembly') self.addDockWidget(Qt.RightDockWidgetArea, self.dock_memory_panel) self.addDockWidget(Qt.RightDockWidgetArea, self.dock_disassembly_panel) if m_width >= 1920: self.splitDockWidget(self.dock_memory_panel, self.dock_disassembly_panel, Qt.Horizontal) else: self.tabifyDockWidget(self.dock_memory_panel, self.dock_disassembly_panel) self.restoreUiState() def restoreUiState(self): ui_state = self.q_settings.value('dwarf_debug_ui_state') if ui_state: self.restoreGeometry(ui_state) window_state = self.q_settings.value('dwarf_debug_ui_window') if window_state: self.restoreState(window_state) def closeEvent(self, event): self.q_settings.setValue('dwarf_debug_ui_state', self.saveGeometry()) self.q_settings.setValue('dwarf_debug_ui_window', self.saveState()) def showEvent(self, event): main_width = self.size().width() new_widths = [] new_widths.append(main_width * .1) new_widths.append(main_width * .4) new_widths.append(main_width * .5) self.resizeDocks([ self.dock_functions_list, self.dock_memory_panel, self.dock_disassembly_panel ], new_widths, Qt.Horizontal) return super().showEvent(event) def update_functions(self, functions_list=None): if functions_list is None: functions_list = {} self.functions_list_model.setRowCount(0) for module_info_base in self.app.dwarf.database.modules_info: module_info = self.app.dwarf.database.modules_info[module_info_base] if len(module_info.functions) > 0: self.functions_list.show() for function in module_info.functions: functions_list[function.name] = function.address for function_name in sorted(functions_list.keys()): function_addr = functions_list[function_name] item = QStandardItem(function_name.replace('.', '_')) item.setData(function_addr, Qt.UserRole + 2) self.functions_list_model.appendRow([item]) def _function_double_clicked(self, model_index): item = self.functions_list_model.itemFromIndex(model_index) address = item.data(Qt.UserRole + 2) self.jump_to_address(address, view=DEBUG_VIEW_DISASSEMBLY) def on_context_setup(self): self.memory_panel.on_context_setup() def on_memory_modified(self, pos, length): data_pos = self.memory_panel.base + pos data = self.memory_panel.data[pos:pos + length] data = [data[0]] # todo: strange js part if self.dwarf.dwarf_api('writeBytes', [data_pos, data]): pass else: utils.show_message_box('Failed to write Memory') def raise_memory_panel(self): self.dock_memory_panel.raise_() def raise_disassembly_panel(self): self.dock_disassembly_panel.raise_() def jump_to_address(self, address, view=DEBUG_VIEW_MEMORY): address = utils.parse_ptr(address) if view == DEBUG_VIEW_MEMORY: if self.memory_panel_range is not None: if self.is_address_in_view(view, address): return self.memory_panel_range = \ Range.build_or_get(self.app.dwarf, address, cb=lambda x: self._apply_range(address, view=view)) elif view == DEBUG_VIEW_DISASSEMBLY: if self.disassembly_panel_range is not None: if self.is_address_in_view(view, address): return self.disassembly_panel_range = \ Range.build_or_get(self.app.dwarf, address, cb=lambda x: self._apply_range(address, view=view)) def _apply_range(self, address, view=DEBUG_VIEW_MEMORY): self.update_functions() if view == DEBUG_VIEW_MEMORY: self.memory_panel.set_data( self.memory_panel_range.data, base=self.memory_panel_range.base, focus_address=address) if not self.dock_memory_panel.isVisible(): self.dock_memory_panel.show() self.raise_memory_panel() if self.disassembly_panel_range is None: self.disassembly_panel_range = self.memory_panel_range self.disassembly_panel.apply_range(self.disassembly_panel_range) elif view == DEBUG_VIEW_DISASSEMBLY: self.disassembly_panel.apply_range(self.disassembly_panel_range) if not self.dock_disassembly_panel.isVisible(): self.dock_disassembly_panel.show() self.raise_disassembly_panel() if self.memory_panel_range is None: self.memory_panel_range = self.disassembly_panel_range self.memory_panel.set_data( self.memory_panel_range.data, base=self.memory_panel_range.base, focus_address=address) def is_address_in_view(self, view, address): if view == DEBUG_VIEW_MEMORY: if self.memory_panel_range is not None: ptr_exists = self.memory_panel.base <= address <= self.memory_panel.base + len(self.memory_panel.data) if ptr_exists: self.memory_panel.caret.position = address - self.memory_panel.base return True elif view == DEBUG_VIEW_DISASSEMBLY: if self.disassembly_panel_range is not None: line_index_for_address = self.disassembly_panel.get_line_for_address(address) if line_index_for_address >= 0: self.disassembly_panel.verticalScrollBar().setValue(line_index_for_address) return True return False def on_cm_jump_to_address(self, view=DEBUG_VIEW_MEMORY): ptr, _ = InputDialog.input_pointer(self.app) if ptr > 0: self.jump_to_address(ptr, view=view) def dump_data(self, address, _len): def _dump(dwarf_range): if address + _len > dwarf_range.tail: self.display_error('length is higher than range size') else: data = dwarf_range.data[address:address + _len] if data is not None: from PyQt5.QtWidgets import QFileDialog _file = QFileDialog.getSaveFileName(self.app) with open(_file[0], 'wb') as f: f.write(data) Range.build_or_get(self.app.dwarf, address, cb=_dump)
class ListDialog(DwarfDialog): def __init__(self, parent=None, setup_list_cb=None, setup_list_cb_args=None, double_click_to_accept=False, checkable=False): super(ListDialog, self).__init__(parent) self.right_click_handler = None layout = QVBoxLayout(self) self.list = DwarfListView() # QListWidget() self.list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) if double_click_to_accept: self.list.doubleClicked.connect(self.accept) if setup_list_cb is not None: setup_list_cb(self.list, setup_list_cb_args) layout.addWidget(self.list) if checkable: buttons = QHBoxLayout() select_all = QPushButton('select all') select_all.clicked.connect(self.select_all) buttons.addWidget(select_all) unselect_all = QPushButton('unselect all') unselect_all.clicked.connect(self.unselect_all) buttons.addWidget(unselect_all) ok = QPushButton('ok') ok.clicked.connect(self.accept) buttons.addWidget(ok) cancel = QPushButton('cancel') cancel.clicked.connect(self.close) buttons.addWidget(cancel) layout.addLayout(buttons) def get_checked_items(self): ret = [] for i in range(0, self.list.count()): item = self.list.item(i) if item.checkState() == Qt.Checked: ret.append(item) return ret def select_all(self): for i in range(0, self.list.count()): item = self.list.item(i) item.setCheckState(Qt.Checked) def unselect_all(self): for i in range(0, self.list.count()): item = self.list.item(i) item.setCheckState(Qt.Unchecked) def keyPressEvent(self, event): super(ListDialog, self).keyPressEvent(event) if event.key() == Qt.Key_Return: self.accept() @staticmethod def build_and_show(setup_list_cb, setup_list_cb_args, double_click_to_accept=False, checkable=False): dialog = ListDialog(setup_list_cb=setup_list_cb, setup_list_cb_args=setup_list_cb_args, double_click_to_accept=double_click_to_accept, checkable=checkable) if dialog.list.count() > 0: result = dialog.exec_() if checkable: if result == QDialog.Accepted: checked_items = dialog.get_checked_items() else: checked_items = [] return result == QDialog.Accepted, checked_items return result == QDialog.Accepted, dialog.list.selectedItems() return None
class JavaExplorerPanel(QWidget): def __init__(self, parent=None): super().__init__(parent=parent) self._app_window = parent self._handle_history = [] self._setup_ui() self._setup_models() def _setup_ui(self): self.setContentsMargins(0, 0, 0, 0) top_font = QFont() top_font.setBold(True) top_font.setPixelSize(19) # main wrapper main_wrapper = QVBoxLayout() main_wrapper.setContentsMargins(1, 1, 1, 1) # wrapwdgt wrap_wdgt = QWidget() self._top_class_name = QLabel(wrap_wdgt) self._top_class_name.setContentsMargins(10, 10, 10, 10) self._top_class_name.setAttribute(Qt.WA_TranslucentBackground, True) # keep this self._top_class_name.setFont(top_font) self._top_class_name.setStyleSheet('color: #ef5350;') wrap_wdgt.setMaximumHeight(self._top_class_name.height() + 20) main_wrapper.addWidget(wrap_wdgt) # left list left_wrap_wdgt = QWidget() left_v_box = QVBoxLayout(left_wrap_wdgt) left_v_box.setContentsMargins(0, 0, 0, 0) methods_label = QLabel('METHODS') font = methods_label.font() font.setBold(True) methods_label.setFont(font) methods_label.setContentsMargins(10, 0, 10, 2) methods_label.setAttribute(Qt.WA_TranslucentBackground, True) # keep this left_v_box.addWidget(methods_label) self._methods_list = DwarfListView() left_v_box.addWidget(self._methods_list) # center list center_wrap_wdgt = QWidget() center_v_box = QVBoxLayout(center_wrap_wdgt) center_v_box.setContentsMargins(0, 0, 0, 0) methods_label = QLabel('NATIVE FIELDS') methods_label.setFont(font) methods_label.setContentsMargins(10, 0, 10, 2) methods_label.setAttribute(Qt.WA_TranslucentBackground, True) # keep this center_v_box.addWidget(methods_label) self._native_fields_list = DwarfListView() self._native_fields_list.doubleClicked.connect( self._on_native_field_dblclicked) center_v_box.addWidget(self._native_fields_list) # right list right_wrap_wdgt = QWidget() right_v_box = QVBoxLayout(right_wrap_wdgt) right_v_box.setContentsMargins(0, 0, 0, 0) methods_label = QLabel('FIELDS') methods_label.setFont(font) methods_label.setContentsMargins(10, 0, 10, 2) methods_label.setAttribute(Qt.WA_TranslucentBackground, True) # keep this right_v_box.addWidget(methods_label) self._fields_list = DwarfListView() self._fields_list.doubleClicked.connect(self._on_field_dblclicked) right_v_box.addWidget(self._fields_list) # main splitter main_splitter = QSplitter(Qt.Horizontal) main_splitter.setContentsMargins(0, 0, 0, 0) main_splitter.addWidget(left_wrap_wdgt) main_splitter.addWidget(center_wrap_wdgt) main_splitter.addWidget(right_wrap_wdgt) main_splitter.setSizes([250, 100, 100]) main_wrapper.addWidget(main_splitter) main_wrapper.setSpacing(0) self.setLayout(main_wrapper) def _setup_models(self): # left list self._methods_model = QStandardItemModel(0, 3) self._methods_model.setHeaderData(0, Qt.Horizontal, 'Name') self._methods_model.setHeaderData(1, Qt.Horizontal, 'Return') self._methods_model.setHeaderData(2, Qt.Horizontal, 'Arguments') self._methods_list.setModel(self._methods_model) self._methods_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._methods_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) # center list self._native_fields_model = QStandardItemModel(0, 2) self._native_fields_model.setHeaderData(0, Qt.Horizontal, 'Name') self._native_fields_model.setHeaderData(1, Qt.Horizontal, 'Value') self._native_fields_list.setModel(self._native_fields_model) self._native_fields_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) # right list self._fields_model = QStandardItemModel(0, 2) self._fields_model.setHeaderData(0, Qt.Horizontal, 'Name') self._fields_model.setHeaderData(1, Qt.Horizontal, 'Class') self._fields_list.setModel(self._fields_model) self._fields_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def _set_data(self, data): if 'class' not in data: return self._top_class_name.setText(data['class']) data = data['data'] self._methods_list.clear() self._native_fields_list.clear() self._fields_list.clear() for key in data: ref = data[key] if ref['type'] == 'function': if not key.startswith('$'): self._add_method(key, ref) elif ref['type'] == 'object': if ref['handle'] is not None: if not key.startswith('$'): self._add_field(key, ref['value'], ref['handle'], ref['handle_class']) else: if not key.startswith('$'): self._add_field(key, ref['value'], is_native=True) self._methods_list.sortByColumn(0, 0) self._native_fields_list.sortByColumn(0, 0) self._fields_list.sortByColumn(0, 0) def _add_method(self, name, ref): ref_overloads = ref['overloads'] for _, ref_overload in enumerate(ref_overloads): args = [] if 'args' in ref_overload: for arg in ref_overload['args']: if 'className' in arg: args.append(arg['className']) self._methods_model.appendRow([ QStandardItem(name), QStandardItem(ref_overload['return']['className']), QStandardItem('(%s)' % ', '.join(args)), ]) def _add_field(self, name, value, handle=None, handle_class=None, is_native=False): if handle: handle = {'handle': handle, 'handle_class': handle_class} handle_item = QStandardItem(name) handle_item.setData(handle, Qt.UserRole + 1) else: handle_item = QStandardItem(name) if not is_native: self._fields_model.appendRow( [handle_item, QStandardItem(str(value))]) else: self._native_fields_model.appendRow( [handle_item, QStandardItem(str(value))]) def _set_handle(self, handle): data = self._app_window.dwarf.dwarf_api('javaExplorer', handle) if not data: return self._handle_history.append({'handle': handle}) self._set_data(data) def _set_handle_arg(self, arg): data = self._app_window.dwarf.dwarf_api('javaExplorer', arg) if not data: return self._handle_history.append({'handle': arg}) self._set_data(data) def clear_panel(self): self._top_class_name.setText('') self._handle_history = [] self._methods_list.clear() self._native_fields_list.clear() self._fields_list.clear() def _back(self): if len(self._handle_history) < 2: return self._handle_history.pop() data = self._handle_history.pop(len(self._handle_history) - 1)['handle'] if isinstance(data, int): self._set_handle_arg(data) else: self._set_handle(data) # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_field_dblclicked(self, _): field_row = self._fields_list.selectionModel().currentIndex().row() if field_row >= 0: field_handle = self._fields_model.item(field_row, 0).data(Qt.UserRole + 1) if field_handle: self._set_handle(field_handle) def _on_native_field_dblclicked(self, _): field_row = self._native_fields_list.selectionModel().currentIndex( ).row() if field_row: field_handle = self._native_fields_model.item( field_row, 0).data(Qt.UserRole + 1) if field_handle: self._set_handle(field_handle) def keyPressEvent(self, event): # pylint: disable=invalid-name if event.key() == Qt.Key_Backspace: self._back() return super().keyPressEvent(event)
def _setup_ui(self): self.setContentsMargins(0, 0, 0, 0) top_font = QFont() top_font.setBold(True) top_font.setPixelSize(19) # main wrapper main_wrapper = QVBoxLayout() main_wrapper.setContentsMargins(1, 1, 1, 1) # wrapwdgt wrap_wdgt = QWidget() self._top_class_name = QLabel(wrap_wdgt) self._top_class_name.setContentsMargins(10, 10, 10, 10) self._top_class_name.setAttribute(Qt.WA_TranslucentBackground, True) # keep this self._top_class_name.setFont(top_font) self._top_class_name.setStyleSheet('color: #ef5350;') wrap_wdgt.setMaximumHeight(self._top_class_name.height() + 20) main_wrapper.addWidget(wrap_wdgt) # left list left_wrap_wdgt = QWidget() left_v_box = QVBoxLayout(left_wrap_wdgt) left_v_box.setContentsMargins(0, 0, 0, 0) methods_label = QLabel('METHODS') font = methods_label.font() font.setBold(True) methods_label.setFont(font) methods_label.setContentsMargins(10, 0, 10, 2) methods_label.setAttribute(Qt.WA_TranslucentBackground, True) # keep this left_v_box.addWidget(methods_label) self._methods_list = DwarfListView() left_v_box.addWidget(self._methods_list) # center list center_wrap_wdgt = QWidget() center_v_box = QVBoxLayout(center_wrap_wdgt) center_v_box.setContentsMargins(0, 0, 0, 0) methods_label = QLabel('NATIVE FIELDS') methods_label.setFont(font) methods_label.setContentsMargins(10, 0, 10, 2) methods_label.setAttribute(Qt.WA_TranslucentBackground, True) # keep this center_v_box.addWidget(methods_label) self._native_fields_list = DwarfListView() self._native_fields_list.doubleClicked.connect( self._on_native_field_dblclicked) center_v_box.addWidget(self._native_fields_list) # right list right_wrap_wdgt = QWidget() right_v_box = QVBoxLayout(right_wrap_wdgt) right_v_box.setContentsMargins(0, 0, 0, 0) methods_label = QLabel('FIELDS') methods_label.setFont(font) methods_label.setContentsMargins(10, 0, 10, 2) methods_label.setAttribute(Qt.WA_TranslucentBackground, True) # keep this right_v_box.addWidget(methods_label) self._fields_list = DwarfListView() self._fields_list.doubleClicked.connect(self._on_field_dblclicked) right_v_box.addWidget(self._fields_list) # main splitter main_splitter = QSplitter(Qt.Horizontal) main_splitter.setContentsMargins(0, 0, 0, 0) main_splitter.addWidget(left_wrap_wdgt) main_splitter.addWidget(center_wrap_wdgt) main_splitter.addWidget(right_wrap_wdgt) main_splitter.setSizes([250, 100, 100]) main_wrapper.addWidget(main_splitter) main_wrapper.setSpacing(0) self.setLayout(main_wrapper)
class EmulatorPanel(QWidget): def __init__(self, app, *__args): super().__init__(*__args) self.app = app self.emulator = self.app.dwarf.emulator self.until_address = 0 self._uc_user_arch = None self._uc_user_mode = None self._cs_user_arch = None self._cs_user_mode = None layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self._toolbar_container = QHBoxLayout() self._toolbar = QToolBar() self._toolbar.addAction('Start', self.handle_start) self._toolbar.addAction('Step', self.handle_step) self._toolbar.addAction('Step next call', self.handle_step_next_call) self._toolbar.addAction('Step next jump', self.handle_step_next_jump) self._toolbar.addAction('Stop', self.handle_stop) self._toolbar.addAction('Clear', self.handle_clear) self._toolbar.addAction('Options', self.handle_options) self._toolbar_container.addWidget(self._toolbar) selection_layout = QHBoxLayout() selection_layout.setAlignment(Qt.AlignRight) self.cpu_selection = QComboBox(self) for v in unicorn_const.__dict__: if 'UC_ARCH_' in v: self.cpu_selection.addItem('_'.join(v.split('_')[2:]).lower(), unicorn_const.__dict__[v]) self.cpu_selection.activated[str].connect(self._on_cpu_selection) self.mode_selection = QComboBox(self) for v in unicorn_const.__dict__: if 'UC_MODE_' in v: self.mode_selection.addItem('_'.join(v.split('_')[2:]).lower(), unicorn_const.__dict__[v]) self.mode_selection.activated[str].connect(self._on_mode_selection) selection_layout.addWidget(self.cpu_selection) selection_layout.addWidget(self.mode_selection) self._toolbar_container.addLayout(selection_layout) layout.addLayout(self._toolbar_container) self.tabs = QTabWidget() self.assembly = DisassemblyView(self.app) self.assembly.display_jumps = False self.assembly.follow_jumps = False self.memory_table = MemoryPanel(self.app) self.memory_table._read_only = True self.tabs.addTab(self.assembly, 'Code') self.tabs.addTab(self.memory_table, 'Memory') layout.addWidget(self.tabs) self.ranges_list = DwarfListView(self.app) self.ranges_list.doubleClicked.connect(self.ranges_item_double_clicked) self._ranges_model = QStandardItemModel(0, 2) self._ranges_model.setHeaderData(0, Qt.Horizontal, 'Memory') self._ranges_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._ranges_model.setHeaderData(1, Qt.Horizontal, 'Size') self._ranges_model.setHeaderData(1, Qt.Horizontal, Qt.AlignLeft, Qt.TextAlignmentRole) self.ranges_list.setModel(self._ranges_model) self.tabs.addTab(self.ranges_list, 'Ranges') self._access_list = DwarfListView(self.app) self._access_list.doubleClicked.connect( self.access_item_double_clicked) self._access_model = QStandardItemModel(0, 3) self._access_model.setHeaderData(0, Qt.Horizontal, 'Address') self._access_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._access_model.setHeaderData(1, Qt.Horizontal, 'Access') self._access_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._access_model.setHeaderData(2, Qt.Horizontal, 'Value') self._access_list.setModel(self._access_model) self.tabs.addTab(self._access_list, 'Access') layout.setSpacing(0) self.setLayout(layout) self.console = self.app.console.get_emu_console() self.emulator.onEmulatorSetup.connect(self.on_emulator_setup) self.emulator.onEmulatorStart.connect(self.on_emulator_start) self.emulator.onEmulatorStop.connect(self.on_emulator_stop) # self.emulator.onEmulatorStep.connect(self.on_emulator_step) self.emulator.onEmulatorHook.connect(self.on_emulator_hook) self.emulator.onEmulatorMemoryHook.connect( self.on_emulator_memory_hook) self.emulator.onEmulatorMemoryRangeMapped.connect( self.on_emulator_memory_range_mapped) self.emulator.onEmulatorLog.connect(self.on_emulator_log) self._require_register_result = None self._last_instruction_address = 0 def _on_cpu_selection(self, cpu): self._uc_user_arch = unicorn_const.__dict__['UC_ARCH_' + cpu.upper()] self._cs_user_arch = capstone.__dict__['CS_ARCH_' + cpu.upper()] self._uc_user_mode = unicorn_const.__dict__[ 'UC_MODE_' + self.mode_selection.itemText( self.mode_selection.currentIndex()).upper()] self._cs_user_mode = capstone.__dict__[ 'CS_MODE_' + self.mode_selection.itemText( self.mode_selection.currentIndex()).upper()] def _on_mode_selection(self, mode): self._uc_user_mode = unicorn_const.__dict__['UC_MODE_' + mode.upper()] self._cs_user_mode = capstone.__dict__['CS_MODE_' + mode.upper()] self._uc_user_arch = unicorn_const.__dict__[ 'UC_ARCH_' + self.cpu_selection.itemText( self.cpu_selection.currentIndex()).upper()] self._cs_user_arch = capstone.__dict__[ 'CS_ARCH_' + self.cpu_selection.itemText( self.cpu_selection.currentIndex()).upper()] def resizeEvent(self, event): self.ranges_list.setFixedHeight((self.height() / 100) * 25) self.ranges_list.setFixedWidth((self.width() / 100) * 30) self._access_list.setFixedHeight((self.height() / 100) * 25) return super().resizeEvent(event) def handle_clear(self): self.ranges_list.clear() self._access_list.clear() self.assembly._lines.clear() self.assembly.viewport().update() # self.memory_table.setRowCount(0) self.console.clear() self.emulator.clean() def handle_options(self): EmulatorConfigsDialog.show_dialog(self.app.dwarf) def handle_start(self): ph = '' if self.until_address > 0: ph = hex(self.until_address) address, inp = InputDialog.input_pointer( self.app, input_content=ph, hint='pointer to last instruction') if address > 0: self.until_address = address self.app.console_panel.show_console_tab('emulator') self.emulator.emulate(self.until_address, user_arch=self._uc_user_arch, user_mode=self._uc_user_mode, cs_arch=self._cs_user_arch, cs_mode=self._cs_user_mode) # if err > 0: # self.until_address = 0 # self.console.log('cannot start emulator. err: %d' % err) # return def handle_step(self): self.app.console_panel.show_console_tab('emulator') try: self.emulator.emulate(step_mode=STEP_MODE_SINGLE, user_arch=self._uc_user_arch, user_mode=self._uc_user_mode, cs_arch=self._cs_user_arch, cs_mode=self._cs_user_mode) except self.emulator.EmulatorAlreadyRunningError: self.console.log('Emulator already running') except self.emulator.EmulatorSetupFailedError as error: self.until_address = 0 self.console.log(error) def handle_step_next_call(self): self.app.console_panel.show_console_tab('emulator') try: self.emulator.emulate(step_mode=STEP_MODE_FUNCTION, user_arch=self._uc_user_arch, user_mode=self._uc_user_mode, cs_arch=self._cs_user_arch, cs_mode=self._cs_user_mode) except self.emulator.EmulatorAlreadyRunningError: self.console.log('Emulator already running') except self.emulator.EmulatorSetupFailedError as error: self.until_address = 0 self.console.log(error) def handle_step_next_jump(self): self.app.console_panel.show_console_tab('emulator') try: self.emulator.emulate(step_mode=STEP_MODE_JUMP, user_arch=self._uc_user_arch, user_mode=self._uc_user_mode, cs_arch=self._cs_user_arch, cs_mode=self._cs_user_mode) except self.emulator.EmulatorAlreadyRunningError: self.console.log('Emulator already running') except self.emulator.EmulatorSetupFailedError as error: self.until_address = 0 self.console.log(error) def handle_stop(self): self.emulator.stop() def on_emulator_hook(self, instruction): # @PinkiePonkie why setting context here (which is triggered each instruction) and later, set it again # in emulator_stop? step = double hit in set_context, running emulation on more than 1 instruction # doesn't need spam of set_context # self.app.context_panel.set_context(0, 2, self.emulator.current_context) # check if the previous hook is waiting for a register result if self._require_register_result is not None: row = 1 if len(self._require_register_result) == 1: res = 'jump = %s' % (hex(self._require_register_result[0])) else: res = '%s = %s' % (self._require_register_result[1], hex( self.emulator.uc.reg_read( self._require_register_result[0]))) if len(self.assembly._lines) > 1: if self.assembly._lines[len(self.assembly._lines) - row] is None: row = 2 telescope = self.get_telescope( self.emulator.uc.reg_read( self._require_register_result[0])) if telescope is not None and telescope != 'None': res += ' (' + telescope + ')' self.assembly._lines[len(self.assembly._lines) - row].string = res # invalidate self._require_register_result = None # check if the code jumped self._last_instruction_address = instruction.address self.assembly.add_instruction(instruction) # add empty line if jump if instruction.is_jump or instruction.is_call: self.assembly.add_instruction(None) self._require_register_result = [instruction.jump_address] else: # implicit regs read are notified later through mem access if len(instruction.regs_read) == 0: if len(instruction.operands) > 0: for i in instruction.operands: if i.type == CS_OP_REG: self._require_register_result = [ i.value.reg, instruction.reg_name(i.value.reg) ] break self.assembly.verticalScrollBar().setValue(len(self.assembly._lines)) self.assembly.viewport().update() if instruction.is_call: range_ = Range(Range.SOURCE_TARGET, self.app.dwarf) if range_.init_with_address(instruction.address, require_data=False) > 0: if range_.base > instruction.call_address > range_.tail: if self.emulator.step_mode == STEP_MODE_NONE: self.emulator.stop() action = JumpOutsideTheBoxDialog.show_dialog( self.app.dwarf) if action == 0: # step to jump if self.emulator.step_mode != STEP_MODE_NONE: self.handle_step() else: self.emulator.emulate(self.until_address, user_arch=self._uc_user_arch, user_mode=self._uc_user_mode, cs_arch=self._cs_user_arch, cs_mode=self._cs_user_mode) if action == 1: # step to next jump if self.emulator.step_mode != STEP_MODE_NONE: self.handle_step_next_jump() else: self.emulator.emulate(self.until_address, user_arch=self._uc_user_arch, user_mode=self._uc_user_mode, cs_arch=self._cs_user_arch, cs_mode=self._cs_user_mode) elif action == 2: # hook lr hook_addr = instruction.address + instruction.size if instruction.thumb: hook_addr += 1 self.app.dwarf.hook_native(input_=hex(hook_addr)) def on_emulator_log(self, log): self.app.console_panel.show_console_tab('emulator') self.console.log(log) def on_emulator_memory_hook(self, data): uc, access, address, value = data _address = QStandardItem() if self.ranges_list.uppercase_hex: if self.app.dwarf.pointer_size > 4: str_frmt = '0x{0:016X}'.format(address) else: str_frmt = '0x{0:08X}'.format(address) else: if self.app.dwarf.pointer_size > 4: str_frmt = '0x{0:016x}'.format(address) else: str_frmt = '0x{0:08x}'.format(address) _address.setText(str_frmt) _address.setTextAlignment(Qt.AlignCenter) _access = QStandardItem() if access == UC_MEM_READ: _access.setText('READ') elif access == UC_MEM_WRITE: _access.setText('WRITE') elif access == UC_MEM_FETCH: _access.setText('FETCH') _access.setTextAlignment(Qt.AlignCenter) _value = QStandardItem() _value.setText(str(value)) self._access_model.appendRow([_address, _access, _value]) res = None row = 1 if len(self.assembly._lines) > 1: if self.assembly._lines[len(self.assembly._lines) - row] is None: row = 2 if access == UC_MEM_READ: if self._require_register_result is not None: if len(self._require_register_result) > 1: res = '%s = %s' % (self._require_register_result[1], hex(value)) else: if self.assembly._lines[len(self.assembly._lines) - row].string: res = '%s, %s = %s' % (self.assembly._lines[ len(self.assembly._lines) - row].string, hex(address), hex(value)) else: res = '%s = %s' % (hex(address), hex(value)) if res is not None: telescope = self.get_telescope(value) if telescope is not None and telescope != 'None': res += ' (' + telescope + ')' # invalidate self._require_register_result = None self.assembly._lines[len(self.assembly._lines) - row].string = res def get_telescope(self, address): try: size = self.app.dwarf.pointer_size telescope = self.emulator.uc.mem_read(address, size) try: for i in range(len(telescope)): if int(telescope[i]) == 0x0 and i != 0: st = telescope.decode('utf8') return st st = telescope.decode('utf8') if len(st) != size: return '0x%s' % telescope.hex() while True: telescope = self.emulator.uc.mem_read(address + size, 1) if int(telescope) == 0x0: break st += telescope.decode('utf8') size += 1 return st except: return '0x%s' % telescope.hex() except UcError as e: # read from js telescope = self.app.dwarf.dwarf_api('getAddressTs', address) if telescope is None: return None telescope = str(telescope[1]).replace('\n', ' ') if len(telescope) > 50: telescope = telescope[:50] + '...' return telescope def on_emulator_memory_range_mapped(self, data): address, size = data _address = QStandardItem() if self.ranges_list.uppercase_hex: if self.app.dwarf.pointer_size > 4: str_frmt = '0x{0:016X}'.format(address) else: str_frmt = '0x{0:08X}'.format(address) else: if self.app.dwarf.pointer_size > 4: str_frmt = '0x{0:016x}'.format(address) else: str_frmt = '0x{0:08x}'.format(address) _address.setText(str_frmt) _address.setTextAlignment(Qt.AlignCenter) _size = QStandardItem() _size.setText("{0:,d}".format(int(size))) self._ranges_model.appendRow([_address, _size]) def on_emulator_setup(self, data): user_arch = data[0] user_mode = data[1] if user_arch is not None and user_mode is not None: index = self.cpu_selection.findData(user_arch) self.cpu_selection.setCurrentIndex(index) index = self.mode_selection.findData(user_mode) self.mode_selection.setCurrentIndex(index) def on_emulator_start(self): pass def on_emulator_stop(self): self.app.context_panel.set_context(0, 2, self.emulator.current_context) # check if the previous hook is waiting for a register result if self._require_register_result is not None: row = 1 if len(self._require_register_result) == 1: res = 'jump = %s' % (hex(self._require_register_result[0])) else: res = '%s = %s' % (self._require_register_result[1], hex( self.emulator.uc.reg_read( self._require_register_result[0]))) telescope = self.get_telescope( self.emulator.uc.reg_read( self._require_register_result[0])) if telescope is not None and telescope != 'None': res += ' (' + telescope + ')' if len(self.assembly._lines) > 1: if self.assembly._lines[len(self.assembly._lines) - row] is None: row = 2 self.assembly._lines[len(self.assembly._lines) - row].string = res # invalidate self._require_register_result = None def ranges_item_double_clicked(self, model_index): row = self._ranges_model.itemFromIndex(model_index).row() if row != -1: item = self._ranges_model.item(row, 0).text() self.memory_table.read_memory(item) self.tabs.setCurrentIndex(1) def access_item_double_clicked(self, model_index): row = self._access_model.itemFromIndex(model_index).row() if row != -1: item = self._access_model.item(row, 0).text() self.memory_table.read_memory(item) self.tabs.setCurrentIndex(1)
class ContextPanel(QTabWidget): # consts CONTEXT_TYPE_NATIVE = 0 CONTEXT_TYPE_JAVA = 1 CONTEXT_TYPE_EMULATOR = 2 onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest') def __init__(self, parent=None): super(ContextPanel, self).__init__(parent=parent) self._app_window = parent self.setAutoFillBackground(True) self._app_window.dwarf.onContextChanged.connect( self._on_context_changed) self._nativectx_model = QStandardItemModel(0, 4) self._nativectx_model.setHeaderData(0, Qt.Horizontal, 'Reg') self._nativectx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(1, Qt.Horizontal, 'Value') self._nativectx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(2, Qt.Horizontal, 'Decimal') #self._nativectx_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._nativectx_model.setHeaderData(3, Qt.Horizontal, 'Telescope') self._nativectx_list = DwarfListView() self._nativectx_list.setModel(self._nativectx_model) self._nativectx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._nativectx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._nativectx_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self._nativectx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._nativectx_list.customContextMenuRequested.connect( self._on_native_contextmenu) self._emulatorctx_model = QStandardItemModel(0, 3) self._emulatorctx_model.setHeaderData(0, Qt.Horizontal, 'Reg') self._emulatorctx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._emulatorctx_model.setHeaderData(1, Qt.Horizontal, 'Value') self._emulatorctx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._emulatorctx_model.setHeaderData(2, Qt.Horizontal, 'Decimal') self._emulatorctx_list = DwarfListView() self._emulatorctx_list.setModel(self._emulatorctx_model) self._emulatorctx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._emulatorctx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._emulatorctx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._emulatorctx_list.customContextMenuRequested.connect( self._on_emulator_contextmenu) self._javactx_model = QStandardItemModel(0, 3) self._javactx_model.setHeaderData(0, Qt.Horizontal, 'Argument') self._javactx_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._javactx_model.setHeaderData(1, Qt.Horizontal, 'Class') #self._javactx_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._javactx_model.setHeaderData(2, Qt.Horizontal, 'Value') self._javactx_list = DwarfListView() self._javactx_list.setModel(self._javactx_model) self._javactx_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self._javactx_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self._javactx_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self._javactx_list.setContextMenuPolicy(Qt.CustomContextMenu) self._javactx_list.customContextMenuRequested.connect( self._on_java_contextmenu) self.addTab(self._nativectx_list, 'Native') self.show_context_tab('Native') # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def clear(self): self._nativectx_list.clear() self._emulatorctx_list.clear() self._javactx_list.clear() def set_context(self, ptr, context_type, context): if isinstance(context, str): context = json.loads(context) if context_type == ContextPanel.CONTEXT_TYPE_NATIVE: self._nativectx_list.clear() self._set_native_context(ptr, context) elif context_type == ContextPanel.CONTEXT_TYPE_JAVA: self._javactx_list.clear() self._set_java_context(ptr, context) elif context_type == ContextPanel.CONTEXT_TYPE_EMULATOR: self._emulatorctx_list.clear() self._set_emulator_context(ptr, context) else: raise Exception('unknown context type') def have_context(self): return self.count() > 0 def show_context_tab(self, tab_name): index = 0 tab_name = tab_name.join(tab_name.split()).lower() if tab_name == 'native': index = self.indexOf(self._nativectx_list) elif tab_name == 'emulator': index = self.indexOf(self._emulatorctx_list) elif tab_name == 'java': index = self.indexOf(self._javactx_list) if self.count() > 0: self.setCurrentIndex(index) def _set_native_context(self, ptr, context): if self.indexOf(self._nativectx_list) == -1: self.addTab(self._nativectx_list, 'Native') self.show_context_tab('Native') else: self.show_context_tab('Native') context_ptr = ptr sorted_regs = self.get_sort_order() for register in sorted(context, key=lambda x: sorted_regs[x] if x in sorted_regs else len(sorted_regs)): reg_name = QStandardItem() reg_name.setTextAlignment(Qt.AlignCenter) if context[register]['isValidPointer']: reg_name.setData(context_ptr) value_x = QStandardItem() if context[register]['isValidPointer']: value_x.setForeground(Qt.red) # value_x.setTextAlignment(Qt.AlignCenter) value_dec = QStandardItem() # value_dec.setTextAlignment(Qt.AlignCenter) telescope = QStandardItem() reg_name.setText(register) if context[register] is not None: str_fmt = '0x{0:x}' if self._nativectx_list.uppercase_hex: str_fmt = '0x{0:X}' value_x.setText( str_fmt.format(int(context[register]['value'], 16))) value_dec.setText('{0:d}'.format( int(context[register]['value'], 16))) if context[register]['isValidPointer']: if 'telescope' in context[register] and context[register][ 'telescope'] is not None: telescope = QStandardItem() telescope_value = str( context[register]['telescope'][1]).replace( '\n', ' ') if len(telescope_value) > 50: telescope_value = telescope_value[:50] + '...' telescope.setText(telescope_value) if context[register]['telescope'][0] == 2: telescope.setData( context[register]['telescope'][1], Qt.UserRole + 1) if context[register]['telescope'][0] == 0: telescope.setForeground(Qt.darkGreen) elif context[register]['telescope'][0] == 2: telescope.setForeground(Qt.white) elif context[register]['telescope'][0] != 1: telescope.setForeground(Qt.darkGray) self._nativectx_model.appendRow( [reg_name, value_x, value_dec, telescope]) self._nativectx_list.resizeColumnToContents(0) def _set_emulator_context(self, ptr, context): if self.indexOf(self._emulatorctx_list) == -1: self.addTab(self._emulatorctx_list, 'Emulator') self.show_context_tab('Emulator') else: self.show_context_tab('Emulator') context_ptr = ptr context = context.__dict__ sorted_regs = self.get_sort_order() for register in sorted(context, key=lambda x: sorted_regs[x] if x in sorted_regs else len(sorted_regs)): if register.startswith('_') or register not in sorted_regs: continue reg_name = QStandardItem() reg_name.setTextAlignment(Qt.AlignCenter) reg_name.setForeground(QColor('#39c')) value_x = QStandardItem() # value_x.setTextAlignment(Qt.AlignCenter) value_dec = QStandardItem() # value_dec.setTextAlignment(Qt.AlignCenter) reg_name.setText(register) reg_name.setData(context_ptr) if context[register] is not None: if isinstance(context[register], int): str_fmt = '0x{0:x}' if self._emulatorctx_list.uppercase_hex: str_fmt = '0x{0:X}' value_x.setText(str_fmt.format(context[register])) value_dec.setText('{0:d}'.format(context[register])) self._emulatorctx_model.appendRow([reg_name, value_x, value_dec]) self._emulatorctx_list.resizeColumnToContents(0) self._emulatorctx_list.resizeColumnToContents(1) def _set_java_context(self, ptr, context): if self.indexOf(self._javactx_list) == -1: self.addTab(self._javactx_list, 'Java') self.show_context_tab('Java') else: self.show_context_tab('Java') for arg in context: _arg = QStandardItem() _arg.setText(arg) _class = QStandardItem() _class.setText(context[arg]['className']) if isinstance(context[arg]['handle'], str): _class.setForeground(Qt.lightGray) _value = QStandardItem() if 'arg' not in context[arg] or context[arg]['arg'] is None: _value.setText('null') _value.setForeground(Qt.gray) else: _value.setText(context[arg]['arg']) self._javactx_model.appendRow([_arg, _class, _value]) self._javactx_list.resizeColumnToContents(0) self._javactx_list.resizeColumnToContents(1) def get_sort_order(self): reg_order = [] if self._app_window.dwarf.arch == 'arm': # arm reg_order = [ 'r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', 'sp', 'lr', 'sb', 'sl', 'fp', 'ip', 'pc', 'cspr' ] elif self._app_window.dwarf.arch == 'arm64': reg_order = [ 'x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10', 'x11', 'x12', 'x13', 'x14', 'x15', 'x16', 'x17', 'x18', 'x19', 'x20', 'x21', 'x22', 'x23', 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'w0', 'w1', 'w2', 'w3', 'w4', 'w5', 'w6', 'w7', 'w8', 'w9', 'w10', 'w11', 'w12', 'w13', 'w14', 'w15', 'w16', 'w17', 'w18', 'w19', 'w20', 'w21', 'w22', 'w23', 'w24', 'w25', 'w26', 'w27', 'w28', 'w29', 'w30', 'sp', 'lr', 'fp', 'wsp', 'wzr', 'xzr', 'nzcv', 'ip0', 'ip1', 's0', 's1', 's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's10', 's11', 's12', 's13', 's14', 's15', 's16', 's17', 's18', 's19', 's20', 's21', 's22', 's23', 's24', 's25', 's26', 's27', 's28', 's29', 's30', 's31', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'd10', 'd11', 'd12', 'd13', 'd14', 'd15', 'd16', 'd17', 'd18', 'd19', 'd20', 'd21', 'd22', 'd23', 'd24', 'd25', 'd26', 'd27', 'd28', 'd29', 'd30', 'd31', 'q0', 'q1', 'q2', 'q3', 'q4', 'q5', 'q6', 'q7', 'q8', 'q9', 'q10', 'q11', 'q12', 'q13', 'q14', 'q15', 'q16', 'q17', 'q18', 'q19', 'q20', 'q21', 'q22', 'q23', 'q24', 'q25', 'q26', 'q27', 'q28', 'q29', 'q30', 'q31', 'sp', 'lr', 'sb', 'sl', 'fp', 'ip', 'pc', 'cspr' ] elif self._app_window.dwarf.arch == 'ia32': reg_order = [ 'eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'esp', 'r8d', 'r9d', 'r10d', 'r11d', 'r12d', 'r13d', 'r14d', 'r15d', 'ebp', 'eip', 'sp', 'pc' ] elif self._app_window.dwarf.arch == 'x64': # x64 reg_order = [ 'rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rbp', 'rsp', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', 'esp', 'ebp', 'rip', 'eip', 'sp', 'pc' ] sorted_regs = {b: i for i, b in enumerate(reg_order)} return sorted_regs # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_native_contextmenu(self, pos): index = self._nativectx_list.indexAt(pos).row() glbl_pt = self._nativectx_list.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: # show contextmenu context_menu.addAction( 'Copy value', lambda: utils.copy_hex_to_clipboard( self._nativectx_model.item(index, 1).text())) context_menu.addAction( 'Jump to address', lambda: self._app_window.jump_to_address( self._nativectx_model.item(index, 1).text())) context_menu.exec_(glbl_pt) def _on_emulator_contextmenu(self, pos): index = self._emulatorctx_list.indexAt(pos).row() glbl_pt = self._emulatorctx_list.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: # show contextmenu context_menu.exec_(glbl_pt) def _on_java_contextmenu(self, pos): index = self._javactx_list.indexAt(pos).row() glbl_pt = self._javactx_list.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: # show contextmenu context_menu.exec_(glbl_pt) def _on_context_changed(self, reg_name, reg_val): x_in = 0 for c in reg_val: if c.lower() not in '1234567890abcdef': if c.lower() == 'x' and x_in == 0: x_in += 1 continue self._app_window.dwarf.onLogToConsole.emit( 'error: invalid reg_value: ' + reg_val + ' - expected dec/hex') return if isinstance(reg_val, str) and reg_val.startswith('0x'): try: reg_val = int(reg_val, 16) except ValueError: self._app_window.dwarf.onLogToConsole.emit( 'error: invalid reg_value: ' + reg_val + ' - expected dec/hex') return try: reg_val = int(reg_val) except ValueError: self._app_window.dwarf.onLogToConsole.emit( 'error: invalid reg_value: ' + reg_val + ' - expected dec/hex') return reg_val = hex(reg_val) was_found, find_result = self._nativectx_list.contains_text( reg_name, True, True, True) if was_found: if len(find_result) == 1: find_result = find_result[0] if self._nativectx_model.item(find_result[0], 0).text() == reg_name: str_fmt = '0x{0:x}' if self._nativectx_list.uppercase_hex: str_fmt = '0x{0:X}' value_x = str_fmt.format(int(reg_val, 16)) value_dec = '{0:d}'.format(int(reg_val, 16)) self._nativectx_model.item(find_result[0], 1).setText(value_x) self._nativectx_model.item(find_result[0], 2).setText(value_dec) self._nativectx_model.item(find_result[0], 3).setText("")
def __init__(self, app, *__args): super().__init__(*__args) self.app = app self.emulator = self.app.dwarf.emulator self.until_address = 0 self._uc_user_arch = None self._uc_user_mode = None self._cs_user_arch = None self._cs_user_mode = None layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self._toolbar_container = QHBoxLayout() self._toolbar = QToolBar() self._toolbar.addAction('Start', self.handle_start) self._toolbar.addAction('Step', self.handle_step) self._toolbar.addAction('Step next call', self.handle_step_next_call) self._toolbar.addAction('Step next jump', self.handle_step_next_jump) self._toolbar.addAction('Stop', self.handle_stop) self._toolbar.addAction('Clear', self.handle_clear) self._toolbar.addAction('Options', self.handle_options) self._toolbar_container.addWidget(self._toolbar) selection_layout = QHBoxLayout() selection_layout.setAlignment(Qt.AlignRight) self.cpu_selection = QComboBox(self) for v in unicorn_const.__dict__: if 'UC_ARCH_' in v: self.cpu_selection.addItem('_'.join(v.split('_')[2:]).lower(), unicorn_const.__dict__[v]) self.cpu_selection.activated[str].connect(self._on_cpu_selection) self.mode_selection = QComboBox(self) for v in unicorn_const.__dict__: if 'UC_MODE_' in v: self.mode_selection.addItem('_'.join(v.split('_')[2:]).lower(), unicorn_const.__dict__[v]) self.mode_selection.activated[str].connect(self._on_mode_selection) selection_layout.addWidget(self.cpu_selection) selection_layout.addWidget(self.mode_selection) self._toolbar_container.addLayout(selection_layout) layout.addLayout(self._toolbar_container) self.tabs = QTabWidget() self.assembly = DisassemblyView(self.app) self.assembly.display_jumps = False self.assembly.follow_jumps = False self.memory_table = MemoryPanel(self.app) self.memory_table._read_only = True self.tabs.addTab(self.assembly, 'Code') self.tabs.addTab(self.memory_table, 'Memory') layout.addWidget(self.tabs) self.ranges_list = DwarfListView(self.app) self.ranges_list.doubleClicked.connect(self.ranges_item_double_clicked) self._ranges_model = QStandardItemModel(0, 2) self._ranges_model.setHeaderData(0, Qt.Horizontal, 'Memory') self._ranges_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._ranges_model.setHeaderData(1, Qt.Horizontal, 'Size') self._ranges_model.setHeaderData(1, Qt.Horizontal, Qt.AlignLeft, Qt.TextAlignmentRole) self.ranges_list.setModel(self._ranges_model) self.tabs.addTab(self.ranges_list, 'Ranges') self._access_list = DwarfListView(self.app) self._access_list.doubleClicked.connect( self.access_item_double_clicked) self._access_model = QStandardItemModel(0, 3) self._access_model.setHeaderData(0, Qt.Horizontal, 'Address') self._access_model.setHeaderData(0, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._access_model.setHeaderData(1, Qt.Horizontal, 'Access') self._access_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self._access_model.setHeaderData(2, Qt.Horizontal, 'Value') self._access_list.setModel(self._access_model) self.tabs.addTab(self._access_list, 'Access') layout.setSpacing(0) self.setLayout(layout) self.console = self.app.console.get_emu_console() self.emulator.onEmulatorSetup.connect(self.on_emulator_setup) self.emulator.onEmulatorStart.connect(self.on_emulator_start) self.emulator.onEmulatorStop.connect(self.on_emulator_stop) # self.emulator.onEmulatorStep.connect(self.on_emulator_step) self.emulator.onEmulatorHook.connect(self.on_emulator_hook) self.emulator.onEmulatorMemoryHook.connect( self.on_emulator_memory_hook) self.emulator.onEmulatorMemoryRangeMapped.connect( self.on_emulator_memory_range_mapped) self.emulator.onEmulatorLog.connect(self.on_emulator_log) self._require_register_result = None self._last_instruction_address = 0