npm install
$ frida QuakeSpasm --enable-jit -l _agent.js
$ curl -s http://localhost:1337/stats | jq
$ curl -s -X POST http://localhost:1337/attack | jq
| 'use strict'; | |
| var TrustManager; | |
| var manager; | |
| Java.perform(function () { | |
| var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager'); | |
| TrustManager = Java.registerClass({ | |
| name: 'com.example.TrustManager', |
| 'use strict'; | |
| Interceptor.attach(ptr('0x103cdbf40'), { | |
| onEnter: function (args) { | |
| send({ type: 'need-input' }); | |
| var operation = recv(function (res) { | |
| args[0] = ptr(res); | |
| }); | |
| operation.wait(); |
For adding temporary logging to help understand behavior. For when it is impractical to use Frida to instrument Frida.
Choose one of these and copy-paste it into e.g. lib/interfaces/session.vala,
then use log_event ("name='%s'", name); to log.
When something appears to be hanging, try applying: x-async-debug.patch.
| 'use strict'; | |
| const slowCallback = new NativeCallback(value => { | |
| console.log('slowCallback hit'); | |
| return 43; | |
| }, 'int', ['int']); | |
| const fastCallback = Memory.alloc(Process.pageSize); | |
| Memory.patchCode(fastCallback, 128, code => { | |
| const cw = new X86Writer(code, { pc: fastCallback }); |
| const Java = require('frida-java-bridge'); | |
| const { getApi, withRunnableArtThread, ArtStackVisitor, translateMethod } = require('frida-java-bridge/lib/android'); | |
| Java.perform(() => { | |
| const AccountManager = Java.use('android.accounts.AccountManager'); | |
| const m = AccountManager.getAccounts; | |
| m.implementation = function (...args) { | |
| console.log('getAccounts() called from: ' + JSON.stringify(captureBacktrace(), null, 2)); | |
| return m.apply(this, args); |
| /* | |
| * Try it on a running process like this: | |
| * | |
| * $ frida gimp-2.10 -l hello.js | |
| * | |
| * This uses the Frida REPL, which supports live-reload. | |
| */ | |
| Interceptor.attach(Module.getExportByName(null, 'open'), { | |
| onEnter: function (args) { |
| const THUMB_HOOK_REDIRECT_SIZE = 8; | |
| const THUMB_BIT_REMOVAL_MASK = ptr(1).not(); | |
| const trampolines: NativePointer[] = []; | |
| const replacements: NativePointer[] = []; | |
| export function makeTrampoline(target: NativePointer): NativePointer { | |
| const targetAddress = target.and(THUMB_BIT_REMOVAL_MASK); | |
| const trampoline = Memory.alloc(Process.pageSize); |
| setImmediate(function () { | |
| var NSAutoreleasePool = ObjC.classes.NSAutoreleasePool; | |
| var NSSpeechSynthesizer = ObjC.classes.NSSpeechSynthesizer; | |
| var pool = NSAutoreleasePool.alloc().init(); | |
| try { | |
| var synth = NSSpeechSynthesizer.alloc().init(); | |
| var voices = NSSpeechSynthesizer.availableVoices(); |
| const vice = Process.getModuleByName('/usr/lib/c64emu.rgl'); | |
| const mainloopOuterLoop = vice.getExportByName('maincpu_mainloop').add(0xf4); | |
| const memStore = new NativeFunction(vice.getExportByName('mem_store'), 'void', ['uint16', 'uint8'], { exceptions: 'propagate' }); | |
| const ioPending = Memory.alloc(4); | |
| const ioCallbacks = []; | |
| function poke(address, value) { | |
| schedule(() => { memStore(address, value); }); | |
| } |