def on_spawn_added(self, spawn: "_frida.Spawn"): """ spaw进程添加回调,默认resume所有spawn进程 :param spawn: spawn进程信息 """ logger.debug(f"Spawn added: {spawn}", tag="[✔]") self.device.resume(spawn.pid)
def _load_script(self, pid: int, resume: bool = False): logger.debug(f"Attempt to load script: pid={pid}, resume={resume}", tag="[✔]") session = self._attach_session(pid) self._unload_script(session) # read the internal script as an entrance entry_code = self._internal_debug_script.source \ if self._debug \ else self._internal_script.source script = FridaScript(session, entry_code) script.on( "message", lambda message, data: self.on_script_message( script, message, data)) script.on("destroyed", lambda: self.on_script_destroyed(script)) session.script = script try: script.load() script.exports.load_scripts(self._load_script_files(), self._user_parameters) finally: if resume: self.device.resume(pid) self._reactor.schedule(lambda: self.on_script_loaded(script))
def on_child_added(self, child: "_frida.Child"): """ 子进程添加回调,默认resume所有子进程 :param child: 子进程信息 """ logger.debug(f"Child added: {child}", tag="[✔]") self.device.resume(child.pid)
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_script_destroyed(self, script: FridaScript): """ 脚本结束回调函数,默认只打印log :param script: frida的脚本 """ logger.debug( f"Script destroyed: {script.session.process_name} ({script.session.pid})", tag="[✔]")
def on_script_loaded(self, script: FridaScript): """ 脚本加载回调,默认只打印log :param script: frida的脚本 """ logger.debug( f"Script loaded: {script.session.process_name} ({script.session.pid})", tag="[✔]")
def on_file_change(self, file: FridaScriptFile): """ 脚本文件改变回调,默认重新加载脚本 :param file: 脚本文件路径 """ logger.debug(f"File changed", tag="[✔]") for session in self.sessions.values(): self.load_script(session.pid)
def monitor_file(file): logger.debug(f"Monitor file: {file.path}", tag="[✔]") monitor = frida.FileMonitor(file.path) monitor.on( "change", lambda changed_file, other_file, event_type: on_change( event_type, file)) monitor.enable() return monitor
def on_script_send(self, script: FridaScript, type: str, message: object, data: object): """ 脚本调用send是收到的回调,例send({trace: "xxx"}, null) :param script: frida的脚本 :param type: 上述例子的"trace" :param message: json/字符串消息,上述例子的"xxx" :param data: 上述例子的null """ logger.debug(f"Script send, type={type}, message={message}", tag="[*]")
def on_change(event_type, changed_file): if event_type == "changes-done-hint": logger.debug( f"Monitor event: {event_type}, file: {changed_file}", tag="[✔]") self._last_change_id += 1 change_id = self._last_change_id changed_file.clear() self._reactor.schedule( lambda: on_change_schedule(change_id, changed_file), delay=0.5)
def _init(self): logger.debug(f"FridaApplication init", tag="[✔]") self._finished.clear() self._monitor_all() self.device.on("spawn-added", self._cb_spawn_added) self.device.on("spawn-removed", self._cb_spawn_removed) self.device.on("child-added", self._cb_child_added) self.device.on("child-removed", self._cb_child_removed) self.device.on("output", self._cb_output) # self.device.on('process-crashed', self._cb_process_crashed) # self.device.on('uninjected', self._cb_uninjected) self.device.on("lost", self._cb_lost) if self._enable_spawn_gating: self.device.enable_spawn_gating()
def _deinit(self): logger.debug(f"FridaApplication deinit", tag="[✔]") utils.ignore_error(self.device.off, "spawn-added", self._cb_spawn_added) utils.ignore_error(self.device.off, "spawn-removed", self._cb_spawn_removed) utils.ignore_error(self.device.off, "child-added", self._cb_child_added) utils.ignore_error(self.device.off, "child-removed", self._cb_child_removed) utils.ignore_error(self.device.off, "output", self._cb_output) # utils.ignore_error(self.device.off, "process-crashed", self._cb_process_crashed) # utils.ignore_error(self.device.off, "uninjected", self._cb_uninjected) utils.ignore_error(self.device.off, "lost", self._cb_lost) with frida.Cancellable(): self._demonitor_all() self._finished.set()
def _attach_session(self, pid: int): with self._lock: session = self._sessions.get(pid) if session is not None: if not session.is_detached: return session self._sessions.pop(pid) logger.debug(f"Attempt to attach process: pid={pid}", tag="[✔]") target_process = None for process in self.enumerate_processes(): if process.pid == pid: target_process = process if target_process is None: raise frida.ProcessNotFoundError( f"unable to find process with pid '{pid}'") session = FridaSession(self.device.attach(target_process.pid)) session.pid = target_process.pid session.process_name = target_process.name if self._enable_child_gating: logger.debug(f"Enable child gating: {pid}", tag="[✔]") session.enable_child_gating() def on_session_detached(reason, crash): with self._lock: self._sessions.pop(pid, None) self._reactor.schedule( lambda: self.on_session_detached(session, reason, crash)) session.on("detached", on_session_detached) with self._lock: self._sessions[target_process.pid] = session self._reactor.schedule(lambda: self.on_session_attached(session)) return session
def on_child_removed(self, child: "_frida.Child"): """ 子进程移除回调,默认只打印log :param child: 子进程信息 """ logger.debug(f"Child removed: {child}", tag="[✔]")
def on_spawn_removed(self, spawn: "_frida.Spawn"): """ spaw进程移除回调,默认只打印log :param spawn: spawn进程信息 """ logger.debug(f"Spawn removed: {spawn}", tag="[✔]")
def on_output(self, pid: int, fd, data): logger.debug(f"Output: pid={pid}, fd={fd}, data={data}", tag="[✔]")
def on_spawn_added(self, spawn): logger.debug(f"Spawn added: {spawn}", tag="[✔]") if device.extract_package(spawn.identifier) == package: self.load_script(spawn.pid, resume=True) else: self.resume(spawn.pid)
def _eternalize_script(self, session: FridaSession): if session is not None and session.script is not None: logger.debug(f"Eternalize script: pid={session.pid}", tag="[✔]") utils.ignore_error(session.script.eternalize) session.script = None
def _unload_script(self, session: FridaSession): if session is not None and session.script is not None: logger.debug(f"Unload script: pid={session.pid}", tag="[✔]") utils.ignore_error(session.script.unload) session.script = None
def _detach_session(self, session: FridaSession): if session is not None: logger.debug(f"Detach process: pid={session.pid}", tag="[✔]") utils.ignore_error(session.detach)
def on_stop(self): logger.debug("Application stopped", tag="[✔]")
def on_spawn_added(self, spawn): logger.debug(f"Spawn added: {spawn}", tag="[✔]") if spawn.identifier == bundle_id: self.load_script(spawn.pid, resume=True) else: self.resume(spawn.pid)