Exemplo n.º 1
0
class ElfInfo(DwarfDialog):
    onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest')

    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 set_elf_file(self, file_path):
        self._elf_file_path = file_path
        self.title = 'ELF Info for ' + file_path
        self._elf_info_mdl.insertRow(
            0, [QStandardItem('File'),
                QStandardItem(file_path)])

    def set_parsed_data(self, parsed_data):
        parent_item = self._elf_info_mdl.item(0)
        if 'endian' in parsed_data:
            parent_item.appendRow([
                QStandardItem('Endian'),
                QStandardItem(parsed_data['endian'])
            ])
        if 'is64bit' in parsed_data:
            txt = 'No'
            if parsed_data['is64bit']:
                txt = 'Yes'
            parent_item.appendRow([QStandardItem('64Bit'), QStandardItem(txt)])

        if 'header' in parsed_data:
            elf_header = QStandardItem('ELF Header')
            parent_item.appendRow([elf_header])
            for d in parsed_data['header']:
                if d == 'e_ident':
                    ident_item = QStandardItem(d)
                    elf_header.appendRow([
                        ident_item,
                        QStandardItem(str(parsed_data['header'][d]))
                    ])
                    a = 0
                    for i in parsed_data['header'][d]:
                        if a >= len(self._ident_titles):
                            a = len(self._ident_titles) - 1
                        ident_item.appendRow([
                            QStandardItem(self._ident_titles[a]),
                            QStandardItem(str(i))
                        ])
                        a += 1
                else:
                    elf_header.appendRow([
                        QStandardItem(d),
                        QStandardItem(hex(parsed_data['header'][d]))
                    ])

        if 'programheaders' in parsed_data:
            prog_headers_item = QStandardItem('Program Headers')
            parent_item.appendRow([prog_headers_item])
            i = 1
            for header in parsed_data['programheaders']:
                header_item = QStandardItem("%d" % i)
                prog_headers_item.appendRow([header_item])
                i += 1
                for d in header:
                    header_item.appendRow(
                        [QStandardItem(d),
                         QStandardItem(hex(header[d]))])

        if 'sectionheaders' in parsed_data:
            sect_headers = QStandardItem('Section Headers')
            parent_item.appendRow([sect_headers])
            i = 1
            for header in parsed_data['sectionheaders']:
                txt = header['name']
                if not txt:
                    txt = 'NULL'
                header_item = QStandardItem(txt)
                sect_headers.appendRow([header_item])
                i += 1
                for d in header:
                    if d == 'name':
                        continue
                    elif d == 'data' and header[d]:
                        data_item = QStandardItem('Data')
                        header_item.appendRow(data_item)
                        base = self.parent().dwarf.dwarf_api(
                            'findModule', self._elf_file_path)['base']
                        for ptr in header[d]:
                            if int(ptr):
                                va = hex(int(base, 16) + int(ptr))
                                fo = hex(int(ptr))
                                if self.elf_info.uppercase_hex:
                                    va = va.upper().replace('0X', '0x')
                                    fo = fo.upper().replace('0X', '0x')
                                data_item.appendRow([
                                    QStandardItem(va),
                                    QStandardItem('FileOffset: ' + fo)
                                ])
                    else:
                        header_item.appendRow(
                            [QStandardItem(d),
                             QStandardItem(hex(header[d]))])

            self.elf_info.expandAll()
            self.elf_info.resizeColumnToContents(0)
            self.elf_info.resizeColumnToContents(1)
            self.setMinimumWidth(
                self.elf_info.columnWidth(0) + self.elf_info.columnWidth(1) +
                50)
            self.setMinimumHeight(400)
            self.elf_info.collapseAll()
            self.elf_info.expandToDepth(1)

    def _on_dblclicked(self, model_index):
        if model_index.column() == 0 and model_index.data():
            if model_index.data().startswith('0x'):
                self.onShowMemoryRequest.emit(model_index.data())

    def _on_context_menu(self, pos):
        model_index = self.elf_info.indexAt(pos)
        if model_index.column() == 0 and model_index.data():
            if model_index.data().startswith('0x'):
                context_menu = QMenu()
                context_menu.addAction(
                    'Add to Bookmarks',
                    lambda: self.parent().bookmarks_panel.insert_bookmark(
                        model_index.data(), 'init_array'))
                context_menu.addAction(
                    'Copy Address',
                    lambda: utils.copy_hex_to_clipboard(model_index.data()))
                # show contextmenu
                glbl_pt = self.elf_info.mapToGlobal(pos)
                context_menu.exec_(glbl_pt)
