Exemple #1
0
class HooksPanel(QWidget):
    """ HooksPanel

        Signals:
            onShowMemoryRequest(str) - ptr
            onHookChanged(str) - ptr
            onHookRemoved(str) - ptr
    """

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

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

        self._app_window = parent

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

        # connect to dwarf
        self._app_window.dwarf.onAddJavaHook.connect(self._on_add_hook)
        self._app_window.dwarf.onAddNativeHook.connect(self._on_add_hook)
        self._app_window.dwarf.onAddNativeOnLoadHook.connect(self._on_add_hook)
        self._app_window.dwarf.onAddJavaOnLoadHook.connect(self._on_add_hook)
        self._app_window.dwarf.onHitNativeOnLoad.connect(
            self._on_hit_native_on_load)
        self._app_window.dwarf.onHitJavaOnLoad.connect(
            self._on_hit_java_on_load)
        self._app_window.dwarf.onDeleteHook.connect(self._on_hook_deleted)

        self._hooks_list = DwarfListView()
        self._hooks_list.doubleClicked.connect(self._on_dblclicked)
        self._hooks_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._hooks_list.customContextMenuRequested.connect(
            self._on_context_menu)
        self._hooks_model = QStandardItemModel(0, 5)

        self._hooks_model.setHeaderData(0, Qt.Horizontal, 'Address')
        self._hooks_model.setHeaderData(1, Qt.Horizontal, 'T')
        self._hooks_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter,
                                        Qt.TextAlignmentRole)
        self._hooks_model.setHeaderData(2, Qt.Horizontal, 'Input')
        self._hooks_model.setHeaderData(3, Qt.Horizontal, '{}')
        self._hooks_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter,
                                        Qt.TextAlignmentRole)
        self._hooks_model.setHeaderData(4, Qt.Horizontal, '<>')
        self._hooks_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter,
                                        Qt.TextAlignmentRole)

        self._hooks_list.setModel(self._hooks_model)

        self._hooks_list.header().setStretchLastSection(False)
        self._hooks_list.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents | QHeaderView.Interactive)
        self._hooks_list.header().setSectionResizeMode(
            1, QHeaderView.ResizeToContents)
        self._hooks_list.header().setSectionResizeMode(2, QHeaderView.Stretch)
        self._hooks_list.header().setSectionResizeMode(
            3, QHeaderView.ResizeToContents)
        self._hooks_list.header().setSectionResizeMode(
            4, QHeaderView.ResizeToContents)

        v_box = QVBoxLayout(self)
        v_box.setContentsMargins(0, 0, 0, 0)
        v_box.addWidget(self._hooks_list)
        #header = QHeaderView(Qt.Horizontal, self)

        h_box = QHBoxLayout()
        h_box.setContentsMargins(5, 2, 5, 5)
        self.btn1 = QPushButton(
            QIcon(utils.resource_path('assets/icons/plus.svg')), '')
        self.btn1.setFixedSize(20, 20)
        self.btn1.clicked.connect(self._on_additem_clicked)
        btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')),
                           '')
        btn2.setFixedSize(20, 20)
        btn2.clicked.connect(self.delete_items)
        btn3 = QPushButton(
            QIcon(utils.resource_path('assets/icons/trashcan.svg')), '')
        btn3.setFixedSize(20, 20)
        btn3.clicked.connect(self.clear_list)
        h_box.addWidget(self.btn1)
        h_box.addWidget(btn2)
        h_box.addSpacerItem(
            QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred))
        h_box.addWidget(btn3)
        # header.setLayout(h_box)
        # header.setFixedHeight(25)
        # v_box.addWidget(header)
        v_box.addLayout(h_box)
        self.setLayout(v_box)

        self._bold_font = QFont(self._hooks_list.font())
        self._bold_font.setBold(True)

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

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

        shortcut_add_native_on_load = QShortcut(
            QKeySequence(Qt.CTRL + Qt.Key_O), self._app_window,
            self._on_add_native_on_load)
        shortcut_add_native_on_load.setAutoRepeat(False)

        # new menu
        self.new_menu = QMenu('New')
        self.new_menu.addAction('Native', self._on_addnative)
        self.new_menu.addAction('Java', self._on_addjava)
        self.new_menu.addAction('Module loading', self._on_add_native_on_load)

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

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

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

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _on_add_hook(self, hook):
        type_ = QStandardItem()
        type_.setFont(self._bold_font)
        type_.setTextAlignment(Qt.AlignCenter)
        if hook.hook_type == Hook.HOOK_NATIVE:
            type_.setText('N')
            type_.setToolTip('Native hook')
        elif hook.hook_type == Hook.HOOK_JAVA:
            type_.setText('J')
            type_.setToolTip('Java hook')
        elif hook.hook_type == Hook.HOOK_ONLOAD:
            type_.setText('O')
            type_.setToolTip('On load hook')
        else:
            type_.setText('U')
            type_.setToolTip('Unknown Type')

        addr = QStandardItem()

        if hook.hook_type == Hook.HOOK_JAVA:
            parts = hook.get_input().split('.')
            addr.setText('.'.join(parts[:len(parts) - 1]))
        else:
            str_fmt = '0x{0:x}'
            if self._hooks_list.uppercase_hex:
                str_fmt = '0x{0:X}'
            # addr.setTextAlignment(Qt.AlignCenter)
            addr.setText(str_fmt.format(hook.get_ptr()))

        inp = QStandardItem()
        inp_text = hook.get_input()
        if hook.hook_type == Hook.HOOK_JAVA:
            parts = inp_text.split('.')
            inp_text = parts[len(parts) - 1]
        # if len(inp_text) > 15:
        #    inp_text = inp_text[:15] + '...'
        #    inp.setToolTip(hook.get_input())
        inp.setText(inp_text)
        inp.setData(hook.get_input(), Qt.UserRole + 2)
        inp.setToolTip(hook.get_input())

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

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

        self._hooks_model.appendRow([addr, type_, inp, logic, condition])

    def _on_hit_native_on_load(self, data):
        items = self._hooks_model.findItems(data[0], Qt.MatchExactly, 2)
        if len(items) > 0:
            self._hooks_model.item(items[0].row(), 0).setText(data[1])

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

    def _on_dblclicked(self, model_index):
        item = self._hooks_model.itemFromIndex(model_index)
        if model_index.column() == 3 and item.text() == 'ƒ':
            self._on_modify_logic(model_index.row())
        elif model_index.column() == 4 and item.text() == 'ƒ':
            self._on_modify_condition(model_index.row())
        else:
            self.onShowMemoryRequest.emit(
                self._hooks_model.item(model_index.row(), 0).text())

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

        context_menu.addSeparator()
        index = self._hooks_list.indexAt(pos).row()
        if index != -1:
            context_menu.addAction(
                'Copy address', lambda: utils.copy_hex_to_clipboard(
                    self._hooks_model.item(index, 0).text()))
            context_menu.addAction(
                'Jump to address', lambda: self._app_window.jump_to_address(
                    self._hooks_model.item(index, 0).text()))
            context_menu.addSeparator()
            context_menu.addAction('Modify Logic',
                                   lambda: self._on_modify_logic(index))
            context_menu.addAction('Modify Condition',
                                   lambda: self._on_modify_condition(index))
            context_menu.addSeparator()
            context_menu.addAction('Delete Hook',
                                   lambda: self._on_delete_hook(index))

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

    def _on_modify_logic(self, num_row):
        item = self._hooks_model.item(num_row, 3)
        data = item.data(Qt.UserRole + 2)
        if data is None:
            data = ''
        ptr = self._hooks_model.item(num_row, 0).text()
        accept, input_ = InputMultilineDialog().input('Insert logic for %s' %
                                                      ptr,
                                                      input_content=data)
        if accept:
            what = utils.parse_ptr(ptr)
            if what == 0:
                what = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2)
            if self._app_window.dwarf.dwarf_api('setHookLogic',
                                                [what, input_]):
                item.setData(input_, Qt.UserRole + 2)
                if not item.text():
                    item.setText('ƒ')
                item.setToolTip(input_)
                self.onHookChanged.emit(ptr)

    def _on_modify_condition(self, num_row):
        item = self._hooks_model.item(num_row, 4)
        data = item.data(Qt.UserRole + 2)
        if data is None:
            data = ''
        ptr = self._hooks_model.item(num_row, 0).text()
        accept, input_ = InputDialog().input(self._app_window,
                                             'Insert condition for %s' % ptr,
                                             input_content=data)
        if accept:
            what = utils.parse_ptr(ptr)
            if what == 0:
                what = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2)
            if self._app_window.dwarf.dwarf_api('setHookCondition',
                                                [what, input_]):
                item.setData(input_, Qt.UserRole + 2)
                if not item.text():
                    item.setText('ƒ')
                item.setToolTip(input_)
                self.onHookChanged.emit(ptr)

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

    # shortcuts/menu
    def _on_addnative(self):
        self._app_window.dwarf.hook_native()

    def _on_addjava(self):
        self._app_window.dwarf.hook_java()

    def _on_add_native_on_load(self):
        self._app_window.dwarf.hook_native_on_load()

    def _on_add_java_on_load(self):
        self._app_window.dwarf.hook_java_on_load()

    def _on_delete_hook(self, num_row):
        hook_type = self._hooks_model.item(num_row, 1).text()
        if hook_type == 'N':
            ptr = self._hooks_model.item(num_row, 0).text()
            ptr = utils.parse_ptr(ptr)
            self._app_window.dwarf.dwarf_api('deleteHook', ptr)
            self.onHookRemoved.emit(str(ptr))
        elif hook_type == 'J':
            input_ = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2)
            self._app_window.dwarf.dwarf_api('deleteHook', input_)
        elif hook_type == 'O':
            input_ = self._hooks_model.item(num_row, 2).data(Qt.UserRole + 2)
            self._app_window.dwarf.dwarf_api('deleteHook', input_)
        elif hook_type == 'U':
            ptr = self._hooks_model.item(num_row, 0).text()
            ptr = utils.parse_ptr(ptr)
            self._app_window.dwarf.dwarf_api('deleteHook', ptr)
            self.onHookRemoved.emit(str(ptr))

    def _on_hook_deleted(self, parts):
        _msg, _type, _val = parts

        additional = None

        if _type == 'java' or _type == 'java_on_load':
            _val = _val.split('.')
            str_frmt = '.'.join(_val[:-1])
            additional = _val[-1]
            item_index = 0
        elif _type == 'native_on_load':
            str_frmt = _val
            item_index = 2
        else:
            _ptr = utils.parse_ptr(_val)
            if self._hooks_list._uppercase_hex:
                str_frmt = '0x{0:X}'.format(_ptr)
            else:
                str_frmt = '0x{0:x}'.format(_ptr)
            item_index = 0

        for _item in range(self._hooks_model.rowCount()):
            item = self._hooks_model.item(_item, item_index)

            if item is None:
                continue

            if str_frmt == item.text():
                if additional is not None:
                    if additional == self._hooks_model.item(_item, 2).text():
                        self._hooks_model.removeRow(_item)
                else:
                    self._hooks_model.removeRow(_item)
