Java 层 Hook 基础写法——Java.perform + Java.use 入门
基本骨架
Frida 类型脚本 Hook Java 层的标准结构:
Java.perform(function () {
// 所有 Java 层操作都放在 Java.perform 里
var TargetClass = Java.use('com.example.app.TargetClass');
TargetClass.someMethod.implementation = function () {
// Hook 逻辑:改参数、记日志、改返回值
console.log('[+] someMethod 被调用了');
// 调用原方法(记得传参)
return this.someMethod.apply(this, arguments);
};
});
逐行拆解
Java.perform
所有与 Java 层相关的操作必须在 Java.perform() 的回调函数里写。它保证 Frida 运行时已准备好,Java 虚拟机已加载。
Java.use
通过全限定类名拿到目标类的包装对象。类名要写完整,包括包名:
// 正确写法
var Activity = Java.use('com.example.app.MainActivity');
// 错误:缺少包名
var Activity = Java.use('MainActivity');
implementation
把目标方法替换成你自己的实现。this 指向方法所属的实例。
常见操作示例
① 记录方法调用
Java.perform(function () {
var LoginActivity = Java.use('com.example.app.LoginActivity');
LoginActivity.login.implementation = function (username, password) {
console.log('[+] login 被调用');
console.log(' username: ' + username);
console.log(' password: ' + password);
return this.login(username, password);
};
});
② 强制修改返回值
Java.perform(function () {
var GameManager = Java.use('com.game.GameManager');
GameManager.isVIP.implementation = function () {
console.log('[+] isVIP 返回 true');
return true; // 不管原逻辑,直接返回 true
};
});
③ 强制修改参数
Java.perform(function () {
var ShopActivity = Java.use('com.game.ShopActivity');
ShopActivity.buyItem.implementation = function (itemId, price) {
// 把价格改成 0
price = 0;
console.log('[+] 购买 item: ' + itemId + ', price 改为 0');
return this.buyItem(itemId, price);
};
});
重载方法怎么办
一个方法名可能有多个重载版本(参数类型/数量不同)。Frida 会自动找匹配的,但如果有歧义需要用 .overload() 指定。
详见 重载方法指定。
私有方法和私有类
Java.use 也能拿到私有类,implementation 也能替换私有方法——Frida 不做访问控制检查。Java 层的 public/private 对 Frida 透明。
调用原方法
替换了 implementation 之后,原来的方法就被覆盖了。要让原逻辑继续执行(只是加日志或改参数),需要在你的实现里手动调原方法。
两种方式:
// 方式一:arguments 转发(推荐,不用记参数名)
TargetClass.method.implementation = function () {
// 你的逻辑
return this.method.apply(this, arguments);
};
// 方式二:显式传参
TargetClass.method.implementation = function (arg1, arg2) {
// 你的逻辑
return this.method(arg1, arg2);
};
用 arguments 转发的好处是方法签名变了也不用改你的 Hook 代码。