关于SegmentFault:抖音数据采集Frida教程Frida-Java-Hook-详解代码及示例上

71次阅读

共计 13064 个字符,预计需要花费 33 分钟才能阅读完成。

抖音数据采集 Frida 教程,Frida Java Hook 详解:代码及示例(上)

短视频、直播数据实时采集接口,请查看文档:TiToData

免责申明:本文档仅供学习与参考,请勿用于非法用处!否则所有后果自负。

** 前言
1.1 FRIDA SCRIPT 的 ”hello world”
1.1.1 “hello world” 脚本代码示例
1.1.2 “hello world” 脚本代码示例详解
1.2 Java 层拦挡一般办法
1.2.1 拦挡一般办法脚本示例
1.2.2 执行拦挡一般办法脚本示例
1.3 Java 层拦挡构造函数
1.3.1 拦挡构造函数脚本代码示例
1.3.2 拦挡构造函数脚本代码示例解详解
1.4 Java 层拦挡办法重载
1.4.1 拦挡办法重载脚本代码示例
1.5 Java 层拦挡结构对象参数
1.5.1 拦挡结构对象参数脚本示例
1.6 Java 层批改成员变量的值以及函数的返回值
1.6.1 批改成员变量的值以及函数的返回值脚本代码示例
1.6.2 批改成员变量的值以及函数的返回值之小实战 
结语

咱们在这篇来深刻学习如何 HOOK Java 层函数,利用于与各种不同的 Java 层函数,结合实际 APK 案例应用 FRIDA 框架对其 APP 进行附加、hook、以及 FRIDA 脚本的具体编写。

1.1 FRIDA SCRIPT 的 ”hello world”

在本章节中,仍然会大量应用注入模式附加到一个正在运行过程程序,亦或是在 APP 程序启动的时候对其 APP 过程进行劫持,再在指标过程中执行咱们的 js 文件代码逻辑。FRIDA脚本就是利用 FRIDA 动静插桩框架,应用 FRIDA 导出的 API 和办法,对内存空间里的对象办法进行监督、批改或者替换的一段代码。FRIDAAPI 是应用 JavaScript 实现的,所以咱们能够充分利用 JS 的匿名函数的劣势、以及大量的 hook 和回调函数的 API。那么大家跟我一起来操作吧,先关上在vscode 中创立一个 js 文件:helloworld.js

1.1.1 “hello world” 脚本代码示例

setTimeout(function(){Java.perform(function(){console.log("hello world!");
    });
});

1.1.2 “hello world” 脚本代码示例详解

这基本上就是一个 FRIDA 版本的 Hello World!,咱们把一个匿名函数作为参数传给了setTimeout() 函数,然而函数体中的 Java.perform() 这个函数自身又承受了一个匿名函数作为参数,该匿名函数中最终会调用 console.log() 函数来打印一个 Hello world! 字符串。咱们须要调用 setTimeout() 办法因为该办法将咱们的函数注册到 JavaScript 运行时中去,而后须要调用 Java.perform() 办法将函数注册到 FridaJava运行时中去,用来执行函数中的操作,当然这里只是打了一条 log。而后咱们在手机上将frida-server 运行起来,在电脑上进行操作:

roysue@ubuntu:~$ adb shell
sailfish:/ $ su
sailfish:/ $ ./data/local/tmp/frida-server

这个时候,咱们须要再开启一个终端运行另外一条命令:
frida -U com.roysue.roysueapplication -l helloworld.js
这句代码是指通过 USB 连贯对 Android 设施中的 com.roysue.roysueapplication 过程对其附加并且注入一个 helloworld.js 脚本。注入实现之后会立即执行 helloworld.js 脚本所写的代码逻辑!
咱们能够看到胜利注入了脚本以及附加到本人所编写包名为:com.roysue.roysueapplicationapk 应用程序中,并且打印了一条 hell world!


roysue@ubuntu:~$ frida -U -l helloworld.js com.roysue.roysueapplication
     ____
    / _  |   Frida 12.7.24 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://www.frida.re/docs/home/
Attaching...
hello world!

执行了该命令之后,FRIDA返回一个了 CLI 终端工具与咱们交互,在下面可见打印进去了一些信息,显示了咱们的 FRIDA 版本信息还有一个反向 R 的图形,往下看,须要退出的时候咱们只须要在终端输出 exit 即可实现退出对 APP 的附加,其后咱们看到的是 Attaching... 正在对指标过程附加,当附加胜利了打印了一句 hello world!,至此,咱们的helloworld.js 通过 FRIDA-l命令胜利的注入到指标过程并且执行结束。学会了注入可不要快乐的太早哟~~ 咱们持续深刻学习 HOOK Java 代码中的一般函数。

