引言*
在移动安全研究领域,动态代码插桩工具Frida以其强大的功能和灵活的特性深受广大研究人员喜爱。本文将聚焦Frida在Java层面上对静态方法和实例方法的Hook过程,通过一个具体的Android应用示例,详细介绍其Hook原理和操作步骤。
Hook静态方法与实例方法
在使用Frida编写Hook脚本时,我们需要遵循一定的组织结构。主要逻辑应封装在Java.perform
方法中,该方法接收一个匿名函数作为参数,在此匿名函数内部编写具体的Hook代码。值得注意的是,在Hook静态方法或实例方法时,无需关注它们的修饰符,统一采用Java.use
进行Hook操作,仅在主动调用时区分两者。
实战Hook演示
我们以一款已安装的Android测试应用为例,通过jadx反编译工具查看其源码,目标为com.xiaojianbang.hook.Money
类中的静态方法setFlag
和非静态方法getInfo
。原始Java代码如下:
package com.xiaojianbang.hook;public class Money {private static String flag;private int amount;private String currency;public static void setFlag(String str) {flag = str;}public String getInfo() {return this.currency + ": " + this.amount + ":" + flag;}
}
首先,我们Hook setFlag
静态方法。由于它属于Money类,所以需通过Java.use("com.xiaojianbang.hook.Money")
定位到该类,然后使用implementation
方法覆写静态方法setFlag
。当Android应用调用setFlag
时,实际上执行的是我们覆写后的代码。在覆写函数中,根据原方法参数数量添加相应参数(类型无需指定),并可通过this.setFlag(a)
调用原始方法返回结果。
接下来,Hook非静态方法getInfo
,同样采用相同方式覆写。在调用原方法获取返回值的同时,插入console.log语句输出相关参数或返回值。具体的Hook脚本如下:
function test() {Java.perform(function () {var money = Java.use("com.xiaojianbang.hook.Money");money.setFlag.implementation = function (a) {console.log("money.setFlag param : ", a);return this.setFlag(a);//原始方法也会执行};money.getInfo.implementation = function () {var result = this.getInfo();//原始方法也会执行console.log("money.getInfo : ", result);return result;};});test();
}
为了确保Hook脚本在应用启动之初就能生效,我们可以借助Frida框架的命令行参数主动启动目标应用并注入脚本。常用命令行参数包括:
-U
:连接USB设备-f
:主动启动指定进程-l
:加载指定的script脚本文件-o
:输出日志-no-pause
:启动主线程运行应用
例如,启动命令如下:
frida -U -f com.xiaojianbang.app -l test.js -o fridaHook.txt --no-pause
执行上述命令后,Frida会自动启动USB连接设备上的com.xiaojianbang.app
应用,并实时输出setFlag
方法的参数以及getInfo
方法的返回值至命令行。
对于修改方法参数和返回值的需求,只需调整Hook脚本。例如,若想改变setFlag
方法的参数,只需在调用原方法的地方替换参数值:
money.setFlag.implementation = function (a) {console.log("money.setFlag param : ", a);return this.setFlag("这是修改后的参数");
};
经过这样的修改并重新运行脚本后,可以看到Money
类中的setFlag
方法参数已被成功更改。
总结,本文通过实际操作演示了如何使用Frida框架Hook Android应用中的Java静态方法和实例方法,并展示了如何在Hook过程中监控、修改方法参数和返回值,为移动应用逆向工程与安全分析提供了实用的技术手段。
问题
以上内容hook相应方法之后,原来的还会执行吗
在使用Frida进行方法Hook后,原有的方法仍然会被执行,但是其执行流程会发生变化。当我们使用implementation属性覆写某个方法时,实际上是替换了原有方法的实现。这意味着,当目标方法被调用时,将执行我们提供的Hook代码,而非原始方法体内的代码。
然而,在Hook代码中,通常我们会保留对原始方法的调用(如上面例子中的return this.setFlag(a);和var result = this.getInfo();),这样在Hook代码执行完额外的操作(如打印日志)之后,会继续执行原始方法的功能,从而保证原有业务逻辑不受影响。如果在Hook代码中没有调用原始方法,则原有的方法逻辑将不会被执行。