Пример #1
0
class WelcomeUi(QSplitter):
    def __init__(self, app, *__args):
        super().__init__(*__args)

        self.app = app

        self.startup_script = ''

        self.menu_bar = None
        self.status_bar = None

        _app = QApplication.instance()
        for w in _app.topLevelWidgets():
            if isinstance(w, QMainWindow):
                #self.menu_bar = w.get_menu()
                self.status_bar = w.get_statusbar()

        self.update_action = QAction('Update Dwarf')
        self.update_action.triggered.connect(self.update_dwarf)

        self.setup_ui()

        self.updated_frida_version = ''
        self.updated_frida_assets_url = {}

        self.frida_update_thread = None
        self.devices_thread = None
        self.procs_update_thread = None
        self.spawns_update_thread = None
        self.update_commits_thread = None
        self.update_dwarf_thread = None

        self.setup_threads()

        frida.get_device_manager().on('added', self.update_device_ui)
        frida.get_device_manager().on('removed', self.update_device_ui)

        if not self.app.get_adb().available():
            # additional check for null local device
            if frida.get_local_device() is None:
                utils.show_message_box('adb/device/emu not found or not rooted! see details or output',
                                       self.app.get_adb().get_states_string())

        self.update_ui_sync()

    def setup_ui(self):
        """ Setups the ui
        """
        left_side = QWidget()
        right_side = QWidget()

        # -------------------------------------------
        # Left Side
        # -------------------------------------------
        wrapper = QVBoxLayout()
        head = QHBoxLayout()

        # dwarf icon
        icon = QLabel()
        icon.setPixmap(self.app.get_icon())
        icon.setFixedWidth(75)
        head.addWidget(icon)

        # main titleDwarf
        title = QLabel('Dwarf')
        title.setFont(QFont('Anton', 58, QFont.Bold))
        head.addWidget(title)

        wrapper.addLayout(head)

        # commit list
        self.commit_list = QListWidget()
        self.commit_list.setSelectionMode(QAbstractItemView.NoSelection)
        wrapper.addWidget(self.commit_list)

        frida_update_box = QHBoxLayout()

        # frida versions
        self.frida_update_label = QLabel('device frida version: -\nupdated frida version: -')
        frida_update_box.addWidget(self.frida_update_label)

        # frida update-button
        self.frida_update_button = QPushButton('update frida')
        self.frida_update_button.setVisible(False)
        self.frida_update_button.clicked.connect(self.update_frida_server)
        frida_update_box.addWidget(self.frida_update_button)

        # frida control-button
        self.frida_control_button = QPushButton('update frida')
        self.frida_control_button.setVisible(False)
        self.frida_control_button.clicked.connect(self.control_frida)
        frida_update_box.addWidget(self.frida_control_button)

        wrapper.addLayout(frida_update_box)

        # finish
        left_side.setLayout(wrapper)

        # -------------------------------------------
        # right side
        # -------------------------------------------
        wrapper = QVBoxLayout()

        # devices label
        devices_label = QLabel('DEVICES')
        devices_label.setFont(QFont('Anton', 20, QFont.Normal))
        wrapper.addWidget(devices_label)

        # devices combobox
        self.devices_list = QComboBox(self)
        self.devices_list.currentIndexChanged.connect(self.device_picked)
        wrapper.addWidget(self.devices_list)

        # procs/spawns lists
        spawns_vbox = QVBoxLayout()

        spawns_label = QLabel('SPAWN')
        spawns_label.setFont(QFont('Anton', 20, QFont.Normal))
        spawns_vbox.addWidget(spawns_label)

        self.spawn_list = PickList(self.on_spawn_picked)
        spawns_vbox.addWidget(self.spawn_list)

        spawns_refresh_button = QPushButton('refresh')
        spawns_refresh_button.clicked.connect(self.on_refresh_spawns)
        spawns_vbox.addWidget(spawns_refresh_button)

        procs_vbox = QVBoxLayout()

        procs_label = QLabel('PROCS')
        procs_label.setFont(QFont('Anton', 20, QFont.Normal))
        procs_vbox.addWidget(procs_label)

        self.proc_list = PickList(self.on_proc_picked)
        procs_vbox.addWidget(self.proc_list)

        procs_refresh_button = QPushButton('refresh')
        procs_refresh_button.clicked.connect(self.on_refresh_procs)
        procs_vbox.addWidget(procs_refresh_button)

        inner_hbox = QHBoxLayout()
        inner_hbox.addLayout(spawns_vbox)
        inner_hbox.addLayout(procs_vbox)
        wrapper.addLayout(inner_hbox)

        # finish
        right_side.setLayout(wrapper)

        # final
        self.addWidget(left_side)
        self.addWidget(right_side)

        self.setAutoFillBackground(True)
        self.setHandleWidth(1)
        self.setStretchFactor(0, 4)
        self.setStretchFactor(1, 2)

    def setup_threads(self):
        """ Setups the Threads used here
        """
        if self.devices_thread is None:
            self.devices_thread = DevicesUpdateThread(self.app)
            self.devices_thread.add_device.connect(self.on_add_deviceitem)
            self.devices_thread.clear_devices.connect(self.on_clear_devicelist)
            self.devices_thread.clear_procs.connect(self.on_clear_proclist)
            self.devices_thread.clear_spawns.connect(self.on_clear_spawnlist)
            self.devices_thread.devices_updated.connect(self.on_devices_updated)

        if self.spawns_update_thread is None:
            self.spawns_update_thread = SpawnsThread(self.app)
            self.spawns_update_thread.add_spawn.connect(self.on_add_spawn)
            self.spawns_update_thread.clear_spawns.connect(self.on_clear_spawnlist)
            self.spawns_update_thread.is_error.connect(self.on_status_text)

        if self.procs_update_thread is None:
            self.procs_update_thread = ProcsThread(self.app)
            self.procs_update_thread.add_proc.connect(self.on_add_proc)
            self.procs_update_thread.clear_procs.connect(self.on_clear_proclist)
            self.procs_update_thread.is_error.connect(self.on_status_text)

        if self.frida_update_thread is None:
            self.frida_update_thread = FridaUpdateThread(self.app)
            self.frida_update_thread.adb = self.app.get_adb()
            self.frida_update_thread.on_status_text.connect(self.frida_status_label)
            self.frida_update_thread.on_finished.connect(self.update_frida_version)
            self.frida_update_thread.adb = self.app.get_adb()

    def update_ui_sync(self):
        self.update_commits()
        self.update_frida_version()
        self.update_device_ui()

    def update_commits(self):
        if self.update_commits_thread is None:
            self.update_commits_thread = DwarfCommitsThread(app=self.app)
            self.update_commits_thread.on_update_available.connect(self.on_dwarf_isupdate)
            self.update_commits_thread.on_add_commit.connect(self.on_dwarf_commit)
            self.update_commits_thread.on_status_text.connect(self.on_status_text)
            self.update_commits_thread.on_finished.connect(self.on_status_text)
            if not self.update_commits_thread.isRunning():
                self.update_commits_thread.start()

    def update_dwarf(self):
        if self.update_dwarf_thread is None:
            self.update_dwarf_thread = DwarfUpdateThread(self.app)
            self.update_dwarf_thread.on_finished.connect(self.on_dwarf_updated)
            self.update_dwarf_thread.on_status_text.connect(self.on_status_text)

            if not self.update_dwarf_thread.isRunning():
                self.update_dwarf_thread.start()

    def on_dwarf_isupdate(self):
        """ Used in DwarfCommitsThread
            enables the UpdateBtn in menu
        """
        # self.menu_bar.menu.addAction(self.update_action)

    def on_dwarf_commit(self, com_text, color=False):
        q = NotEditableListWidgetItem(com_text)
        q.setFlags(Qt.NoItemFlags)
        if color:
            q.setForeground(QColor('#ef5350'))
        self.commit_list.addItem(q)

    def on_status_text(self, text):
        """ Sets text in StatusBar
        """
        if self.status_bar is not None:
            self.status_bar.showMessage(text)

    def on_dwarf_updated(self, sha):
        """ runs after dwarf_update
        """
        if 'error' in sha:
            utils.show_message_box(sha)
            return

        print('')
        print('')
        print('Dwarf updated to commit := ' + sha)
        print('')
        print('')

        utils.show_message_box('Dwarf updated to commit := ' + sha, 'Please restart...')
        sys.exit(0)

    def on_refresh_procs(self):
        self.on_clear_proclist()
        item_id = self.devices_list.itemData(self.devices_list.currentIndex())
        try:
            device = frida.get_device(item_id)
            self.update_proc_list(device)
        except Exception:
            return

    def on_clear_proclist(self):
        """ Clears the ProcList
        """
        self.proc_list.clear()

    def on_refresh_spawns(self):
        self.on_clear_spawnlist()
        item_id = self.devices_list.itemData(self.devices_list.currentIndex())
        try:
            device = frida.get_device(item_id)
            self.update_spawn_list(device)
        except Exception:
            return

    def on_clear_spawnlist(self):
        """ Clears the SpawnList
        """
        self.spawn_list.clear()

    def on_clear_devicelist(self):
        """ Clears Devices ComboBox
        """
        self.devices_list.clear()

    def on_add_deviceitem(self, device_name, custom_data, current=False):
        """ Adds an Item to the DeviceComboBox
        """
        self.devices_list.addItem(device_name, custom_data)
        if current:
            self.devices_list.setCurrentIndex(self.devices_list.count() - 1)

    def on_devices_updated(self):
        self.device_picked(self.devices_list.currentIndex())
        self.devices_list.currentIndexChanged.connect(self.device_picked)

    def update_device_ui(self):
        """ Updates the DeviceComboBox
        """
        if self.devices_thread is not None:
            if not self.devices_thread.isRunning():
                # temp disconnect its reconnected in on_devices_updated
                self.devices_list.currentIndexChanged.disconnect()
                self.devices_thread.start()

    def device_picked(self, index):
        item_id = self.devices_list.itemData(index)
        try:
            device = frida.get_device(item_id)
        except Exception:
            return
        self.app.get_dwarf().device_picked(device)
        self.update_spawn_list(device)
        self.update_proc_list(device)

    def on_add_spawn(self, item):
        self.spawn_list.addItem(item)

    def update_spawn_list(self, device):
        if not device:
            return

        if self.spawns_update_thread is not None:
            if not self.spawns_update_thread.isRunning():
                self.spawns_update_thread.device = device
                self.spawns_update_thread.start()

    def on_add_proc(self, item):
        self.proc_list.addItem(item)

    def update_proc_list(self, device):
        if not device:
            return

        if self.procs_update_thread is not None:
            if not self.procs_update_thread.isRunning():
                self.procs_update_thread.device = device
                self.procs_update_thread.start()

    def control_frida(self):
        """ Controls Frida on Device run/stop
        """
        if self.frida_control_button.text() == 'start frida':
            if self.app.get_adb().available():
                self.app.get_adb().start_frida()
                self.devices_list.currentIndexChanged.disconnect()
                self.on_devices_updated()
        elif self.frida_control_button.text() == 'stop frida':
            if self.app.get_adb().available():
                self.app.get_adb().kill_frida()

        self.update_frida_version()

    def update_frida_version(self):
        data = self.app.get_dwarf().get_git().get_frida_version()
        if data is None:
            self.updated_frida_version = ''
            self.updated_frida_assets_url.clear()
        else:
            data = data[0]
            self.updated_frida_version = data['tag_name']
            for asset in data['assets']:
                try:
                    name = asset['name']
                    tag_start = name.index('android-')
                    if name.index('server') >= 0:
                        tag = name[tag_start + 8:-3]
                        self.updated_frida_assets_url[tag] = asset['browser_download_url']
                except ValueError:
                    pass

        if self.app.get_adb().available():
            local_version = self.app.get_adb().get_frida_version()

            # control button
            if local_version is not None:
                self.frida_control_button.setVisible(True)
                if not self.app.get_adb().is_frida_running():
                    self.frida_control_button.setText('start frida')
                else:
                    self.frida_control_button.setText('stop frida')
            else:
                self.frida_control_button.setVisible(False)

            # update button
            if local_version is not None:
                local_version = local_version.join(local_version.split())
                self.frida_status_label(local_version)
                self.frida_update_button.setVisible(self.updated_frida_version != local_version)
            else:
                self.frida_status_label('frida not found')
                self.frida_update_button.setText('install frida')
                self.frida_update_button.setVisible(True)
                self.frida_update_button.setEnabled(True)
        else:
            self.frida_status_label('-')

    # todo: rename func
    def frida_status_label(self, update_text):
        """ sets status text from fridaserver update
        """
        label_text = ('device frida version: {0}\nupdated frida version: {1}'
                      .format(update_text, self.updated_frida_version))

        self.frida_update_label.setText(label_text)

    def server_update_complete(self):
        """ Fires when FridaServer update is completed
        """
        self.frida_status_label("finished")
        self.update_frida_version()

    def update_frida_server(self):
        """ Updates the FridaServer on the Device
        """

        # urls are empty
        if not self.updated_frida_assets_url:
            return

        arch = self.app.get_adb().get_device_arch()
        request_url = ''

        if arch is not None and len(arch) > 1:
            arch = arch.join(arch.split())

            if arch == 'arm64' or arch == 'arm64-v8a':
                request_url = self.updated_frida_assets_url['arm64']
            elif arch == 'armeabi-v7a':
                request_url = self.updated_frida_assets_url['arm']
            else:
                if arch in self.updated_frida_assets_url:
                    request_url = self.updated_frida_assets_url[arch]

            try:
                if self.app.get_adb().available() and request_url.index('https://') == 0:
                    self.frida_update_button.setEnabled(False)

                    if self.frida_update_thread is not None:
                        if not self.frida_update_thread.isRunning():
                            self.frida_update_thread.frida_url = request_url
                            self.frida_update_thread.start()

            except ValueError:
                # something wrong in .git_cache folder
                print("request_url not set")

    def on_proc_picked(self, widget_android_package):
        editor = JsEditorDialog(self.app, def_text=self.startup_script,
                                placeholder_text='// Javascript with frida and dwarf api to run at injection')
        accept, what = editor.show()
        if accept:
            self.startup_script = what
            app_name = widget_android_package.appname
            app_pid = widget_android_package.get_pid()
            if "\t" in app_name:
                app_name = app_name.split("\t")[1]

            self.app.get_dwarf().attach(app_pid, script=what)
            self.app.get_dwarf().app_window.update_title("Dwarf - Attached to %s (pid %s)" % (app_name, app_pid))

    def on_spawn_picked(self, widget_android_package):
        editor = JsEditorDialog(self.app, def_text=self.startup_script,
                                placeholder_text='// Javascript with frida and dwarf api to run at injection')
        accept, what = editor.show()
        if accept:
            self.startup_script = what

            app_name = widget_android_package.appname
            package_name = widget_android_package.get_package_name()

            self.app.get_dwarf().spawn(package_name, script=what)
            self.app.get_dwarf().app_window.update_title("Dwarf - Attached to %s (%s)" % (app_name, package_name))