Exemplo n.º 2
0
class ModulesPanel(QSplitter):
    """ ModulesPanel

        Signals:
            onAddBreakpoint([ptr, funcname]) - MenuItem AddBreakpoint
            onDumpBinary([ptr, size#int]) - MenuItem DumpBinary
            onModuleSelected([ptr, size#int]) - ModuleDoubleClicked
            onModuleFuncSelected(ptr) - FunctionDoubleClicked
    """
    # pylint: disable=too-many-instance-attributes

    onAddBreakpoint = pyqtSignal(list, name='onAddBreakpoint')
    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._app_window.dwarf.onModuleLoaded.connect(self.on_module_loaded)

        self._uppercase_hex = True
        self._sized = False
        self.setContentsMargins(0, 0, 0, 0)

        # 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, 'Symbol')
        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
        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)
        self.modules_list.selectionModel().selectionChanged.connect(
            self._module_clicked)

        self.addWidget(self.modules_list)

        v_splitter = QSplitter(Qt.Vertical)
        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)
        v_splitter.addWidget(self.imports_list)
        v_splitter.addWidget(self.exports_list)
        v_splitter.addWidget(self.symbols_list)
        v_splitter.setSizes([100, 100, 100])
        self.addWidget(v_splitter)

        self.update_modules()

    # ************************************************************************
    # **************************** 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
        """
        if self.modules_list is None:
            return

        self.modules_list.clear()
        for module in modules:
            self.add_module(module)

        self.modules_list.resizeColumnToContents(0)
        self.modules_list.resizeColumnToContents(1)
        self.modules_list.resizeColumnToContents(2)
        self.modules_list.resizeColumnToContents(3)

    def on_module_loaded(self, data):
        module = data[0]
        self.add_module(module)

    def add_module(self, module):
        name = QStandardItem()
        name.setTextAlignment(Qt.AlignLeft)
        if 'name' in module:
            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}'

        if 'base' in module:
            base.setText(str_fmt.format(int(module['base'], 16)))

        size = QStandardItem()
        size.setTextAlignment(Qt.AlignRight)
        if 'size' in module:
            size.setText("{0:,d}".format(int(module['size'])))

        path = QStandardItem()
        path.setTextAlignment(Qt.AlignLeft)
        if 'path' in module:
            path.setText(module['path'])

        self.modules_model.appendRow([name, base, size, path])

        module_info = ModuleInfo(module)
        if 'exports' in module and module['exports']:
            module_info.apply_exports(module['exports'])
        if 'imports' in module and module['imports']:
            module_info.apply_imports(module['imports'])
        if 'symbols' in module and module['symbols']:
            module_info.apply_symbols(module['symbols'])
        module_info._updated_details = True

    def update_modules(self):
        """ DwarfApiCall updateModules
        """
        return self._app_window.dwarf.dwarf_api('updateModules')

    def set_imports(self, imports):
        """ Fills the ImportsList with data
        """
        if self.imports_list is None:
            return

        self.imports_list.clear()
        for import_ in imports:
            name = QStandardItem()
            name.setTextAlignment(Qt.AlignLeft)
            if 'name' in import_:
                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}'
            if 'address' in import_:
                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
        """
        if self.exports_list is None:
            return

        self.exports_list.clear()
        for export in exports:
            name = QStandardItem()
            name.setTextAlignment(Qt.AlignLeft)
            if 'name' in export:
                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}'

            if 'address' in export:
                address.setText(str_fmt.format(int(export['address'], 16)))

            type_ = QStandardItem()
            type_.setTextAlignment(Qt.AlignLeft)
            if 'type' in export:
                type_.setText(export['type'])

            self.exports_model.appendRow([name, address, type_])

    def set_symbols(self, symbols):
        """ Fills the SymbolsList with data
        """
        if self.symbols_list is None:
            return

        self.symbols_list.clear()
        for symbol in symbols:
            name = QStandardItem()
            name.setTextAlignment(Qt.AlignLeft)
            if 'name' in symbol:
                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}'

            if 'address' in symbol:
                address.setText(str_fmt.format(int(symbol['address'], 16)))

            type_ = QStandardItem()
            type_.setTextAlignment(Qt.AlignLeft)
            if 'type' in symbol:
                type_.setText(symbol['type'])

            self.symbols_model.appendRow([name, address, type_])

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _module_clicked(self):
        """ Module Clicked updates imports/exports/symbols
        """
        if not self.modules_list.hasFocus():
            return

        module_index = self.modules_list.selectionModel().currentIndex().row()
        module_name = self.modules_model.item(module_index, 0)
        if module_name is None:
            return

        module_name = module_name.text()
        module_address = self.modules_model.item(module_index, 1).text()

        module_info = self._app_window.dwarf.database.get_module_info(module_address)
        if module_info is not None:
            if not module_info.have_details:
                module_info = ModuleInfo.build_module_info(self._app_window.dwarf, module_name, fill_ied=True)
        else:
            module_info = ModuleInfo.build_module_info(self._app_window.dwarf, module_name, fill_ied=True)

        if module_info is not None:
            self.update_module_ui(module_info)

        if not self._sized:
            self.setSizes([100, 100])
            self._sized = True

    def update_module_ui(self, module_info):
        if module_info.imports:
            self.set_imports(module_info.imports)
            self.imports_list.setVisible(True)
            self.imports_list.resizeColumnToContents(0)
            self.imports_list.resizeColumnToContents(1)
            self.imports_list.resizeColumnToContents(2)
        else:
            self.imports_list.setVisible(False)

        if module_info.exports:
            self.set_exports(module_info.exports)
            self.exports_list.setVisible(True)
            self.exports_list.resizeColumnToContents(0)
            self.exports_list.resizeColumnToContents(1)
        else:
            self.exports_list.setVisible(False)

        if module_info.symbols:
            self.set_symbols(module_info.symbols)
            self.symbols_list.setVisible(True)
            self.symbols_list.resizeColumnToContents(0)
            self.symbols_list.resizeColumnToContents(1)
        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.addSeparator()
            context_menu.addAction(
                'Copy address', lambda: utils.copy_hex_to_clipboard(
                    self.modules_model.item(index, 1).text()))
            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()
            file_path = self.modules_model.item(index, 3).text()
            if self._app_window.dwarf._platform == 'linux':
                context_menu.addAction(
                    'Show ELF Info', lambda: self._on_parse_elf(file_path))
                context_menu.addSeparator()
            # elif file_path and (file_path.endswith('.dll') or file_path.endswith('.exe')):
            #   context_menu.addAction('Show PE Info', lambda: self._on_parse_pe(file_path))
            #   context_menu.addSeparator()

            if self.modules_list.search_enabled:
                context_menu.addSeparator()
                context_menu.addAction(
                    'Search', self.modules_list._on_cm_search)
                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:
            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 Breakpoint', lambda: self._add_breakpoint(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()))

            if self.imports_list.search_enabled:
                context_menu.addSeparator()
                context_menu.addAction(
                    'Search', self.imports_list._on_cm_search)

            # show context menu
            glbl_pt = self.imports_list.mapToGlobal(pos)
            context_menu.exec_(glbl_pt)

    def _on_exports_contextmenu(self, pos):
        """ ExportsList ContextMenu
        """
        index = self.exports_list.indexAt(pos).row()
        if index != -1:
            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 Breakpoint', lambda: self._add_breakpoint(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))

            if self.exports_list.search_enabled:
                context_menu.addSeparator()
                context_menu.addAction(
                    'Search', self.exports_list._on_cm_search)

            # show contextmenu
            glbl_pt = self.exports_list.mapToGlobal(pos)
            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_breakpoint(self, ptr, name=None):
        """ MenuItem AddBreakpoint
        """
        if name is None:
            name = ptr
        if isinstance(ptr, str):
            if ptr.startswith('0x') or ptr.startswith('#'):
                self.onAddBreakpoint.emit([ptr, name])
        elif isinstance(ptr, int):
            str_fmt = '0x{0:x}'
            self.onAddBreakpoint.emit(str_fmt.format([ptr, name]))

    def _on_parse_elf(self, elf_path):
        from dwarf_debugger.ui.dialogs.elf_info_dlg import ElfInfo
        parsed_infos = self._app_window.dwarf.dwarf_api('parseElf', elf_path)
        if parsed_infos:
            elf_dlg = ElfInfo(self._app_window, elf_path)
            elf_dlg.onShowMemoryRequest.connect(self.onModuleFuncSelected)
            elf_dlg.set_parsed_data(parsed_infos)
            elf_dlg.show()
