六层锁机分析

xiaoeryu Lv5

本章来通过一个案例更深层次的去了解frida,在各种情境下怎么去修改函数的返回值


先使用objection大致了解一下apk

objection附加到app

objection -g com.example.androiddemo explore

先看一下它的activity

  • 这个Activity都能直接跳过登陆界面跳过去,这种直接能跳过登陆界面的在现在的app上基本都不存在了。

接下来开始按正常流程开始分析

登陆

  • 点击SIGN IN按钮会有一个Login failed的Toast

接下来用jadx打开apk搜索这个字符串

进入

  • 这里调用a方法传入了两个相同的obj然后将返回的结果与obj2作比较
  • 接下来查看这个两个str参数的重载a方法
  • hook这个a方法拿到返回的结果输入比较一下

写hook脚本拿到a()的返回结果

function main(){
    Java.perform(function(){
        Java.use("com.example.androiddemo.Activity.LoginActivity").a.overload('java.lang.String', 'java.lang.String').implementation = function(x, y){
            var result = this.a(x, y);
            console.log("x, y, result", x, y, result);
            return result;
        }
    })
}
setImmediate(main)
  • 将result的值粘贴进去试一下(使用input命令也可以粘贴进去)

第一关

  • 点击屏幕上的按钮有Check Failed的弹窗,跟前面一样搜索这个弹窗
  • 发现这里有个CheckSuccess()按X查找它的用例

看第一关的用例

  • 这里只要修改a方法的返回值就可以通过了
  • 用这个脚本hook这个类中的a方法让返回值等于R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL=就通过了

第二关

  • 第二关只需要这两个返回值为true就通过了

  • 这两个方法一个是静态一个是动态

    静态直接调用就可以了

    动态需要找到实例才能调用

  • 写完直接保存一下,或者重新运行一下。这样就通过了

第三关

  • 修改这三个变量为true就通过

    第一个变量为静态布尔类型

    第二个变量为动态布尔类型

    第三个为同名布尔变量

脚本
function third(){
    Java.perform(function(){
        Java.use("com.example.androiddemo.Activity.FridaActivity3").static_bool_var.value = true;
        Java.choose("com.example.androiddemo.Activity.FridaActivity3", {
            onMatch:function(instance){
                console.log("found instance: ", instance);
                instance.bool_var.value = true;
                instance._same_name_bool_var.value = true;
            }, onComplete:function(){}
        })
    })
}
  • 注意修改同名变量的时候要在变量名前面加上下划线,不然会修改失败

第四关

  • 这里我们看怎么修改静态内部类中静态函数的返回值为true
脚本
function fourth(){
    Java.perform(function(){
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check1.implementation = function(){return true};
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check2.implementation = function(){return true};
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check3.implementation = function(){return true};
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check4.implementation = function(){return true};
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check5.implementation = function(){return true};
        Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses").check6.implementation = function(){return true};
    })
}
  • 这样我们就可以通过验证进入下一关

  • 但是这里有一个点需要注意一下

    怎么准确的拿到这个类名:

    可以通过objection去附加然后搜索拿到准确的类名

  • 另外就是像这种需要修改多个返回值的,一个一个修改如果量太多是比较麻烦的。所以可以通过java的反射来枚举所有的方法去修改(反射机制允许在运行时动态获取和使用类的信息,包括类的字段、方法、构造函数等)

通过枚举的方式批量修改返回值脚本
function fourth_2() {
    Java.perform(function () {
        var innerClass = Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses");

        // 获取内部类的所有方法
        var methods = innerClass.class.getDeclaredMethods();

        // 遍历方法数组
        for (var i = 0; i < methods.length; i++) {
            var methodName = methods[i].getName();

            var finalMethodString = methodName.toString();
            // console.log(finalMethodString);
            // hook修改返回值
            innerClass[finalMethodString].implementation = function(){return true};
        }
    });
}

第五关

第五关的代码使用jadx反编译失败了

可以换GDA编译试试

  • 反编译ok,可以看到它加载了DynamicPlugin.dex文件中的com.example.androiddemo.Dynamic.DynamicCheck

  • 但是我们在这里找不到chech()的实现,解压apk找一下这个文件

    • 找到之后我们可以来hook这个check()

