rev-frida

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

rev-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
--no-pause
flag. The process resumes automatically.
bash
undefined
新版Frida CLI不包含
--no-pause
参数,进程会自动恢复运行。
bash
undefined

Spawn 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:
  1. Always use modern API
    Process.getModuleByName()
    ,
    mod.getExportByName()
    , not deprecated
    Module.findBaseAddress()
  2. No
    --no-pause
    — the new Frida CLI does not support this flag
  3. 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);
        }
    }
  4. Print hex for pointers — use
    ptr.toString(16)
    or
    hexdump(ptr, { length: 64 })
  5. Wrap in try/catch for robustness in production hooks
  6. Use
    hexdump()
    for binary data inspection:
    javascript
    console.log(hexdump(args[0], { offset: 0, length: 64, header: true, ansi: false }));
生成Frida脚本时请遵循以下规则:
  1. 始终使用现代API —— 优先使用
    Process.getModuleByName()
    mod.getExportByName()
    ,不要使用已废弃的
    Module.findBaseAddress()
  2. 不要使用
    --no-pause
    参数
    —— 新版Frida CLI不支持该参数
  3. 处理模块加载时机 —— 如果需要在进程启动早期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);
        }
    }
  4. 指针使用十六进制格式打印 —— 推荐使用
    ptr.toString(16)
    hexdump(ptr, { length: 64 })
  5. 使用try/catch包裹逻辑 提升生产环境Hook的鲁棒性
  6. 使用
    hexdump()
    查看二进制数据:
    javascript
    console.log(hexdump(args[0], { offset: 0, length: 64, header: true, ansi: false }));