zoukankan      html  css  js  c++  java
  • andorid jar/库源码解析之frida体验

    目录:andorid jar/库源码解析 

    Frida体验:

      作用:

        android手机上可以对,java和so层代码,进行hook.监控数据和处理内存数据。

        官译:面向开发人员、逆向工程师和安全研究人员的动态工具工具包。

      栗子:

        运行步骤:

        1、https://github.com/frida/frida/releases 下载适合需要运行环境的可执行程序。我这里是arm64,所以下载了一个最新版本的frida64位。

        2、PC端,安装python环境,直接从官网下载一个python安装包安装即可,我这里安装的是python3, 安装包会自己配置环境变量,cmd运行 python,看看有没有,有就是安装上了环境变量了。

        3、使用 pip install frida 安装 frida 环境,基于 python的。  再安装  pip install frida-tools ,我看大部分都是按照了。tools的。

        4、一切ok。开始跑了,,,把步骤1中得到的,可执行文件,拷贝到手机上面  adb push D:xxxxxxfrixxxx   /data/local/tmp/

        5、因为push上去的可执行文件默认没有权限,下一步授权。。adb shell 进入手机  su,得到root权限。。cd /data/local 进入 local文件夹  chmod 777 -R *  授权可执行。。 再  cd tmp  进入 tmp  执行 :./frXXX回车运行exe

    效果如下图:

        

        6、端口转发,因为要把手机的数据和本地电脑互通,需要设置端口转发,两个端口:执行两条命令

        

    adb forward tcp:27042 tcp:27042
    adb forward tcp:27043 tcp:27043

        7、接着就可以允许python了。

        8、代码示例:

    import frida, sys
    
    jsCode = """
    
    Java.perform(function () {
        var impl = Java.use("com.android.test.TestUtil");
        impl.test1.implementation = function () {
            send("test1 called!");
            this.test1();
        };
    
        impl.test2.implementation = function () {
            send("test2 called!");
        };
    
        impl.test3.implementation = function (a) {
            send("test3 called!");
        };
    
        impl.test4.implementation = function (a,b,c) {
            send("test4 called!");
            return this.test4(a,b,c);
        };
    
        impl.test5.overload("int").implementation = function (a) {
            send("test5 1 called!");
        };
    
        impl.test5.overload("int", "java.lang.String").implementation = function (a,b) {
            send("test5 2 called!");
        };
    
    });
    
    """
    def message(message, data):
        if message["type"] == 'send':
            print(u"[*] {0}".format(message['payload']))
        else:
            print(message)
    
    process = frida.get_remote_device().attach("com.android.test")
    script= process.create_script(jsCode)
    script.on("message", message)
    script.load()
    sys.stdin.read()

      代码中,把js写到了一个string变量中。多行都是用这个固定格式。

      对test1方法进行了hook同时,在后面也对 test1方法进行了调用,如果不调用,方法就不会执行了。参考 test2

      test3针对单个参数的情况,test4针对多个参数。test5,针对不同参数进行了重载,需要指明参数类型,上面做了处理。

      执行js的send方法,内容回呗,发往,scritp的绑定方法 。def message(message, data)在里面,进行输出,你也可以在js中使用 console.log进行输出参数。

      针对是复杂类型的情况,可以直接a.XXXX拿到复杂类型的变量。

      8.2、其他js

    // 遍历所有js.指定名称,过滤
    Java.perform(function(){
        Java.enumerateLoadedClasses({
            onMatch: function(className) {
                if(className.toString().indexOf("down") >= 0){
                    send(className+'"));');
                }
            },
            onComplete:function(){
                send("done");
            }
        });
    });

      9:so,hook处理。

      

    import frida, sys
    
    jsCode3 = """
    Java.perform(function(){
        
        var exports = Module.enumerateExportsSync("xxx.so");
        for(var i = 0; i < exports.length; i++) {
            if(exports[i] && exports[i].name != undefined){
                if(exports[i].name.indexOf("rapidjson")>=0){
                    var nativePointer = new NativePointer(exports[i].address);
                    send("exports " + exports[i].name + " nativePointer " + nativePointer);
                    Interceptor.attach(nativePointer, {
                        onEnter: function(args) {
                            send(this.context.pc + " called! ");
                            send("context " + JSON.stringify(this.context));
                            
                            // 保存长度,在返回方法进行调用
                            this.fd = args[1];
                            // send(nativePointer + " arg0 " +args[0] + " arg1 " +args[1] + " arg2 " +args[2]);
                        },
                        onLeave:function(retval){
                            send(this.context.pc + " retval " +retval);
                            
                            // dump出内容
                            var size = parseInt(this.fd);
                            if(size > 0){
                                const r = Memory.alloc();
                                    
                                // 复制以module.base地址开始的10个字节 那肯定会是7F 45 4C 46...因为一个ELF文件的Magic属性如此。
                                Memory.copy(r,ptr(retval),size);
                                console.log(hexdump(r, {
                                    offset: 0,
                                    length: size,
                                    header: true,
                                    ansi: false
                                }));
                            }
                        }
                    });
                }
            }
        }
    });
    
    """;
    
    jsCode2 = """
    Java.perform(function(){
        // 遍历所有模块
        Process.enumerateModules({
            onMatch: function(exp){
                //先获取so的module对象
                var module = Process.findModuleByName(exp.name); 
                
                //??是通配符
                var pattern = "11 22 33 44 55 66"; //
                //基址
                // console.log("base:" + module.base)
                //从so的基址开始搜索,搜索大小为so文件的大小,搜指定条件03 49 ?? 50 20 44的数据
                var res = Memory.scan(module.base, module.size, pattern, {
                    onMatch: function(address, size){
                        //搜索成功
                        console.log('搜索到 ' + pattern +" 地址是:"+ address.toString());  
                    }, 
                    onError: function(reason){
                        //搜索失败
                        // console.log('搜索失败 ' + reason);
                    },
                    onComplete: function(){
                        //搜索完毕
                        // console.log("搜索完毕")
                    }
                });
            },
            onComplete: function(){
                send('stop');
            }
        });
    
        // 导入函数
        var imports = Module.enumerateImportsSync("xxx.so");
        for(var i = 0; i < imports.length; i++) {
            if(imports[i].name == 'strncat'){
                send(imports[i].name + ": " + imports[i].address);
                break;
            }
        }
        
        // 导出函数
        var exports = Module.enumerateExportsSync("xxx.so");
        for(var i = 0; i < exports.length; i++) {
            if(exports[i].name.indexOf('add') != -1){
                send(exports[i].name + ": " + exports[i].address);
                break;
            }
        }
    });
    
    """;
        
    jsCode = """
    
    var module = Process.findModuleByName("xxx.so"); 
    var nativePointer = new NativePointer(module.base.add(0x1740));
    send("nativePointer " + nativePointer);
    Interceptor.attach(nativePointer, {
        onEnter: function(args) {
            send("mou sub_method called!");
        },
        onLeave:function(retval){
        
        }
    });
    
    var nativePointer = new NativePointer(ptr(0x00001122));
    send("nativePointer " + nativePointer);
    Interceptor.attach(nativePointer, {
        onEnter: function(args) {
            send("mou sub_method 2 called!");
        },
        onLeave:function(retval){
        
        }
    });
    
    """
    def message(message, data):
        if message["type"] == 'send':
            print(u"[*] {0}".format(message['payload']))
        else:
            print(message)
    
    process = frida.get_remote_device().attach("com.android.test")
    script= process.create_script(jsCode2)
    script.on("message", message)
    script.load()
    sys.stdin.read()

      提供了多种方法:

      a>遍历所有so模块,查找指定关键字。

      b>遍历某个模块的所有导出函数,名称包含

      c>遍历某个模块的所有导入函数,名称包含。

      d>直接通过,模块得到内存地址和偏移,进行hook.

      e>通过利用 this.的成员变量,在结果中,dump出,入参的参数的某个值进行dump内容。

      f>输出 this.context对象。

      源码解读:

      待补充

      参考:

            https://www.anquanke.com/post/id/195215

      https://www.anquanke.com/member/131652

      源码:https://frida.re/

      引入:

     
  • 相关阅读:
    在SpringBoot中使用JWT
    异常解决:non-compatible bean definition of same name and class【com.xxx.xxx.XXX】
    mysql 字段名和关键字冲突
    约束(主键、非空、唯一性、外键、检查约束)
    唯一索引与非唯一索引区别(UNIQUE INDEX, NON-UNIQUE INDEX)
    数据库设计mysql字段不默认为NULL原因搜集
    mysql索引总结----mysql 索引类型以及创建
    互联网数据库架构设计思路
    干货满满!10分钟看懂Docker和K8S
    PowerDesigner 使用教程(很具体,很实用)
  • 原文地址:https://www.cnblogs.com/Supperlitt/p/12981516.html
Copyright © 2011-2022 走看看