rev-frida
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineserev-frida - Frida Script Generator
rev-frida - Frida脚本生成器
Generate Frida instrumentation scripts for dynamic analysis, hooking, and runtime inspection.
生成用于动态分析、Hook和运行时检测的Frida插桩脚本。
Important: Modern Frida CLI
重要说明:现代Frida CLI
The new Frida CLI does not have a flag. The process resumes automatically.
--no-pausebash
undefined新版Frida CLI不包含参数,进程会自动恢复运行。
--no-pausebash
undefinedSpawn and hook (process starts after script loads)
启动并Hook(脚本加载完成后进程才会启动)
frida -U -f com.example.app -l hook.js
frida -U -f com.example.app -l hook.js
Attach to running process
附加到正在运行的进程
frida -U com.example.app -l hook.js
frida -U com.example.app -l hook.js
Attach by PID
通过PID附加
frida -U -p 1234 -l hook.js
---frida -U -p 1234 -l hook.js
---Modern API Reference
现代API参考
Module & Symbol Lookup
模块与符号查找
javascript
// Get a loaded module by name
var mod = Process.getModuleByName("libssl.so");
// Module properties
mod.name // "libssl.so"
mod.base // NativePointer - base address
mod.size // module size in bytes
mod.path // full filesystem path
// Get export address directly
var ptr = mod.getExportByName("SSL_read");
// Enumerate all loaded modules
Process.enumerateModules()
// Returns: [{ name, base, size, path }, ...]
// Enumerate exports of a module
mod.enumerateExports()
// Returns: [{ type, name, address }, ...]
// Enumerate imports of a module
mod.enumerateImports()
// Returns: [{ type, name, module, address }, ...]
// Find export across all modules
var addr = Module.getExportByName(null, "open");javascript
// 通过名称获取已加载的模块
var mod = Process.getModuleByName("libssl.so");
// 模块属性
mod.name // "libssl.so"
mod.base // NativePointer - 基地址
mod.size // 模块大小,单位字节
mod.path // 完整文件系统路径
// 直接获取导出函数地址
var ptr = mod.getExportByName("SSL_read");
// 枚举所有已加载的模块
Process.enumerateModules()
// 返回: [{ name, base, size, path }, ...]
// 枚举模块的所有导出项
mod.enumerateExports()
// 返回: [{ type, name, address }, ...]
// 枚举模块的所有导入项
mod.enumerateImports()
// 返回: [{ type, name, module, address }, ...]
// 跨所有模块查找导出项
var addr = Module.getExportByName(null, "open");Interceptor
Interceptor
javascript
Interceptor.attach(ptr, {
onEnter(args) {
// args[0], args[1], ... are NativePointer
console.log("arg0:", args[0].toInt32());
console.log("arg1 str:", args[1].readUtf8String());
},
onLeave(retval) {
console.log("ret:", retval.toInt32());
// retval.replace(ptr(0x1)); // modify return value
}
});
// Replace function implementation entirely
Interceptor.replace(ptr, new NativeCallback(function (a0, a1) {
console.log("replaced!");
return 0;
}, 'int', ['pointer', 'int']));javascript
Interceptor.attach(ptr, {
onEnter(args) {
// args[0], args[1], ... 都是NativePointer类型
console.log("arg0:", args[0].toInt32());
console.log("arg1 str:", args[1].readUtf8String());
},
onLeave(retval) {
console.log("ret:", retval.toInt32());
// retval.replace(ptr(0x1)); // 修改返回值
}
});
// 完全替换函数实现
Interceptor.replace(ptr, new NativeCallback(function (a0, a1) {
console.log("replaced!");
return 0;
}, 'int', ['pointer', 'int']));NativeFunction & NativeCallback
NativeFunction & NativeCallback
javascript
// Call a native function from JS
var open = new NativeFunction(
Module.getExportByName(null, "open"),
'int', ['pointer', 'int']
);
var fd = open(Memory.allocUtf8String("/etc/hosts"), 0);
// Create a callback for native code to call
var cb = new NativeCallback(function (arg) {
console.log("called with:", arg);
return 0;
}, 'int', ['int']);javascript
// 从JS调用原生函数
var open = new NativeFunction(
Module.getExportByName(null, "open"),
'int', ['pointer', 'int']
);
var fd = open(Memory.allocUtf8String("/etc/hosts"), 0);
// 创建回调供原生代码调用
var cb = new NativeCallback(function (arg) {
console.log("called with:", arg);
return 0;
}, 'int', ['int']);Memory Operations
内存操作
javascript
// Read
ptr(addr).readByteArray(size) // ArrayBuffer
ptr(addr).readUtf8String() // string
ptr(addr).readU32() // number
ptr(addr).readPointer() // NativePointer
// Write
ptr(addr).writeByteArray(bytes)
ptr(addr).writeUtf8String("hello")
ptr(addr).writeU32(0x41414141)
// Allocate
var buf = Memory.alloc(256);
var str = Memory.allocUtf8String("hello");
// Scan memory for pattern
Memory.scan(mod.base, mod.size, "48 89 5C 24 ?? 48 89 6C", {
onMatch(address, size) {
console.log("found at:", address);
},
onComplete() {}
});javascript
// 读取
ptr(addr).readByteArray(size) // ArrayBuffer
ptr(addr).readUtf8String() // string
ptr(addr).readU32() // number
ptr(addr).readPointer() // NativePointer
// 写入
ptr(addr).writeByteArray(bytes)
ptr(addr).writeUtf8String("hello")
ptr(addr).writeU32(0x41414141)
// 分配内存
var buf = Memory.alloc(256);
var str = Memory.allocUtf8String("hello");
// 内存特征码扫描
Memory.scan(mod.base, mod.size, "48 89 5C 24 ?? 48 89 6C", {
onMatch(address, size) {
console.log("found at:", address);
},
onComplete() {}
});ObjC (iOS/macOS)
ObjC (iOS/macOS)
javascript
if (ObjC.available) {
var NSString = ObjC.classes.NSString;
// Hook ObjC method
var hook = ObjC.classes.ClassName["- methodName:"];
Interceptor.attach(hook.implementation, {
onEnter(args) {
// args[0] = self, args[1] = _cmd, args[2] = first param
var self = new ObjC.Object(args[0]);
var param = new ObjC.Object(args[2]);
console.log("self:", self.toString());
console.log("param:", param.toString());
}
});
// Enumerate classes
Object.keys(ObjC.classes).filter(c => c.includes("KeyChain"));
}javascript
if (ObjC.available) {
var NSString = ObjC.classes.NSString;
// Hook ObjC方法
var hook = ObjC.classes.ClassName["- methodName:"];
Interceptor.attach(hook.implementation, {
onEnter(args) {
// args[0] = self, args[1] = _cmd, args[2] = 第一个参数
var self = new ObjC.Object(args[0]);
var param = new ObjC.Object(args[2]);
console.log("self:", self.toString());
console.log("param:", param.toString());
}
});
// 枚举类
Object.keys(ObjC.classes).filter(c => c.includes("KeyChain"));
}Java (Android)
Java (Android)
javascript
if (Java.available) {
Java.perform(function () {
var Activity = Java.use("android.app.Activity");
Activity.onCreate.implementation = function (bundle) {
console.log("onCreate called");
this.onCreate(bundle);
};
// Enumerate loaded classes
Java.enumerateLoadedClasses({
onMatch(name) {
if (name.includes("crypto")) console.log(name);
},
onComplete() {}
});
});
}javascript
if (Java.available) {
Java.perform(function () {
var Activity = Java.use("android.app.Activity");
Activity.onCreate.implementation = function (bundle) {
console.log("onCreate called");
this.onCreate(bundle);
};
// 枚举已加载的类
Java.enumerateLoadedClasses({
onMatch(name) {
if (name.includes("crypto")) console.log(name);
},
onComplete() {}
});
});
}Script Generation Guidelines
脚本生成规范
When generating Frida scripts:
- Always use modern API — ,
Process.getModuleByName(), not deprecatedmod.getExportByName()Module.findBaseAddress() - No — the new Frida CLI does not support this flag
--no-pause - Handle module load timing — if hooking early, check if the module is loaded first:
javascript
function hookWhenReady(moduleName, exportName, callbacks) { var mod = Process.findModuleByName(moduleName); if (mod) { Interceptor.attach(mod.getExportByName(exportName), callbacks); } else { var interval = setInterval(function () { mod = Process.findModuleByName(moduleName); if (mod) { clearInterval(interval); Interceptor.attach(mod.getExportByName(exportName), callbacks); } }, 100); } } - Print hex for pointers — use or
ptr.toString(16)hexdump(ptr, { length: 64 }) - Wrap in try/catch for robustness in production hooks
- Use for binary data inspection:
hexdump()javascriptconsole.log(hexdump(args[0], { offset: 0, length: 64, header: true, ansi: false }));
生成Frida脚本时请遵循以下规则:
- 始终使用现代API —— 优先使用、
Process.getModuleByName(),不要使用已废弃的mod.getExportByName()Module.findBaseAddress() - 不要使用参数 —— 新版Frida CLI不支持该参数
--no-pause - 处理模块加载时机 —— 如果需要在进程启动早期Hook,先检查模块是否已加载:
javascript
function hookWhenReady(moduleName, exportName, callbacks) { var mod = Process.findModuleByName(moduleName); if (mod) { Interceptor.attach(mod.getExportByName(exportName), callbacks); } else { var interval = setInterval(function () { mod = Process.findModuleByName(moduleName); if (mod) { clearInterval(interval); Interceptor.attach(mod.getExportByName(exportName), callbacks); } }, 100); } } - 指针使用十六进制格式打印 —— 推荐使用或
ptr.toString(16)hexdump(ptr, { length: 64 }) - 使用try/catch包裹逻辑 提升生产环境Hook的鲁棒性
- 使用查看二进制数据:
hexdump()javascriptconsole.log(hexdump(args[0], { offset: 0, length: 64, header: true, ansi: false }));