1.2 Java 层拦挡一般办法

Java层的一般办法相当常见,也是咱们要学习的根底中的根底,咱们先来看几个比拟常见的一般的办法,见下图 1 -1。

图 1 -1 JADX-GUI 软件关上的反编译代码
通过图 1 - 1 咱们能看三个函数别离是构造函数 a()、一般函数a()b()。诸如这种一般函数会特地多,那咱们在本小章节中尝试 hook 一般函数、查看函数中的参数的具体值。
在尝试写 FRIDA HOOK 脚本之前咱们先来看看须要 hook 的代码吧~,Ordinary_Class类中有四个函数,都是很一般的函数,add函数的性能也很简略,参数 a+b;sub 函数性能是参数ab;而getNumber 只返回 100getString 办法返回了 getString()+ 参数的 str。见下图 1 -2。

图 1 -2 反编译的 Ordinary_Class 类的代码
而后咱们再看 MainActivity 中的编写的代码,通过反编译进去的代码一共有四个按钮(Button),当 btn_add 点击时会运行 Ordinary_Class 类中 add 办法,计算 100+200 的后果,通过 String.valueOf 函数把计算构造转字符串而后通过 Toast 弹出信息;点击 btn_sub 按钮的时候触发点击事件会运行 Ordinary_Class 类中 sub 办法,计算 100-100 的后果,通过 String.valueOf 函数把计算构造转字符串而后通过 Toast 弹出信息。在 MainActivity 类中的 onCreate 办法中的四个按钮别离对应状况是 ADD 按钮对应 btn_add 点击事件,SUB对应 btn_sub 的点击事件。见下图 1 -3。

图 1 -3 MainActivity 中的编写的代码
依照失常流程当咱们点击 ADD 的按钮界面会弹出一条信息显示,其中的值是 300,因为咱们在ADD 的点击事件中增加了 Toast,将ADD 办法运行的后果放在 Toast 参数中,通过它显示了咱们的计算结果;而 SUB 函数会显示 0,见下图 1 -4,图 1 -5。

图 1 -4 点击 ADD 按钮时显示的后果

图 1 -5 点击 SUB 按钮时显示的后果
咱们当初晓得曾经晓得它的运行流程以及函数的执行后果和所填写的参数,咱们当初来正式编写一个根本的应用 Frida 钩子来拦挡图 1 - 2 中 addsub函数的调用并且在终端显示每个函数所传入的参数、返回的值,开始写roysue_0.js

1.2.1 拦挡一般办法脚本示例

setTimeout(function(){
    // 判断是否加载了 Java VM,如果没有加载则不运行上面的代码
    if(Java.available) {Java.perform(function(){
            // 先打印一句提醒开始 hook
            console.log("start hook");
            // 先通过 Java.use 函数失去 Ordinary_Class 类
            var Ordinary_Class = Java.use("com.roysue.roysueapplication.Ordinary_Class");
            // 这里咱们须要进行一个 NULL 的判断,通常这样做会排除一些不必要的 BUG
            if(Ordinary_Class != undefined) {// 格局是:类名. 函数名.implementation = function (a,b){
                // 在这里应用钩子拦挡 add 办法,留神办法名称和参数个数要统一,这里的 a 和 b 能够本人任意填写,Ordinary_Class.add.implementation = function (a,b){
                    // 在这里先失去运行的后果,因为咱们要输入这个函数的后果
                    var res = this.add(a,b);
                    // 把计算的后果和参数一起输入
                    console.log("执行了 add 办法 计算 result:"+res);
                    console.log("执行了 add 办法 计算参数 a:"+a);
                    console.log("执行了 add 办法 计算参数 b:"+b);
                    // 返回后果,因为 add 函数自身是有返回值的,否则 APP 运行的时候会报错
                    return res;
                }
                Ordinary_Class.sub.implementation = function (a,b){var res = this.sub(a,b);
                    console.log("执行了 sub 办法 计算 result:"+res);
                    console.log("执行了 sub 办法 计算参数 a:"+a);
                    console.log("执行了 sub 办法 计算参数 b:"+b);
                    return res;
                }
                Ordinary_Class.getString.implementation = function (str){var res = this.getString(str);
                    console.log("result:"+res);
                    return res;
                }
            } else {console.log("Ordinary_Class: undefined");
            }
            console.log("hook end");
          });
    }
});

