精华内容
下载资源
问答
  • frida hook native 大家好,我是王铁头 一个乙方安全公司搬砖的菜鸡 今天分享的是 frida hook native 也就是 frida hook so层函数 视频演示:https://space.bilibili.com/430241559 frida是一个轻便好用的工具,不仅...

    frida hook native

    大家好,我是王铁头 一个乙方安全公司搬砖的菜鸡
    持续更新移动安全,iot安全,编译原理相关原创视频文章

    今天分享的是 frida hook native 也就是 frida hook so层函数

    视频演示:https://space.bilibili.com/430241559

    frida是一个轻便好用的工具,不仅支持java层的hook,同样支持so层的hook. 那么,frida hook so 是如何实现的哪?

    这里,根据场景的不同 分为有导出和无导出

    原理 通过地址进行hook

    有导出:函数名可以在导出表找到 通过导出表的数据结构 用函数名称进行函数的定位
    无导出:函数名在导出表找不到。 这里需要根据函数特征 比如字符串等 手动搜索关键字符串定位函数地址

    1 有导出so层hook

    原理:通过导出表的结构找到函数名对应的汇编代码的地址。

    frida hook native frida hook so层

    1.1 有导出适用场景

    一般情况下,要hook的函数名可以在导出表找到
    找不到只有下面两种情况

    1. 写代码时使用__attribute__((visibility(“hidden”)))关键字隐藏导出
    2. 编译后 被开发者, 加固壳或者第三方框架修改elf格式 被加密抹去相关信息,

    下面先讨论正常可以在导出表看到的情况
    这里我写了两个函数

    extern "C" void func_exp()
    {
        LOGD("exp");
    }
    
    //这里没有extern "C"关键字 默认是c++风格导出的
    //hook时要注意名称粉碎 
    void func_exp_cpp()
    {
        LOGD("exp_cpp");
    }
    

    这里只要不做啥骚操作 导出表绝对是可以看到的 如下图
    frida hook native

    1.2 frida hook so层有导出代码

    这里 func_exp 函数是c风格导出 所以函数名直接填写就可以了
    但是 func_exp_cpp 函数这里要进入ida里面看具体函数名 如图
    frida hook so层

    var str_name_so = "libnative-lib.so";    //要hook的so名
    var str_name_func = "func_exp";          //要hook的函数名
    //var str_name_func = "_Z12func_exp_cppv";    //这里注意名称粉碎
    
    var n_addr_func = Module.findExportByName(str_name_so , str_name_func);
    console.log("func addr is ---" + n_addr_func);
    
    Interceptor.attach(n_addr_func, {
        //在hook函数之前执行的语句
        onEnter: function(args) 
        {
            console.log("hook on enter")
        },
        //在hook函数之后执行的语句
        onLeave:function(retval)
        {
            console.log("hook on leave")
        }
    });
    

    1.3 hook效果图

    frida hook so frida hook native

    2 无导出

    无导出这里要使用一个关键字才能达到无导出的效果

    __attribute__((visibility("hidden")))
    

    这里写一个例子:

    //extern "C" c语言格式导出
    __attribute__((visibility("hidden"))) void func_no_exp()
    {
        LOGD("hidden");
    }
    

    生成so文件后,导出表是看不到这个函数的:
    如下图。
    frida hook so层

    因为无导出的函数无法通过函数名去定位地址:
    所以这里只能通过手动定位去找到函数对应的偏移 这里可以根据情况用字符串或者看上下级调用定位到偏移 这里的函数偏移是0x7078 还有一点 确定偏移的时候要注意使用的so是v7 arm32 还是 v8 arm64
    函数偏移如下 如图 这里 函数 func_no_exp的偏移是 0x7078

    这种函数在ida里面一般是 sub_xxx xxx是16进制的地址

    2.2 frida hook so层无导出代码

    var str_name_so = "libnative-lib.so";    //要hook的so名
    var n_addr_func_offset = 0x7078;         //要hook的函数在函数里面的偏移
    
    //加载到内存后 函数地址 = so地址 + 函数偏移
    var n_addr_so = Module.findBaseAddress(str_name_so);
    var n_addr_func = parseInt(n_addr_so, 16) + n_addr_func_offset;
    
    var ptr_func = new NativePointer(n_addr_func);
    Interceptor.attach(ptr_func, 
    {
        onEnter: function(args) 
        {
            console.log("hook on enter no exp");
        },
        onLeave:function(retval)
        {
            console.log("hook on Leave no exp");
        }
    });
    

    2.3 frida hook so 无导出效果图

    视频演示:https://space.bilibili.com/430241559

    持续更新移动安全,iot安全,编译原理相关原创视频文章

    资料代码下载 请关注公众号 [移动安全王铁头] 回复关键字 frida

    展开全文
  • Frida Hook 学习记录】Frida Hook Android 常用方法

    万次阅读 多人点赞 2019-04-30 22:38:38
    Frida hook 常用方法 1 概述 在逆向过程中,Frida是非常常用的Hook工具,这个工具在日常使用的过程中,有很多通用方法,这里记录一下,方便查阅 参考文章 Android逆向之旅—Hook神器家族的Frida工具使用详解 2 待...

    1 概述

    在逆向过程中,Frida是非常常用的Hook工具,这个工具在日常使用的过程中,有很多通用方法,这里记录一下,方便查阅,部分函数使用的时候,可能需要稍微修改一下,本文记录是Android的方法,不涉及其他的
    主要是搬迁的一下参考文章的片段
    Android逆向之旅—Hook神器家族的Frida工具使用详解
    Frida官方文档
    看雪 Frida官方手册 - JavaScript API(篇一)
    看雪 Frida官方手册 - JavaScript API(篇二)
    Js中几种String Byte转换方法
    Frida learn by example
    补充一个参考文章–Hook 属性

    2 启动方式

    2.1 使用js脚本启动

     frida -U -l exploit.js -f com.package.name 
    

    其中js脚本的写作方式如下

    setImmediate(function() { //prevent timeout
        console.log("[*] Starting script");
    
        Java.perform(function() {
          myClass = Java.use("com.package.name.xxActivity");
          myClass.implementation = function(v) {
             // do sth.
          }
    
        })
    })
    
    

    2.2 使用python脚本启动

    import frida, sys
    
    def on_message(message, data):
        if message['type'] == 'send':
            print("[*] {0}".format(message['payload']))
        else:
            print(message)
    
    jscode = """
    Java.perform(function () {
        // Function to hook is defined here
        var MainActivity = Java.use('com.example.hook.MainActivity');
        // hook method is setString
        MainActivity.setString.implementation = function (str) {
            // Show a message to know that the function got called
            send('hook success');
            console.log('string is: ' + str));
        };
    });
    """
    
    process = frida.get_usb_device().attach('com.example.hook')
    #pid = device.spawn(["com.android.chrome"])
    #session = device.attach(pid)
    #device.resume(pid)
    script = process.create_script(jscode)
    script.on('message', on_message)
    print('[*] Hook Start Running')
    script.load()
    sys.stdin.read()
    

    3 Android 常用Hook方法汇总

    3.1 Hook 一般函数—使用implementation

    var MainActivity = Java.use('ese.xposedtest.MainActivity');
    //外部类 修改返回值
    MainActivity.OutClass.implementation = function (arg) {
        var ret = this.OutClass(arg);
        console.log('Done:' + arg);
        return ret;
    }
    

    3.2 Hook 重载函数—使用overload

    // If two methods of a class have the same name
    // you need to use 'overload'
    // hook method 1
    myClass.myMethod.overload().implementation = function(){
      // do sth
    }
    
    myClass.myMethod.overload("[B", "[B").implementation = function(param1, param2) {
      // do sth
    }
    
    myClass.myMethod.overload("android.context.Context", "boolean").implementation = function(param1, param2){
      // do sth
    }
    
    // hook method 2
    //待补充
    

    3.3 Hook 构造函数—使用$init

    // Intercept the initialization of java.lang.Stringbuilder's overloaded constructor.
    // Write the partial argument to the console.
    const StringBuilder = Java.use('java.lang.StringBuilder');
    //We need to overwrite .$init() instead of .$new(), since .$new() = .alloc() + .init()
    StringBuilder.$init.overload('java.lang.String').implementation = function (arg) {
        var partial = "";
        var result = this.$init(arg);
        if (arg !== null) {
             partial = arg.toString().replace('\n', '').slice(0,10);
        }
        // console.log('new StringBuilder(java.lang.String); => ' + result)
        console.log('new StringBuilder("' + partial + '");')
        return result;
    }
    console.log('[+] new StringBuilder(java.lang.String) hooked');
    

    3.4 Hook 生成对象—使用$new

    const JavaString = Java.use('java.lang.String');
    var exampleString1 = JavaString.$new('Hello World, this is an example string in Java.');
    console.log('[+] exampleString1: ' + exampleString1);
    

    3.5 Hook 内部类—使用$

    var inInnerClass = Java.use('ese.xposedtest.MainActivity$inInnerClass');
    
    inInnerClass.methodInclass.implementation = function()
    {
        var arg0 = arguments[0];
        var arg1 = arguments[1];
        send("params1: "+ arg0 +" params2: " + arg1);
        return this.formInclass(1,"Frida");
    }
    

    3.6 Hook native 函数

    Interceptor.attach(Module.findExportByName("xxx.so" , "xxxx"), {
        onEnter: function(args) {
            send("open(" + Memory.readCString(args[0])+","+args[1]+")");
        },
        onLeave:function(retval){
        
        }
    });
    

    3.7 Hook 静态变量(属性)/参考文章中有反射的方法

    var ah = Java.use("com.ah");
    console.log("To Log: " + ah.a.value);
    ah.a.value = true;
    

    3.8 打印堆栈

    AndroidLog = Java.use("android.util.Log")
    AndroidException = Java.use("java.lang.Exception")
    function printStackTrace(){
    	console.log(AndroidLog .getStackTraceString(AndroidException .$new()));
    }
    

    3.9 byte转String

    function byte2string(array){
        var result = "";
        for(var i = 0; i < array.length; ++i){
            result+= (String.fromCharCode(array[i]));
        }
       return result;
    }
    

    3.10 字符串转Uint8Array

    function string2byte(str){
      for (var i = 0,arr=[]; i < str.length;i++){
        arr.push(str.charCodeAt(i));
      }
      return new Uint8Array(arr);
    }
    

    3.11 int转bytes

    function intTobytes(n) {
      var bytes = [];
      for (var i = 0; i < 2; i++) {
        bytes[i] = n >> (8 - i * 8);
     
      }
      return bytes;
    }
    

    3.12 string转ArrayBuffer

    function str2arraybuffer(str) {
      var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
      var bufView = new Uint16Array(buf);
      for (var i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
      }
      return buf;
    }
    

    3.13 ArrayBuffer转String

    function ab2str(buf) {
      return String.fromCharCode.apply(null, new Uint8Array(buf));
    }
    

    3.14 添加时间戳

     console.log(new Date(new Date().getTime())
    

    3.15 byte转Hex

    这个非常常用,因为有些byte是没有办法转成string的,只能转成hex,用来查看
    参考文章

    function byteToHexString(uint8arr) {
      if (!uint8arr) {
        return '';
      }
      
      var hexStr = '';
      for (var i = 0; i < uint8arr.length; i++) {
        var hex = (uint8arr[i] & 0xff).toString(16);
        hex = (hex.length === 1) ? '0' + hex : hex;
        hexStr += hex;
      }
      
      return hexStr.toUpperCase();
    }
    

    3.16 Hex转byte

    function hexStringToByte(str) {
      if (!str) {
        return new Uint8Array();
      }
      
      var a = [];
      for (var i = 0, len = str.length; i < len; i+=2) {
        a.push(parseInt(str.substr(i,2),16));
      }
      
      return new Uint8Array(a);
    }
    
    展开全文
  • frida-script 储存自己的FRIDA HOOK脚本
  • Frida Hook scripts

    2020-11-02 14:33:15
    Frida Hook - Hook Dlopen //第一种方式(针对较老的系统版本) var dlopen = Module.findExportByName(null, "dlopen"); console.log(dlopen); if(dlopen != null){ Interceptor.attach(dlopen,{ onEnter: ...

    Frida Hook

    - Hook Dlopen

    //第一种方式(针对较老的系统版本)
    var dlopen = Module.findExportByName(null, "dlopen");
    console.log(dlopen);
    if(dlopen != null){
        Interceptor.attach(dlopen,{
            onEnter: function(args){
                var soName = args[0].readCString();
                console.log(soName);
                if(soName.indexOf("libc.so") != -1){
                    this.hook = true;
                }
            },
            onLeave: function(retval){
                if(this.hook) { 
                    dlopentodo();
                };
            }
        });
    }
    
    //第二种方式(针对新系统版本)
    var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
    console.log(android_dlopen_ext);
    if(android_dlopen_ext != null){
        Interceptor.attach(android_dlopen_ext,{
            onEnter: function(args){
                var soName = args[0].readCString();
                console.log(soName);
                if(soName.indexOf("libc.so") != -1){
                    this.hook = true;
                }
            },
            onLeave: function(retval){
                if(this.hook) {
                    dlopentodo();
                };
            }
        });
    }
    function dlopentodo(){
        //todo ...
    }
    

    - Java堆栈打印

    function show_java_trace(){
        Java.perform(function(){
            var MessageDigest = Java.use("java.security.MessageDigest");
            MessageDigest.digest.overload().implementation = function(){
                //var stack = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
                var stack = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
                console.log(stack);
                return this.digest();
            }
        });
    }
    

    - Native堆栈打印

    function show_native_trace(){
        var func = Module.findBaseAddress("libil2cpp.so").add(0x56FCA8);
        Interceptor.attach(func, {
            onEnter: function(args){
                console.log("called from:\n"+
                    Thread.backtrace(this.context,Backtracer.ACCURATE)
                    .map(DebugSymbol.fromAddress).join("\n"));
            },
            onLeave: function(retval){
                
            }
        });
    }
    

    - HookJava中的loadLibrary并打印堆栈

    function hook_library(){
        Java.perform(function() {
            const System = Java.use('java.lang.System');
            const Runtime = Java.use('java.lang.Runtime');
            const VMStack = Java.use('dalvik.system.VMStack');
    
            System.loadLibrary.implementation = function(library) {
                try {
                    console.log('System.loadLibrary("' + library + '")');
                    console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
                    const loaded = Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), library);
                    return loaded;
                } catch(ex) {
                    console.log(ex);
                }
            };
    
            System.load.implementation = function(library) {
                try {
                    console.log('System.load("' + library + '")');
                    console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
                    const loaded = Runtime.getRuntime().load0(VMStack.getCallingClassLoader(), library);
                    return loaded;
                } catch(ex) {
                    console.log(ex);
                }
            };
        });
    }
    

    - String转Byte

    function stringToBytes(str) {  
        var ch, st, re = []; 
        for (var i = 0; i < str.length; i++ ) { 
            ch = str.charCodeAt(i);  
            st = [];                 
            do {  
                st.push( ch & 0xFF );  
                ch = ch >> 8;          
            }    
            while ( ch );  
            re = re.concat( st.reverse() ); 
        }  
        return re;  
    }
    

    - hexToBytes

    function hexToBytes(str) {
        var pos = 0;
        var len = str.length;
        if (len % 2 != 0) {
            return null;
        }
        len /= 2;
        var hexA = new Array();
        for (var i = 0; i < len; i++) {
            var s = str.substr(pos, 2);
            var v = parseInt(s, 16);
            hexA.push(v);
            pos += 2;
        }
        return hexA;
    }
    

    - bytes2Hex

    function bytes2Hex(arr) {
        var str = "[";
        for (var i = 0; i < arr.length; i++) {
            var z = parseInt(arr[i]);
            if (z < 0) z = 255 + z;
            var tmp = z.toString(16);
            if (tmp.length == 1) {
                tmp = "0" + tmp;
            }
            str = str + " " + tmp;
        }
        return (str + " ]").toUpperCase();
    }
    

    - ArrayBuffer 转换

    function ab2Hex(buffer) {
        var arr = Array.prototype.map.call(new Uint8Array(buffer), function (x) {return ('00' + x.toString(16)).slice(-2)}).join(" ").toUpperCase();
        return "[" + arr + "]";
    }
     
    function ab2Str(buffer) {
        return String.fromCharCode.apply(null, new Uint8Array(buffer));
    }
    

    - jstring, jbytearray显示

    function jstring2Str(jstring) {
       var ret;
       Java.perform(function() {
           var String = Java.use("java.lang.String");
           ret = Java.cast(jstring, String);
       });
       return ret;
    }
     
    function jbyteArray2Array(jbyteArray) {
       var ret;
       Java.perform(function() {
           var b = Java.use('[B');
           var buffer = Java.cast(jbyteArray, b);
           ret = Java.array('byte', buffer);
       });
       return ret;
    }
    

    - 主线程调用

    function RunOnMain(){
        Java.perform(function(){
            var cls_main = null
            //获取Context
            Java.choose("com.lzy.ndk.MainActivity",{
                onMatch:function(clazz){
                    cls_main = clazz
                },
                onComplete:function(){}
            })
            //动态注册一个类实现Runnable方法
            var cls_run = Java.registerClass({
                name:"com.lzy.frida.runnable",
                implements:[Java.use("java.lang.Runnable")],
                //创建类成员变量
                fields:{
                    description: 'java.lang.String',
                    limit: 'int'
                },
                //创建方法以及重载方法的用法
                methods:{
                    run:function(){
                        Java.use("android.widget.Toast").makeText(cls_main,Java.use("java.lang.String").$new("this is a test Toast"),1).show()
                    
                    },
                    add:[{
                        returnType:'java.lang.String',
                        argumentTypes:['java.lang.String','java.lang.String'],
                        implementation:function(str1,str2){
                            return str1+"+++"+str2
                        }
                    },
                    {
                        returnType:'java.lang.String',
                        argumentTypes:['java.lang.String'],
                        implementation:function(str1){
                            return str1+"==="
                        }
                    }
                    ]
                }
            })
            //这里的实现主线程调用方法很多,这里举例一种
            //1.随便在MainActivity找一个View,View.post(Runnable)
            cls_main.bt1.value.post(cls_run.$new())
            //2.Activity的方法runOnUiThread()
            cls_main.runOnUiThread(cls_run.$new())
            //3.new Handler(getMainLooper()).post()
            Java.use("android.os.Handler").$new(cls_main.getMainLooper()).post(cls_run.$new())
            //4.Java.scheduleOnMainThread(function(){}) 不推荐,不好用总是出问题
            Java.scheduleOnMainThread(function(){
                console.log(Java.isMainThread())
            })
        })
    }
    

    批量断点定位调用

    function add_native_break_points(){
        
    // 结合Il2CppDumper使用,用于批量快速下断点,跟踪native函数调用
    // frida -U -f <PackageName> -l C:\Users\lzy\utils\bpoints.js --no-pause
    
    const soName = "libil2cpp.so"
    
    const arrayAddr =
        ['0x71541c', '0x715b38', '0x715be4', '0x715c61']
    
    const arrayName =
        ['GameManager$$Awake', 'GameManager$$GetParam', 'GameManager$$SaveParam', 'GameManager$$ActivatePrivacyButton']
    
    function breakPoints(){
    
        const soAddr = Module.findBaseAddress(soName);
        console.error('\nsoAddr:' + soAddr + "\n");
    
        Java.perform(function(){
            arrayAddr
                .map(function(temp){return soAddr.add(temp)})
                .forEach(function(value,index,array){
                    console.log("-------------------------");
                    console.log('currentAddr:' + value);
                    try{
                        funcTmp(value,index,arrayName);
                    }catch(e){
                        //Thumb指令集地址要加一
                        funcTmp(value.add(1),soAddr,index,arrayName);
                    }
                console.log("\t\t---->"+index,value+" is prepared ");
            })
            console.log("\n")
        })
    
        function funcTmp(currentAddr,index,arrayName){
            Interceptor.attach(currentAddr, {
                onEnter: function(args){
                    console.log("called : "+arrayName[index]+"  ----- addr : " + currentAddr.sub(soAddr) +"\n");
                    this.temp = currentAddr.sub(soAddr);
                    if(this.temp === 0xef3080) {
                        console.log('CCCryptorCreate called from:\n' +
                            Thread.backtrace(this.context, Backtracer.ACCURATE)
                                .map(DebugSymbol.fromAddress).join('\n') + '\n');
                    }
                },
                onLeave: function(retval){
    
                }
            });
        }
    }
    
    function hook_dlopen() {
        // const dlopen = Module.findExportByName(null, "dlopen");
        const dlopen = Module.findExportByName(null, "android_dlopen_ext");
    
        if (dlopen != null) {
            Interceptor.attach(dlopen, {
                onEnter: function (args) {
                    var l_soName = args[0].readCString()
                    console.log(l_soName)
                    if (l_soName.indexOf(soName) != -1) {
                        this.hook = true
                    }
                },
                onLeave: function (retval) {
                    if (this.hook) {
                        console.warn("\nLoaded "+soName + " add break points")
                        breakPoints()
                    }
                }
            })
        }
    }
    
    setImmediate(hook_dlopen())
    }
    

    配合Il2CppDumper生成的script.json食用更香

    import json
    
    if __name__ == '__main__':
    
        # json地址
        f = open('C:\\Users\\lzy\\Desktop\\Il2CppDumper-v6.2.1\\script.json',encoding='utf-8')
        # 查找的字符串
        searchStr = "Network"
    
        j = json.load(f)
        ScriptMethod = j['ScriptMethod']
        ScriptMetadataMethod = j['ScriptMetadataMethod']
    
        temp_name = []
        temp_addr = []
    
        for temp in ScriptMethod:
            if searchStr in temp["Name"]:
                temp_name.append(temp["Name"])
                temp_addr.append(hex(temp["Address"]))
    
        print('Found : '+str(len(temp_name))+' Function')
        print('--------------------------------')
        print(temp_addr)
        print('--------------------------------')
        print(temp_name)
        print('--------------------------------')
    

    - TracerPid fgets 反调试

        var anti_fgets = function () {
            show_log("anti_fgets");
            var fgetsPtr = Module.findExportByName("libc.so", "fgets");
            var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']);
            Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) {
                var retval = fgets(buffer, size, fp);
                var bufstr = Memory.readUtf8String(buffer);
                if (bufstr.indexOf("TracerPid:") > -1) {
                    Memory.writeUtf8String(buffer, "TracerPid:\t0");
                    // dmLogout("tracerpid replaced: " + Memory.readUtf8String(buffer));
                }
                return retval;
            }, 'pointer', ['pointer', 'int', 'pointer']));
        };
    
    

    - 日志打印

    function log(str){
        var threadid = Process.getCurrentThreadId()
        var date = new Date()
        var month = date.getMonth() + 1
        var strDate = date.getDate()
        var hour = date.getHours()
        var Minutes = date.getMinutes()
        var Seconds = date.getSeconds()
        if (month >= 1 && month <= 9) {
            month = "0" + month
        }
        if (strDate >= 0 && strDate <= 9) {
            strDate = "0" + strDate
        }
        if (hour >= 0 && hour <= 9) {
            hour = "0" + hour
        }
        if (Minutes >= 0 && Minutes <= 9) {
            Minutes = "0" + Minutes
        }
        if (Seconds >= 0 && Seconds <= 9) {
            Second = "0" + Seconds
        }
        var currentDate = date.getFullYear() + "-" + month + "-" + strDate
                + " " + hour + ":" + Minutes + ":" + Seconds
        var log = "["+threadid+"][" + currentDate + "] --- " + str
        console.log('\x1b[3' + '6;01' + 'm', log, '\x1b[39;49;00m')
    }
    

    - 内存dump so(脱壳upx壳)

    function dump_so(so_name) {
        Java.perform(function () {
            var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
            var dir = currentApplication.getApplicationContext().getFilesDir().getPath();
            var libso = Process.getModuleByName(so_name);
            console.error("------------------------------");
            console.warn("[name]:", libso.name);
            console.warn("[base]:", libso.base);
            console.warn("[size]:", libso.size);
            console.warn("[path]:", libso.path);
            console.error("------------------------------");
            var file_path = dir + "/" + libso.name + "_" + libso.base + "_" + ptr(libso.size) + ".so";
            var file_handle = new File(file_path, "wb");
            if (file_handle && file_handle != null) {
                Memory.protect(ptr(libso.base), libso.size, 'rwx');
                var libso_buffer = ptr(libso.base).readByteArray(libso.size);
                file_handle.write(libso_buffer);
                file_handle.flush();
                file_handle.close();
                console.log("[dump]:", file_path);
            }
        });
    }
    

    - 动态加载Dex

    function loadDex(){
        //这里只是提一下可以使用Frida提供的Api加载dex,你也可以解包再打包,但是显然这个方便得多
        //手动去加载一些工具类(Gson,AndroidUtilCode,自己写的工具类等等)
        Java.openClassFile("/data/local/tmp/helper.dex").load()
        var gson = Java.use("com.google.gson.Gson").$new()
        ...
    }
    

    - 计划任务

    function ScheduledTask(){
        //用在Spawn启动的时候
        setImmediate(function(){
            console.log("立即执行,只执行一次")
        })
        setTimeout(function(){
            console.log("一秒后执行,只执行一次")
        },1000)
        //Frida Api
        setInterval(function(){
            console.log("每隔一秒执行一次")
        },1000)
        // Java Api
        Java.perform(function(){
            Java.registerClass({
                name:"com.lzy.frida.tsk",
                superClass:Java.use("java.util.TimerTask"),
                methods:{
                    run:function(){
                        console.log("等待两秒后每隔一秒调用一次")
                    }
                }
            })
            Java.use("java.util.Timer").$new().schedule(Java.use("com.lzy.frida.tsk").$new(),2000,1000)
        })
    }
    

    - JNI函数Trace Demo

    function TraceJni(){
        Java.perform(function(){
    
            var pSize = Process.pointerSize
            var env = Java.vm.getEnv()
    
            //JNI函数相对env偏移位置参考:
            //https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#NewStringUTF
            var GetStaticMethodID = 113,findclass = 6,RegisterNatives = 215;
        
            function getNativeAddress(idx) {
                return env.handle.readPointer().add(idx * pSize).readPointer()
            }
    
            Interceptor.attach(getNativeAddress(findclass),{
                onEnter:function(args){
                    console.error("-------------findClass-------------")
                    console.warn("env\t--->\t"+args[0])
                    console.warn("class\t--->\t"+args[1].readCString())
                },
                onLeave:function(retval){}
            })
    
            Interceptor.attach(getNativeAddress(GetStaticMethodID),{
                onEnter:function(args){
                    console.error("\n-------------GetStaticMethodID-------------")
                    console.warn(args[0])
                    console.warn(args[1])
                    console.warn(args[2].readCString())
                },
                onLeave:function(retval){}
            })
    
            //RegisterNative结构体参照:
            //https://android.googlesource.com/platform/libnativehelper/+/master/include_jni/jni.h#129
            Interceptor.attach(getNativeAddress(RegisterNatives), {
                onEnter: function(args) {
                    console.log(parseInt(args[3]))
                    for (var i = 0,nMethods = parseInt(args[3]); i < nMethods; i++) {
                        var structSize = pSize * 3; // = sizeof(JNINativeMethod)
                        var methodsPtr = ptr(args[2]);
                        var signature = methodsPtr.add(i * structSize + pSize).readPointer();
                        var fnPtr = methodsPtr.add(i * structSize + (pSize * 2)).readPointer(); // void* fnPtr
                        var jClass = jclassAddress2NameMap[args[0]].split('/');
                        var methodName = methodsPtr.add(i * structSize).readPointer().readCString();
                        console.log('\x1b[3' + '6;01' + 'm', JSON.stringify({
                            module: DebugSymbol.fromAddress(fnPtr)['moduleName'],
                            // https://www.frida.re/docs/javascript-api/#debugsymbol
                            package: jClass.slice(0, -1).join('.'),
                            class: jClass[jClass.length - 1],
                            method: methodName,
                            // methodsPtr.readPointer().readCString(), // char* name
                            signature: signature.readCString(),
                            // char* signature TODO Java bytecode signature parser { Z: 'boolean', B: 'byte', C: 'char', S: 'short', I: 'int', J: 'long', F: 'float', D: 'double', L: 'fully-qualified-class;', '[': 'array' } https://github.com/skylot/jadx/blob/master/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java
                            address: fnPtr
                        }), '\x1b[39;49;00m');
                    }
                }
            });
        })
    }
    

    - Native Log日志Hook

    #int __android_log_print(int prio, const char* tag, const char* fmt, ...)
    function hookLog() {
        Interceptor.attach(Module.findExportByName("liblog.so","__android_log_print"), {
            onEnter: function (args) {
                // var level = ""
                // var level_i = parseInt(args[0])
                // if(level_i == 0){
                //     level = "ANDROID_LOG_UNKNOWN"
                // }else if(level_i == 1){
                //     level = "ANDROID_LOG_DEFAULT"
                // }else if(level_i == 2){
                //     level = "ANDROID_LOG_VERBOSE"
                // }else if(level_i == 3){
                //     level = "ANDROID_LOG_DEBUG"
                // }else if(level_i == 4){
                //     level = "ANDROID_LOG_INFO"
                // }else if(level_i == 5){
                //     level = "ANDROID_LOG_WARN"
                // }else if(level_i == 6){
                //     level = "ANDROID_LOG_ERROR"
                // }else if(level_i == 7){
                //     level = "ANDROID_LOG_FATAL"
                // }else if(level_i == 8){
                //     level = "ANDROID_LOG_SILENT"
                // }
                // if(level_i==5){
                //     console.warn(level+"\t"+args[1].readCString()+"\t"+args[2].readCString())
                // }else if(level_i > 5){
                //     console.error(level+"\t"+args[1].readCString()+"\t"+args[2].readCString())
                // }else{
                //     console.log(level+"\t"+args[1].readCString()+"\t"+args[2].readCString())
                // }
                console.log(args[1].readCString()+"\t"+args[2].readCString())
            }
        });
    }
    

    - Native函数断点/调用/替换

    //主动调用native函数
        var soAddr = Module.findBaseAddress("libil2cpp.so");
        new NativeFunction(soAddr.add(0x4c33b0),"void",['pointer'])(Java.vm.tryGetEnv())
    
    //替换native函数
    //支持的类型:void,pointer,int,uint,long,ulong,char,uchar,float,double,int8,uint8,int16,uint16,int32,uint32,int64,uint64,bool
        Interceptor.replace(new NativeFunction(soAddr.add(0x58F0F4),'void', ['pointer']), new NativeCallback(function (arg) {
            console.log("called from:\n"+
                    Thread.backtrace(this.context,Backtracer.FUZZY)
                    .map(DebugSymbol.fromAddress).join("\n"));
        }, 'void', ['pointer']));
    
    //拦截native函数
        Interceptor.attach(soAddr.add(0xb7a93c),{
            onEnter:function(arg){
                console.log("called 0xb7a93c")
            },
            onLeave:function(retval){
                console.warn(retval)
            }
        })
    

    - 获取类型

    function getParamType(obj) {
        return obj == null ? String(obj) : Object.prototype.toString.call(obj).replace(/\[object\s+(\w+)\]/i, "$1") || "object";
    }
    

    - hook 所有重载函数

    function hookAllOverloads(targetClass, targetMethod) {
        Java.perform(function () {
             var targetClassMethod = targetClass + '.' + targetMethod;
             var hook = Java.use(targetClass);
             var overloadCount = hook[targetMethod].overloads.length;
             for (var i = 0; i < overloadCount; i++) {
                    hook[targetMethod].overloads[i].implementation = function() {
                         var retval = this[targetMethod].apply(this, arguments);
                         //这里可以打印结果和参数
                         return retval;
                     }
                  }
       });
     }
    
    //基础数据类型
    var char= Java.use("java.lang.Class").getPrimitiveClass("char")
    展开全文
  • Frida Dynamic instrumentation toolkit for developers, reverse-engineers, and security researchers. Learn more at frida.re. Two ways to install 1. Install from prebuilt binaries This is the ...
  • Frida hook Java层

    2020-12-17 15:46:40
    Frida hook Java层包括Hook普通方法(包含静态方法)、构造方法、重载方法、以及构造对象参数和修改对象属性象参数。

    往期推荐

    frida环境安装

    Xposed框架安装、使用及插件开发

    HOOK startActivity

    HOOK框架——动态代理

    需要相关资料的朋友,可以【[加入此处即可打包获取]】

    需要对在进程外传递的消息进行拦截处理就必须采取一种称为HOOK的技术,HOOK作为Windows操作系统中非常重要的一种系统接口,用它可以轻松截获并处理在其他应用程序之间传递的消息,并由此可以完成一些普通应用程序难以实现的特殊功能。

    Frida hook Java层包括Hook普通方法(包含静态方法)、构造方法、重载方法、以及构造对象参数和修改对象属性象参数。

    一:编写Hook代码

    1.分析目标app找到hook的具体类以及方法名、参数、类型等基本信息。

    2.编写相应的hook代码。

    (1)普通方法

    填写要hook的包名、类名、方法具体所在的类、方法名、参数列表、参数类型,如下图所示。

    在这里插入图片描述

    (2)构造方法

    填写要hook的包名、类名、方法具体所在的类、方法名、参数列表、参数类型、返回值、参数类型,如如下图所示。

    在这里插入图片描述

    (3)重载方法

    填写要hook的包名、类名、方法具体所在的类、方法名、参数列表、参数类型、返回值,如下图所示。

    在这里插入图片描述

    (4)构造对象参数、

    填写要hook的包名、类名、方法具体所在的类、方法名、参数列表、参数类型、返回值、参数信息,如下图所示。

    在这里插入图片描述

    (5)修改对象属性

    填写要hook的包名、类名、方法具体所在的类、方法名、参数列表、参数类型、返回值、参数信息,如下图所示。

    在这里插入图片描述

    二:开始hook

    1.cmd输入hook命令:python Java.py。
    2.启动程序,触发后查看hook结果信息。

    小结

    分享了frida hook Java层,使用模板注意修改参数以及包名类名,启动程序触发,hook成功显示结果。

    如果你也对安卓逆向感兴趣。可以加入下方的群,大家一起讨论问题,或者扫描下方二维码关注公众号,关注回复 “安卓逆向” 获取免费教程

    安卓逆向交流学习 Q群:876526335
    vx:yijin_LX

    在这里插入图片描述

    展开全文
  • Frida hook app

    千次阅读 2017-11-03 16:55:43
    Frida hook app需要的工具小米人改之理:反编译appIDA:针对.so文件fridahook函数,可以打印入参,函数返回值启动frida-serveradb push /home/michael/Downloads/frida-server-10.0.15-android-arm /data/local/...
  • frida hook Windows程序

    千次阅读 2021-03-02 14:32:22
    内容讲的是用frida hook C语言编写的控制台程序,我用的C编译器Dev C++: https://wwx.lanzoui.com/iIEQlmddw7c 第一个例子:hello.exe exe代码,将这个代码命名为hello.c用dev打开编译一下会生成hello.exe。打开让他...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,068
精华内容 827
关键字:

fridahook