千家信息网

Frida Java Hook示例分析

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要讲解了"Frida Java Hook示例分析",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Frida Java Hook示例分析"吧!1
千家信息网最后更新 2026年11月03日Frida Java Hook示例分析

这篇文章主要讲解了"Frida Java Hook示例分析",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Frida Java Hook示例分析"吧!

1.1 Java层拦截内部类函数

HOOK在Android逆向中,我们也会经常遇到在Java层的内部类。Java内部类函数,使得我们更难以分析代码。我们在这章节中对内部类进行一个基本了解和使用FRIDA对内部类进行钩子拦截处理。什么是内部类?所谓内部类就是在一个类内部进行其他类结构的嵌套操作,它的优点是内部类与外部类可以方便的访问彼此的私有域(包括私有方法、私有属性),所以Android中有很多的地方都会使用到内部类,我们来见一个例子也是最直观的,如下图4-17。

图4-17 User类中的clz类
在图4-17中看到User类中嵌套了一个clz,这样的操作也是屡见不鲜了。在frida中,我们可以使用$符号对起进行处理。首先打开jadxgui软件对代码进行反编译,反编译之后进入User类,下方会有一个smali的按钮,点击smali则会进入smali代码,进入smali代码直接按ctrl+f局部搜索字符串clz,因为clz是内部类的名称,那么就会搜到Lcom/roysue/roysueapplication/User\$clz;,我们将翻译成java代码就是:com.roysue.roysueapplication.User\$clz,去掉第一个字符串的L和/以及;就构成了内部类的具体类名了,见下图4-18。

图4-18 smali代码
经过上面的分析我们已经得知最重要的部分类的路径:com.roysue.roysueapplication.User\$clz,现在来对内部类进行HOOK,现在开始编写js脚本。

1.1.1 拦截内部类函数代码示例

