class ProcessList(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(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() # ************************************************************************ # **************************** 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.process_list.clear() def set_device(self, device): """ Set frida Device """ if isinstance(device, frida.core.Device): self._device = device self.procs_update_thread.device = device self._on_refresh_procs() # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_item_clicked(self, model_index): model = self.process_list.model() index = model.itemFromIndex(model_index).row() if index != -1: sel_pid = self.process_list.get_item_text(index, 0) sel_name = self.process_list.get_item_text(index, 1) self.onProcessSelected.emit([int(sel_pid), sel_name]) def _on_add_proc(self, item): model = self.process_list.model() pid = QStandardItem() pid.setText(str(item['pid'])) pid.setTextAlignment(Qt.AlignCenter) name = QStandardItem() name.setText(item['name']) model.appendRow([pid, name]) def _on_error(self, error_str): self.onRefreshError.emit(error_str) def _on_refresh_procs(self): if not self._device: return if self.procs_update_thread.isRunning(): self.procs_update_thread.terminate() if not self.procs_update_thread.isRunning(): self.clear() self.refresh_button.setEnabled(False) self.procs_update_thread.device = self._device self.procs_update_thread.start() def _on_refresh_finished(self): self.refresh_button.setEnabled(True)
class ModulesPanel(QWidget): """ ModulesPanel Signals: onAddHook([ptr, funcname]) - MenuItem AddHook onDumpBinary([ptr, size#int]) - MenuItem DumpBinary onModuleSelected([ptr, size#int]) - ModuleDoubleClicked onModuleFuncSelected(ptr) - FunctionDoubleClicked """ # pylint: disable=too-many-instance-attributes onAddHook = pyqtSignal(list, name='onAddHook') onDumpBinary = pyqtSignal(list, name='onDumpBinary') onModuleSelected = pyqtSignal(list, name='onModuleSelected') onModuleFuncSelected = pyqtSignal(str, name='onModuleFuncSelected') def __init__(self, parent=None): # pylint: disable=too-many-statements super(ModulesPanel, self).__init__(parent) self._app_window = parent if self._app_window.dwarf is None: print('ModulesPanel created before Dwarf exists') return self._app_window.dwarf.onSetModules.connect(self.set_modules) self._uppercase_hex = True # setup models self.modules_list = None self.modules_model = QStandardItemModel(0, 4, self) self.modules_model.setHeaderData(0, Qt.Horizontal, 'Name') self.modules_model.setHeaderData(1, Qt.Horizontal, 'Base') self.modules_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.modules_model.setHeaderData(2, Qt.Horizontal, 'Size') self.modules_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.modules_model.setHeaderData(3, Qt.Horizontal, 'Path') self.imports_list = None self.imports_model = QStandardItemModel(0, 4, self) self.imports_model.setHeaderData(0, Qt.Horizontal, 'Import') self.imports_model.setHeaderData(1, Qt.Horizontal, 'Address') self.imports_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.imports_model.setHeaderData(2, Qt.Horizontal, 'Module') self.imports_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.imports_model.setHeaderData(3, Qt.Horizontal, 'Type') self.exports_list = None self.exports_model = QStandardItemModel(0, 3, self) self.exports_model.setHeaderData(0, Qt.Horizontal, 'Export') self.exports_model.setHeaderData(1, Qt.Horizontal, 'Address') self.exports_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.exports_model.setHeaderData(2, Qt.Horizontal, 'Type') self.symbols_list = None self.symbols_model = QStandardItemModel(0, 3, self) self.symbols_model.setHeaderData(0, Qt.Horizontal, 'Export') self.symbols_model.setHeaderData(1, Qt.Horizontal, 'Address') self.symbols_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole) self.symbols_model.setHeaderData(2, Qt.Horizontal, 'Type') # setup ui main_wrapper = QVBoxLayout() main_wrapper.setContentsMargins(0, 0, 0, 0) h_box = QHBoxLayout() self.modules_list = DwarfListView() self.modules_list.setContextMenuPolicy(Qt.CustomContextMenu) self.modules_list.customContextMenuRequested.connect( self._on_modules_contextmenu) self.modules_list.setEditTriggers(self.modules_list.NoEditTriggers) self.modules_list.clicked.connect(self._module_clicked) self.modules_list.doubleClicked.connect(self._module_dblclicked) self.modules_list.setModel(self.modules_model) self.modules_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.modules_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.modules_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) h_box.addWidget(self.modules_list) self.modules_list.selectionModel().selectionChanged.connect( self._module_clicked) hv_box = QVBoxLayout() self.imports_list = DwarfListView() self.imports_list.setContextMenuPolicy(Qt.CustomContextMenu) self.imports_list.customContextMenuRequested.connect( self._on_imports_contextmenu) self.imports_list.setEditTriggers(self.modules_list.NoEditTriggers) self.imports_list.doubleClicked.connect(self._import_dblclicked) self.imports_list.setModel(self.imports_model) self.imports_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.imports_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.imports_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self.imports_list.setVisible(False) self.exports_list = DwarfListView() self.exports_list.setContextMenuPolicy(Qt.CustomContextMenu) self.exports_list.customContextMenuRequested.connect( self._on_exports_contextmenu) self.exports_list.setEditTriggers(self.modules_list.NoEditTriggers) self.exports_list.doubleClicked.connect(self._export_dblclicked) self.exports_list.setModel(self.exports_model) self.exports_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.exports_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.exports_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self.exports_list.setVisible(False) self.symbols_list = DwarfListView() self.symbols_list.setContextMenuPolicy(Qt.CustomContextMenu) self.symbols_list.doubleClicked.connect(self._symbol_dblclicked) self.symbols_list.setModel(self.symbols_model) self.symbols_list.header().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.symbols_list.header().setSectionResizeMode( 1, QHeaderView.ResizeToContents) self.symbols_list.header().setSectionResizeMode( 2, QHeaderView.ResizeToContents) self.symbols_list.setVisible(False) hv_box.addWidget(self.imports_list) hv_box.addWidget(self.exports_list) hv_box.addWidget(self.symbols_list) h_box.addLayout(hv_box) main_wrapper.addLayout(h_box) self.setLayout(main_wrapper) # ************************************************************************ # **************************** Properties ******************************** # ************************************************************************ @property def uppercase_hex(self): """ HexDisplayStyle """ return self._uppercase_hex @uppercase_hex.setter def uppercase_hex(self, value): """ HexDisplayStyle """ if isinstance(value, bool): self._uppercase_hex = value elif isinstance(value, str): self._uppercase_hex = (value == 'upper') # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def set_modules(self, modules): """ Fills the ModulesList with data """ self.modules_list.clear() for module in modules: name = QStandardItem() name.setTextAlignment(Qt.AlignLeft) name.setText(module['name']) base = QStandardItem() base.setTextAlignment(Qt.AlignCenter) str_fmt = '0x{0:X}' if not self.uppercase_hex: str_fmt = '0x{0:x}' base.setText(str_fmt.format(int(module['base'], 16))) size = QStandardItem() size.setTextAlignment(Qt.AlignRight) size.setText("{0:,d}".format(int(module['size']))) path = QStandardItem() path.setTextAlignment(Qt.AlignLeft) path.setText(module['path']) self.modules_model.appendRow([name, base, size, path]) def update_modules(self): """ DwarfApiCall updateModules """ return self._app_window.dwarf.dwarf_api('updateModules') def set_imports(self, imports): """ Fills the ImportsList with data """ self.imports_list.clear() for import_ in imports: name = QStandardItem() name.setTextAlignment(Qt.AlignLeft) name.setText(import_['name']) address = QStandardItem() address.setTextAlignment(Qt.AlignCenter) str_fmt = '0x{0:X}' if not self.uppercase_hex: str_fmt = '0x{0:x}' address.setText(str_fmt.format(int(import_['address'], 16))) module = QStandardItem() if 'module' in import_: module.setTextAlignment(Qt.AlignLeft) module.setText(import_['module']) type_ = QStandardItem() if 'type' in import_: type_.setTextAlignment(Qt.AlignLeft) type_.setText(import_['type']) self.imports_model.appendRow([name, address, module, type_]) def set_exports(self, exports): """ Fills the ExportsList with data """ self.exports_list.clear() for export in exports: name = QStandardItem() name.setTextAlignment(Qt.AlignLeft) name.setText(export['name']) address = QStandardItem() address.setTextAlignment(Qt.AlignCenter) str_fmt = '0x{0:X}' if not self.uppercase_hex: str_fmt = '0x{0:x}' address.setText(str_fmt.format(int(export['address'], 16))) type_ = QStandardItem() type_.setTextAlignment(Qt.AlignLeft) type_.setText(export['type']) self.exports_model.appendRow([name, address, type_]) def set_symbols(self, symbols): """ Fills the SymbolsList with data """ self.symbols_list.clear() for symbol in symbols: name = QStandardItem() name.setTextAlignment(Qt.AlignLeft) name.setText(symbol['name']) address = QStandardItem() address.setTextAlignment(Qt.AlignCenter) str_fmt = '0x{0:X}' if not self.uppercase_hex: str_fmt = '0x{0:x}' address.setText(str_fmt.format(int(symbol['address'], 16))) type_ = QStandardItem() type_.setTextAlignment(Qt.AlignLeft) type_.setText(symbol['type']) self.symbols_model.appendRow([name, address, type_]) # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _module_clicked(self): """ Module Clicked updates imports/exports/symbols """ module_index = self.modules_list.selectionModel().currentIndex().row() module = self.modules_model.item(module_index, 0) # module name if module is None: return imports = self._app_window.dwarf.dwarf_api('enumerateImports', module.text()) if imports and (imports is not None): imports = json.loads(imports) if imports: self.set_imports(imports) self.imports_list.setVisible(True) else: self.imports_list.setVisible(False) exports = self._app_window.dwarf.dwarf_api('enumerateExports', module.text()) if exports and exports is not None: exports = json.loads(exports) if exports: self.set_exports(exports) self.exports_list.setVisible(True) else: self.exports_list.setVisible(False) symbols = self._app_window.dwarf.dwarf_api('enumerateSymbols', module.text()) if symbols and symbols is not None: symbols = json.loads(symbols) if symbols: self.set_symbols(symbols) self.symbols_list.setVisible(True) else: self.symbols_list.setVisible(False) def _module_dblclicked(self): """ Module DoubleClicked """ module_index = self.modules_list.selectionModel().currentIndex().row() base = self.modules_model.item(module_index, 1).text() size = self.modules_model.item(module_index, 2).text().replace(',', '') self.onModuleSelected.emit([base, size]) def _import_dblclicked(self): """ ImportFunction DoubleClicked """ index = self.imports_list.selectionModel().currentIndex().row() addr = self.imports_model.item(index, 1).text() self.onModuleFuncSelected.emit(addr) def _export_dblclicked(self): """ ExportFunction DoubleClicked """ index = self.exports_list.selectionModel().currentIndex().row() addr = self.exports_model.item(index, 1).text() self.onModuleFuncSelected.emit(addr) def _symbol_dblclicked(self): """ Symbol DoubleClicked """ index = self.symbols_list.selectionModel().currentIndex().row() addr = self.symbols_model.item(index, 1).text() self.onModuleFuncSelected.emit(addr) def _on_modules_contextmenu(self, pos): """ Modules ContextMenu """ index = self.modules_list.indexAt(pos).row() glbl_pt = self.modules_list.mapToGlobal(pos) context_menu = QMenu(self) if index != -1: context_menu.addAction( 'Dump Binary', lambda: self._on_dumpmodule( self.modules_model.item(index, 1).text(), self.modules_model.item(index, 2).text())) context_menu.addAction( 'Copy address', lambda: utils.copy_hex_to_clipboard( self.modules_model.item(index, 1).text())) context_menu.addSeparator() context_menu.addAction( 'Copy Name', lambda: utils.copy_str_to_clipboard( self.modules_model.item(index, 0).text())) context_menu.addAction( 'Copy Path', lambda: utils.copy_str_to_clipboard( self.modules_model.item(index, 3).text())) context_menu.addSeparator() context_menu.addAction('Refresh', self.update_modules) context_menu.exec_(glbl_pt) def _on_imports_contextmenu(self, pos): """ ImportList ContextMenu """ index = self.imports_list.indexAt(pos).row() if index != -1: glbl_pt = self.imports_list.mapToGlobal(pos) context_menu = QMenu(self) func_name = self.imports_model.item(index, 0).text() addr = self.imports_model.item(index, 1).text() context_menu.addAction('Add Hook', lambda: self._add_hook(addr, func_name)) context_menu.addSeparator() context_menu.addAction( 'Copy address', lambda: utils.copy_hex_to_clipboard( self.imports_model.item(index, 1).text())) context_menu.addSeparator() context_menu.addAction( 'Copy FunctionName', lambda: utils.copy_str_to_clipboard(func_name)) context_menu.addAction( 'Copy ModuleName', lambda: utils.copy_str_to_clipboard( self.imports_model.item(index, 2).text())) context_menu.exec_(glbl_pt) def _on_exports_contextmenu(self, pos): """ ExportsList ContextMenu """ index = self.exports_list.indexAt(pos).row() if index != -1: glbl_pt = self.exports_list.mapToGlobal(pos) context_menu = QMenu(self) func_name = self.exports_model.item(index, 0).text() addr = self.exports_model.item(index, 1).text() context_menu.addAction('Add Hook', lambda: self._add_hook(addr, func_name)) context_menu.addSeparator() context_menu.addAction( 'Copy address', lambda: utils.copy_hex_to_clipboard( self.exports_model.item(index, 1).text())) context_menu.addSeparator() context_menu.addAction( 'Copy FunctionName', lambda: utils.copy_str_to_clipboard(func_name)) context_menu.exec_(glbl_pt) def _on_dumpmodule(self, ptr, size): """ MenuItem DumpBinary """ if isinstance(ptr, int): str_fmt = '0x{0:X}' if not self.uppercase_hex: str_fmt = '0x{0:x}' ptr = str_fmt.format(ptr) size = size.replace(',', '') self.onDumpBinary.emit([ptr, size]) def _add_hook(self, ptr, name=None): """ MenuItem AddHook """ if name is None: name = ptr if isinstance(ptr, str): if ptr.startswith('0x') or ptr.startswith('#'): self.onAddHook.emit([ptr, name]) elif isinstance(ptr, int): str_fmt = '0x{0:x}' self.onAddHook.emit(str_fmt.format([ptr, name]))
class EmulatorPanel(QWidget): def __init__(self, app, *__args): super().__init__(*__args) self.app = app self.emulator = self.app.dwarf.emulator self.until_address = 0 layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self._toolbar = QToolBar() self._toolbar.addAction('Start', self.handle_start) self._toolbar.addAction('Step', self.handle_step) self._toolbar.addAction('Stop', self.handle_stop) self._toolbar.addAction('Clean', self.handle_clean) self._toolbar.addAction('Options', self.handle_options) layout.addWidget(self._toolbar) 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) h_box = QHBoxLayout() 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_list.setModel(self._ranges_model) 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) h_box.addWidget(self.ranges_list) h_box.addWidget(self._access_list) layout.addLayout(h_box) self.setLayout(layout) self.console = self.app.console.get_emu_console() 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 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_clean(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.emulator.emulate(self.until_address) # if err > 0: # self.until_address = 0 # self.console.log('cannot start emulator. err: %d' % err) # return def handle_step(self): try: result = self.emulator.emulate() if not result: self.console.log('Emulation failed') except self.emulator.EmulatorAlreadyRunningError: self.console.log('Emulator already runnging') 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): 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 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 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: self.assembly.add_instruction(None) # 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() 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() str_frmt = '' 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: 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: # invalidate self._require_register_result = None self.assembly._lines[len(self.assembly._lines) - row].string = res def on_emulator_memory_range_mapped(self, data): address, size = data _address = QStandardItem() str_frmt = '' 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_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 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 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 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 """ onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest') 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._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() # ************************************************************************ # **************************** 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_dblclicked) def set_ranges(self, ranges): """ Fills Rangelist with Data """ 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_dblclicked(self, model_index): item = self._result_model.itemFromIndex(model_index) if item: self.onShowMemoryRequest.emit( 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 if self._blocking_search: self.progress = QProgressDialog() self.progress.setFixedSize(300, 50) self.progress.setAutoFillBackground(True) self.progress.setWindowModality(Qt.WindowModal) self.progress.setWindowTitle('Please wait') self.progress.setLabelText('searching...') self.progress.setSizeGripEnabled(False) self.progress.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.progress.setWindowFlag(Qt.WindowContextHelpButtonHint, False) self.progress.setWindowFlag(Qt.WindowCloseButtonHint, False) self.progress.setModal(True) self.progress.setCancelButton(None) self.progress.setRange(0, 0) self.progress.setMinimumDuration(0) self.progress.forceShow() self._app_window.show_progress('searching...') 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 """
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 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' ] 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' ] 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)} for register in sorted(context, key=lambda x: sorted_regs[x]): reg_name = QStandardItem() reg_name.setTextAlignment(Qt.AlignCenter) if context[register]['isValidPointer']: reg_name.setForeground(Qt.red) reg_name.setData(context_ptr) value_x = QStandardItem() # 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) > 25: telescope_value = telescope_value[:25] + '...' 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__ for register in context: if register.startswith('_'): 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) # ************************************************************************ # **************************** 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 address', 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("")
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._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 for register in context: reg_name = QStandardItem() reg_name.setTextAlignment(Qt.AlignCenter) if context[register]['isValidPointer']: reg_name.setForeground(Qt.red) reg_name.setData(context_ptr) value_x = QStandardItem() # 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.setText( str(context[register]['telescope'][1])) 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.insertRow(0, [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__ for register in sorted(context): # todo: ??? if register.startswith('_'): 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 context[arg] is not None: _value.setText('null') _value.setForeground(Qt.gray) self._javactx_model.appendRow([_arg, _class, _value]) self._javactx_list.resizeColumnToContents(0) self._javactx_list.resizeColumnToContents(1) # ************************************************************************ # **************************** 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: context_menu.addAction( 'Jump to address', lambda: self._app_window.jump_to_address( self._nativectx_model.item(index, 1).text())) context_menu.addAction( 'Copy address', lambda: utils.copy_hex_to_clipboard( self._nativectx_model.item(index, 1).text())) context_menu.addAction( 'Jump to address', lambda: self.onShowMemoryRequest.emit( 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: pass 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: pass context_menu.exec_(glbl_pt)