Frida
2026/5/29工具工具逆向工程FridaHook大约 3 分钟
Frida
是什么
Frida 是动态插桩框架,可以在运行时 hook 函数、修改参数、观察返回值。
CTF 中常用于:
- Android Java 层 hook
- native 函数 hook
- 绕过校验或反调试
- 打印加解密中间值
安装与配置
Python 客户端:
python3 -m pip install frida-tools
frida --versionAndroid 设备需要对应架构的 frida-server,版本要和客户端匹配。
基本用法
查看进程
frida-ps -U附加进程
frida -U -n com.example.app加载脚本
frida -U -f com.example.app -l hook.jsJava Hook 示例
Java.perform(function () {
var MainActivity = Java.use("com.example.MainActivity");
MainActivity.check.implementation = function (s) {
console.log("input = " + s);
return this.check(s);
};
});更多 Hook 示例
Hook 构造函数
Java.perform(function () {
var MyClass = Java.use("com.example.MyClass");
MyClass.$init.implementation = function (arg1, arg2) {
console.log("MyClass.<init>(" + arg1 + ", " + arg2 + ")");
this.$init(arg1, arg2);
};
});Hook 静态方法
Java.perform(function () {
var Utils = Java.use("com.example.Utils");
Utils.encrypt.implementation = function (input) {
console.log("encrypt input: " + input);
var result = this.encrypt(input);
console.log("encrypt result: " + result);
return result;
};
});Hook 重载方法
Java.perform(function () {
var MyClass = Java.use("com.example.MyClass");
MyClass.process.overload("java.lang.String").implementation = function (s) {
console.log("process(String): " + s);
return this.process(s);
};
MyClass.process.overload("int").implementation = function (n) {
console.log("process(int): " + n);
return this.process(n);
};
});修改返回值
Java.perform(function () {
var MainActivity = Java.use("com.example.MainActivity");
MainActivity.check.implementation = function (s) {
console.log("bypass check: " + s);
return true; // 直接返回 true
};
});Native Hook
// Hook native 函数
Interceptor.attach(Module.findExportByName("libnative.so", "check"), {
onEnter: function (args) {
console.log("check called with: " + Memory.readUtf8String(args[0]));
},
onLeave: function (retval) {
console.log("check returned: " + retval);
retval.replace(1); // 修改返回值
}
});Hook JNI 函数
Java.perform(function () {
var env = Java.vm.getEnv();
var GetStringUTFChars = env.GetStringUTFChars;
Interceptor.attach(GetStringUTFChars.implementation, {
onEnter: function (args) {
console.log("GetStringUTFChars called");
},
onLeave: function (retval) {
console.log("GetStringUTFChars result: " + Memory.readUtf8String(retval));
}
});
});枚举类和方法
Java.perform(function () {
Java.enumerateLoadedClasses({
onMatch: function (className) {
if (className.includes("com.example")) {
console.log("Found class: " + className);
}
},
onComplete: function () {}
});
});Hook Android API
Java.perform(function () {
// Hook SharedPreferences
var SharedPreferences = Java.use("android.app.SharedPreferencesImpl");
SharedPreferences.getString.implementation = function (key, defValue) {
var result = this.getString(key, defValue);
console.log("SharedPreferences.getString(" + key + ") = " + result);
return result;
};
// Hook Log
var Log = Java.use("android.util.Log");
Log.d.overload("java.lang.String", "java.lang.String").implementation = function (tag, msg) {
console.log("Log.d: " + tag + ": " + msg);
this.d(tag, msg);
};
});读写内存
// 读取内存
var addr = Module.findBaseAddress("libnative.so").add(0x1234);
console.log("Value at addr: " + Memory.readInt(addr));
// 写入内存
Memory.writeInt(addr, 0);
// 读取字符串
console.log("String: " + Memory.readUtf8String(addr));CTF常用技巧
打印校验函数参数
先用 JADX 找到可疑函数,再用 Frida hook 参数和返回值。
绕过返回值
MainActivity.check.implementation = function (s) {
console.log("bypass check: " + s);
return true;
};WP 中要继续分析原理,不要只写绕过。
native hook
使用 Module.findExportByName 或 Interceptor.attach 追踪 so 函数。
反调试绕过
// 绕过 ptrace 检测
Interceptor.attach(Module.findExportByName(null, "ptrace"), {
onEnter: function (args) {
console.log("ptrace called");
},
onLeave: function (retval) {
retval.replace(0);
}
});
// 绕过 Debugger 检测
Java.perform(function () {
var Debug = Java.use("android.os.Debug");
Debug.isDebuggerConnected.implementation = function () {
return false;
};
});打印调用栈
Java.perform(function () {
var MainActivity = Java.use("com.example.MainActivity");
MainActivity.check.implementation = function (s) {
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
return this.check(s);
};
});常见问题
版本不匹配
frida 客户端和 frida-server 版本需要一致或接近。
找不到类
确认包名、类名、加载时机。可能需要等待类加载。
// 等待类加载
Java.perform(function () {
Java.enumerateLoadedClasses({
onMatch: function (name) {
if (name === "com.example.MyClass") {
// hook 逻辑
}
},
onComplete: function () {}
});
});App 闪退
可能有反 Frida 检测或脚本错误。先最小 hook 测试。
反 Frida 检测绕过
// 修改 frida-server 默认端口
// frida-server -l 0.0.0.0:8888
// 使用 frida-gadget 注入
// 修改 frida 默认特征关联
- APK逆向基础
- JNI深入
- 动态调试基础
- JADX
- Ghidra