21、Frida基础:Hook Java方法、参数修改、返回值篡改
说到移动安全测试,Frida 绝对是个绕不开的工具。我个人觉得,它就像一把瑞士军刀——轻巧、灵活,关键时刻能解决大问题。今天咱们聊聊 Frida 最核心的用法:Hook Java 方法、改参数、篡改返回值。
说白了,Frida 能让你在 App 运行时“偷梁换柱”。你不需要改 APK,不需要重打包,只要写一段 JavaScript 脚本,就能拦截目标方法,看看它传了什么参数,返回了什么结果,甚至直接改掉它们。我在项目中遇到过好几次,App 的签名校验、加密逻辑,都是靠 Frida 一把梭搞定的。
环境准备
先确认你的环境。Frida 分两部分:电脑端和手机端。
- 电脑端:安装 frida-tools,命令是
pip install frida-tools - 手机端:下载对应架构的 frida-server,推送到手机并运行
嗯,这里要注意:frida-server 的版本必须和电脑端的 frida 版本一致,否则连不上。我曾经因为版本号差了一个小版本,折腾了半小时才发现问题。
核心命令:
# 启动 frida-server(手机端)
adb push frida-server-16.0.1-android-arm64 /data/local/tmp/
adb shell chmod 755 /data/local/tmp/frida-server-16.0.1-android-arm64
adb shell /data/local/tmp/frida-server-16.0.1-android-arm64 &
Hook Java 方法:从入门到实战
Frida 的 Hook 机制,本质上是在运行时修改 Java 方法的实现。你想想看,App 跑着跑着,突然某个方法的逻辑被你替换了,这种感觉很爽。
先看一个最简单的例子:Hook 一个无参方法。
// hook_demo.js
Java.perform(function() {
var TargetClass = Java.use('com.example.target.MainActivity');
TargetClass.secretMethod.implementation = function() {
console.log('[+] secretMethod 被调用了!');
return this.secretMethod();
};
});
运行命令:frida -U -l hook_demo.js com.example.target
这里我解释一下:Java.use() 是获取 Java 类的引用,.implementation 是替换方法的实现。注意,在替换后的函数里,如果你想调用原始方法,必须用 this.secretMethod(),否则会死循环。
个人习惯:我一般会在 Hook 脚本开头加一个 console.log('[+] Script loaded'),确认脚本已经注入成功。不然有时候脚本没加载,你还在那傻等输出。
参数修改:让 App 按你的想法走
很多时候,我们需要修改方法的参数。比如某个登录方法,传入了用户名和密码,你想看看如果传一个空字符串会怎样。
Java.perform(function() {
var LoginClass = Java.use('com.example.app.LoginManager');
LoginClass.login.implementation = function(username, password) {
console.log('[+] 原始参数: ' + username + ', ' + password);
// 修改参数
username = 'admin';
password = '123456';
console.log('[+] 修改后参数: ' + username + ', ' + password);
return this.login(username, password);
};
});
为什么会这样?因为 Frida 的 Hook 函数里,参数是 JavaScript 变量,你可以随意赋值。但要注意类型匹配——如果原方法参数是 int,你传个字符串进去,App 可能会崩溃。
避坑指南:我曾经在 Hook 一个加密方法时,把 byte[] 参数改成了字符串,结果 App 直接闪退。后来才发现,Java 的 byte[] 在 Frida 里对应的是 Java.array('byte', [0x01, 0x02]),不能直接用字符串。
返回值篡改:让 App 以为一切正常
返回值篡改是安全测试的常用手段。比如 App 做了签名校验,返回 true 表示校验通过,false 表示失败。我们直接让它永远返回 true。
Java.perform(function() {
var SignCheck = Java.use('com.example.security.SignChecker');
SignCheck.verifySign.implementation = function() {
console.log('[+] 签名校验被调用,直接返回 true');
return true;
};
});
更复杂的情况:如果方法返回一个对象,我们可以修改对象的字段。
Java.perform(function() {
var UserInfo = Java.use('com.example.model.UserInfo');
UserInfo.getUserStatus.implementation = function() {
var result = this.getUserStatus();
console.log('[+] 原始状态: ' + result.isVip.value);
result.isVip.value = true; // 修改为 VIP
result.expireTime.value = '2099-12-31';
return result;
};
});
注意,Java 对象的字段在 Frida 里需要通过 .value 来访问和修改。这是 Frida 的一个小坑,我刚开始用的时候经常忘记。
知识体系总览
下面这张图概括了 Frida Hook 的核心流程和关键点:
实战:Hook 一个带复杂参数的方法
咱们来个综合例子。假设 App 有一个加密方法:
public class CryptoHelper {
public String encrypt(String plainText, byte[] key, int mode) {
// 实际加密逻辑
return "encrypted_data";
}
}
我们要 Hook 它,打印参数,修改明文,然后篡改返回值。
Java.perform(function() {
var CryptoHelper = Java.use('com.example.security.CryptoHelper');
CryptoHelper.encrypt.implementation = function(plainText, key, mode) {
console.log('[+] 原始明文: ' + plainText);
console.log('[+] 原始密钥长度: ' + key.length);
console.log('[+] 加密模式: ' + mode);
// 修改明文
plainText = 'hacked_data';
// 构造新的密钥(注意 byte[] 的构造方式)
var newKey = Java.array('byte', [0x01, 0x02, 0x03, 0x04]);
// 调用原始方法
var result = this.encrypt(plainText, newKey, mode);
console.log('[+] 原始返回值: ' + result);
// 篡改返回值
var fakeResult = 'fake_encrypted_' + plainText;
console.log('[+] 篡改后返回值: ' + fakeResult);
return fakeResult;
};
});
个人经验:在实际测试中,我经常先打印所有参数和返回值,看看 App 在正常情况下的行为。然后再逐步修改参数,观察 App 的反应。这样能快速定位关键逻辑。
常见问题与调试技巧
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 脚本注入后无输出 | 方法名写错或类未加载 | 用 Java.enumerateLoadedClasses() 确认类名 |
| App 崩溃 | 参数类型不匹配 | 检查 Java 方法签名,用 $dispose 清理 |
| 无法 Hook 静态方法 | 忘记用 Java.perform() |
所有 Hook 代码必须包裹在 Java.perform() 内 |
| 返回值修改无效 | 原始方法返回基本类型 | 基本类型直接 return 新值,对象类型需修改字段 |
嗯,这里还要提一点:Frida 的 Java.perform() 是异步的,如果你的脚本里有多个 Hook,最好用 setTimeout 或者 Promise 来控制执行顺序。我刚开始写复杂脚本时,经常因为执行顺序问题导致 Hook 失败。
核心要点总结:
- Hook 三步走:附加进程 → 获取类 → 替换实现
- 参数修改:直接赋值,注意类型
- 返回值篡改:基本类型直接 return,对象类型改字段
- 调试技巧:多打 log,确认类名和方法签名
Frida 的威力远不止这些。当你熟练掌握了 Hook 方法、改参数、改返回值这三板斧,很多 App 的安全机制在你面前就像纸糊的一样。当然,前提是你得知道目标方法在哪里——这就要靠逆向分析来定位了。
好了,这一章的内容就到这里。记住,工具只是手段,思路才是关键。