1.2.2 执行拦挡一般办法脚本示例

写完脚本后咱们执行:frida -U com.roysue.roysueapplication -l roysue_0.js,当咱们执行了脚本后会进入 cli 控制台与 frida 交互,能够看到曾经对该 app 附加并且胜利注入脚本。立即打印出了 start hookhook end,正是咱们刚刚所写的。再持续点击 app 利用中的 ADD 按钮和 SUB 按钮会在终端立即输入计算的后果和参数,在这里甚至能够看到清晰,参数、返回值和盘托出。

roysue@ubuntu:~$ frida -U com.roysue.roysueapplication -l roysue_0.js
     ____
    / _  |   Frida 12.7.24 - A world-class dynamic instrumentation toolkit
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at https://www.frida.re/docs/home/
Attaching...
start hook
hook end
[Google Pixel::com.roysue.roysueapplication]-> 执行了 add 办法 计算 result:300
执行了 add 办法 计算参数 a:100
执行了 add 办法 计算参数 b:200
执行了 sub 办法 计算 result:0
执行了 sub 办法 计算参数 a:100
执行了 sub 办法 计算参数 b:100

这样咱们就曾经胜利的打印了来了咱们想要晓得的值,每个参数的值和返回值的构造。咱们就对一般函数的钩子实现了一个基本操作,大家能够本人多多尝试对其余的一般的函数进行hook,多多练习,那咱们这一章节就欢快的实现了~~ 持续深刻吧。

1.3 Java 层拦挡构造函数

那咱们这章来玩如何 HOOK 类的构造函数,很多时候在实例化类的霎时就会把参数传递到外部为成员变量赋值,这样一来就省的类中的成员变量一个个去赋值,在 Android 逆向中,也有很多的相似的场景,利用有参构造函数实例化类并且赋值。我建设了一个 class 类,类名是User,其中代码这样写:

public class User {
    public int age;
    public String name;
    public String toString() {StringBuilder sb = new StringBuilder();
        sb.append("User{name='");
        sb.append(this.name);
        sb.append('\'');
        sb.append(", age=");
        sb.append(this.age);
        sb.append('}');
        return sb.toString();}

    public User(String name2, int age2) {
        this.name = name2;
        this.age = age2;
    }
    public User() {}
}

咱们能够看到 User 类中有 2 个成员变量别离是 agename,还有 2 个构造方法,别离是无参结构有有参结构。咱们当初要做的是在 User 类进行有参实例化时查看所填入的参数别离是什么值。在图 1 - 3 中,能够看到 btn_init 的点击事件时会对 User 类进行实例化参数别离填写了 roysue30,而后再持续调用了 toString 办法把它们组合到一起并且通过 Toast 弹出信息显示值。TEST_INTI 对应 btn_init的点击事件,点击时成果见下图 1 -6。

图 1 -6 点击 TEST_INIT 时显示的值

1.3.1 拦挡构造函数脚本代码示例

当初开始编写 frida 钩子来拦挡 User 类的构造函数的脚本, 来打印出构造函数的参数,编写roysue_1.js

setTimeout(function(){if(Java.available) {Java.perform(function(){console.log("start hook");
            // 同样的在这里先获取 User 类对象
            var User = Java.use("com.roysue.roysueapplication.User");
            if(User != undefined) {
                // 留神在应用钩子拦挡构造函数时须要应用到 $init 也要留神参数的个数,因为该构造函数是 2 个所以此处填 2 个参数
                User.$init.implementation = function (name,age){
                    // 这里打印成员变量 name 和 age 的在运行中被调用填写的值
                    console.log("name:"+name);
                    console.log("age:"+age);
                    // 最终要执行本来的 init 办法否则运行时会报异样导致原程序无奈失常运行。this.$init(name, age);
                }
            } else {console.log("User: undefined");
            }
            console.log("hook end");
          });
    }
});

1.3.2 拦挡构造函数脚本代码示例解详解

脚本写好之后关上终端执行 frida -U com.roysue.roysueapplication -l roysue_1.js,把刚刚写的脚本注入的指标过程,而后咱们在APP 利用中按下 TEST_INIT 按钮,注入的脚本会立刻拦挡构造函数并且打印 2 个参数的具体的值,见下图 1 -7。

