引言

在 Android 逆向工程和动态调试中,Frida 是一个非常强大的工具。它允许你在运行时对应用程序进行动态插桩,修改其行为、绕过安全检查、调试逻辑等。本文将带你从零开始,了解如何使用 Frida 对 Java 函数进行 Hook,并通过一个简单的案例来展示整个过程。


什么是 Frida?

Frida 是一个开源的动态插桩工具包,支持多种平台(包括 Android、iOS、Windows、Linux 等)。它可以让你在不修改 APK 或应用源码的情况下,在运行时注入 JavaScript 脚本,实时修改程序的行为。

核心特性:

  • 动态 Hook 函数

  • 内存读写

  • 调用任意函数

  • 拦截 API 调用

  • 修改返回值


为什么使用 Frida 进行 Java Hook?

Android 应用主要使用 Java/Kotlin 编写,而 Frida 提供了对 Java 层的完整支持(通过 Java.perform() 方法),可以轻松地 Hook 到 Java 函数,查看参数、修改参数、篡改返回值等。


环境准备

1. 安装 Frida 工具链

你需要在主机上安装 Frida 的 Python 客户端,以及在目标设备上运行 frida-server

主机环境:

1
pip install frida-tools

或者使用 Node.js 版本:

1
npm install -g frida

Android 设备环境:

前往 Frida 官网下载页 下载对应架构的 frida-server(例如 frida-server-xx.x.x-android-arm64.xz)。

解压后上传到手机并赋予执行权限:

1
2
3
4
5
adb push frida-server /data/local/tmp/
adb shell
cd /data/local/tmp
chmod 755 frida-server
./frida-server &

注意:frida的客户端和服务端版本一定一致(避免出现乱七八糟的错误)

示例场景

我们以一个简单的 Android App 为例,假设它有一个类 a.b.k0801.MainActivity,其中定义了一个方法:

1
2
3
public boolean checkSN(String sn, String key) {
// 实现逻辑
}

我们的目标是 Hook 这个方法,修改传入的参数,并强制返回 true


编写 Frida Hook 脚本

下面是一个完整的 Frida Hook 脚本示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function hook_java_main() {
Java.perform(() => {

// 加载目标类
var cls_MainActivity = Java.use("a.b.k0801.MainActivity");

// Hook checkSN 方法,并指定参数类型
var fun_checkSN = cls_MainActivity.checkSN.overload('java.lang.String', 'java.lang.String');

// 替换实现
fun_checkSN.implementation = function(p0, p1){
console.log("checkSN in:", p0, p1);

// 修改输入参数
p0 = "cccc";
p1 = "dddd";

// 调用原始方法
var ret = this.checkSN(p0, p1);

// 修改返回值
ret = true;

console.log("checkSN out:", ret);
return ret;
};

console.log("hook_java_main run over");
});
}

setTimeout(hook_java_main, 0); // 延迟执行

如何运行脚本

  1. 启动目标应用。

  2. 使用以下命令附加到目标进程:

1
frida -U -n <包名> -l hook_script.js

例如:

1
frida -U -n com.example.app -l hook_script.js
  • -U 表示连接 USB 设备

  • -n 指定要 Hook 的应用包名

  • -l 指定脚本路径

你也可以使用 Python 脚本来更灵活地控制 Frida:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import frida
import sys

def on_message(message, data):
print("[*] Message: ", message)

device = frida.get_usb_device()
pid = device.spawn(["com.example.app"])
device.resume(pid)
session = device.attach(pid)

with open("hook_script.js") as f:
script = session.create_script(f.read())

script.on('message', on_message)
script.load()

sys.stdin.read()

技术点解析

1. Java.perform()

这是 Frida 提供的入口函数,用于在 JVM 上下文中执行代码。所有对 Java 类的操作都必须在这个上下文中进行。

2. Java.use("ClassName")

加载指定的 Java 类,返回一个代理对象,可以用来调用或 Hook 该类的方法。

3. .overload(...)

当方法存在多个重载版本时,可以通过 .overload(...) 来明确指定参数类型。例如:

1
var method = cls.method.overload('int', 'java.lang.String');

4. implementation

替换原方法的实现。你可以在此处插入自己的逻辑,比如打印参数、修改输入输出等。

5. this.OriginalMethod(...)

调用原始方法,确保程序流程继续执行。如果你直接返回结果而不调用原始方法,可能会导致后续逻辑出错。


扩展功能建议

✅ 参数类型自动识别

Frida 支持省略 .overload() 直接 Hook 方法,但会匹配所有重载版本,适用于简单场景:

1
2
3
cls.method.implementation = function(arg1, arg2) {
// 自动匹配所有重载
}

✅ Hook 多个方法

你可以一次 Hook 多个方法:

1
2
3
var cls = Java.use("some.Class");
cls.method1.implementation = function() { ... }
cls.method2.implementation = function() { ... }

✅ 修改静态方法

对于静态方法,使用 Java.use().$new() 创建实例或直接调用静态方法:

1
2
3
4
5
var cls = Java.use("some.Class");
cls.staticMethod.overload('int').implementation = function(x) {
console.log("Called staticMethod with", x);
return this.staticMethod(x);
};

✅ Hook 构造函数

构造函数使用 $init 来表示:

1
2
3
4
5
var cls = Java.use("some.Class");
cls.$init.overload('java.lang.String').implementation = function(str) {
console.log("Constructor called with", str);
return this.$init(str);
};

常见问题与解决方案

❓ Hook 不生效?

  • 检查类名是否正确(混淆后的类名可能为 a.b.c.d

  • 使用 console.log(cls) 查看类是否存在

  • 添加日志确认脚本是否成功加载

❓ 返回值无法修改?

  • 确保返回值类型正确(如 boolean 应返回 true/false

  • 如果是 native 方法,可能需要切换到 Native Hook(后续文章会讲)

❓ Frida 连接失败?

  • 确保设备已 root 并运行 frida-server

  • 使用 frida-ps -U 查看进程列表确认设备连接正常


法律风险提示

本文内容仅用于合法授权的安全测试和研究,请勿用于非法用途。任何未经授权的系统入侵、数据篡改行为均属违法行为。


结语

Frida 是 Android 逆向和动态分析的强大助手,尤其在 Hook Java 函数方面表现尤为出色。本文介绍了基本的 Hook 流程、核心 API 和常见技巧,适合初学者快速上手。

下一讲我们将介绍如何 Hook Native 函数(C/C++层),敬请期待!