Exemple #2
0
class WelcomeDialog(QDialog):
    onSessionSelected = pyqtSignal(str, name='onSessionSelected')
    onSessionRestore = pyqtSignal(dict, name='onSessionRestore')
    onUpdateComplete = pyqtSignal(name='onUpdateComplete')
    onIsNewerVersion = pyqtSignal(name='onIsNewerVersion')

    def __init__(self, parent=None):
        super(WelcomeDialog, self).__init__(parent=parent)

        self._prefs = parent.prefs

        self._sub_titles = [
            ['duck', 'dumb', 'doctor', 'dutch', 'dark', 'dirty'],
            ['warriors', 'wardrobes', 'waffles', 'wishes'],
            ['are', 'aren\'t', 'ain\'t', 'appears to be'],
            ['rich', 'real', 'riffle', 'retarded', 'rock'],
            [
                'as f**k', 'fancy', 'f****d', 'front-ended', 'falafel',
                'french fries'
            ],
        ]

        self._recent_list_model = QStandardItemModel(0, 6)
        self._recent_list_model.setHeaderData(0, Qt.Horizontal, 'Path')
        self._recent_list_model.setHeaderData(1, Qt.Horizontal, 'Session')
        self._recent_list_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter,
                                              Qt.TextAlignmentRole)
        self._recent_list_model.setHeaderData(2, Qt.Horizontal, 'Hooks')
        self._recent_list_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter,
                                              Qt.TextAlignmentRole)
        self._recent_list_model.setHeaderData(3, Qt.Horizontal, 'Watchers')
        self._recent_list_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter,
                                              Qt.TextAlignmentRole)
        self._recent_list_model.setHeaderData(4, Qt.Horizontal, 'OnLoads')
        self._recent_list_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter,
                                              Qt.TextAlignmentRole)
        self._recent_list_model.setHeaderData(5, Qt.Horizontal, 'Bookmarks')
        self._recent_list_model.setHeaderData(5, Qt.Horizontal, Qt.AlignCenter,
                                              Qt.TextAlignmentRole)
        #self._recent_list_model.setHeaderData(6, Qt.Horizontal, 'Custom script')
        #self._recent_list_model.setHeaderData(6, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)

        self._recent_list = DwarfListView(self)
        self._recent_list.setModel(self._recent_list_model)

        self._recent_list.header().setSectionResizeMode(
            0, QHeaderView.ResizeToContents | QHeaderView.Interactive)
        self._recent_list.header().setSectionResizeMode(1, QHeaderView.Stretch)
        self._recent_list.header().setSectionResizeMode(2, QHeaderView.Stretch)
        self._recent_list.header().setSectionResizeMode(3, QHeaderView.Stretch)
        self._recent_list.header().setSectionResizeMode(4, QHeaderView.Stretch)
        self._recent_list.header().setSectionResizeMode(5, QHeaderView.Stretch)
        #self._recent_list.header().setSectionResizeMode(6, QHeaderView.Stretch)

        self._recent_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._recent_list.customContextMenuRequested.connect(
            self._on_recent_sessions_context_menu)
        self._recent_list.doubleClicked.connect(
            self._on_recent_session_double_click)

        # setup size and remove/disable titlebuttons
        self.setFixedSize(860, 420)
        self.setSizeGripEnabled(False)
        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.setWindowFlag(Qt.WindowCloseButtonHint, True)
        self.setModal(True)

        # setup ui elements
        self.setup_ui()

        self.update_commits_thread = DwarfCommitsThread(parent)
        self.update_commits_thread.on_update_available.connect(
            self._on_dwarf_isupdate)
        self.update_commits_thread.start()
        # center
        self.setGeometry(
            QStyle.alignedRect(Qt.LeftToRight, Qt.AlignCenter, self.size(),
                               qApp.desktop().availableGeometry()))

    def setup_ui(self):
        """ Setup Ui
        """
        main_wrap = QVBoxLayout()
        main_wrap.setContentsMargins(0, 0, 0, 0)

        # updatebar on top
        self.update_bar = UpdateBar(self)
        self.update_bar.onUpdateNowClicked.connect(self._update_dwarf)
        self.update_bar.setVisible(False)
        main_wrap.addWidget(self.update_bar)

        # main content
        h_box = QHBoxLayout()
        h_box.setContentsMargins(15, 15, 15, 15)
        wrapper = QVBoxLayout()
        # wrapper.setGeometry(QRect(0, 0, 400, 200))
        head = QHBoxLayout()
        head.setContentsMargins(0, 20, 0, 20)
        # dwarf icon
        icon = QLabel()
        icon.setContentsMargins(40, 0, 0, 0)
        dwarf_logo = QPixmap(utils.resource_path('assets/dwarf.png'))
        icon.setPixmap(dwarf_logo)
        head.addWidget(icon)

        # main title
        v_box = QVBoxLayout()
        title = QLabel('Dwarf')
        title.setContentsMargins(0, 0, 50, 0)
        title.setFont(QFont('Anton', 90, QFont.Bold))
        title.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        title.setFixedHeight(110)
        title.setAlignment(Qt.AlignCenter)
        v_box.addWidget(title)

        sub_title_text = (self._pick_random_word(0) + ' ' +
                          self._pick_random_word(1) + ' ' +
                          self._pick_random_word(2) + ' ' +
                          self._pick_random_word(3) + ' ' +
                          self._pick_random_word(4))
        sub_title_text = sub_title_text[:1].upper() + sub_title_text[1:]
        sub_title = QLabel(sub_title_text)
        sub_title.setFont(QFont('OpenSans', 14, QFont.Bold))
        sub_title.setFixedHeight(25)
        sub_title.setAlignment(Qt.AlignCenter)
        sub_title.setContentsMargins(0, 0, 50, 0)
        sub_title.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        v_box.addWidget(sub_title)
        head.addLayout(v_box)

        wrapper.addLayout(head)

        recent = QLabel('Last saved Sessions')
        font = recent.font()
        font.setBold(True)
        font.setPointSize(10)
        recent.setFont(font)
        wrapper.addWidget(recent)
        wrapper.addWidget(self._recent_list)
        h_box.addLayout(wrapper, stretch=False)
        buttonSpacer = QSpacerItem(15, 100, QSizePolicy.Fixed,
                                   QSizePolicy.Minimum)
        h_box.addItem(buttonSpacer)
        wrapper = QVBoxLayout()

        btn = QPushButton()
        ico = QIcon(QPixmap(utils.resource_path('assets/android.png')))
        btn.setIconSize(QSize(75, 75))
        btn.setIcon(ico)
        btn.setToolTip('New Android Session')
        btn.clicked.connect(self._on_android_button)

        wrapper.addWidget(btn)
        btn = QPushButton()
        ico = QIcon(QPixmap(utils.resource_path('assets/apple.png')))
        btn.setIconSize(QSize(75, 75))
        btn.setIcon(ico)
        btn.setToolTip('New iOS Session')
        wrapper.addWidget(btn)

        btn = QPushButton()
        ico = QIcon(QPixmap(utils.resource_path('assets/local.png')))
        btn.setIconSize(QSize(75, 75))
        btn.setIcon(ico)
        btn.setToolTip('New Local Session')
        btn.clicked.connect(self._on_local_button)
        wrapper.addWidget(btn)

        btn = QPushButton()
        ico = QIcon(QPixmap(utils.resource_path('assets/remote.png')))
        btn.setIconSize(QSize(75, 75))
        btn.setIcon(ico)
        btn.setToolTip('New Remote Session')
        wrapper.addWidget(btn)

        session_history = self._prefs.get(prefs.RECENT_SESSIONS, default=[])
        invalid_session_files = []
        for recent_session_file in session_history:
            if os.path.exists(recent_session_file):
                with open(recent_session_file, 'r') as f:
                    exported_session = json.load(f)
                hooks = '0'
                watchers = '0'
                on_loads = 0
                bookmarks = '0'
                have_user_script = False
                if 'hooks' in exported_session and exported_session[
                        'hooks'] is not None:
                    hooks = str(len(exported_session['hooks']))
                if 'watchers' in exported_session and exported_session[
                        'watchers'] is not None:
                    watchers = str(len(exported_session['watchers']))
                if 'nativeOnLoads' in exported_session and exported_session[
                        'nativeOnLoads'] is not None:
                    on_loads += len(exported_session['nativeOnLoads'])
                if 'javaOnLoads' in exported_session and exported_session[
                        'javaOnLoads'] is not None:
                    on_loads += len(exported_session['javaOnLoads'])
                if 'bookmarks' in exported_session and exported_session[
                        'bookmarks'] is not None:
                    bookmarks = str(len(exported_session['bookmarks']))
                if 'user_script' in exported_session and exported_session[
                        'user_script']:
                    have_user_script = exported_session['user_script'] != ''

                #user_script_item = QStandardItem()
                #if have_user_script:
                #user_script_item.setIcon(self._dot_icon)

                on_loads = str(on_loads)

                recent_session_file_item = QStandardItem(recent_session_file)
                recent_session_file_item.setData(exported_session,
                                                 Qt.UserRole + 2)

                item_1 = QStandardItem(exported_session['session'])
                item_1.setTextAlignment(Qt.AlignCenter)
                item_2 = QStandardItem(hooks)
                item_2.setTextAlignment(Qt.AlignCenter)
                item_3 = QStandardItem(watchers)
                item_3.setTextAlignment(Qt.AlignCenter)
                item_4 = QStandardItem(on_loads)
                item_4.setTextAlignment(Qt.AlignCenter)
                item_5 = QStandardItem(bookmarks)
                item_5.setTextAlignment(Qt.AlignCenter)
                #item_6 = QStandardItem(user_script_item)
                #item_6.setTextAlignment(Qt.AlignCenter)

                self._recent_list_model.insertRow(
                    self._recent_list_model.rowCount(), [
                        recent_session_file_item, item_1, item_2, item_3,
                        item_4, item_5
                    ])
            else:
                invalid_session_files.append(recent_session_file)
        for invalid in invalid_session_files:
            session_history.pop(session_history.index(invalid))
        self._prefs.put(prefs.RECENT_SESSIONS, session_history)

        h_box.addLayout(wrapper, stretch=False)
        main_wrap.addLayout(h_box)
        self.setLayout(main_wrap)

    def _on_dwarf_isupdate(self):
        self.update_bar.setVisible(True)
        self.onIsNewerVersion.emit()

    def _update_dwarf(self):
        self._update_thread = DwarfUpdateThread(self)
        self._update_thread.on_finished.connect(self._update_finished)
        if not self._update_thread.isRunning():
            self._update_thread.start()

    def _update_finished(self):
        self.onUpdateComplete.emit()

    def _on_android_button(self):
        self.onSessionSelected.emit('Android')
        self.close()

    def _on_local_button(self):
        self.onSessionSelected.emit('Local')
        self.close()

    def _pick_random_word(self, arr):
        return self._sub_titles[arr][random.randint(
            0,
            len(self._sub_titles[arr]) - 1)]

    def _on_recent_sessions_context_menu(self, pos):
        index = self.list_view.indexAt(pos).row()
        glbl_pt = self.list_view.mapToGlobal(pos)
        context_menu = QMenu(self)
        if index != -1:
            context_menu.addAction(
                'Delete recent session', lambda: self._remove_recent_sessions(
                    self._recent_list_model.item(index, 0).text()))
        context_menu.exec_(glbl_pt)

    def _remove_recent_session(self, session_file):
        if os.path.exists(session_file):
            os.remove(session_file)
            session_history = self._prefs.get(prefs.RECENT_SESSIONS,
                                              default=[])
            if session_file in session_history:
                session_history.pop(session_history.index(session_file))
                self._prefs.put(prefs.RECENT_SESSIONS, session_history)

    def _on_recent_session_double_click(self, model_index):
        row = self._recent_list_model.itemFromIndex(model_index).row()
        recent_session_file = self._recent_list_model.item(row, 0)
        recent_session_data = recent_session_file.data(Qt.UserRole + 2)
        self.onSessionRestore.emit(recent_session_data)