图 1 -7 终端显示
打印的值就是图 1 - 3 中所填的 roysue30,这就阐明咱们应用 FRIDA 钩子拦挡到了 User 类的有参构造函数并且无效的打印了参数的值。须要留神的是在输出打印参数的值之后肯定要记得执行本来的有参构造函数,这样程序才能够失常执行。

1.4 Java 层拦挡办法重载

在学习 HOOK 之前,咱们先理解一下什么是办法重载,办法重载是指在同一个类内定义了多个雷同的办法名称,然而每个办法的参数类型和参数的个数都不同。在调用办法重载的函数编译器会依据所填入的参数的个数以及类型来匹配具体调用对应的函数。总结起来就是办法名称一样然而参数不一样。在逆向 JAVA 代码的时候时常会遇到办法重载函数,见下图 1 -8。

图 1 -8 反编译后重载函数样本代码
在图 1 - 8 中,咱们能看到一共有三个办法重载的函数,有时候理论状况甚至更多。咱们也不要怕,撸起袖子加油干。对于这种重载函数在 FRIDA 中,js会写 .overload 来拦挡办法重载函数,当咱们应用 overload 关键字的时候 FRIDA 会十分智能把以后所有的重载函数的所须要的类型打印进去。在理解了这个之后咱们来开始实战应用 FRIDA 钩子拦挡咱们想拦挡的重载函数的脚本吧!还是之前的那个 app,还是之前的那个类,原汁原味~~,我新增了一些add 的办法,使 add 办法重载,见下图 1 -9。

图 1 -9 反编译后的 Ordinary_Class 中的重载函数样本代码
在图 1 - 9 中 add 有三个重名的办法名称,然而参数的个数不同,在图 1 - 3 中的 btn_add 点击事件会执行领有 2 个参数的办法重载的 add 函数,当我在脚本中写 Ordinary_Class.add..implementation = function (a,b),而后持续注入所写好的脚本,FRIDA 在终端提醒了红色的字体,一看吓一跳!但咱们认真看,它说 add 是一个办法重载的函数,有三个参数不同的 add 函数,让咱们写 .overload(xxx),以辨认 hook 的到底是哪个add 的办法重载函数。
当咱们写了这样的 js 脚本去运行的时候,frida提醒报错了,因为有三个重载函数,我用红色的框圈出了,能够看到 frida 非常的智能,三个重载的参数类型完全一致的打印进去了,当它打印进去之后咱们就能够复制它的这个智能提醒的 overloadxxx 重载来批改咱们本人的脚本了,进一步欠缺咱们的脚本代码如下。

1.4.1 拦挡办法重载脚本代码示例

function hook_overload() {if(Java.available) {Java.perform(function () {console.log("start hook");
            var Ordinary_Class = Java.use("com.roysue.roysueapplication.Ordinary_Class");
            if(Ordinary_Class != undefined) {
                // 要做的仅仅是将 frida 提醒进去的 overload 复制在此处
                Ordinary_Class.add.overload('int', 'int').implementation = function (a,b){var res = this.add(a,b);
                    console.log("result:"+res);
                    return res;
                }
                Ordinary_Class.add.overload('int', 'int', 'int').implementation = function (a,b,d){var res = this.add(a,b,d);
                    console.log("result:"+res);
                    return res;
                }
                Ordinary_Class.add.overload('int', 'int', 'int', 'int').implementation = function (a,b,d,c){var res = this.add(a,b,d,c);
                    console.log("result:"+res);
                    return res;
                }
            } else {console.log("Ordinary_Class: undefined");
            }
            console.log("start end");
        });
    }
}
setImmediate(hook_overload);

批改完相应的中央之后咱们保留代码时终端会主动再次运行 js 中的代码,不得不说 frida 太强大了~,当 js 再次运行的时候咱们在 app 利用中点击图 1 - 4 中 ADD 按钮时会立即打印出后果,因为 FRIDA 钩子曾经对该类中的所有的 add 函数进行了拦挡,执行了本人所写的代码逻辑。点击成果如下图 1 -11。

图 1 -11 终端显示成果
在这一章节中咱们学会了解决办法重载的函数,咱们只有根据 FRIDA 的终端提醒,将智能提醒进去的代码连接到本人的代码就可能对办法重载函数进行拦挡,执行咱们本人想要执行的代码。

1.5 Java 层拦挡结构对象参数

