# -*- coding: utf-8 -*- import frida from frida_tools.application import Reactor class Application(object): def __init__(self): self._reactor = Reactor(run_until_return=self._process_input) self._device = None self._session = None def run(self): self._reactor.schedule(lambda: self._start()) self._reactor.run() def _start(self): device = frida.get_remote_device() self._device = device session = self._device.attach("hello2", persist_timeout=30) self._session = session session.on('detached', lambda *args: self._reactor.schedule(lambda: self._on_detached(*args))) script = session.create_script(""" let _puts = null; Interceptor.attach(DebugSymbol.getFunctionByName('f'), { onEnter(args) { const n = args[0].toInt32(); send(n); } }); rpc.exports.dispose = () => { puts('Script unloaded'); }; let serial = 1; setInterval(() => { puts(`Agent still here! serial=${serial++}`); }, 5000); function puts(s) { if (_puts === null) { _puts = new NativeFunction(Module.getExportByName(null, 'puts'), 'int', ['pointer']); } _puts(Memory.allocUtf8String(s)); } """) self._script = script script.on('message', lambda *args: self._reactor.schedule(lambda: self._on_message(*args))) script.load() def _process_input(self, reactor): while True: try: command = input("> ").strip() except: self._reactor.cancel_io() return if command == "resume": try: self._session.resume() except Exception as e: print("Failed to resume:", e) else: print("Unknown command") def _on_detached(self, reason, crash): print("⚡ detached: reason={}, crash={}".format(reason, crash)) def _on_message(self, message, data): print("⚡ message: {}".format(message)) app = Application() app.run()