Frida动态hook进阶:重载方法、构造函数和native层拦截
接着逆向系列说,这次讲 Frida 动态 hook 的进阶用法。上一篇讲了基础 hook,这次讲实战中真正有用的技巧。一、hook 重载方法
Java 里经常有方法重载(同名方法不同参数),Frida hook 时要指定参数类型:
Java.perform(function() {
var cls = Java.use("com.target.Util");
cls.encrypt.overload('java.lang.String', 'int').implementation = function(input, mode) {
console.log("encrypt called: input=" + input + " mode=" + mode);
var ret = this.encrypt(input, mode);
console.log("return: " + ret);
return ret;
};
});
不指定 overload 的话,如果有多个同名方法会报错。
二、hook 构造函数
有时候你想看对象初始化时传了什么参数:
Java.perform(function() {
var Cls = Java.use("com.target.Config");
Cls.$init.overload('[B').implementation = function(bytes) {
console.log("Config init with bytes: " + bytes);
return this.$init(bytes);
};
});
$init 就是构造函数在 Frida 里的名字。
三、主动调用方法
不只是被动等方法被调用,你还可以主动调:
Java.perform(function() {
var CryptoUtil = Java.use("com.target.CryptoUtil");
var instance = CryptoUtil.$new();
var result = instance.decrypt("base64string");
console.log("decrypt result: " + result);
});
这样你不用操作 App 界面,直接在脚本里调目标方法,省时间。
四、hook native 方法(so 库)
有些关键逻辑在 C/C++ 写的 so 库里,Java 层 hook 不到:
Interceptor.attach(Module.findExportByName("libtarget.so", "native_encrypt"), {
onEnter: function(args) {
console.log("input ptr: " + args);
console.log("input len: " + args);
},
onLeave: function(retval) {
console.log("return: " + retval);
}
});
onEnter 看输入,onLeave 看返回,两次都能截获。
五、实战要点
[*]Frida 要用 frida-server,推到手机上跑,版本要跟 Python 端的 frida 一致
[*]Android 7+ 要用 frida 的 gadget 模式或者 root 后跑 frida-server
[*]遇到反调试检测,先 hook 检测函数绕过,常见的是 hook Debug.isDebuggerConnected
[*]复杂 App 用 objection(Frida 封装框架),一条命令 hook 所有类
https://www.metk.cn/img/posts/reverse_frida.jpg
Frida 的核心思路:不管 App 怎么混淆加密,运行时代码必须以明文执行,在运行时拦截就能看到一切。静态分析是猜,动态 hook 是看。 有个坑提醒,不同厂商ROM差异很大,通用性没有想象中那么强。 这个方法我用过,确实可行,不过新一点的版本已经加了检测。 写得很好,不过第三部分有点跳跃,新手可能跟不上。 感谢分享,之前一直卡在这个点,看完豁然开朗。 我这边环境是Mac,有些步骤要调整,回头补个差异说明。 想请教一下,你用的这个版本是哪个?我这边跑起来报错。 有个细节,日志记得清掉,不然很容易被发现。 讲得挺细的,不过我建议加一句免责,这东西容易被拿去做坏事。 实战出来的经验和文档里写的完全是两码事,楼主这个很真实。