很多时候,咱们岂但要 HOOK 应用钩子拦挡函数对函数的参数和返回值进行记录,而且还要本人被动调用类中的函数应用。FRIDA中有一个 new() 关键字,而这个关键字就是实例化类的重要办法。
在官网 API 中有这样写道:“Java.use(ClassName):动静获取 classNameJavaScript包装器,通过对其调用 new() 来调用构造函数,能够从中实例化对象。对实例调用 Dispose() 以显式清理它 (或期待JavaScript 对象被垃圾收集,或脚本被卸载)。动态和非静态方法都是可用的。”,那咱们就晓得通过 Java.use 获取的 class 类能够调用 $new() 来调用构造函数,能够从实例化对象。在图 1 - 9 中有 6 个函数,理解了 API 的调用之后咱们来开始动手编写咱们的 js 文件。(在这里我感觉大家肯定要动手做测试,入手尝试,你会发现其中的妙趣无穷!)。

1.5.1 拦挡结构对象参数脚本示例

function hook_overload_1() {if(Java.available) {Java.perform(function () {console.log("start hook");
            // 还是先获取类
            var Ordinary_Class = Java.use("com.roysue.roysueapplication.Ordinary_Class");
            if(Ordinary_Class != undefined) {
                // 这里因为 add 是一个静态方法可能间接调用办法
                var result = Ordinary_Class.add(100,200);
                console.log("result :" +result);
                // 调用办法重载无压力
                result = Ordinary_Class.add(100,200,300);
                console.log("result :" +result);
                // 调用办法重载
                result = Ordinary_Class.add(100,200,300,400);
                console.log("result :" +result);         
                // 调用办法重载       
                result = Ordinary_Class.getNumber();
                console.log("result :" +result);   
                // 调用办法重载             
                result = Ordinary_Class.getString("HOOK");
                console.log("result :" +result);

                // 在这里,应用了官网 API 的 $new()办法来实例化类,实例化之后返回一个实例对象,通过这个实例对象来调用类中办法。var Ordinary_Class_instance = Ordinary_Class.$new();
                result = Ordinary_Class_instance.getString("Test");
                console.log("instance --> result :" +result);
                result = Ordinary_Class_instance.add(1,2,3,4);
                console.log("instance --> result :" +result);     
            } else {console.log("Ordinary_Class: undefined");
            }
            console.log("start end");
        });
    }
}
setImmediate(hook_overload_1);

当咱们执行了下面写的脚本之后终端会打印调用办法之后的后果,见下图 1 -12。

图 1 -12 终端显示调用函数的后果
因为很多时候类中的办法并不一定是动态的,所以这里提供了 2 种调用办法,第一种调用形式非常的不便,不须要实例化一个对象,再通过对象调自身的办法。然而遇到了没有 static 关键字的函数时只能应用第二种形式来实现办法调用,在这一章节中咱们学会了如何本人被动去调用类中的函数了~~ 大家也能够尝试被动调用有参的构造函数玩玩。

1.6 Java 层批改成员变量的值以及函数的返回值

咱们上章学完了如何本人被动调用 JAVA 层的函数了,通过上章的学习咱们的功夫又精进了一些~~,当初咱们来深刻外部批改类的对象的成员变量和返回值,打入敌人外部,进步本人的内功。当初咱们来看下图 1 -13。

图 1 -13 User 类
上图中的 User 类是我之前建的一个类,类中写了 2 个公开成员变量别离是 agename;还有 2 个办法别离是 User 的有参构造函数和一个 toString 函数打印成员变量的函数。咱们要做就是在 User 类实例化的时候拦挡程序并且批改掉 agename的值,从而改写成咱们本人须要的值再运行程序,那咱们接下开始编写 JS 脚本来批改成员变量的值。
这段代码次要有的性能是:通过 User.$new("roysue",29) 拿到 User 类的有参数结构的实例化对象,这个恰好也是应用了上章节中学到的常识本人构建对象,这里咱们也学习了如何应用 FRIDA 框架通过有参构造函数实例化对象,实例化之后先是调用了类自身的 toString 办法打印出未修改前的成员变量的值,打印了之后再通过 User_instance.age.value = 0; 来批改对象以后的成员变量的值,能够看到批改 age 批改为 0name 批改为 roysue_123,而后再次调用toString 办法查看其成员变量的最新值是否曾经被更改。

1.6.1 批改成员变量的值以及函数的返回值脚本代码示例