Пример #2
0
class WelcomeUi(QSplitter):
    def __init__(self, app, *__args):
        super().__init__(*__args)

        self.app = app

        self.startup_script = ''

        self.setHandleWidth(1)

        box_container = QWidget()
        left_box = QVBoxLayout()
        header = QHBoxLayout()

        icon = QLabel()
        icon.setPixmap(utils.get_app_icon())
        icon.setFixedWidth(75)
        title = QLabel('DWARF')
        title.setFont(QFont('impact', 75, QFont.Normal))

        header.addWidget(icon)
        header.addWidget(title)

        self.commit_list = QListWidget()

        frida_update_box = QHBoxLayout()
        self.frida_update_label = QLabel('device frida version: -\nupdated frida version: -')

        self.frida_update_button = QPushButton('update frida')
        self.frida_update_button.setVisible(False)
        self.frida_update_button.clicked.connect(self.update_frida)

        self.dwarf_update_button = QPushButton('update dwarf')
        self.dwarf_update_button.setVisible(False)
        self.dwarf_update_button.clicked.connect(self.update_dwarf)

        frida_update_box.addWidget(self.frida_update_label)
        frida_update_box.addWidget(self.frida_update_button)
        frida_update_box.addWidget(self.dwarf_update_button)

        left_box.addLayout(header)
        left_box.addWidget(self.commit_list)
        left_box.addLayout(frida_update_box)

        box_container.setLayout(left_box)

        right_box_container = QWidget()
        right_box = QVBoxLayout()

        self.devices_list = QComboBox(self)
        self.devices_list.currentIndexChanged.connect(self.device_picked)
        right_box.addWidget(self.devices_list)

        cols = QHBoxLayout()

        spawns_container = QVBoxLayout()
        spawns_label = QLabel('SPAWN')
        spawns_label.setFont(QFont('impact', 35, QFont.Normal))

        self.spawn_list = PickList(self.on_spawn_picked)
        spawns_container.addWidget(spawns_label)
        spawns_container.addWidget(self.spawn_list)

        procs_container = QVBoxLayout()
        procs_label = QLabel('PROCS')
        procs_label.setFont(QFont('impact', 35, QFont.Normal))

        self.proc_list = PickList(self.on_proc_picked)
        procs_container.addWidget(self.proc_list)
        procs_container.addWidget(procs_label)

        cols.addLayout(spawns_container)
        cols.addLayout(procs_container)
        right_box.addLayout(cols)

        right_box_container.setLayout(right_box)

        self.addWidget(box_container)
        self.addWidget(right_box_container)

        frida.get_device_manager().on('added', self.on_device_changed)
        frida.get_device_manager().on('removed', self.on_device_changed)

        self.setStretchFactor(0, 4)
        self.setStretchFactor(1, 2)

        self.updated_frida_version = ''
        self.updated_frida_assets_url = {}

        Thread(target=self.update_ui_sync).start()

    def on_device_changed(self):
        if self.isVisible():
            self.update_device_ui()
        else:
            self.spawn_list.clear()
            self.proc_list.clear()

    def update_ui_sync(self):
        self.update_device_ui()
        self.update_commits()
        self.update_frida_version()

    def update_commits(self):
        data = self.app.get_dwarf().get_git().get_dwarf_commits()
        if data is None:
            q = NotEditableListWidgetItem('Failed to fetch commit list. Try later.')
            q.setFlags(Qt.NoItemFlags)
            self.commit_list.addItem(q)
            return

        most_recent_remote_commit = ''
        most_recent_local_commit = utils.do_shell_command('git log -1 master --pretty=format:%H')
        most_recent_date = ''
        for commit in data:
            if most_recent_remote_commit == '':
                most_recent_remote_commit = commit['sha']
                if most_recent_remote_commit != most_recent_local_commit:
                    self.dwarf_update_button.setVisible(True)

                    q = NotEditableListWidgetItem('')
                    q.setFlags(Qt.NoItemFlags)
                    self.commit_list.addItem(q)
            commit = commit['commit']
            date = commit['committer']['date'].split('T')
            if most_recent_date != date[0]:
                if most_recent_date != '':
                    q = NotEditableListWidgetItem('')
                    q.setFlags(Qt.NoItemFlags)
                    self.commit_list.addItem(q)
                q = NotEditableListWidgetItem(date[0])
                q.setFlags(Qt.NoItemFlags)
                self.commit_list.addItem(q)
                most_recent_date = date[0]

            q = NotEditableListWidgetItem('%s - %s (%s)' % (date[1][:-1], commit['message'],
                                                            commit['author']['name']))
            q.setFlags(Qt.NoItemFlags)
            q.setForeground(Qt.white)
            self.commit_list.addItem(q)

    def update_dwarf(self, item):
        self.commit_list.clear()
        q = NotEditableListWidgetItem('Updating dwarf...')
        q.setFlags(Qt.NoItemFlags)
        self.commit_list.addItem(q)

        utils.do_shell_command('git fetch -q https://github.com/iGio90/Dwarf.git', stdout=subprocess.DEVNULL)
        utils.do_shell_command('git checkout -f -q master', stdout=subprocess.DEVNULL)
        utils.do_shell_command('git reset --hard FETCH_HEAD', stdout=subprocess.DEVNULL)
        sha = utils.do_shell_command('git log -1 master --pretty=format:%H')

        print('')
        print('')
        print('Dwarf updated to commit := ' + sha)
        print('')
        print('')

        sys.exit(0)

    def update_device_ui(self):
        devices = frida.enumerate_devices()
        self.devices_list.clear()
        should_clear = True
        for device in devices:
            self.devices_list.addItem('%s (%s)' % (device.name, device.type))
            self.devices_list.setItemData(self.devices_list.count() - 1, device.id)
            if device.type == 'usb' and should_clear:
                # set the first usb device found
                should_clear = False
                self.devices_list.setCurrentIndex(self.devices_list.count() - 1)
        if should_clear:
            self.spawn_list.clear()
            self.proc_list.clear()

    def device_picked(self, index):
        id = self.devices_list.itemData(index)
        try:
            device = frida.get_device(id)
        except:
            return
        self.app.get_dwarf().device_picked(device)
        self.update_spawn_list(device)
        self.update_proc_list(device)

    def update_spawn_list(self, device):
        self.spawn_list.clear()
        try:
            apps = device.enumerate_applications()
        except:
            return
        last_letter = ''
        for app in sorted(apps, key=lambda x: x.name):
            app_name = app.name
            l = app.name[0].upper()
            if last_letter != l:
                if last_letter != '':
                    q = NotEditableListWidgetItem('')
                    q.setFlags(Qt.NoItemFlags)
                    self.spawn_list.addItem(q)
                last_letter = l
                q = NotEditableListWidgetItem(last_letter)
                q.setFlags(Qt.NoItemFlags)
                self.spawn_list.addItem(q)
            q = AndroidPackageWidget(app_name, app.identifier, 0)
            self.spawn_list.addItem(q)

    def update_proc_list(self, device):
        self.proc_list.clear()
        try:
            procs = device.enumerate_processes()
        except:
            return
        for proc in procs:
            q = AndroidPackageWidget('%s\t%s' % (proc.pid, proc.name), '', proc.pid)
            self.proc_list.addItem(q)

    def update_frida_version(self):
        data = self.app.get_dwarf().get_git().get_frida_version()
        if data is None:
            self.updated_frida_version = ''
            self.updated_frida_assets_url.clear()
        else:
            data = data[0]
            self.updated_frida_version = data['tag_name']
            for asset in data['assets']:
                try:
                    name = asset['name']
                    tag_start = name.index('android-')
                    if name.index('server') >= 0:
                        tag = name[tag_start + 8:-3]
                        self.updated_frida_assets_url[tag] = asset['browser_download_url']
                except:
                    pass

        local_version = self.app.get_adb().get_frida_version()
        if local_version:
            local_version = local_version.replace('\n', '')\
                .replace('\n', '').replace('\t', '').replace(' ', '').replace('\r', '')
            try:
                if local_version.index('frida') >= 0:
                    local_version = '-'
            except:
                pass
        else:
            # adb not found or device not found through adb
            self.frida_update_label.setText('device frida version: %s\nupdated frida version: %s'
                                            % ('-', self.updated_frida_version))
            return

        self.frida_update_label.setText('device frida version: %s\nupdated frida version: %s'
                                        % (local_version, self.updated_frida_version))

        self.frida_update_button.setVisible(self.updated_frida_version != local_version)

    def update_frida(self):
        def _update():
            if os.path.exists('frida'):
                os.remove('frida')

            r = None
            arch = self.app.get_adb().get_device_arch().replace('\n', '').replace('\t', '')\
                .replace(' ', '').replace('\r', '')
            if arch == 'arm64' or arch == 'arm64-v8a':
                r = requests.get(self.updated_frida_assets_url['arm64'], stream=True)
            elif arch == 'armeabi-v7a':
                r = requests.get(self.updated_frida_assets_url['arm'], stream=True)
            else:
                if arch in self.updated_frida_assets_url:
                    r = requests.get(self.updated_frida_assets_url[arch], stream=True)
            if r is not None:
                with open('frida.xz', 'wb') as f:
                    for chunk in r.iter_content(chunk_size=1024):
                        if chunk:
                            f.write(chunk)
                res = utils.do_shell_command('unxz frida.xz')
                if len(res) == 0:
                    res = self.app.get_adb().mount_system()
                    if res is None or len(res) == 0:
                        self.app.get_adb().push('frida', '/sdcard/')
                        self.app.get_adb().su('killall -9 frida', stdout=subprocess.DEVNULL)
                        self.app.get_adb().su('mv /sdcard/frida /system/xbin/frida', stdout=subprocess.DEVNULL)
                        self.app.get_adb().su('chmod 755 /system/xbin/frida', stdout=subprocess.DEVNULL)
                        self.update_frida_version()
                        self.app.get_adb().su('frida -D', stdout=subprocess.DEVNULL)
                    os.remove('frida')
                else:
                    os.remove('frida.xz')
            self.update_frida_version()

        self.frida_update_button.setVisible(False)
        self.frida_update_label.setText('downloading latest frida server... please wait...')
        Thread(target=_update).start()

    def on_proc_picked(self, widget_android_package):
        editor = JsEditorDialog(self.app, def_text=self.startup_script,
                                placeholder_text='// Javascript with frida and dwarf api to run at injection')
        accept, what = editor.show()
        if accept:
            self.startup_script = what
            app_name = widget_android_package.appname
            app_pid = widget_android_package.get_pid()
            if "\t" in app_name:
                app_name = app_name.split("\t")[1]

            self.app.get_dwarf().attach(app_pid, script=what)
            self.app.get_dwarf().app_window.update_title("Dwarf - Attached to %s (pid %s)" % (app_name, app_pid))

    def on_spawn_picked(self, widget_android_package):
        editor = JsEditorDialog(self.app, def_text=self.startup_script,
                                placeholder_text='// Javascript with frida and dwarf api to run at injection')
        accept, what = editor.show()
        if accept:
            self.startup_script = what

            app_name = widget_android_package.appname
            package_name = widget_android_package.get_package_name()

            self.app.get_dwarf().spawn(package_name, script=what)
            self.app.get_dwarf().app_window.update_title("Dwarf - Attached to %s (%s)" % (app_name, package_name))