|
|
@@ -0,0 +1,167 @@
|
|
|
+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/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/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()
|