function hook_overload_2() {if(Java.available) {Java.perform(function () {console.log("start hook");
            // 拿到 User 类
            var User = Java.use("com.roysue.roysueapplication.User");
            if(User != undefined) {
                // 这里利用上章学到常识来本人构建一个 User 的有参结构的实例化对象
                var User_instance  = User.$new("roysue",29);
                // 并且调用了类中的 toString()办法
                var str = User_instance.toString();
                // 打印成员变量的值
                console.log("str:"+str);

                // 这里获取了属性的值以及打印
                console.log("User_instance.name:"+User_instance.name);
                console.log("User_instance.age:"+User_instance.age);

                // 这里从新设置了 age 和 name 的值
                User_instance.age.value = 0;
                User_instance.name.value = "roysue_123";
                str = User_instance.toString();
                // 再次打印成员变量的值
                console.log("str:"+str);
            } else {console.log("User: undefined");
            }
            console.log("start end");
        });
    }
}

能够看到终端显示了本来有参构造函数的值 roysue 和 30 批改为 roysue_123 和 0 曾经胜利了,成果见下图 1 -14。

图 1 -14 终端显示批改成果
通过下面的学习,咱们学会了如何批改类的成员变量,上个例子中是应用的有参构造函数给与成员变量赋值,通常在写代码相似这种实体类会定义相干的 get set 办法以及修饰符为公有权限,内部不可调用,这个时候他们可能会通过 set 办法来设置其值和 get 办法获取成员的变量的值,这个时候咱们能够通过钩子拦挡 setget办法本人定义值也是能够达到批改和获取的成果。当初学完了如何批改成员变量了,那咱们接下来要学习如何批改函数的返回值,假如在逆向的过程中已知检测函数 A 的后果为 B,正确后果为C,那咱们能够强行批改函数A 的返回值,不管在函数中执行了什么与返回后果无关,咱们只有批改后果即可。

1.6.2 批改成员变量的值以及函数的返回值之小实战

我在 rdinary_Class 类建设了 2 个函数别离是 isCheckisCheckResult,假如 isCheck 是一个检测办法,通过 add 运行后必然结果 2,代表被检测到了,在isCheckResult 办法进行了判断调用 isCheck 函数后果为 2 就是谬误的,那这个时候要把 isCheck 函数或者 add 函数的后果强行改成不是 2 之后 isCheckResult 即可打印 Successful,见下图 1 -15。

图 1 -15 isCheck 函数与 isCheckResult 函数
咱们当初要做的是使 sCheckResult 函数胜利打印出 "Successful",而不是errer,那咱们当初开始来写js 脚本吧~~

function hook_overload_7() {if(Java.available) {Java.perform(function () {console.log("start hook");
            // 先获取类
            var Ordinary_Class = Java.use('com.roysue.roysueapplication.Ordinary_Class');
            if(Ordinary_Class != undefined) {
                // 先调用一次必定会输入 error
                Ordinary_Class.isCheckResult();
                // 在这里重写 isCheck 办法将返回值强行改为 123 并且输入了一句 Ordinary_Class: isCheck
                Ordinary_Class.isCheck.implementation = function (){console.log("Ordinary_Class: isCheck");
                    return 123;
                }
                // 再调用一次 isCheckResult()办法
                Ordinary_Class.isCheckResult();} else {console.log("Ordinary_Class: undefined");
            }
            console.log("hook end");
        });
    }
}

下面这段代码的次要性能是:首先通过 Java.use 获取 Ordinary_Class, 因为isCheckResult() 是静态方法,能够间接调用,在这里先调用一次,因为这样比拟难看成果,第一次调用会在 Android LOG 中打印 errer,之后紧接着利用FRIDA 钩子对 isCheck 函数进行拦挡,改掉其返回值为 123,这样每次调用isCheck 函数时返回值都必定会是 123,再调用一次isCheckResult() 办法,isCheckResult()办法中判断 isCheck 返回值是否等于 2,因为咱们曾经重写了isCheck 函数,所以不等于 2,所以程序往下执行,会打印Successful 字符串到 Android Log 中,理论运行成果见下图 1 -16。

图 1 -16 终端显示以及 Android Log 信息
能够清晰的看到先是打印了 errer 后打印了 Successful 了,这阐明咱们曾经胜利过掉 isCheck 的判断了。这是一个小小的综合例子。倡议大家多多入手尝试。

结语

在这章中咱们学习了 HOOK Java 层的一些函数,如拦挡一般函数、构造函数、以及批改成员变量以及函数返回值。下一篇中咱们来枚举所有的类、所有的办法重载、所有的子类以及 RPC 近程调用 Java 层函数。

短视频、直播数据实时采集接口,请查看文档:TiToData

免责申明:本文档仅供学习与参考,请勿用于非法用处!否则所有后果自负。

正文完
 0