def _on_delete_breakpoint(self, num_row): breakpoint_type = self._breakpoints_model.item(num_row, 1).text() if breakpoint_type == 'N': ptr = self._breakpoints_model.item(num_row, 0).text() ptr = utils.parse_ptr(ptr) self._app_window.dwarf.dwarf_api('removeBreakpoint', ptr) self.onBreakpointRemoved.emit(str(ptr)) elif breakpoint_type == 'J': target = self._breakpoints_model.item(num_row, 0).text() self._app_window.dwarf.dwarf_api('removeBreakpoint', target) elif breakpoint_type == 'O': target = self._breakpoints_model.item(num_row, 0).text() self._app_window.dwarf.dwarf_api('removeBreakpoint', target) elif breakpoint_type == 'C': item = self._breakpoints_model.item(num_row, 0) target = item.text() is_native = item.data(Qt.UserRole + 2) is None if is_native: self._app_window.dwarf.dwarf_api( 'removeModuleInitializationBreakpoint', target) else: self._app_window.dwarf.dwarf_api( 'removeJavaClassInitializationBreakpoint', target) elif breakpoint_type == 'U': ptr = self._breakpoints_model.item(num_row, 0).text() ptr = utils.parse_ptr(ptr) self._app_window.dwarf.dwarf_api('removeBreakpoint', ptr) self.onBreakpointRemoved.emit(str(ptr))
def _on_showmemory_request(self, ptr): # its simple ptr show in memorypanel if isinstance(ptr, str): ptr = utils.parse_ptr(ptr) self.jump_to_address(ptr, 0) elif isinstance(ptr, list): # TODO: extend caller, ptr = ptr ptr = utils.parse_ptr(ptr) if caller == 'backtrace' or caller == 'bt': # jumpto in disasm self.jump_to_address(ptr, 1)
def search(self, start, size, pattern): # sanify args start = utils.parse_ptr(start) size = int(size) # convert to frida accepted pattern pattern = ' '.join([pattern[i:i + 2] for i in range(0, len(pattern), 2)]) self.dwarf_api('memoryScan', [start, size, pattern])
def breakpoint_native(self, input_=None): if input_ is None or not isinstance(input_, str): ptr, input_ = InputDialog.input_pointer(self._app_window) else: ptr = utils.parse_ptr(self._app_window.dwarf.dwarf_api('evaluatePtr', input_)) if ptr > 0: self.dwarf_api('putBreakpoint', ptr)
def _on_breakpoint_deleted(self, parts): _msg, _type, _val = parts additional = None if _type == 'objc' or _type == 'java' or _type == 'java_class_initialization': str_frmt = _val item_index = 0 elif _type == 'module_initialization': str_frmt = _val item_index = 0 else: _ptr = utils.parse_ptr(_val) if self._breakpoints_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._breakpoints_model.rowCount()): item = self._breakpoints_model.item(_item, item_index) if item is None: continue if str_frmt == item.text(): if additional is not None: if additional == self._breakpoints_model.item(_item, 2).text(): self._breakpoints_model.removeRow(_item) else: self._breakpoints_model.removeRow(_item)
def _on_watchpoint_removed(self, ptr): """ Callback from Dwarf after watchpoint is removed """ ptr = utils.parse_ptr(ptr) # remove from list self.remove_address(ptr, from_api=True) self.onItemRemoved.emit(ptr)
def _on_dump_module(self, data): """ DumpBinary MenuItem in ModulePanel was selected """ ptr, size = data ptr = utils.parse_ptr(ptr) size = int(size, 10) self.dwarf.dump_memory(ptr=ptr, length=size)
def _jump_to_address_impl(self, address, view=DEBUG_VIEW_MEMORY): address = utils.parse_ptr(address) if view == DEBUG_VIEW_MEMORY: if self.debug_panel.memory_panel.number_of_lines() > 0: if self.debug_panel.is_address_in_view(view, address): return elif view == DEBUG_VIEW_DISASSEMBLY: if self.debug_panel.disassembly_panel.number_of_lines() > 0: if self.debug_panel.is_address_in_view(view, address): return if not self._working: if self.pipe is None: self._create_pipe() self._working = True if self.pipe is not None: start_address = hex(address) if self.current_seek != start_address: self.current_seek = start_address self._seek_view_type = view self.pipe.cmd('s %s' % self.current_seek) if self.call_refs_model is not None: self.call_refs_model.setRowCount(0) if self.code_xrefs_model is not None: self.code_xrefs_model.setRowCount(0) else: self._on_finish_analysis([0, bytes(), 0])
def _on_add_breakpoint(self, breakpoint): try: # set highlight ptr = breakpoint.get_target() ptr = utils.parse_ptr(ptr) self.debug_panel.memory_panel.add_highlight( HighLight('breakpoint', ptr, self.dwarf.pointer_size)) except HighlightExistsError: pass
def read_range_async(self, ptr, callback): ptr = utils.parse_ptr(ptr) if hex(ptr) in self.refs: # already reading this range return reader = Reader(self, ptr, 0) reader.ioReaderFinish.connect(lambda x: self._on_io_reader_range_finish(x[0], x[1], x[2], callback)) self.refs[hex(ptr)] = reader reader.start()
def do_addwatchpoint_dlg(self, ptr=None): # pylint: disable=too-many-branches """ Shows AddWatchpointDialog """ watchpoint_dlg = AddWatchpointDialog(self, ptr) if watchpoint_dlg.exec_() == QDialog.Accepted: mem_r = watchpoint_dlg.acc_read.isChecked() mem_w = watchpoint_dlg.acc_write.isChecked() mem_x = watchpoint_dlg.acc_execute.isChecked() mem_s = watchpoint_dlg.singleshot.isChecked() ptr = watchpoint_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)
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('putWatchpoint', [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._watchpoints_model.insertRow( 0, [addr, read, write, execute, singleshot])
def jump_to_address(self, address, view=DEBUG_VIEW_MEMORY): address = utils.parse_ptr(address) if view == DEBUG_VIEW_MEMORY: if self.memory_panel.number_of_lines() > 0: if self.is_address_in_view(view, address): return elif view == DEBUG_VIEW_DISASSEMBLY: if self.disassembly_panel.number_of_lines() > 0: if self.is_address_in_view(view, address): return self.app.show_progress('reading data...') self.app.dwarf.read_range_async( address, lambda base, data, offset: self._apply_data( base, data, offset, view=view))
def _on_modify_condition(self, num_row): item = self._breakpoints_model.item(num_row, 2) data = item.data(Qt.UserRole + 2) if data is None: data = '' ptr = self._breakpoints_model.item(num_row, 0).text() accept, input_ = InputMultilineDialog().input( 'Condition for breakpoint %s' % ptr, input_content=data) if accept: what = utils.parse_ptr(ptr) if what == 0: what = self._breakpoints_model.item(num_row, 2).data(Qt.UserRole + 2) if self._app_window.dwarf.dwarf_api('setBreakpointCondition', [what, input_.replace('\n', '')]): item.setData(input_, Qt.UserRole + 2) if not item.text(): item.setText('ƒ') item.setToolTip(input_) self.onBreakpointChanged.emit(ptr)
def read_range_data(self): data = bytes() base = 0 try: _range = self.dwarf.dwarf_api('getRange', self.ptr) if _range: if _range['protection'][0] == 'r': base = utils.parse_ptr(_range['base']) self.ptr = base self.length = _range['size'] hex_base = hex(base) if hex_base in self.io.range_cache: data = self.io.range_cache[hex_base] else: data = self.read_data() if data: self.io.range_cache[hex_base] = data except Exception as e: print('IO - failed to read data') raise e return base, data
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 watchpoint in dwarf too self._app_window.dwarf.dwarf_api('removeWatchpoint', 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 _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: ptr = utils.parse_ptr(ptr) 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 != '' if note == '': 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 _on_modulefunc_dblclicked(self, ptr): """ Function in ModulePanel was doubleclicked """ ptr = utils.parse_ptr(ptr) self.jump_to_address(ptr)
def is_address_bookmarked(self, ptr): return utils.parse_ptr(ptr) in self.bookmarks
def is_address_watched(self, ptr): ptr = utils.parse_ptr(ptr) if hex(ptr) in self.watchpoints: return True return False
def read_async(self, ptr, length, callback): ptr = utils.parse_ptr(ptr) reader = Reader(self, ptr, length) reader.ioReaderFinish.connect(lambda x: self._on_io_reader_finish(x[0], x[1], callback)) self.refs[hex(ptr)] = reader reader.start()
def read(self, ptr, length): ptr = utils.parse_ptr(ptr) reader = Reader(self, ptr, length) return ptr, reader.read_data()
def read_range(self, ptr): ptr = utils.parse_ptr(ptr) reader = Reader(self, ptr, 0) base, data = reader.read_range_data() return base, data, ptr - base
def _on_breakpoint_removed(self, ptr): ptr = utils.parse_ptr(ptr) self.debug_panel.memory_panel.remove_highlight(ptr)
def _range_dblclicked(self, ptr): """ Range in RangesPanel was doubleclicked """ ptr = utils.parse_ptr(ptr) self.jump_to_address(ptr)
def _on_message(self, message, data): QApplication.processEvents() if 'payload' not in message: print('payload: ' + str(message)) return self.onReceiveCmd.emit([message, data]) what = message['payload'] parts = what.split(':::') if len(parts) < 2: return cmd = parts[0] if cmd == 'api_ping_timeout': self._script.post({"type": str(parts[1])}) elif cmd == 'backtrace': self.onBackTrace.emit(json.loads(parts[1])) elif cmd == 'class_loader_loading_class': str_fmt = ('@thread {0} loading class := {1}'.format(parts[1], parts[2])) self.log_event(str_fmt) elif cmd == 'enumerate_java_classes_start': self.onEnumerateJavaClassesStart.emit() elif cmd == 'enumerate_java_classes_match': self.onEnumerateJavaClassesMatch.emit(parts[1]) elif cmd == 'enumerate_java_classes_complete': self.onEnumerateJavaClassesComplete.emit() elif cmd == 'enumerate_java_methods_complete': self.onEnumerateJavaMethodsComplete.emit([parts[1], json.loads(parts[2])]) elif cmd == 'enumerate_objc_modules': modules = json.loads(parts[1]) self.onEnumerateObjCModules.emit(modules) elif cmd == 'enumerate_objc_classes_start': self.onEnumerateObjCClassesStart.emit() elif cmd == 'enumerate_objc_classes_match': self.onEnumerateObjCClassesMatch.emit(parts[1]) elif cmd == 'enumerate_objc_classes_complete': self.onEnumerateObjCClassesComplete.emit() elif cmd == 'enumerate_objc_methods_start': self.onEnumerateObjCMethodsStart.emit() elif cmd == 'enumerate_objc_methods_match': self.onEnumerateObjCMethodsMatch.emit(parts[1]) elif cmd == 'enumerate_objc_methods_complete': self.onEnumerateObjCMethodsComplete.emit() elif cmd == 'ftrace': if self.app.get_ftrace_panel() is not None: self.app.get_ftrace_panel().append_data(parts[1]) elif cmd == 'enable_kernel': self._app_window.get_menu().enable_kernel_menu() elif cmd == 'breakpoint_java_callback': b = Breakpoint(BREAKPOINT_JAVA) b.set_target(parts[1]) if len(parts) > 2: b.set_condition(parts[2]) self.java_breakpoints[parts[1]] = b self.onAddJavaBreakpoint.emit(b) elif cmd == 'breakpoint_objc_callback': b = Breakpoint(BREAKPOINT_OBJC) # WORKAROUND: Some ObjC Methods have multiple ':' in name. Restoring ':::': target = ":::".join(parts[1:-1]) b.set_target(target) if parts[-1] != '': b.set_condition(parts[-1]) self.objc_breakpoints[target] = b self.onAddObjCBreakpoint.emit(b) elif cmd == 'java_class_initialization_callback': b = Breakpoint(BREAKPOINT_INITIALIZATION) b.set_target(parts[1]) b.set_debug_symbol(parts[1]) self.java_class_initialization_breakpoints[parts[1]] = b self.onAddJavaClassInitializationBreakpoint.emit(b) elif cmd == 'breakpoint_native_callback': b = Breakpoint(BREAKPOINT_NATIVE) b.set_target(int(parts[1], 16)) if len(parts) > 2: b.set_condition(parts[2]) self.breakpoints[b.get_target()] = b self.onAddNativeBreakpoint.emit(b) elif cmd == 'module_initialization_callback': b = Breakpoint(BREAKPOINT_INITIALIZATION) b.set_target(parts[1]) self.module_initialization_breakpoints[parts[1]] = b self.onAddModuleInitializationBreakpoint.emit(b) elif cmd == 'breakpoint_deleted': if parts[1] == 'java': self.java_breakpoints.pop(parts[2]) elif parts[1] == 'objc': self.objc_breakpoints.pop(":::".join(parts[2:])) elif parts[1] == 'module_initialization': if parts[2] in self.module_initialization_breakpoints: self.module_initialization_breakpoints.pop(parts[2]) elif parts[1] == 'java_class_initialization': if parts[2] in self.java_class_initialization_breakpoints: self.java_class_initialization_breakpoints.pop(parts[2]) else: self.breakpoints.pop(utils.parse_ptr(parts[2])) self.onDeleteBreakpoint.emit(parts) elif cmd == 'breakpoint_java_class_initialization_callback': str_fmt = ('Breakpoint java class initialization {0} @thread := {1}'.format(parts[1], parts[2])) self.log_event(str_fmt) self.onHitJavaClassInitializationBreakpoint.emit(parts[1]) elif cmd == 'java_trace': self.onJavaTraceEvent.emit(parts) elif cmd == 'log': self.log(parts[1]) elif cmd == 'breakpoint_module_initialization_callback': data = json.loads(parts[2]) str_fmt = ('Breakpoint module initialization {0} @thread := {1}'.format(data['module'], parts[1])) self.log_event(str_fmt) self.onHitModuleInitializationBreakpoint.emit([parts[1], data]) elif cmd == 'module_initialized': module = json.loads(parts[2]) if module is not None: str_fmt = ('@thread {0} loading module := {1}'.format(parts[1], module['name'])) self.log_event(str_fmt) module_info = ModuleInfo.build_module_info_with_data(module) self.database.put_module_info(module_info.base, module_info) self.onModuleLoaded.emit([module]) elif cmd == 'new_thread': str_fmt = ('@thread {0} starting new thread with target fn := {1}'.format(parts[1], parts[2])) self.log_event(str_fmt) elif cmd == 'release': reason = 0 if len(parts) > 1: reason = int(parts[2]) p = 'releasing' if reason != 3 else 'stepping' str_fmt = (p + ' := {0}'.format(parts[1])) self.log_event(str_fmt) if parts[1] in self.contexts: del self.contexts[parts[1]] self.onThreadResumed.emit(int(parts[1])) elif cmd == 'resume': if not self.resumed: self.resume_proc() elif cmd == 'release_js': # releasing the thread must be done by calling py funct dwarf_api('release') # there are cases in which we want to release the thread from a js api so we need to call this self.onRequestJsThreadResume.emit(int(parts[1])) elif cmd == 'set_context': #data = json.loads(parts[1]) # WORKAROUND: Some ObjC Methods have multiple ':' in name. Restoring ':::' data = json.loads(":::".join(parts[1:])) if 'modules' in data: self.onSetModules.emit(data['modules']) if 'ranges' in data: self.onSetRanges.emit(data['ranges']) if 'backtrace' in data: self.onBackTrace.emit(data['backtrace']) self.onApplyContext.emit(data) elif cmd == 'set_context_value': context_property = parts[1] value = parts[2] self.onContextChanged.emit(str(context_property), value) elif cmd == 'set_data': if data is not None: self.onSetData.emit(['raw', parts[1], data]) else: self.onSetData.emit(['plain', parts[1], str(parts[2])]) elif cmd == 'unhandled_exception': # todo pass elif cmd == 'update_modules': modules = json.loads(parts[2]) self.onSetModules.emit(modules) elif cmd == 'update_ranges': self.onSetRanges.emit(json.loads(parts[2])) elif cmd == 'update_searchable_ranges': self.onSearchableRanges.emit(json.loads(parts[2])) elif cmd == 'watchpoint': exception = json.loads(parts[1]) self.log_event('watchpoint hit op %s address %s @thread := %s' % (exception['memory']['operation'], exception['memory']['address'], parts[2])) elif cmd == 'watchpoint_added': ptr = utils.parse_ptr(parts[1]) hex_ptr = hex(ptr) flags = int(parts[2]) w = Watchpoint(ptr, flags) w.set_debug_symbol(json.loads(parts[3])) self.watchpoints[hex_ptr] = w self.onWatchpointAdded.emit(w) elif cmd == 'watchpoint_removed': hex_ptr = hex(utils.parse_ptr(parts[1])) self.watchpoints.pop(hex_ptr) self.onWatchpointRemoved.emit(hex_ptr) elif cmd == 'memoryscan_result': if parts[1] == '': self.onMemoryScanResult.emit([]) else: self.onMemoryScanResult.emit(json.loads(parts[1]))
def disasm_ref_double_click(self, model, modelIndex): ptr = utils.parse_ptr( model.item(model.itemFromIndex(modelIndex).row(), 0).text()) self.debug_panel.jump_to_address(ptr, DEBUG_VIEW_DISASSEMBLY)
def get_line_for_address(self, ptr): ptr = utils.parse_ptr(ptr) for x in range(len(self._lines)): if self._lines[x].address == ptr: return x return -1
def _on_module_dblclicked(self, data): """ Module in ModulePanel was doubleclicked """ addr, size = data addr = utils.parse_ptr(addr) self.jump_to_address(addr)