function hook_overload_3() {    if(Java.available) {        Java.perform(function () {            console.log("start hook");            //注意此处类的路径填写更改所分析的路径            var clz = Java.use('com.roysue.roysueapplication.User$clz');            if(clz != undefined) {                //这边也是像正常的函数来hook即可                clz.toString.implementation = function (){                    console.log("成功hook clz类");                    return this.toString();                }            } else {                console.log("clz: undefined");            }            console.log("start end");        });    }}

执行脚本之后,我们可以看到控制也已经成功附加并且打印了成功hook clz类,这样我们也能够对Java层的内部类进行处理了。

[Google Pixel::com.roysue.roysueapplication]-> 成功hook clz类成功hook clz类

1.2 Java层枚举所有的类并定位类

在前面我们学会了如何在java层的各种函数的HOOK操作了,现在开始学习枚举所有的类并定位类的骚套路了~,学习之前我们要了解API中的enumerateLoadedClasses方法,它是属于Java对象中的一个方法。能够枚举现在加载的所有类,enumerateLoadedClasses存在2个回调函数,分别是onMatch:function(ClassName):为每个加载的具有className的类调用,每个ClassName返回来的都是一个类名;和onComplete:function():在枚举所有类枚举完之后回调一次。

1.2.1 枚举所有的类并定位类代码示例

setTimeout(function (){  Java.perform(function (){    console.log("n[*] enumerating classes...");    //Java对象的API enumerateLoadedClasses    Java.enumerateLoadedClasses({      //该回调函数中的_className参数就是类的名称,每次回调时都会返回一个类的名称      onMatch: function(_className){        //在这里将其输出        console.log("[*] found instance of '"+_className+"'");        //如果只需要打印出com.roysue包下所有类把这段注释即可,想打印其他的替换掉indexOf中参数即可定位到~        //if(_className.toString().indexOf("com.roysue")!=-1)        //{        //    console.log("[*] found instance of '"+_className+"'");        //}      },      onComplete: function(){        //会在枚举类结束之后回调一次此函数        console.log("[*] class enuemration complete");      }    });  });});

当我们执行该脚本时,注入目标进程之后会开始调用onMatch函数,每次调用都会打印一次类的名称,当onMatch函数回调完成之后会调用一次onComplete函数,最后会打印出class enuemration complete,见下图。

图4-19 枚举所有类

1.3 Java层枚举类的所有方法并定位方法

上文已经将类以及实例枚举出来,接下来我们来枚举所有方法,打印指定类或者所有的类的内部方法名称,主要核心功能是通过类的反射方法中的getDeclaredMethods(),该api属于JAVAJDK中自带的API,属于java.lang.Class包中定义的函数。该方法获取到类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。在Java中它是这样定义的:public Method[] getDeclaredMethods();其返回值是一个Method数组,Method实际上就是一个方法名称字符串,当然也是一个对象数组,然后我们将它打印出来。

1.3.1 枚举类的所有方法并定位方法代码示例

function enumMethods(targetClass){    var hook = Java.use(targetClass);    var ownMethods = hook.class.getDeclaredMethods();    hook.$dispose;    return ownMethods;}function hook_overload_5() {    if(Java.available) {        Java.perform(function () {           var a = enumMethods("com.roysue.roysueapplication.User$clz")           a.forEach(function(s) {                console.log(s);           });        });    }}

我们先定义了一个enumMethods方法,其参数targetClass是类的路径名称,用于Java.use获取类对象本身,获取类对象之后再通过其.class.getDeclaredMethods()方法获取目标类的所有方法名称数组,当调用完了getDeclaredMethods()方法之后再调用$dispose方法释放目标类对象,返回目标类所有的方法名称、返回类型以及函数的权限,这是实现获取方法名称的核心方法,下面一个方法主要用于注入到目标进程中去执行逻辑代码,在hook_overload_5方法中先是使用了Java.perform方法,再在内部调用enumMethods方法获取目标类的所有方法名称、返回类型以及函数的权限,返回的是一个Method数组,通过forEach迭代器循环输出数组中的每一个值,因为其本身实际就是一个字符串所以直接输出就可以得到方法名称,脚本执行效果如下图4-20。

图4-20 脚本执行后效果在图4-17中clz只有一个toString方法,我们填入参数为com.roysue.roysueapplication.User$clz,就能够定位到该类中所有的方法。

1.4 Java层拦截方法的所有方法重载

我们学会了枚举所有的类以及类的有方法之后,那我们还想知道如何获取所有的方法重载函数,毕竟在Android反编译的源码中方法重载不在少数,对此,一次性hook所有的方法重载是非常有必要的学习。我们已经知道在hook重载方法时需要写overload('x'),也就是说我们需要构造一个重载的数组,并把每一个重载都打印出来。

1.4.1 拦截方法的所有方法重载代码示例

function hook_overload_8() {    if(Java.available) {        Java.perform(function () {            console.log("start hook");            var targetMethod = 'add';            var targetClass = 'com.roysue.roysueapplication.Ordinary_Class';            var targetClassMethod = targetClass + '.' + targetMethod;            //目标类            var hook = Java.use(targetClass);            //重载次数            var overloadCount = hook[targetMethod].overloads.length;            //打印日志:追踪的方法有多少个重载            console.log("Tracing " + targetClassMethod + " [" + overloadCount + " overload(s)]");            //每个重载都进入一次            for (var i = 0; i < overloadCount; i++) {                    //hook每一个重载                    hook[targetMethod].overloads[i].implementation = function() {                        console.warn("n*** entered " + targetClassMethod);                        //可以打印每个重载的调用栈,对调试有巨大的帮助,当然,信息也很多,尽量不要打印,除非分析陷入僵局                        Java.perform(function() {                            var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());                                console.log("nBacktrace:n" + bt);                        });                           // 打印参数                        if (arguments.length) console.log();                        for (var j = 0; j < arguments.length; j++) {                            console.log("arg[" + j + "]: " + arguments[j]);                        }                        //打印返回值                        var retval = this[targetMethod].apply(this, arguments); // rare crash (Frida bug?)                        console.log("nretval: " + retval);                        console.warn("n*** exiting " + targetClassMethod);                        return retval;                    }                }            console.log("hook end");        });    }}

1.4.2 拦截方法的所有方法重载代码示例详解

上面这段代码可以打印出com.roysue.roysueapplication.Ordinary_Class类中add方法重载的个数以及hook该类中所有的方法重载函数,现在来剖析上面的代码为什么可以对一个类中的所有的方法重载HOOK挂上钩子。首先我们定义了三个变量分别是targetMethod、targetClass、targetClassMethod,这三个变量主要于定义方法的名称、类名、以及类名+方法名的赋值,首先使用了Java.use获取了目标类对象,再获取重载的次数。这里详细说一下如何获取的:var method_overload = cls[].overloads[index];这句代码可以看出通过cls索引func_name到类中的方法,而后面写到overloads[index]是指方法重载的第index个函数,大致意思就是返回了一个method对象的第index位置的函数。而在代码中写道:var overloadCount = hook[targetMethod].overloads.length;,采取的方法是先获取类中某个函数所有的方法重载个数。继续往下走,开始循环方法重载的函数,刚刚开始循环时hook[targetMethod].overloads[i].implementation这句对每一个重载的函数进行HOOK。这里也说一下Arguments:Arguments是js中的一个对象,js内的每个函数都会内置一个Arguments对象实例arguments,它引用着方法实参,调用其实例对象可以通过arguments[]下标的来引用实际元素,arguments.length为函数实参个数,arguments.callee引用函数自身。这就是为什么在该段代码中并看不到arguments的定义却能够直接调用的原因,因为它是内置的一个对象。好了,讲完了arguments咱们接着说,打印参数通过arguments.length来循环以及arguments[j]来获取实际参数的元素。那现在来看apply,apply在js中是怎么样的存在,apply的含义是:应用某一对象的一个方法,用另一个对象替换当前对象,this[targetMethod].apply(this, arguments);这句代码简言之就是执行了当前的overload方法。执行完当前的overload方法并且打印以及返回给真实调用的函数,这样不会使程序错误。那么最终执行效果见下图4-21:

图4-21 终端显示
可以看到成功打印了add函数的方法重载的数量以及hook打印出来的参数值、返回值!

1.5 Java层拦截类的所有方法

学会了如何HOOK所有方法重载函数后,我们可以把之前学习的整合到一起,来hook指定类中的所有方法,也包括方法重载的函数。下面js中核心代码是利用重载函数的特点来HOOK全部的方法,普通的方法也是一个特殊方法重载,只是它只是一个方法而已,直接把它当作方法重载来HOOK就好了,打个比方正方形是特殊的长方形,而长方形是不是特殊的正方形。这个正方形是普通函数,而长方形是重载方法这样大家应该很好理解了~在上一章节中已经知道了如何hook方法重载,只是方法名称和类名是写死的,只需要把成员的targetClass、targetMethod定义方法中的参数即可,在该例子中拿到指定类所有的所有方法名称,更加灵活使用了,代码如下。

1.5.1 拦截类的所有方法代码示例

function traceClass(targetClass){    //Java.use是新建一个对象哈,大家还记得么?    var hook = Java.use(targetClass);    //利用反射的方式,拿到当前类的所有方法    var methods = hook.class.getDeclaredMethods();    //建完对象之后记得将对象释放掉哈    hook.$dispose;    //将方法名保存到数组中    var parsedMethods = [];    methods.forEach(function(method) {        //通过getName()方法获取函数名称        parsedMethods.push(method.getName());    });    //去掉一些重复的值    var targets = uniqBy(parsedMethods, JSON.stringify);    //对数组中所有的方法进行hook    targets.forEach(function(targetMethod) {        traceMethod(targetClass + "." + targetMethod);    });}function hook_overload_9() {    if(Java.available) {        Java.perform(function () {            console.log("start hook");            traceClass("com.roysue.roysueapplication.Ordinary_Class");            console.log("hook end");        });    }}s1etImmediate(hook_overload_9);

执行脚本效果可以看到,hook到了com.roysue.roysueapplication.Ordinary_Class类中所有的函数,在执行其被hook拦截的方法时候,也打印出了每个方法相应的的参数以及返回值,见下图4-22。

图4-22 终端运行显示效果

1.6 Java层拦截类的所有子类

这里的核心功能也用到了上一小章节中定义的traceClass函数,该函数只需要传入一个class路径即可对class中的函数完成注入hook。那么在本小章节来hook掉所有类的子类,使我们的脚本更加的灵活方便。通过之前的学习我们已经知道enumerateLoadedClasses这个api可以枚举所有的类,用它来获取所有的类然后再调用traceClass函数就可以对所有类的子进行全面的hook。但是一般不会hook所有的函数,因为AndroidAPI函数实在太多了,在这里我们需要匹配自己需要hook的类即可,代码如下。

//枚举所有已经加载的类Java.enumerateLoadedClasses({    onMatch: function(aClass) {        //迭代和判断        if (aClass.match(pattern)) {            //做一些更多的判断,适配更多的pattern            var className = aClass.match(/[L]?(.*);?/)[1].replace(///g, ".");            //进入到traceClass里去            traceClass(className);        }    },    onComplete: function() {}});

1.7 RPC远程调用Java层函数

在FRIDA中,不但提供很完善的HOOK机制,并且还提供rpc接口。可以导出某一个指定的函数,实现在python层对其随意的调用,而且是随时随地想调用就调用,极其方便,因为是在供给外部的python,这使得rpc提供的接口可以与python完成一些很奇妙的操作,这些导出的函数可以是任意的java内部的类的方法,调用我们自己想要的对象和特定的方法。那我们开始动手吧,现在我们来通过RPC的导出功能将图4-9中的add方法供给外部调用,开始编写rpc_demo.py文件,这次是python文件了哦~不是js文件了

1.7.1 rpc导出Java层函数代码示例

import codecsimport fridafrom time import sleep# 附加进程名称为:com.roysue.roysueapplicationsession = frida.get_remote_device().attach('com.roysue.roysueapplication')# 这是需要执行的js脚本,rpc需要在js中定义source = """    //定义RPC    rpc.exports = {        //这里定义了一个给外部调用的方法:sms        sms: function () {            var result = "";            //嵌入HOOK代码            Java.perform(function () {                //拿到class类                var Ordinary_Class = Java.use("com.roysue.roysueapplication.Ordinary_Class");                //最终rpc的sms方法会返回add(1,3)的结果!                result = Ordinary_Class.add(1,3);             });            return result;        },    };"""# 创建js脚本script = session.create_script(source)script.load()# 这里可以直接调用java中的函数rpc = script.exports# 在这里也就是python下直接通过rpc调用sms()方法print(rpc.sms())sleep(1)session.detach()

当我们执行python rpc_demo.py时先会创建脚本并且注入到目标进程,在上面的source实际上就是js逻辑代码了。在js代码内我们定义了rpc可以给python调用的sms函数,而sms函数内部嵌套调用Java.perform再对需要拿到的函数的类进行主动调用,把最终的结果返回作为sms的返回值,当我们在python层时候可以任意调用sms中的原型add方法~

1.8 综合案例一:在安卓8.1上dump蓝牙接口和实例

一个比较好的综合案例 :dump蓝牙信息的"加强版"--BlueCrawl。

VERSION="1.0.0"setTimeout(function(){    Java.perform(function(){        Java.enumerateLoadedClasses({                onMatch: function(instance){                    if (instance.split(".")[1] == "bluetooth"){                        console.log("[->]t"+lightBlueCursor()+instance+closeCursor());                    }                },                onComplete: function() {}            });        Java.choose("android.bluetooth.BluetoothGattServer",{                onMatch: function (instance){                    ...                onComplete: function() { console.log("[*] -----");}            });        Java.choose("android.bluetooth.BluetoothGattService",{                onMatch: function (instance){                    ...                onComplete: function() { console.log("[*] -----");}            });         Java.choose("android.bluetooth.BluetoothSocket",{                onMatch: function (instance){                    ...                onComplete: function() { console.log("[*] -----");}            });          Java.choose("android.bluetooth.BluetoothServerSocket",{                onMatch: function (instance){                    ...                onComplete: function() { console.log("[*] -----");}            });          Java.choose("android.bluetooth.BluetoothDevice",{                onMatch: function (instance){                    ...                onComplete: function() { console.log("[*] -----");}            });    });},0);

该脚本首先枚举了很多蓝牙相关的类,然后choose了很多类,包括蓝牙接口信息以及蓝牙服务接口对象等,还加载了内存中已经分配好的蓝牙设备对象,也就是上文我们已经演示的信息。我们可以用这个脚本来"查看"App加载了哪些蓝牙的接口,App是否正在查找蓝牙设备、或者是否窃取蓝牙设备信息等。在电脑上运行命令:$ frida -U -l bluecrawl-1.0.0.js com.android.bluetooth执行该脚本时会详细打印所有蓝牙接口信息以及服务接口对象~~

1.9 综合案例二:动静态结合逆向WhatsApp

我们来试下它的几个主要的功能,首先是本地库的导出函数。

setTimeout(function() {    Java.perform(function() {        trace("exports:*!open*");        //trace("exports:*!write*");        //trace("exports:*!malloc*");        //trace("exports:*!free*");    });}, 0);

我们hook的是open()函数,跑起来看下效果:

$ frida -U -f com.whatsapp -l raptor_frida_android_trace_fixed.js --no-pause

如图所示*!open*根据正则匹配到了openlog、open64等导出函数,并hook了所有这些函数,打印出了其参数以及返回值。接下来想要看哪个部分,只要扔到jadx里,静态"分析"一番,自己随便翻翻,或者根据字符串搜一搜。比如说我们想要看上图中的com.whatsapp.app.protocol包里的内容,就可以设置trace("com.whatsapp.app.protocol")。可以看到包内的函数、方法、包括重载、参数以及返回值全都打印了出来。这就是frida脚本的魅力。当然,脚本终归只是一个工具,你对Java、安卓App的理解,和你的创意才是至关重要的。接下来可以搭配Xposed module看看别人都给whatsapp做了哪些模块,hook的哪些函数,实现了哪些功能,学习自己写一写。

感谢各位的阅读,以上就是"Frida Java Hook示例分析"的内容了,经过本文的学习后,相信大家对Frida Java Hook示例分析这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

方法 函数 代码 对象 名称 脚本 参数 示例 就是 接口 蓝牙 分析 目标 学习 数组 定位 成功 信息 效果 功能 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 壹账通互联网科技 腾讯科技 互联网女皇 友谊互联网络科技 长亮科技 互联网金融 互联网 科技服务平台 金融科技与互联网金融相同和不同 宁夏众和广鑫互联网科技有限公司 互联网和黑科技的看法 互联网科技人工智能实验室 如何创新互联网科技 南博望互联网科技有限公司 合肥互联网科技公司公章图片 互联网方面的科技前沿 厦门江牛科技互联网 上海创道互联网络科技有限公司 35岁以上互联网科技行业 2021世界互联网领先科技成果发布 互联网科技机房 西安左小互联网科技有限公司 前海云享互联网科技 互联网金融科技 金融科技与互联网金融 滨湖区互联网智能科技产品供应 互联网对科技的发展 华夏互联网科技业 张召忠谈中国互联网科技 绵阳真晨互联网科技有限公司 北京瑞云互联网科技有限公司 宁波允成互联网科技有限公司 恒生科技互联网指数十大成分股
0