def _load(self): with FileLock(self._path + ".share.lock"): # 文件锁,避免多进程同时操作 if not self._cached or not os.path.exists(self._path): if os.path.exists(self._path): logger.debug(f"Remove shared script cache: {self._path}", tag="[*]") os.remove(self._path) logger.info(f"Download shared script: {self._url}", tag="[*]") utils.download(self._url, self._path) with open(self._path, "rb") as f: source = f.read().decode("utf-8") if self._trusted: logger.info(f"Load trusted shared script: {self._path}", tag="[✔]") return source cached_md5 = "" cached_md5_path = self._path + ".md5" if os.path.exists(cached_md5_path): with open(cached_md5_path, "rt") as fd: cached_md5 = fd.read() source_md5 = utils.get_md5(source) if cached_md5 == source_md5: logger.info(f"Load trusted shared script: {self._path}", tag="[✔]") return source line_count = 20 source_lines = source.splitlines(keepends=True) source_summary = "".join(source_lines[:line_count]) if len(source_lines) > line_count: source_summary += "... ..." logger.warning( f"This is the first time you're running this particular snippet, " f"or the snippet's source code has changed.{os.linesep}" f"Url: {self._url}{os.linesep}" f"Original md5: {cached_md5}{os.linesep}" f"Current md5: {source_md5}{os.linesep}{os.linesep}", f"{source_summary}", tag="[!]") while True: response = input( ">>> Are you sure you'd like to trust it? [y/N]: ") if response.lower() in ('n', 'no') or response == '': logger.info( f"Ignore untrusted shared script: {self._path}", tag="[✔]") return None if response.lower() in ('y', 'yes'): with open(cached_md5_path, "wt") as fd: fd.write(source_md5) logger.info(f"Load trusted shared script: {self._path}", tag="[✔]") return source
def on_session_detached(self, session, reason, crash) -> None: logger.info( f"Detach process: {session.process_name} ({session.pid}), reason={reason}", tag="[*]") if reason in ("connection-terminated", "device-lost"): self.stop() elif len(self._sessions) == 0: app.load_script(app.device.spawn(package), resume=True)
def on_session_attached(self, session: FridaSession): """ 会话建立连接回调函数,默认只打印log :param session: 附加的会话 """ logger.info( f"Session attached: {session.process_name} ({session.pid})", tag="[*]")
def prepare(self): if not os.path.exists(self.local_path): logger.info("Download frida server ...", tag="[*]") utils.download(self._download_url, self._temp_path) with lzma.open(self._temp_path, "rb") as read, open(self.local_path, "wb") as write: shutil.copyfileobj(read, write) os.remove(self._temp_path)
def on_session_detached(self, session: FridaSession, reason: str, crash: "_frida.Crash"): """ 会话结束回调函数,默认只打印log :param session: 结束的会话 :param reason: 结束原因 :param crash: crash信息 """ logger.info( f"Session detached: {session.process_name} ({session.pid}), reason={reason}", tag="[*]")
def on_script_event(self, script: FridaScript, message: object, data: object): """ 脚本发送事件回调 :param script: frida的脚本 :param message: 事件消息 :param data: 事件数据 """ logger.info( f"Script event: {json.dumps(message, indent=2, ensure_ascii=False)}", tag="[*]")
def stop(self) -> bool: """ 强制结束frida server :return: 结束成功为True,否则为False """ logger.info("Kill frida server ...", tag="[*]") try: self._stop() return True except frida.ServerNotRunningError: return True except: return False
def _prepare(self): if not self._device.is_file_exist(self._environ.remote_path): self._environ.prepare() logger.info(f"Push frida server to {self._environ.remote_path}", tag="[*]") temp_path = self._device.get_storage_path( "frida", self._environ.remote_name) self._device.push(self._environ.local_path, temp_path, capture_output=False) self._device.sudo("mv", temp_path, self._environ.remote_path, capture_output=False) self._device.sudo("chmod", "755", self._environ.remote_path)
def start(self) -> bool: """ 根据frida版本和设备abi类型下载并运行server :return: 运行成功为True,否则为False """ if self.is_running: logger.info("Frida server is running ...", tag="[*]") return True logger.info("Start frida server ...", tag="[*]") self._start() for i in range(10): time.sleep(0.5) if self.is_running: logger.info("Frida server is running ...", tag="[*]") return True raise frida.ServerNotRunningError("Frida server failed to run ...")
def on_script_message(self, script: FridaScript, message: object, data: object): """ 脚本消息回调函数,默认按照格式打印 :param script: frida的脚本 :param message: frida server发送的数据 :param data: frida server发送的data """ if utils.get_item(message, "type") == "send": payload = utils.get_item(message, "payload") if payload is not None and isinstance(payload, dict): # log单独解析 log = payload.pop("log", None) if log is not None: self.on_script_log(script, log) # event单独解析 event = payload.pop("event", None) if event is not None: self.on_script_event(script, event, data) # 解析完log,解析其他的 while len(payload) > 0: key, value = payload.popitem() self.on_script_send(script, key, value, data) # 字符串类型,直接输出 if not utils.is_empty(payload): logger.info(payload, tag="[*]") elif utils.get_item(message, "type") == "error" and utils.is_contain( message, "stack"): logger.info(utils.get_item(message, "stack"), tag="[!]", fore=Fore.RED) else: logger.info(message, tag="[?]", fore=Fore.RED)
def _load(self) -> Optional[str]: with open(self._path, "rb") as f: logger.info(f"Load script: {self._path}", tag="[✔]") return f.read().decode("utf-8")
def on_device_lost(self): logger.info("Device lost", tag="[!]") self.stop()