Exemple #3
0
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
        """
        if self.modules_list is None:
            return

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

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

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

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

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

            # 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_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]))
Exemple #4
0
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

        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.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.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 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(
                '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:
            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)
Exemple #5
0
class WatchersPanel(QWidget):
    """ WatcherPanel

        Signals:
            onItemSelected(addr_str) - item dblclicked
            onItemAddClick

        Constants:
            MEMORY_ACCESS_READ = 1
            MEMORY_ACCESS_WRITE = 2
            MEMORY_ACCESS_EXECUTE = 4
            MEMORY_WATCH_SINGLESHOT = 8
    """
    MEMORY_ACCESS_READ = 1
    MEMORY_ACCESS_WRITE = 2
    MEMORY_ACCESS_EXECUTE = 4
    MEMORY_WATCH_SINGLESHOT = 8

    onItemDoubleClicked = pyqtSignal(int, name='onItemDoubleClicked')
    onItemAdded = pyqtSignal(int, name='onItemAdded')
    onItemRemoved = pyqtSignal(int, name='onItemRemoved')

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

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

        self._uppercase_hex = True
        self.setAutoFillBackground(True)

        # connect to dwarf
        self._app_window.dwarf.onWatcherAdded.connect(self._on_watcher_added)
        self._app_window.dwarf.onWatcherRemoved.connect(
            self._on_watcher_removed)

        # setup our model
        self._watchers_model = QStandardItemModel(0, 5)
        self._watchers_model.setHeaderData(0, Qt.Horizontal, 'Address')
        self._watchers_model.setHeaderData(1, Qt.Horizontal, 'R')
        self._watchers_model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter,
                                           Qt.TextAlignmentRole)
        self._watchers_model.setHeaderData(2, Qt.Horizontal, 'W')
        self._watchers_model.setHeaderData(2, Qt.Horizontal, Qt.AlignCenter,
                                           Qt.TextAlignmentRole)
        self._watchers_model.setHeaderData(3, Qt.Horizontal, 'X')
        self._watchers_model.setHeaderData(3, Qt.Horizontal, Qt.AlignCenter,
                                           Qt.TextAlignmentRole)
        self._watchers_model.setHeaderData(4, Qt.Horizontal, 'S')
        self._watchers_model.setHeaderData(4, Qt.Horizontal, Qt.AlignCenter,
                                           Qt.TextAlignmentRole)

        # setup ui
        v_box = QVBoxLayout(self)
        v_box.setContentsMargins(0, 0, 0, 0)
        self.list_view = DwarfListView()
        self.list_view.setModel(self._watchers_model)
        self.list_view.header().setSectionResizeMode(0, QHeaderView.Stretch)
        self.list_view.header().setSectionResizeMode(
            1, QHeaderView.ResizeToContents | QHeaderView.Fixed)
        self.list_view.header().setSectionResizeMode(
            2, QHeaderView.ResizeToContents | QHeaderView.Fixed)
        self.list_view.header().setSectionResizeMode(
            3, QHeaderView.ResizeToContents | QHeaderView.Fixed)
        self.list_view.header().setSectionResizeMode(
            4, QHeaderView.ResizeToContents | QHeaderView.Fixed)
        self.list_view.header().setStretchLastSection(False)
        self.list_view.doubleClicked.connect(self._on_item_dblclick)
        self.list_view.setContextMenuPolicy(Qt.CustomContextMenu)
        self.list_view.customContextMenuRequested.connect(self._on_contextmenu)

        v_box.addWidget(self.list_view)
        #header = QHeaderView(Qt.Horizontal, self)

        h_box = QHBoxLayout()
        h_box.setContentsMargins(5, 2, 5, 5)
        btn1 = QPushButton(QIcon(utils.resource_path('assets/icons/plus.svg')),
                           '')
        btn1.setFixedSize(20, 20)
        btn1.clicked.connect(self._on_additem_clicked)
        btn2 = QPushButton(QIcon(utils.resource_path('assets/icons/dash.svg')),
                           '')
        btn2.setFixedSize(20, 20)
        btn2.clicked.connect(self.delete_items)
        btn3 = QPushButton(
            QIcon(utils.resource_path('assets/icons/trashcan.svg')), '')
        btn3.setFixedSize(20, 20)
        btn3.clicked.connect(self.clear_list)
        h_box.addWidget(btn1)
        h_box.addWidget(btn2)
        h_box.addSpacerItem(
            QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Preferred))
        h_box.addWidget(btn3)
        # header.setLayout(h_box)
        # header.setFixedHeight(25)
        # v_box.addWidget(header)
        v_box.addLayout(h_box)

        # create a centered dot icon
        _section_width = self.list_view.header().sectionSize(2)
        self._new_pixmap = QPixmap(_section_width, 20)
        self._new_pixmap.fill(Qt.transparent)
        painter = QPainter(self._new_pixmap)
        rect = QRect((_section_width * 0.5), 0, 20, 20)
        painter.setBrush(QColor('#666'))
        painter.setPen(QColor('#666'))
        painter.drawEllipse(rect)
        self._dot_icon = QIcon(self._new_pixmap)

        # shortcuts
        shortcut_add = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_W),
                                 self._app_window, self._on_additem_clicked)
        shortcut_add.setAutoRepeat(False)

        self.setLayout(v_box)

    # ************************************************************************
    # **************************** Properties ********************************
    # ************************************************************************
    @property
    def uppercase_hex(self):
        """ Addresses displayed lower/upper-case
        """
        return self._uppercase_hex

    @uppercase_hex.setter
    def uppercase_hex(self, value):
        """ Addresses displayed lower/upper-case
            value - bool or str
                    'upper', 'lower'
        """
        if isinstance(value, bool):
            self._uppercase_hex = value
        elif isinstance(value, str):
            self._uppercase_hex = (value == 'upper')

    # ************************************************************************
    # **************************** Functions *********************************
    # ************************************************************************
    def do_addwatcher_dlg(self, ptr=None):  # pylint: disable=too-many-branches
        """ Shows AddWatcherDialog
        """
        watcher_dlg = AddWatcherDialog(self, ptr)
        if watcher_dlg.exec_() == QDialog.Accepted:
            mem_r = watcher_dlg.acc_read.isChecked()
            mem_w = watcher_dlg.acc_write.isChecked()
            mem_x = watcher_dlg.acc_execute.isChecked()
            mem_s = watcher_dlg.singleshot.isChecked()

            ptr = watcher_dlg.text_field.text()

            if ptr:
                if isinstance(ptr, str):
                    if ptr.startswith('0x') or ptr.startswith('#'):
                        ptr = utils.parse_ptr(ptr)
                    else:
                        try:
                            ptr = int(ptr, 10)
                        except ValueError:
                            pass

                    # int now?
                    if not isinstance(ptr, int):
                        try:
                            ptr = int(
                                self._app_window.dwarf.dwarf_api(
                                    'evaluatePtr', ptr), 16)
                        except ValueError:
                            ptr = 0

                        if ptr == 0:
                            return

                        if not self._app_window.dwarf.dwarf_api(
                                'isValidPointer', ptr):
                            return
                else:
                    return

                mem_val = 0
                if mem_r:
                    mem_val |= self.MEMORY_ACCESS_READ
                if mem_w:
                    mem_val |= self.MEMORY_ACCESS_WRITE
                if mem_x:
                    mem_val |= self.MEMORY_ACCESS_EXECUTE
                if mem_s:
                    mem_val |= self.MEMORY_WATCH_SINGLESHOT

                self.add_address(ptr, mem_val, from_api=False)

                # return [ptr, mem_val]

    def add_address(self, ptr, flags, from_api=False):
        """ Adds Address to display

            ptr - str or int
            flags - int
        """
        if isinstance(ptr, str):
            ptr = utils.parse_ptr(ptr)

        if not isinstance(flags, int):
            try:
                flags = int(flags, 10)
            except ValueError:
                flags = 3

        if not from_api:
            # function was called directly so add it to dwarf
            if not self._app_window.dwarf.is_address_watched(ptr):
                self._app_window.dwarf.dwarf_api('addWatcher', [ptr, flags])
                return

        # show header
        self.list_view.setHeaderHidden(False)

        # create items to add
        if self._uppercase_hex:
            str_frmt = '0x{0:X}'
        else:
            str_frmt = '0x{0:x}'

        addr = QStandardItem()
        addr.setText(str_frmt.format(ptr))

        read = QStandardItem()
        write = QStandardItem()
        execute = QStandardItem()
        singleshot = QStandardItem()

        if flags & self.MEMORY_ACCESS_READ:
            read.setIcon(self._dot_icon)
        if flags & self.MEMORY_ACCESS_WRITE:
            write.setIcon(self._dot_icon)
        if flags & self.MEMORY_ACCESS_EXECUTE:
            execute.setIcon(self._dot_icon)
        if flags & self.MEMORY_WATCH_SINGLESHOT:
            singleshot.setIcon(self._dot_icon)

        # add items as new row on top
        self._watchers_model.insertRow(
            0, [addr, read, write, execute, singleshot])

    def remove_address(self, ptr, from_api=False):
        """ Remove Address from List
        """
        if isinstance(ptr, str):
            ptr = utils.parse_ptr(ptr)

        if not from_api:
            # called somewhere so remove watcher in dwarf too
            self._app_window.dwarf.dwarf_api('removeWatcher', ptr)
            return

        str_frmt = ''
        if self._uppercase_hex:
            str_frmt = '0x{0:X}'.format(ptr)
        else:
            str_frmt = '0x{0:x}'.format(ptr)

        model = self.list_view.model()
        for item in range(model.rowCount()):
            if str_frmt == model.item(item).text():
                model.removeRow(item)

    def delete_items(self):
        """ Delete selected Items
        """
        model = self.list_view.model()

        index = self.list_view.selectionModel().currentIndex().row()
        if index != -1:
            ptr = model.item(index, 0).text()
            self.remove_address(ptr)

    def clear_list(self):
        """ Clear the List
        """
        model = self.list_view.model()

        # go through all items and tell it gets removed
        for item in range(model.rowCount()):
            ptr = model.item(item, 0).text()
            self.remove_address(ptr)

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

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    def _on_contextmenu(self, pos):
        index = self.list_view.indexAt(pos).row()
        glbl_pt = self.list_view.mapToGlobal(pos)
        context_menu = QMenu(self)
        context_menu.addAction('Add watcher', self._on_additem_clicked)
        if index != -1:
            context_menu.addSeparator()
            context_menu.addAction(
                'Copy address', lambda: utils.copy_hex_to_clipboard(
                    self._watchers_model.item(index, 0).text()))
            context_menu.addAction(
                'Jump to address', lambda: self._app_window.jump_to_address(
                    self._watchers_model.item(index, 0).text()))
            context_menu.addAction(
                'Delete watcher', lambda: self.remove_address(
                    self._watchers_model.item(index, 0).text()))
        context_menu.exec_(glbl_pt)

    def _on_item_dblclick(self, model_index):
        row = self._watchers_model.itemFromIndex(model_index).row()
        if row != -1:
            ptr = self._watchers_model.item(row, 0).text()
            self.onItemDoubleClicked.emit(ptr)

    def _on_additem_clicked(self):
        if self._app_window.dwarf.pid == 0:
            return

        self.do_addwatcher_dlg()

    def _on_watcher_added(self, ptr, flags):
        """ Callback from Dwarf after Watcher is added
        """
        ptr = utils.parse_ptr(ptr)
        # add to watcherslist
        self.add_address(ptr, flags, from_api=True)
        self.onItemAdded.emit(ptr)

    def _on_watcher_removed(self, ptr):
        """ Callback from Dwarf after watcher is removed
        """
        ptr = utils.parse_ptr(ptr)
        # remove from list
        self.remove_address(ptr, from_api=True)
        self.onItemRemoved.emit(ptr)
Exemple #6
0
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.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)