Exemplo n.º 3
0
class ContextWidget(QTabWidget):
    # consts
    CONTEXT_TYPE_NATIVE = 0
    CONTEXT_TYPE_JAVA = 1

    onShowMemoryRequest = pyqtSignal(str, name='onShowMemoryRequest')

    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')

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def clear(self):
        self._nativectx_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 == ContextWidget.CONTEXT_TYPE_NATIVE:
            self._nativectx_list.clear()
            self._set_native_context(ptr, context)
        elif context_type == ContextWidget.CONTEXT_TYPE_JAVA:
            self._javactx_list.clear()
            self._set_java_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 == '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, Qt.UserRole + 1)

            value_x = QStandardItem()
            if context[register]['isValidPointer']:
                value_x.setForeground(Qt.red)

            value_dec = QStandardItem()
            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_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:
            item = self._nativectx_model.item(index, 1)
            dec = self._nativectx_model.item(index, 2)
            telescope = self._nativectx_model.item(index, 3)
            # show contextmenu
            if self._nativectx_model.item(index, 0).data(Qt.UserRole + 1):
                context_menu.addAction(
                    'Jump to {0}'.format(item.text()),
                    lambda: self._app_window.jump_to_address(item.text()))
                context_menu.addSeparator()
            # copy menu
            context_sub_menu = QMenu('Copy', context_menu)
            context_sub_menu.addAction(
                'Value', lambda: utils.copy_str_to_clipboard(item.text()))
            if dec.text():
                context_sub_menu.addAction(
                    'Decimal', lambda: utils.copy_str_to_clipboard(dec.text()))
            if telescope.text():
                context_sub_menu.addAction(
                    'Telescope',
                    lambda: utils.copy_str_to_clipboard(telescope.text()))
            context_menu.addMenu(context_sub_menu)

            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
            argument = self._javactx_model.item(index, 1)
            _class = self._javactx_model.item(index, 2)
            value = self._javactx_model.item(index, 3)
            context_sub_menu = QMenu('Copy', context_menu)
            context_sub_menu.addAction(
                'Argument',
                lambda: utils.copy_str_to_clipboard(argument.text()))
            if _class.text():
                context_sub_menu.addAction(
                    'Class',
                    lambda: utils.copy_str_to_clipboard(_class.text()))
            if value:
                if value.text():
                    context_sub_menu.addAction(
                        'Value',
                        lambda: utils.copy_str_to_clipboard(value.text()))
            context_menu.addMenu(context_sub_menu)
            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("")
