• 【Android安全】Frida 指定classloader | hook动态加载的类 | 安卓多apk hook


    Frida 指定classloader 进行hook

    一些安卓app中包含多个apk。app这样做的好处是:方便局部/增量更新。主dex通过DexClassLoader,去加载指定路径下的apk、dex或者jar文件,反射出相应的类,然后根据获得相应的代码和资源。

    例如,某app的apk中,在\assets\chimera-modules下面就存在着多个apk。
    一些类和方法的源码存在于这些apk中,attach到进程后,使用默认的classloader是不行的(会报错:类不存在)。

    例如,某个类org.chromium.net.AndroidNetworkLibrary不存在于apk的某个class.dex下面,而存在于\assets\chimera-modules\CronetDynamite.apk中。

    如果直接attach到com.google.android.gms进行hook,会报错:

    Error: java.lang.ClassNotFoundException: Didn’t find class “org.chromium.net.AndroidNetworkLibrary” on path: DexPathList …………

    需要先检索到对应的loader,再通过设置Java.classFactory.loader 让Frida切换到对应的loader,然后再去hook。

    下面是两种检索loader的方案

    通过包含某个class找到loader

    Java.perform(function () {
    	
    	// dh.a(java.security.cert.X509Certificate[], java.lang.String, java.lang.String) : java.util.List
        Java.enumerateClassLoaders({
            onMatch: function (loader) {
                try {
                    // the apk contains class: org.chromium.net.AndroidNetworkLibrary
                    if (loader.findClass("org.chromium.net.AndroidNetworkLibrary")) {
                        if (loader.toString().indexOf("CronetDynamite") != -1) {
                            Java.classFactory.loader = loader;
                            send("loader: " + loader);
                            // [*] loader: dalvik.system.DelegateLastClassLoader[DexPathList[[zip file "/data/user_de/0/com.google.android.gms/app_chimera/m/00000009/CronetDynamite.apk"],nativeLibraryDirectories=[/data/user_de/0/com.google.android.gms/app_chimera/m/00000009/CronetDynamite.apk!/lib/arm64-v8a, /system/lib64, /system/product/lib64]]]
                        }
                    }
                } catch (error) {
                }
            }, onComplete: function () {
            }
        });
    
    	var class_name = 'dh';
    	var DymClass = Java.use(class_name);
    
    	DymClass.a.implementation = function (arg1,arg2,arg3)
    	{
            var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
            // if(bt.indexOf("bdpg") != -1)
            if (1) {
                send('');
                console.log("Backtrace:" + bt);
    
                send('arg1 : ' + arg1);
                send('arg2 : ' + arg2);
                send('arg3 : ' + arg3);
                send('ret : ' + this.a(arg1,arg2,arg3));
            }
    		return this.a(arg1,arg2,arg3);
    	}
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    直接过滤loader

    Java.perform(function () {
    	
    	// dh.a(java.security.cert.X509Certificate[], java.lang.String, java.lang.String) : java.util.List
        Java.enumerateClassLoaders({
            onMatch: function (loader) {
                try {
                    // [*] loader: dalvik.system.DelegateLastClassLoader[DexPathList[[zip file "/data/user_de/0/com.google.android.gms/app_chimera/m/00000009/CronetDynamite.apk"],nativeLibraryDirectories=[/data/user_de/0/com.google.android.gms/app_chimera/m/00000009/CronetDynamite.apk!/lib/arm64-v8a, /system/lib64, /system/product/lib64]]]
                    if (loader.toString().startsWith(" dalvik.system.DelegateLastClassLoader")) {
                        Java.classFactory.loader = loader;
                        send("loader: " + loader);
                    }
                } catch (error) {
    
                }
            }, onComplete: function () {
            }
        });
    
    	var class_name = 'dh';
    	var DymClass = Java.use(class_name);
    
    	DymClass.a.implementation = function (arg1,arg2,arg3)
    	{
            var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
            // if(bt.indexOf("bdpg") != -1)
            if (1) {
                send('');
                console.log("Backtrace:" + bt);
    
                send('arg1 : ' + arg1);
                send('arg2 : ' + arg2);
                send('arg3 : ' + arg3);
                send('ret : ' + this.a(arg1,arg2,arg3));
            }
    		return this.a(arg1,arg2,arg3);
    	}
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    完整代码(以类包含为例)

    #coding=utf-8
    
    import frida,importlib, sys
    importlib.reload(sys)
    
    def on_message(message, data):
        if message['type'] == 'send':
            print("[*] {0}".format(message['payload']))
        else:
            print(message)
    
    jscode = """
    
    Java.perform(function () {
        Java.enumerateClassLoaders({
            onMatch: function (loader) {
                try {
                    if (loader.findClass("org.chromium.net.AndroidNetworkLibrary")) {
                        Java.classFactory.loader = loader;
                        send("loader: "+ loader);
                        // console.log(loader);
                    }
                } catch (error) {
    
                }
            }, onComplete: function () {
            }
        });
        var DynamicAndroidNetworkLibrary = Java.use("org.chromium.net.AndroidNetworkLibrary");
        
        DynamicAndroidNetworkLibrary.verifyServerCertificates.implementation = function (arg1,arg2,arg3) {
            // send('arg1 : ' + arg1);
            send('arg2 : ' + arg2);
            send('arg3 : ' + arg3);
            return this.verifyServerCertificates(arg1,arg2,arg3);
        }
    });
    
    
    """
    
    process = frida.get_usb_device().attach('com.google.android.gms')
    script = process.create_script(jscode)
    script.on('message', on_message)
    print('[*] Running hooking')
    script.load()
    sys.stdin.read()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    关键性语句是Java.classFactory.loader = loader;
    这里的Java.classFactory.loader 可以参考:https://frida.re/docs/javascript-api/

    Java.ClassFactory: class with the following properties:
    loader: read-only property providing a wrapper for the class loader currently being used. For the default class factory this is updated by the first call to Java.perform().

    也就是说Java.classFactory.loader是当前的class loader的一个wrapper。修改Java.classFactory.loader就可以修改当前的class loader。


    主要参考:https://blog.csdn.net/freeking101/article/details/107720802

    其他参考:
    新建类对象并调用某方法:http://pollux.cc/2019/11/08/%E4%BD%BF%E7%94%A8frida-Hook%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BDDex/

    切换dex环境:
    https://blog.csdn.net/lilongsy/article/details/122261331


  • 相关阅读:
    水溶性Cy3 NHS酯Sulfo-Cyanine3酯用于生物偶联标记多肽
    Servlet生命周期知识点汇总
    【Python自动化办公】分享几个好用到爆的模块,建议收藏
    OpenLayers实战,OpenLayers调用手机陀螺仪方向实现指南针效果
    Python用户认证JWT——PyJWT
    (Matalb分类预测)WOA-BP鲸鱼算法优化BP神经网络的多维分类预测
    NIO与BIO服务器端对比
    【AntDesign】封装全局异常处理-全局拦截器
    python爬虫基础(二)
    python自(2)切片 字典 遍历删除添加修改查询定义函数函数返回值作用域序列化异常报错urllib使用一个类型六个方法下载 视频音频图片
  • 原文地址:https://blog.csdn.net/qq_39441603/article/details/126732909