import frida from 'frida' import fs from 'fs' import url from 'url' import path from 'path' import util from 'util' import Vorpal from 'vorpal' import { spawn, execSync } from 'child_process' import { setTimeout } from 'timers/promises' const filePath = url.fileURLToPath(import.meta.url) const __dirname = path.dirname(filePath) function loadSource(filePath) { Log.s(`Loading ${filePath}`) return fs.readFileSync(path.resolve(__dirname, filePath)).toString() } class Log { static TAG = '' static format(...msg) { let m = [] for (let i = 0; i < msg.length; i++) { if (typeof msg[i] === 'object') { if ('[object Object]' === msg[i].toString()) { m.push(util.inspect(msg[i])) } } else { m.push(msg[i]) } } m = m.join(' ') return m } static i(...msg) { console.log(`\x1b[30m${this.TAG} ${this.format(...msg)}\x1b[0m`) } static w(...msg) { console.log(`\x1b[33m${this.TAG} ${this.format(...msg)}\x1b[0m`) } static e(...msg) { console.log(`\x1b[31m${this.TAG} ${this.format(...msg)}\x1b[0m`) } static s(...msg) { console.log(`\x1b[32m${this.TAG} ${this.format(...msg)}\x1b[0m`) } } let device = null let tracers = [] async function stop() { Log.i('[*] Stopping all tracers') for (const tracer of tracers) { Log.i('[*] Stopping', tracer.pid) tracer.session.detach() try { await device.kill(tracer.pid) } catch (error) {} } process.exit(1) } process.on('SIGTERM', stop) process.on('SIGINT', stop) async function main() { device = await frida.getUsbDevice() device.spawnAdded.connect(onSpawnAdded) Log.i('[*] Enabling spawn gating') await device.enableSpawnGating() Log.i('[*] Enabled spawn gating') // Log.i("[*] Spawning com.google.android.apps.messaging") // const pid = await device.spawn("com.google.android.apps.messaging") // Log.i("[*] Spawned com.google.android.apps.messaging: " + pid) // const tracer = await Tracer.open(pid) // tracers.push(tracer) const processes = await device.enumerateProcesses() for (const process of processes) { if (process.name.startsWith('com.google.android.apps.messaging') || process.name.startsWith('信息')) { console.log('[*] Attaching to', process.pid, process.name) const session = await device.attach(process.pid) const script = await session.createScript(loadSource('../scripts/spoof_sms.js')) await script.load() } } } async function onSpawnAdded(spawn) { try { if (spawn.identifier.startsWith('com.google.android.apps.messaging')) { Log.i('[*] Tracing', spawn.pid, spawn.identifier) const tracer = await Tracer.open(spawn.pid, '../scripts/spoof_sms.js') tracers.push(tracer) } else { Log.i('[*] Resuming', spawn.pid, spawn.identifier) await device.resume(spawn.pid) } } catch (e) { Log.e(`err: ${e}`) } } class Tracer { static async open(pid, source) { const tracer = new Tracer(pid, source) await tracer._initialize() return tracer } constructor(pid, sourceFile) { this.pid = pid this.sourceFile = sourceFile this.source = loadSource(sourceFile) this.session = null this.script = null } async _initialize() { const session = await device.attach(this.pid) this.session = session session.detached.connect(this._onSessionDetached.bind(this)) const script = await session.createScript(this.source) this.script = script script.message.connect(this._onScriptMessage.bind(this)) await script.load() // const script_ssl = await session.createScript(source_ssl) // await script_ssl.load() try { await device.resume(this.pid) } catch (e) { Log.e(e) } } async reload() { if (this.script) { this.script.unload() } this.source = loadSource(this.sourceFile) this.script = await this.session.createScript(this.source) this.script.message.connect(this._onScriptMessage.bind(this)) await this.script.load() } _onSessionDetached(reason) { Log.i(`[PID ${this.pid}] onSessionDetached(reason='${reason}')`) const i = tracers.findIndex((tracer) => tracer.pid === this.pid) if (i !== -1) { tracers.splice(i, 1) } } _onScriptMessage(message, data) { if (message.type === 'error') { Log.e(`[PID ${this.pid}] onScriptMessage()`, message, data ? JSON.stringify(data) : '') } else { Log.i(`[PID ${this.pid}] onScriptMessage()`, message, data ? JSON.stringify(data) : '') } } } main()