| name | frida |
| description | Use this skill whenever writing, debugging, or reviewing Frida instrumentation scripts targeting iOS ARM64 or Android. Triggers include: any mention of 'Frida', 'dynamic instrumentation', 'hooking', 'Interceptor', 'Stalker', 'ObjC bridge', 'Java bridge', 'frida-server', 'frida-gadget', 'NativeFunction', or requests to hook/trace/patch native or managed functions at runtime. Also use when bypassing SSL pinning, root detection, anti-cheat systems, or Frida self-detection. Apply for both JavaScript and TypeScript agents targeting frida-tools 14+ and Frida 17.x. Do NOT use for static binary analysis (use radare2/Ghidra skills instead), build-time patching, or non-Frida instrumentation frameworks. |
Frida 17 JavaScript API Reference
Version: Frida 17.x (latest: 17.6.2, Feb 2026) · frida-tools 14+
Runtimes: QuickJS (default), V8 (opt-in) · TypeScript supported via frida-compile
Script templates: See EXAMPLES.md for ready-to-use iOS ARM64 & Android scripts.
Table of Contents
- Setup & Tooling
- Migration Notes from Frida 16.x
- Global / Script Scope
- Process
- Module
- Memory
- NativePointer
- NativeFunction & NativeCallback
- Interceptor
- Stalker
- Thread
- DebugSymbol
- CModule
- ObjC Bridge (iOS/macOS)
- Java Bridge (Android)
- Socket
- File & I/O
- Hexdump & Utilities
- Script IPC (send / recv)
- Frida.Compiler
- Arm64Writer / X86Writer / ThumbWriter
- Platform Tips: iOS ARM64
- Platform Tips: Android
- Quick Reference Table
1. Setup & Tooling
Install Frida and launch an agent against a target process over USB, TCP, or locally.
pip install frida frida-tools
frida -U -f com.example.App -l script.js
frida -U -F -l script.js
pip install frida frida-tools
frida -U -f com.example.App -l script.js
frida -U -F -l script.js
frida -H 192.168.1.10:27042 -f com.example.App -l script.js
frida -U -F
frida-compile agent.ts -o agent.js
frida-compile agent.ts -o agent.js -w
frida-trace -U -F -i "open" -I "NSURLSession*"
adb push frida-server /data/local/tmp/
adb shell "chmod +x /data/local/tmp/frida-server && /data/local/tmp/frida-server &"
2. Migration Notes from Frida 16.x
Frida 17 removed three categories of long-deprecated APIs — update existing scripts before running them against a 17.x agent.
Process.enumerateModules({ onMatch(m) { ... }, onComplete() { } });
Process.enumerateModulesSync();
for (const mod of Process.enumerateModules()) { console.log(mod.name); }
Memory.readU32(ptr('0x1234'));
Memory.writeU32(ptr('0x1234'), 100);
ptr('0x1234').readU32();
ptr('0x1234').writeU32(100);
ptr('0x1234').add(4).writeU32(10).add(4).writeU16(20);
Module.getBaseAddress('libc.so');
Module.getExportByName('libc.so', 'open');
Module.findExportByName('libc.so', 'open');
Module.ensureInitialized('libc.so');
Process.getModuleByName('libc.so').base;
Process.getModuleByName('libc.so').getExportByName('open');
Process.getModuleByName('libc.so').findExportByName('open');
Module.getGlobalExportByName('open');
import "frida-objc-bridge";
import "frida-java-bridge";
3. Global / Script Scope
Top-level globals and built-ins available in every Frida agent without any import.
const base = Process.mainModule.base;
const libc = Process.getModuleByName('libc.so');
const openAddr = libc.getExportByName('open');
send({ type: 'ready', base: base.toString() });
ptr(val)
NULL
Process
Memory
Interceptor
Stalker
Thread
DebugSymbol
CModule
Module
ObjC
Java
console
hexdump(buf)
send(msg, data?)
recv(type, cb)
rpc.exports
Script.pin();
Script.unpin();
const result = await SomeAsyncOperation();
4. Process
Provides identity, module lookup, memory range enumeration, thread listing, and exception handling for the instrumented process.
console.log(Process.id, Process.arch, Process.platform);
const libc = Process.getModuleByName('libc.so');
console.log('libc base:', libc.base, 'size:', libc.size);
Process.id
Process.arch
Process.platform
Process.pageSize
Process.pointerSize
Process.codeSigningPolicy
Process.mainModule
Process.currentDir
Process.enumerateModules()
Process.getModuleByName('libc.so')
Process.findModuleByName('libc.so')
Process.getModuleByAddress(ptr('0x1234'))
Process.findModuleByAddress(ptr('0x1234'))
Process.enumerateRanges('r-x')
Process.enumerateRanges({ protection: 'r-x', coalesce: true })
Process.enumerateMallocRanges()
Process.enumerateThreads()
Process.getCurrentThreadId()
Process.setExceptionHandler((details) => {
console.log('Exception:', details.type, details.address);
return false;
});
5. Module
Represents a loaded binary (.so, .dylib, or executable) and exposes its exports, symbols, imports, and sections.
const libc = Process.getModuleByName('libc.so');
const openFn = libc.getExportByName('open');
const readFn = libc.getExportByName('read');
console.log('open @', openFn, 'read @', readFn);
mod.name
mod.path
mod.base
mod.size
mod.enumerateImports()
mod.enumerateExports()
mod.enumerateSymbols()
mod.enumerateSections()
mod.enumerateDependencies()
mod.findExportByName('fn')
mod.getExportByName('fn')
mod.findSymbolByName('_ZN…')
mod.getSymbolByName('_ZN…')
Module.getGlobalExportByName('open')
Module.findGlobalExportByName('open')
Module.load('/path/to/lib.so')
6. Memory
Allocates, copies, protects, patches, and scans process memory.
const buf = Memory.allocUtf8String('FIND_ME');
Memory.scan(buf, 8, '46 49 4e 44', {
onMatch(addr) { console.log('found at', addr); },
onError() {},
onComplete() {}
});
Memory.alloc(256)
Memory.allocUtf8String('hello')
Memory.allocUtf16String('hello')
Memory.allocByteArray(new Uint8Array([0x90, 0x90]))
Memory.copy(dst, src, n)
Memory.dup(src, n)
Memory.protect(addr, size, 'rwx')
Memory.queryProtection(addr)
Memory.patchCode(addr, size, (code) => {
const w = new Arm64Writer(code, { pc: addr });
w.putNop();
w.flush();
});
Memory.scan(base, size, 'DE AD BE EF', {
onMatch(address, size) { console.log('found @', address); },
onError(reason) { },
onComplete() { }
});
7. NativePointer
The universal address type in Frida — every memory address is a NativePointer with built-in arithmetic, read, and write methods.
const obj = ptr('0x200000');
const vtbl = obj.readPointer();
const hp = obj.add(8).readU32();
const mp = obj.add(12).readU32();
console.log('vtable:', vtbl, 'hp:', hp, 'mp:', mp);
const p = ptr('0x100400000');
p.add(0x10) p.sub(4)
p.and(0xFFF) p.or(1) p.xor(0xFF)
p.shl(2) p.shr(1) p.not()
p.equals(q)
p.compare(q)
p.isNull()
p.toInt32() p.toUInt32()
p.toString() p.toString(16)
p.toMatchPattern()
p.readPointer()
p.readS8() p.readU8()
p.readS16() p.readU16()
p.readS32() p.readU32()
p.readS64() p.readU64()
p.readFloat() p.readDouble()
p.readByteArray(n)
p.readCString()
p.readUtf8String(len?)
p.readUtf16String(len?)
p.readAnsiString(len?)
p.writePointer(q)
p.writeS8(v) p.writeU8(v)
p.writeS16(v) p.writeU16(v)
p.writeS32(v) p.writeU32(v)
p.writeS64(v) p.writeU64(v)
p.writeFloat(v) p.writeDouble(v)
p.writeByteArray(arrayBuffer)
p.writeUtf8String('hello')
p.writeUtf16String('hello')
ptr('0x5000')
.add(8).writeU32(100)
.add(4).writeU16(42)
.add(2).writeU8(1);
8. NativeFunction & NativeCallback
Wraps a native C function so it can be called directly from JavaScript, and creates a native-callable stub backed by a JavaScript function.
const strlen = new NativeFunction(
Module.getGlobalExportByName('strlen'), 'int', ['pointer']
);
console.log('length:', strlen(Memory.allocUtf8String('hello')));
const open = new NativeFunction(
Process.getModuleByName('libc.so').getExportByName('open'),
'int',
['pointer', 'int'],
{ abi: 'default' }
);
const fd = open(Memory.allocUtf8String('/etc/hosts'), 0 );
const myHook = new NativeCallback(
(a, b) => {
console.log('called with:', a, b);
return a + b;
},
'int',
['int', 'int']
);
9. Interceptor
The primary hooking engine — attaches onEnter/onLeave callbacks to observe any native function, or replaces it entirely with a new implementation.
Interceptor.attach(Module.getGlobalExportByName('open'), {
onEnter(args) {
console.log('[open]', args[0].readCString(), 'flags:', args[1].toInt32());
},
onLeave(retval) {
console.log('[open] fd =', retval.toInt32());
}
});
const hook = Interceptor.attach(targetPtr, {
onEnter(args) {
this.savedArg = args[0].readUtf8String();
},
onLeave(retval) {
retval.replace(ptr(1));
}
});
hook.detach();
Interceptor.replace(targetPtr,
new NativeCallback((arg0) => {
console.log('replaced, arg0 =', arg0);
}, 'void', ['pointer'])
);
const origPtr = Interceptor.replaceFast(targetPtr,
new NativeCallback((arg0) => {
return new NativeFunction(origPtr, 'int', ['pointer'])(arg0);
}, 'int', ['pointer'])
);
Interceptor.revert(targetPtr);
Interceptor.flush();
10. Stalker
A dynamic code tracing engine that follows thread execution at the basic-block or instruction level, enabling coverage collection, call tracing, and inline code transformation.
Interceptor.attach(targetFn, {
onEnter() {
Stalker.follow(this.threadId, {
events: { block: true },
onReceive(events) {
for (const [, start] of Stalker.parse(events))
console.log('block @', start);
}
});
},
onLeave() {
Stalker.unfollow(this.threadId);
Stalker.flush();
Stalker.garbageCollect();
}
});
Stalker.follow(threadId, {
events: {
call: true,
ret: false,
exec: false,
block: true,
compile: false
},
transform(iterator) {
let instr = iterator.next();
while (instr !== null) {
iterator.putCallout((ctx) => { });
iterator.keep();
instr = iterator.next();
}
},
onReceive(events) {
const parsed = Stalker.parse(events, { annotate: true, stringify: false });
},
onCallSummary(summary) {
}
});
Stalker.unfollow(threadId)
Stalker.flush()
Stalker.garbageCollect()
Stalker.isFollowing(threadId)
Stalker.exclude({ base: mod.base, size: mod.size })
Stalker.queueCapacity = 16384
Stalker.queueDrainInterval = 250
11. Thread
Enumerates process threads, generates symbolicated backtraces, and provides sleep control for the current thread.
Interceptor.attach(targetFn, {
onEnter(args) {
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress)
.forEach(s => console.log(' ', s.toString()));
}
});
Process.enumerateThreads()
Process.getCurrentThreadId()
Thread.sleep(0.5)
Thread.backtrace(context, Backtracer.ACCURATE)
Thread.backtrace(context, Backtracer.FUZZY)
12. DebugSymbol
Resolves memory addresses to human-readable symbol names and source locations, and looks up addresses by symbol name.
Thread.backtrace(this.context, Backtracer.FUZZY)
.forEach(addr => console.log(DebugSymbol.fromAddress(addr).toString()));
const sym = DebugSymbol.fromAddress(ptr('0x100403f10'));
sym.address
sym.name
sym.moduleName
sym.fileName
sym.lineNumber
sym.toString()
const sym2 = DebugSymbol.fromName('_ZN7UObjectL13ProcessEventEPS_P9UFunctionPv');
DebugSymbol.load(Process.getModuleByName('libgame.so').path);
13. CModule
Compiles and links a snippet of C source code into the process at runtime, producing native callbacks with zero JavaScript overhead — ideal for hot hooks and performance-critical instrumentation.
const cm = new CModule(`
#include <stdint.h>
static uint32_t hits = 0;
void on_enter(void) { hits++; }
uint32_t get_hits(void) { return hits; }
`);
Interceptor.attach(targetFn, { onEnter: cm.on_enter });
const getHits = new NativeFunction(cm.get_hits, 'uint32', []);
console.log('hits:', getHits());
const cm = new CModule(`
#include <gum/guminterceptor.h> // GumInvocationContext etc.
#include <stdint.h>
// Available: GumStalker, GumInterceptor, gum_* APIs, standard C headers
extern void imported_fn(void); // symbol imported from JS
static uint32_t call_count = 0;
void on_enter(GumInvocationContext * ic) { call_count++; }
uint32_t get_count(void) { return call_count; }
`,
{ imported_fn: someNativeFuncPtr }
);
cm.on_enter
cm.get_count
Interceptor.attach(target, { onEnter: cm.on_enter });
const getCount = new NativeFunction(cm.get_count, 'uint32', []);
console.log('calls:', getCount());
cm.dispose();
14. ObjC Bridge (iOS/macOS)
Exposes the Objective-C runtime, letting you look up classes and protocols, hook instance and class methods, intercept and replace blocks, and schedule work on the main queue.
Interceptor.attach(
ObjC.classes.NSURLSession['- dataTaskWithRequest:completionHandler:'].implementation,
{
onEnter(args) {
const req = new ObjC.Object(args[2]);
console.log('[NSURLSession] URL:', req.URL().absoluteString().toString());
}
}
);
ObjC.available
const NSString = ObjC.classes.NSString;
NSString['+ stringWithUTF8String:']
NSString['- length']
const obj = new ObjC.Object(ptr);
obj.$className
obj.$methods
obj.$ownMethods
obj.description()
obj.retain() obj.release() obj.autorelease()
ObjC.enumerateLoadedClasses()
const proto = ObjC.protocols.NSURLSessionDelegate;
proto.methods
const block = new ObjC.Block({
retType: 'void',
argTypes: ['pointer'],
implementation(arg) { console.log('block called', arg); }
});
const existing = new ObjC.Block(args[3]);
existing.implementation = (arg) => { };
ObjC.selector('viewDidLoad')
ObjC.selectorAsString(selPtr)
ObjC.schedule(ObjC.mainQueue, () => {
const pool = ObjC.classes.NSAutoreleasePool.alloc().init();
pool.release();
});
15. Java Bridge (Android)
Exposes the Android ART/JVM runtime, enabling you to hook Java methods, access static fields, instantiate classes, enumerate live objects on the heap, and work with custom class loaders.
Java.perform(() => {
const GameManager = Java.use('com.example.game.GameManager');
GameManager.isUserPremium.implementation = function() {
console.log('[+] isUserPremium hooked → true');
return true;
};
});
Java.available
Java.perform(() => {
const Activity = Java.use('android.app.Activity');
Activity.onResume.implementation = function() {
console.log('[+] onResume:', this.getClass().getName());
this.onResume();
};
Activity.startActivity
.overload('android.content.Intent')
.implementation = function(intent) {
console.log('[+] intent:', intent.toString());
this.startActivity(intent);
};
const Build = Java.use('android.os.Build');
console.log('Model:', Build.MODEL.value);
Build.MODEL.value = 'Pixel 9 Pro';
const Intent = Java.use('android.content.Intent');
const i = Intent.$new('android.intent.action.VIEW');
const Runnable = Java.use('java.lang.Runnable');
const r = Java.cast(somePtr, Runnable);
Java.choose('com.example.game.GameManager', {
onMatch(instance) { console.log('[+] found:', instance); },
onComplete() {}
});
const retained = Java.retain(instance);
Java.scheduleOnMainThread(() => { });
Java.enumerateClassLoaders({
onMatch(loader) {
try { console.log(loader.loadClass('com.hidden.X')); } catch(e) {}
},
onComplete() {}
});
Java.enumerateLoadedClasses({
onMatch(name) { if (name.includes('cheat')) console.log(name); },
onComplete() {}
});
});
const env = Java.vm.getEnv();
const jstring = env.newStringUtf('hello from JNI');
16. Socket
Creates outbound TCP/UDP connections or inbound listeners directly from within the agent, useful for building a side-channel without going through send()/recv().
const conn = await Socket.connect({ family: 'ipv4', host: '127.0.0.1', port: 9999 });
await conn.output.writeAll(new TextEncoder().encode('hello\n'));
await conn.close();
const conn = await Socket.connect({
family: 'ipv4',
host: '127.0.0.1',
port: 1337
});
await conn.output.writeAll(new Uint8Array([0x01, 0x02, 0x03]));
const data = await conn.input.read(256);
await conn.close();
const listener = await Socket.listen({ family: 'ipv4', host: '0.0.0.0', port: 9999 });
const accepted = await listener.accept();
17. File & I/O
Reads and writes files on the device filesystem directly from the agent — useful for dumping memory regions, reading /proc entries, or writing logs without going through the host.
console.log(new File('/proc/self/maps', 'r').readText());
const f = new File('/path/to/file', 'r');
f.read(n)
f.readText()
f.readLine()
f.write(data)
f.flush()
f.seek(offset, whence)
f.tell()
f.close()
const out = new File('/tmp/memdump.bin', 'wb');
out.write(ptr('0x100000000').readByteArray(0x1000));
out.flush();
out.close();
18. Hexdump & Utilities
Pretty-prints memory as a hex + ASCII dump, and provides Int64/UInt64 types for safely handling 64-bit values beyond JavaScript's safe integer range.
console.log(hexdump(Process.mainModule.base, { length: 64, header: true, ansi: true }));
hexdump(target, options)
const big = new Int64('0xDEADBEEFCAFEBABE');
const u = new UInt64('18446744073709551615');
big.add(1) big.sub(1) big.and(mask)
big.or(v) big.xor(v) big.shl(n) big.shr(n) big.not()
big.compare(other)
big.toNumber() big.toString() big.toString(16)
const ab = somePtr.readByteArray(16);
const buf = Memory.alloc(16);
buf.writeByteArray(ab);
19. Script IPC (send / recv)
Provides bidirectional messaging between the in-process JS agent and the Python/Node.js host, and an rpc.exports object for synchronous remote procedure calls.
Interceptor.attach(targetFn, {
onEnter(args) { send({ type: 'hit', arg: args[0].readCString() }); }
});
rpc.exports = {
getModules() {
return Process.enumerateModules().map(m => ({ name: m.name, base: m.base.toString() }));
}
};
send({ type: 'log', msg: 'hello' })
send({ type: 'dump' }, somePtr.readByteArray(64))
recv('command', (msg) => {
console.log('got command:', msg.payload.action);
recv('command', arguments.callee);
});
rpc.exports = {
dumpMemory(addrHex, size) {
return ptr(addrHex).readByteArray(size);
},
patchAddress(addrHex, value) {
ptr(addrHex).writeU32(value);
}
};
import frida, sys
def on_message(msg, data):
if msg['type'] == 'send':
print('[agent]', msg['payload'])
device = frida.get_usb_device()
session = device.attach('com.example.game')
script = session.create_script(open('agent.js').read())
script.on('message', on_message)
script.load()
modules = script.exports.get_modules()
dump = script.exports.dump_memory('0x12345678', 256)
script.post({'type': 'command', 'payload': {'action': 'start'}})
sys.stdin.read()
20. Frida.Compiler
Compiles TypeScript (or modern JavaScript with ESM imports) into a self-contained bundle loadable as a Frida agent, replacing any manual Node.js build step.
frida-compile agent/index.ts -o bundle.js
frida-compile agent/index.ts -o bundle.js -w
import frida, asyncio
async def main():
compiler = frida.Compiler()
bundle = await compiler.build('agent/index.ts', compression='terser')
session = await frida.get_usb_device_async().attach_async('com.example.App')
script = await session.create_script_async(bundle)
await script.load_async()
asyncio.run(main())
import "frida-objc-bridge";
import "frida-java-bridge";
const openAddr: NativePointer = Module.getGlobalExportByName('open');
Interceptor.attach(openAddr, {
onEnter(args: InvocationArguments) {
console.log('[open]', args[0].readCString());
}
});
21. Arm64Writer / X86Writer / ThumbWriter
Emit machine instructions into a writable code buffer — used inside Memory.patchCode() to build patches, trampolines, or inline stubs without hand-encoding raw bytes.
Memory.patchCode(targetAddr, 16, (code) => {
const w = new Arm64Writer(code, { pc: targetAddr });
w.putNop(); w.putNop(); w.putNop(); w.putNop();
w.flush();
});
Memory.patchCode(targetAddr, 64, (code) => {
const w = new Arm64Writer(code, { pc: targetAddr });
w.putNop()
w.putBImm(destAddr)
w.putBCondImm('eq', destAddr)
w.putBlImm(funcAddr)
w.putLdrRegAddress('x0', dataAddr)
w.putMovRegReg('x1', 'x0')
w.putRetReg('x30')
w.putInstruction(0xD503201F)
w.putLabel('loop_top')
w.putBCondLabel('ne', 'loop_top')
w.flush()
});
Memory.patchCode(targetAddr, 32, (code) => {
const w = new X86Writer(code, { pc: targetAddr });
w.putNop()
w.putRet()
w.putJmpAddress(destAddr)
w.putCallAddress(funcAddr)
w.flush()
});
Memory.patchCode(targetAddr, 8, (code) => {
const w = new ThumbWriter(code, { pc: targetAddr });
w.putNop()
w.putBImm(destAddr)
w.flush()
});
22. Platform Tips: iOS ARM64
Practical patterns for working with iOS binaries: ASLR slide calculation, converting IDA Pro offsets to runtime addresses, Swift symbol demangling, and ObjC class discovery.
const runtimeAddr = Process.mainModule.base.add(ptr('0x1000403F0').sub(ptr('0x100000000')));
Interceptor.attach(runtimeAddr, { onEnter() { console.log('hit'); } });
const app = Process.mainModule;
const slide = app.base.sub(ptr('0x100000000'));
console.log('App:', app.name, '@ base', app.base, '(slide', slide, ')');
const IDA_BASE = ptr('0x100000000');
const fromIDA = (va) => app.base.add(ptr(va).sub(IDA_BASE));
Interceptor.attach(fromIDA('0x100123456'), { onEnter() { console.log('hit'); } });
Object.keys(ObjC.classes)
.filter(n => n.startsWith('Game'))
.forEach(n => console.log(n, '→', ObjC.classes[n].$ownMethods.slice(0, 5)));
const swiftCore = Process.getModuleByName('libswiftCore.dylib');
const demangleFn = swiftCore.findExportByName('swift_demangle_getDemangledName')
?? swiftCore.findExportByName('swift_demangle');
if (demangleFn) {
const demangle = new NativeFunction(demangleFn, 'pointer',
['pointer', 'pointer', 'pointer', 'pointer', 'uint32']);
const sym = Memory.allocUtf8String('_$s9TargetApp14GameControllerC10checkCheatyyF');
const outBuf = Memory.alloc(256);
const result = demangle(sym, NULL, outBuf, ptr(256), 0);
if (!result.isNull()) console.log('demangled:', result.readCString());
}
const swiftFn = app.findSymbolByName('_$s9TargetApp14GameControllerC10checkCheatyyF');
if (swiftFn) {
Interceptor.attach(swiftFn, { onLeave(retval) { retval.replace(ptr(0)); } });
}
23. Platform Tips: Android
Practical patterns for Android: waiting for native library load via dlopen, intercepting RegisterNatives to discover JNI bindings, and accessing ART internals.
function whenLoaded(libName, cb) {
if (Process.findModuleByName(libName)) { cb(Process.getModuleByName(libName)); return; }
const dlopen = Module.getGlobalExportByName('android_dlopen_ext')
?? Module.getGlobalExportByName('dlopen');
let done = false;
Interceptor.attach(dlopen, {
onLeave() {
if (!done && Process.findModuleByName(libName)) {
done = true; cb(Process.getModuleByName(libName));
}
}
});
}
whenLoaded('libgame.so', mod => {
const check = mod.findExportByName('checkLicense');
if (check) Interceptor.attach(check, { onLeave(r) { r.replace(ptr(1)); } });
});
console.log(new File('/proc/self/maps', 'r').readText());
const libart = Process.getModuleByName('libart.so');
const regNat = libart.findExportByName(
'_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi');
if (regNat) {
Interceptor.attach(regNat, {
onEnter(args) {
const count = args[3].toInt32();
for (let i = 0; i < count; i++) {
const entry = args[2].add(i * 3 * Process.pointerSize);
const name = entry.readPointer().readCString();
const sig = entry.add(Process.pointerSize).readPointer().readCString();
const fn = entry.add(Process.pointerSize * 2).readPointer();
console.log(`[RegisterNatives] ${name}${sig} → ${fn}`);
}
}
});
}
Java.perform(() => {
const env = Java.vm.getEnv();
const cls = env.findClass('com/example/Target');
const mid = env.getMethodID(cls, 'secretMethod', '()V');
console.log('Method ID:', mid);
const tramp = Process.getModuleByName('libart.so')
.findExportByName('artQuickGenericJniTrampoline');
if (tramp) Interceptor.attach(tramp, { onEnter(args) { } });
});
Java.perform(() => {
const VMRuntime = Java.use('dalvik.system.VMRuntime');
console.log('Target SDK:', VMRuntime.getRuntime().targetSdkVersion());
});
24. Quick Reference Table
| Goal | Frida 17 API |
|---|
| Get module base | Process.getModuleByName('lib.so').base |
| Get export address | Process.getModuleByName('lib.so').getExportByName('fn') |
| Global export (any module) | Module.getGlobalExportByName('open') |
| Hook function (observe) | Interceptor.attach(addr, { onEnter, onLeave }) |
| Replace function | Interceptor.replace(addr, new NativeCallback(…)) |
| Fast replace (no overhead) | Interceptor.replaceFast(addr, new NativeCallback(…)) |
| Read memory | ptr('0x…').readU32() |
| Write memory | ptr('0x…').writeU32(val) |
| Chain writes | ptr('0x…').add(4).writeU32(x).add(4).writeU16(y) |
| Allocate buffer | Memory.alloc(size) |
| Patch code (W^X safe) | Memory.patchCode(addr, size, writerCb) |
| Scan memory for bytes | Memory.scan(base, size, 'AA BB ?? DD', callbacks) |
| Enumerate modules | Process.enumerateModules() |
| Enumerate memory ranges | Process.enumerateRanges('r-x') |
| Call native function | new NativeFunction(ptr, retType, argTypes)(…) |
| Hook ObjC method | Interceptor.attach(ObjC.classes.Cls['- m'].implementation, …) |
| Hook Java method | Java.perform(() => Java.use('Cls').method.implementation = fn) |
| Backtrace | Thread.backtrace(this.context, Backtracer.ACCURATE) |
| Resolve symbol | DebugSymbol.fromAddress(addr).toString() |
| Trace execution | Stalker.follow(tid, { events: { block: true }, onReceive }) |
| Send to Python host | send({ type: 'x', data: val }) |
| Receive from Python host | recv('type', callback) |
| Expose function as RPC | rpc.exports = { fnName(args) { … } } |
| Inline C for hot hooks | new CModule('void f() { … }') |
| Emit ARM64 instructions | new Arm64Writer(code, { pc: addr }).putNop().flush() |
| IDA offset → runtime addr | app.base.add(ptr(ida_va).sub(ptr('0x100000000'))) |
For ready-to-use script templates, see EXAMPLES.md.