Exemplo n.º 4
0
class BreakpointsWidget(QWidget):
    """ BreakpointsWidget

        Signals:
            onBreakpointChanged(str) - ptr
            onBreakpointRemoved(str) - ptr
    """

    onBreakpointChanged = pyqtSignal(str, name='onBreakpointChanged')
    onBreakpointsRemoved = pyqtSignal(str, name='onBreakpointRemoved')

    def __init__(self, parent=None):  # pylint: disable=too-many-statements
        super(BreakpointsWidget, self).__init__(parent=parent)

        self._app_window = parent

        if self._app_window.dwarf is None:
            print('BreakpointsWidget created before Dwarf exists')
            return

        # connect to dwarf
        self._app_window.dwarf.onApplyContext.connect(self._on_apply_context)
        self._app_window.dwarf.onAddJavaBreakpoint.connect(
            self._on_add_breakpoint)
        self._app_window.dwarf.onAddObjCBreakpoint.connect(
            self._on_add_breakpoint)
        self._app_window.dwarf.onAddNativeBreakpoint.connect(
            self._on_add_breakpoint)
        self._app_window.dwarf.onAddModuleInitializationBreakpoint.connect(
            self._on_add_breakpoint)
        self._app_window.dwarf.onAddJavaClassInitializationBreakpoint.connect(
            self._on_add_breakpoint)
        self._app_window.dwarf.onHitModuleInitializationBreakpoint.connect(
            self._on_hit_module_initialization_breakpoint)
        self._app_window.dwarf.onHitJavaClassInitializationBreakpoint.connect(
            self._on_hit_java_class_initialization_breakpoint)
        self._app_window.dwarf.onDeleteBreakpoint.connect(
            self._on_breakpoint_deleted)

        self._breakpoints_list = DwarfListView()
        self._breakpoints_list.doubleClicked.connect(self._on_double_clicked)
        self._breakpoints_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._breakpoints_list.customContextMenuRequested.connect(
            self._on_context_menu)
        self._breakpoints_model = QStandardItemModel(0, 3)

        self._breakpoints_model.setHeaderData(0, Qt.Horizontal, 'Address')
        self._breakpoints_model.setHeaderData(1, Qt.Horizontal, 'T')
        self._breakpoints_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter,
                                              Qt.TextAlignmentRole)
        self._breakpoints_model.setHeaderData(2, Qt.Horizontal, '<>')
        self._breakpoints_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter,
                                              Qt.TextAlignmentRole)

        self._breakpoints_list.setModel(self._breakpoints_model)

        self._breakpoints_list.header().setStretchLastSection(False)
        self._breakpoints_list.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents | QHeaderView.Interactive)
        self._breakpoints_list.header().setSectionResizeMode(
            1, QHeaderView.ResizeToContents)
        self._breakpoints_list.header().setSectionResizeMode(
            2, QHeaderView.ResizeToContents)

        v_box = QVBoxLayout(self)
        v_box.setContentsMargins(0, 0, 0, 0)
        v_box.addWidget(self._breakpoints_list)

        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_add_item_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._breakpoints_list.font())
        self._bold_font.setBold(True)

        shortcut_addnative = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_N),
                                       self._app_window,
                                       self._on_add_native_breakpoint)
        shortcut_addnative.setAutoRepeat(False)

        shortcut_addjava = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_J),
                                     self._app_window,
                                     self._on_add_java_breakpoint)
        shortcut_addjava.setAutoRepeat(False)

        shortcut_add_native_onload = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_O), self._app_window,
            self._on_add_module_initialization_breakpoint)
        shortcut_add_native_onload.setAutoRepeat(False)

        # new menu
        self.new_menu = QMenu('New')
        self.new_menu.addAction('Native', self._on_add_native_breakpoint)
        self.new_menu.addAction('Module initialization',
                                self._on_add_module_initialization_breakpoint)

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def delete_items(self):
        """ Delete selected Items
        """
        index = self._breakpoints_list.selectionModel().currentIndex().row()
        if index != -1:
            self._on_delete_breakpoint(index)
            self._breakpoints_model.removeRow(index)

    def clear_list(self):
        """ Clear the List
        """
        # go through all items and tell it gets removed
        for item in range(self._breakpoints_model.rowCount()):
            self._on_delete_breakpoint(item)

        if self._breakpoints_model.rowCount() > 0:
            # something was wrong it should be empty
            self._breakpoints_model.removeRows(
                0, self._breakpoints_model.rowCount())

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _on_apply_context(self, context):
        if context['reason'] == -1:
            if self._app_window.dwarf.java_available:
                self.new_menu.addAction('Java', self._on_add_java_breakpoint)
                self.new_menu.addAction(
                    'Java class initialization',
                    self._on_add_java_class_initialization_breakpoint)

    def _on_add_breakpoint(self, breakpoint):
        type_ = QStandardItem()
        type_.setFont(self._bold_font)
        type_.setTextAlignment(Qt.AlignCenter)
        if breakpoint.breakpoint_type == BREAKPOINT_NATIVE:
            type_.setText('N')
            type_.setToolTip('Native breakpoint')
        elif breakpoint.breakpoint_type == BREAKPOINT_JAVA:
            type_.setText('J')
            type_.setToolTip('Java breakpoint')
        elif breakpoint.breakpoint_type == BREAKPOINT_INITIALIZATION:
            type_.setText('C')
            type_.setToolTip('Initialization breakpoint')
        elif breakpoint.breakpoint_type == BREAKPOINT_OBJC:
            type_.setText('O')
            type_.setToolTip('ObjC breakpoint')
        else:
            type_.setText('U')
            type_.setToolTip('Unknown Type')

        addr = QStandardItem()

        if breakpoint.breakpoint_type == BREAKPOINT_JAVA:
            addr.setText(breakpoint.get_target())
        elif breakpoint.breakpoint_type == BREAKPOINT_OBJC:
            addr.setText(breakpoint.get_target())
        elif breakpoint.breakpoint_type == BREAKPOINT_INITIALIZATION:
            addr.setText(breakpoint.get_target())
            addr.setData(breakpoint.debug_symbol, Qt.UserRole + 2)
        else:
            str_fmt = '0x{0:x}'
            if self._breakpoints_list.uppercase_hex:
                str_fmt = '0x{0:X}'
            # addr.setTextAlignment(Qt.AlignCenter)
            addr.setText(str_fmt.format(breakpoint.get_target()))

        condition = QStandardItem()
        condition.setTextAlignment(Qt.AlignCenter)
        condition.setFont(self._bold_font)
        if breakpoint.condition and breakpoint.condition != 'null' and breakpoint.condition != 'undefined':
            condition.setText('ƒ')
            condition.setToolTip(breakpoint.condition)
            condition.setData(breakpoint.condition, Qt.UserRole + 2)

        self._breakpoints_model.appendRow([addr, type_, condition])
        self._breakpoints_list.resizeColumnToContents(0)

    def _on_hit_module_initialization_breakpoint(self, data):
        items = self._breakpoints_model.findItems(data[1]['module'],
                                                  Qt.MatchExactly, 2)
        if len(items) > 0:
            self._breakpoints_model.item(items[0].row(),
                                         0).setText(data[1]['moduleBase'])

    def _on_hit_java_class_initialization_breakpoint(self, data):
        items = self._breakpoints_model.findItems(data[0], Qt.MatchExactly, 2)
        if len(items) > 0:
            pass

    def _on_double_clicked(self, model_index):
        item = self._breakpoints_model.itemFromIndex(model_index)
        if model_index.column() == 2 and item.text() == 'ƒ':
            self._on_modify_condition(model_index.row())
        else:
            self._app_window.jump_to_address(self._breakpoints_model.item(
                model_index.row(), 0).text(),
                                             view=1)

    def _on_context_menu(self, pos):
        context_menu = QMenu(self)
        context_menu.addMenu(self.new_menu)

        context_menu.addSeparator()
        index = self._breakpoints_list.indexAt(pos).row()
        if index != -1:
            context_menu.addAction(
                'Copy address', lambda: utils.copy_hex_to_clipboard(
                    self._breakpoints_model.item(index, 0).text()))
            context_menu.addAction(
                'Jump to address', lambda: self._app_window.jump_to_address(
                    self._breakpoints_model.item(index, 0).text()))
            context_menu.addSeparator()
            context_menu.addAction('Edit Condition',
                                   lambda: self._on_modify_condition(index))
            context_menu.addSeparator()
            context_menu.addAction('Delete Breakpoint',
                                   lambda: self._on_delete_breakpoint(index))

            if self._breakpoints_list.search_enabled:
                context_menu.addSeparator()
                context_menu.addAction('Search',
                                       self._breakpoints_list._on_cm_search)

        # show context menu
        global_pt = self._breakpoints_list.mapToGlobal(pos)
        context_menu.exec(global_pt)

    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)

    # + button
    def _on_add_item_clicked(self):
        self.new_menu.exec_(QCursor.pos())

    # shortcuts/menu
    def _on_add_native_breakpoint(self):
        self._app_window.dwarf.breakpoint_native()

    def _on_add_java_breakpoint(self):
        self._app_window.dwarf.breakpoint_java()

    def _on_add_module_initialization_breakpoint(self):
        self._app_window.dwarf.breakpoint_module_initialization()

    def _on_add_java_class_initialization_breakpoint(self):
        self._app_window.dwarf.breakpoint_java_class_initialization()

    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_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)
Exemplo n.º 5
0
class BookmarksWidget(QWidget):
    def __init__(self, parent=None):  # pylint: disable=too-many-statements
        super(BookmarksWidget, 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_double_clicked)
        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_B),
                                       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_double_clicked(self, index):
        index = self._bookmarks_list.selectionModel().currentIndex().row()
        if index != -1:
            addr = self._bookmarks_model.item(index, 0).text()
            if addr:
                self._app_window.jump_to_address(addr, view=1)

    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 breakpoint 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:
            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 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)

    def is_address_bookmarked(self, ptr):
        return utils.parse_ptr(ptr) in self.bookmarks

    # 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)
Exemplo n.º 6
0
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)

        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()

    # ************************************************************************
    # **************************** 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)

    def _on_toggle_break_spawn(self, state):
        self.break_at_start = state == Qt.Checked