第 6 章 Frida 动态插桩
Frida 是跨平台动态插桩框架(Android/iOS/Windows/Linux/macOS),能在不重打包的前提下注入 JS 代码,Hook 函数、改参数、改返回值、扫内存。它是移动逆向和现代恶意样本分析的第一动态工具。
📍 知识点地图 | 主题:Frida动态插桩 | 前置:第5章 | 后续:第10-11章 | 核心概念:Hook、onEnter/onLeave、Java层、Objection
6.1 核心概念
你的 JS 脚本(Hook 逻辑)
↓
Frida 注入到目标进程
↓
拦截函数调用: onEnter(参数) / onLeave(返回值)
↓
修改或观察 → 打印 / 存储 / 直接改
两种启动方式:
# attach: 附加到已运行进程
frida -U -n com.example.app
# spawn: 启动时注入(能在早期代码执行前 Hook,绕过反调试首选)
frida -U -f com.example.app -l hook.js
6.2 第一个 Hook(通用)
// hook.js — Hook strcmp 观察比较内容
const strcmp = Module.findExportByName(null, "strcmp");
Interceptor.attach(strcmp, {
onEnter(args) {
console.log("[strcmp] a=" + Memory.readUtf8String(args[0]));
console.log("[strcmp] b=" + Memory.readUtf8String(args[1]));
},
onLeave(retval) {
console.log("[strcmp] => " + retval.toInt32());
}
});
frida -U -f com.example.app -l hook.js
6.3 常用模式速查
观察 vs 修改
// 只观察(推荐先观察)
onEnter(args) { console.log(...); }
// 修改返回值(Hook 验证逻辑、绕检测)
onLeave(retval) { retval.replace(0); }
// 修改参数
onEnter(args) { args[0] = Memory.allocUtf8String("new_value"); }
按名称 Hook
// 任意模块导出函数
Interceptor.attach(Module.findExportByName("libc.so", "open"), {...});
// 未导出函数按地址
Interceptor.attach(ptr("0x7a0b1c00"), {...});
Stalker 指令跟踪
Stalker.follow(threadId, {
events: { call: true },
onCallSummary(summary) { console.log(JSON.stringify(summary)); }
});
6.4 Android Java 层 Hook
Java.perform(function () {
// 1. Hook 方法并改返回值
var RootBeer = Java.use("com.scottyab.rootbeer.RootBeer");
RootBeer.isRooted.implementation = function () { return false; };
// 2. Hook 加密拿密钥(最经典的用法)
var Cipher = Java.use("javax.crypto.Cipher");
Cipher.init.overload('int', 'java.security.Key').implementation =
function (mode, key) {
console.log("[Cipher] Key bytes: " +
bytesToHex(key.getEncoded()));
return this.init(mode, key);
};
// 3. 枚举已加载类(找目标)
Java.enumerateLoadedClasses({
onMatch: function (name) {
if (name.includes("sign")) console.log(name);
},
onComplete: function () {}
});
// 4. 动态调用任意 Java 方法
var Activity = Java.use("android.app.Activity");
Java.scheduleOnMainThread(function () {
// 主线程操作
});
});
6.5 iOS Hook
// Hook ObjC 方法
var cls = ObjC.classes.NSString;
Interceptor.attach(ObjC.classes.NSString['-stringByAppendingString:']
.implementation, {
onEnter(args) {
console.log("self=" + ObjC.Object(args[0]));
console.log("param=" + ObjC.Object(args[2]));
}
});
// Hook 系统 C 函数(CCCrypt 拿密钥)
Interceptor.attach(Module.findExportByName(
"libcommonCrypto.dylib", "CCCrypt"), {
onEnter(args) {
console.log("op=" + args[0] + " alg=" + args[1]);
console.log("key=" + hexdump(args[3], {length: args[4].toInt32()}));
}
});
6.6 Objection(Frida 免脚本层)
日常移动测试 80% 的工作不需要写脚本:
objection -g "com.example.app" explore
# Android
android root disable
android sslpinning disable
android keystore list
android heap search instances com.example.Sign
android hooking list activities
# iOS
ios jailbreak disable
ios sslpinning disable
ios keychain dump
ios hooking list classes
# 通用
env
ls
sqlite connect /data/data/com.example.app/databases/db
memory dump from_base 0x0
6.7 SSL Pinning 绕过速查
# Objection 一行
objection -g "com.example.app" explore
android sslpinning disable
# Frida 通用脚本
frida -U -l ssl_pinning_bypass.js -f com.example.app
# Xposed(Android)
TrustMeAlready 模块 → 全局禁用证书校验
6.8 Root / 越狱检测绕过速查
# Objection
android root disable
ios jailbreak disable
# Frida 多层检测
Java.perform(function () {
var RootBeer = Java.use("com.scottyab.rootbeer.RootBeer");
RootBeer.isRooted.implementation = function () { return false; };
});
6.9 Frida Gadget(免 Root / 免越狱)
把 frida-gadget.so / FridaGadget.dylib 注入目标 APK/IPA,重新签名安装,即可在无 Root 设备上 Hook:
objection patchapk --source app.apk # 全自动注入+重签
# iOS: frida-gadget.dylib 注入 + re-sign
6.10 r2frida(radare2 + Frida 合体)
r2 frida://usb//com.example.app # r2 里直接操作运行中的进程
# 内存搜索、patch、dump 一步到位
6.11 Frida 高级技巧
- spawn 模式绕反调试:
-f冷启动,在onEnter里先把反调试函数返回值改掉 - 内存扫描:
Memory.scan搜特征字节 - 递归函数提速(记忆化):Hook 一个函数缓存结果,指数级提速
- Firebase Cloud Functions 绕过:Hook 拦截器层
- hook 全部 JNI 调用:观察 Java↔native 边界,判断核心逻辑在哪层
动手练习
- 在模拟器/真机上给一个普通 App 写 Hook:打印
onClick的参数和返回值。 - 用 Objection 完成一次
sslpinning disable+keystore list。 - 写一个"密钥窃取"脚本:Hook
Cipher.init打印所有密钥字节。 - 练习 spawn 模式,感受与 attach 的区别。
深入阅读
- 仓库:
skills/reverse-engineering/tools-dynamic.md(Frida 全章节:Stalker、r2frida、记忆化) - 仓库:
skills/apk-reverse/SKILL.md(Android Hook 工作流) - 仓库:
skills/mobile-reverse/references/frida-objection-deep.md(Frida/Objection 深度) - 仓库:
skills/mobile-reverse/references/anti-detection-bypass.md(多层绕过方法论) - 仓库:
skills/apk-reverse/references/frida-cookbook.md/frida-bypass-kit.md