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); }); | |
} |