Skip to content

Instantly share code, notes, and snippets.

@miticollo
Last active June 2, 2023 17:20
Show Gist options
  • Save miticollo/747d0569360ac7ebbb37e5514c474f6a to your computer and use it in GitHub Desktop.
Save miticollo/747d0569360ac7ebbb37e5514c474f6a to your computer and use it in GitHub Desktop.
frida spawn gating with send message on process termination.
#!/usr/bin/env python3
import signal
import sys
import threading
from typing import List, Tuple
import _frida
import frida
from frida.core import Session, Device, Script
pending: List[Tuple[_frida.Process, _frida.Spawn]] = []
event: threading.Event = threading.Event()
signal_event: threading.Event = threading.Event()
PREFIXES = ("/var/containers/Bundle/Application/",
"/Applications/",
"/private/var/containers/Bundle/Application/",
"/System/Library/Frameworks/")
def signal_handler(sig, frame):
print("Interrupted by Ctrl-C, stopping...")
signal_event.set()
signal.signal(signal.SIGINT, signal_handler)
def on_spawned(_spawn: _frida.Spawn):
p: _frida.Process = device.enumerate_processes([_spawn.pid], scope='full')[0]
if any(p.parameters['path'].startswith(prefix) for prefix in PREFIXES):
# this spawned process is interesting
print(f'⬆️ {p.name} (PID {p.pid}, PPID {p.parameters["ppid"]}, bundleID {_spawn.identifier}) will be resumed!')
pending.append((p, _spawn))
event.set()
else:
device.resume(_spawn.pid)
def on_message(_process: _frida.Process, message):
if message["type"] == "send":
print(f'💀 {_process.name} (PID {_process.pid}) is nearly {message["payload"]}!')
else:
print("Unhandled message:", message)
device: Device = frida.get_usb_device()
device.on('spawn-added', on_spawned)
device.on('spawn-removed', lambda _spawn: print(f'🗣 {spawn.pid} is gone!'))
device.enable_spawn_gating()
print('Press Ctrl-C to exit...')
process: _frida.Process
spawn: _frida.Spawn
sessions = []
while not signal_event.wait(.1):
if event.is_set():
while len(pending) >= 1:
process, spawn = pending.pop()
# TODO: this is a bad idea because we CAN'T hook the Safari engine!!!
if 'com.apple.WebKit.' not in process.name:
try:
session: Session = device.attach(process.pid)
sessions.append(session)
script: Script = session.create_script(source="""\
const msg = "closed";
console.log('🔄 ' + Process.id + ' loading script!');
// https://frida.re/news/2018/04/28/frida-10-8-released/#flush-before-exit
rpc.exports = {
dispose: function () {
send(JSON.stringify(msg));
console.log('👋 ' + Process.id + ' says Goodbye!');
}
};""")
script.on("message", lambda message, data, proc=process: on_message(proc, message))
script.load()
except frida.ProcessNotRespondingError as e:
print(f'🤬 {e}')
else:
print(f'⏭ {process.name} skipped!')
device.resume(spawn.pid)
event.clear()
device.disable_spawn_gating()
for session in sessions:
session.detach()
sys.exit(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment