def __init__(self, parent=None, device_type='usb'): super().__init__(parent=parent) # dont show for local if device_type != 'usb': return self.parent = parent self.wait_for_devtype = device_type self.is_waiting = True self._adb = Adb() if not self._adb.min_required: raise Exception('Adb missing or no Device') self._git = Git() self.setAutoFillBackground(True) self.setStyleSheet( 'background-color: crimson; color: white; font-weight: bold; margin: 0; padding: 10px;' ) self.setup() self._timer = QTimer() self._timer.setInterval(500) self._timer.timeout.connect(self._on_timer) self._timer.start() self._timer_step = 0 frida.get_device_manager().on('added', self._on_device) frida.get_device_manager().on('removed', self._on_device) self.devices_thread = DevicesUpdateThread(self) self.devices_thread.onAddDevice.connect(self.on_add_deviceitem) self.devices_thread.onDevicesUpdated.connect(self._on_devices_finished) self._update_thread = FridaUpdateThread(self) self._update_thread._adb = self._adb self._update_thread.onStatusUpdate.connect(self._update_statuslbl) self._update_thread.onFinished.connect(self._frida_updated) self._update_thread.onError.connect(self._on_download_error) self.updated_frida_version = '' self.updated_frida_assets_url = {} self._device_id = None self._devices = [] remote_frida = self._git.get_frida_version() if remote_frida is None: self.updated_frida_version = '' self.updated_frida_assets_url.clear() else: remote_frida = remote_frida[0] self.updated_frida_version = remote_frida['tag_name'] for asset in remote_frida['assets']: if 'android-' not in asset: continue 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
def __init__(self, parent=None, show_path=True): super(ApkList, self).__init__(parent=parent) self.adb = Adb() self.adb.device = parent.dwarf.device.id if not self.adb.available(): return self.retrieve_thread = PackageRetrieveThread(self.adb) if self.retrieve_thread is not None: self.retrieve_thread.onAddPackage.connect(self._on_addpackage) if show_path: self.apk_model = QStandardItemModel(0, 2) else: self.apk_model = QStandardItemModel(0, 1) self.apk_model.setHeaderData(0, Qt.Horizontal, 'Name') if show_path: self.apk_model.setHeaderData(1, Qt.Horizontal, 'Path') self.setModel(self.apk_model) self.header().setSectionResizeMode(0, QHeaderView.ResizeToContents) self.doubleClicked.connect(self._on_apk_selected) if self.retrieve_thread is not None: if not self.retrieve_thread.isRunning(): self.retrieve_thread.start()
class DeviceBar(QWidget): """ DeviceBar Signals: onDeviceUpdated() onDeviceSelected(str) # str = id onDeviceChanged(str) # str = id """ onDeviceUpdated = pyqtSignal(str, name="onDeviceUpdated") onDeviceSelected = pyqtSignal(str, name="onDeviceSelected") onDeviceChanged = pyqtSignal(str, name="onDeviceChanged") def __init__(self, parent=None, device_type='usb'): super().__init__(parent=parent) # dont show for local if device_type != 'usb': return self.parent = parent self.wait_for_devtype = device_type self.is_waiting = True self._adb = Adb() if not self._adb.min_required: raise Exception('Adb missing or no Device') self._git = Git() self.setAutoFillBackground(True) self.setStyleSheet( 'background-color: crimson; color: white; font-weight: bold; margin: 0; padding: 10px;' ) self.setup() self._timer = QTimer() self._timer.setInterval(500) self._timer.timeout.connect(self._on_timer) self._timer.start() self._timer_step = 0 frida.get_device_manager().on('added', self._on_device) frida.get_device_manager().on('removed', self._on_device) self.devices_thread = DevicesUpdateThread(self) self.devices_thread.onAddDevice.connect(self.on_add_deviceitem) self.devices_thread.onDevicesUpdated.connect(self._on_devices_finished) self._update_thread = FridaUpdateThread(self) self._update_thread._adb = self._adb self._update_thread.onStatusUpdate.connect(self._update_statuslbl) self._update_thread.onFinished.connect(self._frida_updated) self._update_thread.onError.connect(self._on_download_error) self.updated_frida_version = '' self.updated_frida_assets_url = {} self._device_id = None self._devices = [] remote_frida = self._git.get_frida_version() if remote_frida is None: self.updated_frida_version = '' self.updated_frida_assets_url.clear() else: remote_frida = remote_frida[0] self.updated_frida_version = remote_frida['tag_name'] for asset in remote_frida['assets']: if 'name' not in asset: continue if 'android-' not in asset['name']: continue 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 def setup(self): """ Setup ui """ h_box = QHBoxLayout() h_box.setContentsMargins(0, 0, 0, 0) self.update_label = QLabel('Waiting for Device') self.update_label.setFixedWidth(self.parent.width()) self.update_label.setOpenExternalLinks(True) self.update_label.setTextFormat(Qt.RichText) self.update_label.setFixedHeight(35) self.update_label.setTextInteractionFlags(Qt.TextBrowserInteraction) self._install_btn = QPushButton('Install Frida', self.update_label) self._install_btn.setStyleSheet('padding: 0; border-color: white;') self._install_btn.setGeometry(self.update_label.width() - 110, 5, 100, 25) self._install_btn.clicked.connect(self._on_install_btn) self._install_btn.setVisible(False) self._start_btn = QPushButton('Start Frida', self.update_label) self._start_btn.setStyleSheet('padding: 0; border-color: white;') self._start_btn.setGeometry(self.update_label.width() - 110, 5, 100, 25) self._start_btn.clicked.connect(self._on_start_btn) self._start_btn.setVisible(False) self._update_btn = QPushButton('Update Frida', self.update_label) self._update_btn.setStyleSheet('padding: 0; border-color: white;') self._update_btn.setGeometry(self.update_label.width() - 110, 5, 100, 25) self._update_btn.clicked.connect(self._on_install_btn) self._update_btn.setVisible(False) self._restart_btn = QPushButton('Restart Frida', self.update_label) self._restart_btn.setStyleSheet('padding: 0; border-color: white;') self._restart_btn.setGeometry(self.update_label.width() - 110, 5, 100, 25) self._restart_btn.clicked.connect(self._on_restart_btn) self._restart_btn.setVisible(False) self._devices_combobox = QComboBox(self.update_label) self._devices_combobox.setStyleSheet( 'padding: 2px 5px; border-color: white;') self._devices_combobox.setGeometry(self.update_label.width() - 320, 5, 200, 25) self._devices_combobox.currentIndexChanged.connect( self._on_device_changed) self._devices_combobox.setVisible(False) h_box.addWidget(self.update_label) self.setLayout(h_box) def on_add_deviceitem(self, device_ident): """ Adds an Item to the DeviceComboBox """ if device_ident['type'] == self.wait_for_devtype: if device_ident['name'] not in self._devices: self._devices.append(device_ident) self._timer_step = -1 self.is_waiting = False def _on_device_changed(self, index): device = None device_id = self._devices_combobox.itemData(index) if device_id: try: device = frida.get_device(device_id) except: return if device: self._device_id = device.id self._check_device(device) self.onDeviceChanged.emit(self._device_id) def _check_device(self, frida_device): self.update_label.setStyleSheet('background-color: crimson;') self._install_btn.setVisible(False) self._update_btn.setVisible(False) self._start_btn.setVisible(False) self._restart_btn.setVisible(False) self._adb.device = frida_device.id self._device_id = frida_device.id if self._adb.available(): self.update_label.setText('Device: ' + frida_device.name) # try getting frida version device_frida = self._adb.get_frida_version() # frida not found show install button if device_frida is None: self._install_btn.setVisible(True) else: # frida is old show update button if self.updated_frida_version != device_frida: self._start_btn.setVisible(True) self._update_btn.setVisible(False) # old frida is running allow use of this version if self._adb.is_frida_running(): self._start_btn.setVisible(False) if self.updated_frida_assets_url: self._update_btn.setVisible(True) self.update_label.setStyleSheet( 'background-color: yellowgreen;') self.onDeviceUpdated.emit(frida_device.id) # frida not running show start button elif device_frida and not self._adb.is_frida_running(): self._start_btn.setVisible(True) # frida is running with last version show restart button elif device_frida and self._adb.is_frida_running(): self.update_label.setStyleSheet( 'background-color: yellowgreen;') self._restart_btn.setVisible(True) self.onDeviceUpdated.emit(frida_device.id) elif self._adb.non_root_available(): self.update_label.setText('Device: ' + frida_device.name + ' (NOROOT!)') self.onDeviceUpdated.emit(frida_device.id) def _on_devices_finished(self): if self._devices: if len(self._devices) > 1: self._devices_combobox.clear() self._devices_combobox.setVisible(True) self.update_label.setText('Please select the Device: ') for device in self._devices: self._devices_combobox.addItem(device['name'], device['id']) else: self._devices_combobox.setVisible(False) try: device = frida.get_device(self._devices[0]['id']) self._check_device(device) except: pass def _on_timer(self): if self._timer_step == -1: self._timer.stop() return if self._timer_step == 0: self.update_label.setText(self.update_label.text() + ' .') self._timer_step = 1 elif self._timer_step == 1: self.update_label.setText(self.update_label.text() + '.') self._timer_step = 2 elif self._timer_step == 2: self.update_label.setText(self.update_label.text() + '.') self._timer_step = 3 else: self.update_label.setText( self.update_label.text()[:-self._timer_step]) self._timer_step = 0 if self.is_waiting and self.devices_thread is not None: if not self.devices_thread.isRunning(): self.devices_thread.start() def _on_download_error(self, text): self._timer_step = -1 self.update_label.setStyleSheet('background-color: crimson;') self.update_label.setText(text) self._install_btn.setVisible(True) self._update_btn.setVisible(False) def _on_device(self): self.update_label.setText('Waiting for Device ...') self._timer_step = 3 self.is_waiting = True self._on_timer() def _on_install_btn(self): # urls are empty if not self.updated_frida_assets_url: return arch = self._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._adb.available() and request_url.index( 'https://') == 0: self._install_btn.setVisible(False) self._update_btn.setVisible(False) qApp.processEvents() if self._update_thread is not None: if not self._update_thread.isRunning(): self._update_thread.frida_update_url = request_url self._update_thread.adb = self._adb self._update_thread.start() except ValueError: # something wrong in .git_cache folder print("request_url not set") def _update_statuslbl(self, text): self._timer.stop() self._timer_step = 0 self._timer.start() self.update_label.setText(text) def _frida_updated(self): # self._timer_step = 3 # self.is_waiting = True self._on_devices_finished() def _on_start_btn(self): if self._adb.available(): self._start_btn.setVisible(False) qApp.processEvents() if self._adb.start_frida(): # self.onDeviceUpdated.emit(self._device_id) self._on_devices_finished() else: self._start_btn.setVisible(True) def _on_restart_btn(self): if self._adb.available(): self._restart_btn.setVisible(False) qApp.processEvents() if self._adb.start_frida(restart=True): self._restart_btn.setVisible(True) # self.onDeviceUpdated.emit(self._device_id) self._on_devices_finished()
def __init__(self, app_window): super(AndroidSession, self).__init__(app_window) self.adb = Adb() if not self.adb.min_required: utils.show_message_box(self.adb.get_states_string())
class AndroidSession(Session): """ All Android Stuff goes here if u look for something android related its here then """ def __init__(self, app_window): super(AndroidSession, self).__init__(app_window) self.adb = Adb() if not self.adb.min_required: utils.show_message_box(self.adb.get_states_string()) @property def session_type(self): """ return session name to show in menus etc """ return 'android' @property def device_manager_type(self): return 'usb' @property def frida_device(self): version = frida.__version__.split('.') if len(version) == 3: if int(version[0]) >= 12 and int(version[1]) >= 7: return frida.get_usb_device(timeout=60) return frida.get_usb_device() def _setup_menu(self): """ Build Menus """ # additional menus file_menu = QMenu('&Device') save_apk = QAction("&Save APK", self) save_apk.triggered.connect(self.save_apk) decompile_apk = QAction("&Decompile APK", self) decompile_apk.triggered.connect(self.decompile_apk) file_menu.addAction(save_apk) file_menu.addAction(decompile_apk) self._menu.append(file_menu) super()._setup_menu() java_menu = QMenu('&Java') java_menu.addAction('Trace', self._on_java_trace) java_menu.addSeparator() java_menu.addAction('Classes', self._on_java_classes) self._menu.append(java_menu) def start(self, args): super().start(args) self.adb.device = self.dwarf.device.id def decompile_apk(self): apk_dlg = ApkListDialog(self._app_window) apk_dlg.onApkSelected.connect(self._decompile_package) apk_dlg.show() def _decompile_package(self, data): package, path = data if path is not None: # todo: make qthread AndroidDecompileUtil.decompile(self.adb, path) def save_apk(self): apk_dlg = ApkListDialog(self._app_window) apk_dlg.onApkSelected.connect(self._save_package) apk_dlg.show() def _save_package(self, data): package, path = data if path is not None: result = QFileDialog.getSaveFileName( caption='Location to save ' + package, directory='./' + package + '.apk', filter='*.apk') if result and result[0]: self.adb.su_cmd('cp ' + path + ' /sdcard/' + package + '.apk') self.adb.pull('/sdcard/' + package + '.apk', result[0]) self.adb.su_cmd('rm /sdcard/' + package + '.apk') def _on_proc_selected(self, data): super()._on_proc_selected(data) device, pid = data if device: self.adb.device = device.id def _on_spawn_selected(self, data): device, package_name, break_at_start = data if device: self.adb.device = device.id self.dwarf.device = device if package_name: try: self.dwarf.spawn(package_name, break_at_start=break_at_start) except Exception as e: utils.show_message_box( 'Failed spawning {0}'.format(package_name), str(e)) self.stop() return self._on_java_classes() def _on_java_trace(self): tag = 'jvm-tracer' should_request_classes = \ self._app_window.java_trace_panel is None or tag not in self._app_window.ui_elements self._app_window.show_main_tab(tag) if should_request_classes: self.dwarf.dwarf_api('enumerateJavaClasses') def _on_java_classes(self): self._app_window.show_main_tab('jvm-inspector') self.dwarf.dwarf_api('enumerateJavaClasses')
class ApkList(DwarfListView): """ Displays installed APKs """ onApkSelected = pyqtSignal(list, name='onApkSelected') def __init__(self, parent=None, show_path=True): super(ApkList, self).__init__(parent=parent) self.adb = Adb() self.adb.device = parent.dwarf.device.id if not self.adb.available(): return self.retrieve_thread = PackageRetrieveThread(self.adb) if self.retrieve_thread is not None: self.retrieve_thread.onAddPackage.connect(self._on_addpackage) if show_path: self.apk_model = QStandardItemModel(0, 2) else: self.apk_model = QStandardItemModel(0, 1) self.apk_model.setHeaderData(0, Qt.Horizontal, 'Name') if show_path: self.apk_model.setHeaderData(1, Qt.Horizontal, 'Path') self.setModel(self.apk_model) self.header().setSectionResizeMode(0, QHeaderView.ResizeToContents) self.doubleClicked.connect(self._on_apk_selected) if self.retrieve_thread is not None: if not self.retrieve_thread.isRunning(): self.retrieve_thread.start() # ************************************************************************ # **************************** Functions ********************************* # ************************************************************************ def refresh(self): """ Refresh Packages """ if self.retrieve_thread is not None: if not self.retrieve_thread.isRunning(): self.clear() self.retrieve_thread.start() # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ def _on_addpackage(self, package): if package: name = QStandardItem() name.setText(package[0]) if self.apk_model.columnCount() == 2: path = QStandardItem() path.setText(package[1]) self.apk_model.appendRow([name, path]) else: self.apk_model.appendRow([name]) def _on_apk_selected(self, model_index): item = self.apk_model.itemFromIndex(model_index).row() if item != -1: package = self.apk_model.item(item, 0).text() if self.apk_model.columnCount() == 2: path = self.apk_model.item(item, 1).text() self.onApkSelected.emit([package, path]) else: self.onApkSelected.emit([package, None])