第五关有点奇怪,试了几种方法都找不到这个类:

  1. enumerateClassLoaders

  2. Java.choose

  3. 加载外部dex再进行hook

这个dex文件也在

function fifth(){
    Java.perform(function(){
        
        // Java.use("com.example.androiddemo.Dynamic.DynamicCheck").check.implementation = function(){return true};
        Java.enumerateClassLoaders({
            onMatch:function(loader){
                try {
                    if(loader.loadClass("com.example.androiddemo.Dynamic.DynamicCheck")){
                        Java.classFactory.loader = loader;
                        var b = Java.use(loader);
                        console.log(b);
                    }
                } catch (error) {
                    console.log("loadClass error: "+error)
                }
                try {
                    if(loader.findClass("com.example.androiddemo.Dynamic.DynamicCheck")){
                        console.log("Succefully found loader!",loader);
                        Java.classFactory.loader = loader;
                    }
                } catch (error) {
                    console.log("found error "+error)
                    
                }
            },
            onComplete:function(){"enum completed fifth!"}
        })
    })
}

function fifth_1() {
    Java.perform(function () {
        Java.choose("com.example.androiddemo.Dynamic.DynamicCheck", {
            onMatch: function (instance) {
                console.log("Found instance:", instance);
                try {
                    instance.check.implementation = function () {
                        console.log("DynamicCheck.check() is hooked!");
                        return true;
                    };
                } catch (error) {
                    console.log("Error:", error);
                }
            },
            onComplete: function () {
                console.log("Enumeration completed!");
            }
        });
    });
}
  • 先记录下来后续再搞
  • 类在文件中但是加载不上

报错

Error: java.lang.ClassNotFoundException: Didn't find class "com.example.androiddemo.Dynamic.DynamicCheck" on path: DexPathList[[zip file "/data/app/com.example.androiddemo-1/base.apk"],nativeLibraryDirectories=[/data/app/com.example.androiddemo-1/lib/arm64, /data/app/com.example.androiddemo-1/base.apk!/lib/arm64-v8a, /system/lib64, /vendor/lib64]]
    at frida/node_modules/frida-java-bridge/lib/env.js:122
    at ensureClass (frida/node_modules/frida-java-bridge/lib/class-factory.js:380)
    at frida/node_modules/frida-java-bridge/lib/class-factory.js:102
    at /lesson6.js:158
    at frida/node_modules/frida-java-bridge/lib/vm.js:11                                                                                                   
    at frida/node_modules/frida-java-bridge/index.js:279
    at searchClass (/lesson6.js:159)
    at frida/runtime/core.js:55
  • 报错提示在/data/app/com.example.androiddemo-1/base.apk下找不到类名
  • 我们dex的类名是在/data/data/com.example.androiddemo/files/DynamicPlugin.dex文件中
尝试使用objection搜索
  • 只能找到接口类名,找不到check()的实现类名

把pixel XL从7.1刷到了8.1也还是一样

  • 暂时先放下,回头有时间可以再试试其它系统或者frida版本
  • 这个应该是环境的问题,因为类名只要加载了使用Java.use肯定是可以hook到的,但是现在就是没有加载上哪里都找不到

第六关

  • 还是修改这几个返回值为true

直接通过java.use修改就可以

function sixth(){
    Java.perform(function(){
        Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class0").check.implementation = function(){return true};
        Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class1").check.implementation = function(){return true};
        Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class2").check.implementation = function(){return true};  
    })
}

同样的我们也可以把这个脚本修改为枚举的方式,方便批量修改

枚举HOOK脚本

 Java.perform(function(){
        Java.enumerateLoadedClasses({
            onMatch:function(name, handle){
                if(name.toString().indexOf("com.example.androiddemo.Activity.Frida6") >= 0){
                    // console.log("name", name);
                    Java.use(name).check.implementation = function(){return true}
                }
            },onComplete(){}
        })
    })

最后第七关没有东西

附件:

hook脚本

  • 标题: 六层锁机分析
  • 作者: xiaoeryu
  • 创建于 : 2023-11-22 13:37:50
  • 更新于 : 2023-11-25 10:15:09
  • 链接: https://github.com/xiaoeryu/2023/11/22/六层锁机分析/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论