frida hook note


FRIDA-HOOK note

0x1 java层hook

function hook_java(){
    Java.perform(function(){
        var LoginActivity = Java.use("com.example.androiddemo.Activity.LoginActivity");
        LoginActivity.a.overload('java.lang.String', 'java.lang.String').implementation = function(str , str2){
            var result = this.a(str,str2);
            console.log("LoginActivity.a:",str,str2,result);
            return result;
        };
    });
}
function main(){
    hook_java();
}
setImmediate(main);

Java.perform 附加线程

Java.use 反射获取类

.overload 出现同名函数时使用

0x2 扫描java类

function call_FridaActivity2(){
    Java.perform(function (){
        var FridaActivity2 = Java.use("com.example.androiddemo.Activity.FridaActivity2");
        FridaActivity2.setStatic_bool_var();
        Java.choose("com.example.androiddemo.Activity.FridaActivity2", {
            onMatch: function (instance){
                instance.setBool_var();
            },
            onComplete: function (){

            }
        });
    });
}

Java.choose(className, callback)

在内存中扫描 Java 堆,枚举 Java 对象(className)实例。比如可以使用 java.lang.String 扫描内存中的字符串。callbacks 提供两个参数:onMatch(instance) 和 onComplete,分别是找到匹配对象和扫描完成调用

function call_FridaActivity3(){
    Java.perform(function(){
        var FridaActivity3 = Java.use("com.example.androiddemo.Activity.FridaActivity3");
        FridaActivity3.static_bool_var.value =true;
        Java.choose("com.example.androiddemo.Activity.FridaActivity3",{
            onMatch: function(instance){
                instance.bool_var.value=true;
                //相同名称开头要加下划线
                instance._same_name_bool_var.value=true;
            },
            onComplete: function(){

            }
        })
    });

}

参数名相同前面需要加下划线

0x3 遍历所有类方法找到自己想要的类方法

function call_FridaActivity4(){
    Java.perform(function(){
        var class_name = "com.example.androiddemo.Activity.FridaActivity4$InnerClasses";
        var InnerClasses = Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses");
        var all_methonds = InnerClasses.class.getDeclaredMethods();
        for(var i=0 ;i < all_methonds.length;i++){
            var methods=(all_methonds[i]);
            var methods_str = methods.toString();
            var methodnames = methods_str.substr(methods_str.indexOf(class_name) + class_name.length + 1);
            var methodname = methodnames.substr(0,methodnames.indexOf("("));
            console.log(methodname);

            InnerClasses[methodname].implementation = function(){
                return true;
            }
        }

    });
}

getMethods:获取当前类或父类或父接口的 public 修饰的字段;包含接口中 default 修饰的方法

getDeclaredMethods: 获取当前类的所有方法;包括 protected/默认/private 修饰的方法;不包括父类 、接口 public 修饰的方法

0x4 hook 动态dex

function hook_dyn_dex(){
    Java.perform(function(){
        var FridaActivity5 = Java.use("com.example.androiddemo.Activity.FridaActivity5");
        Java.choose("com.example.androiddemo.Activity.FridaActivity5",{
            onMatch: function(instance){
                console.log(instance.getDynamicDexCheck().$classname);
            },
            onComplete: function(){

            }
        });
   
        Java.enumerateClassLoaders({
            onMatch: function(loader){
                try{
                    if (loader.findClass("com.example.androiddemo.Dynamic.DynamicCheck")){
                        console.log(loader);
                        Java.classFactory.loader = loader;
                    }
                } catch(error){

                }
            }, onComplete:function(){

            }
        });

        var DynamicCheck = Java.use("com.example.androiddemo.Dynamic.DynamicCheck");
        DynamicCheck.check.implementation = function(){
            console.log("DynamicCheck.check");
            return true;
        }

    });

}

enumerateClassLoaders 枚举 Java VM 中存在的类加载器

0x5 枚举已经加载的类

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

            }
        })
    });
}

enumerateLoadedClasses(callbacks) 注意与上方的不是同一个函数

枚举当前已加载的类。callbacks 参数是一个对象,需要提供两个回调函数—— onMatch(className)onComplete。每次找到一个类就会调用一次 onMatch,全部找完之后,调用 onComplete

0x6 打印调用栈

function print_stack(){
    Java.perform(function(){
        var Exception = Java.use("java.lang.Exception");
        var instance = Exception.$new("print_stack");
        var stack = instance.getStackTrace();
        console.log(stack);
        instance.$dispose();
    });
}

通过app自带的Exception中的getstackTrace 直接打印

0x7 加载并调用自写dex中的函数

先是用安卓studio写自己想要用的函数编译出class文件

jar -cvf dex.jar DecodeUtils.class 用jar把class转换成jar

然后这里可以有两个方法一是安卓sdk中的工具dx –dex –output=ddex.dex dex.jar 将jar转换成dex

第二种就是用ApkToolBox直接jar转dex都是可以的

最后用adb命令把dex push到真机或模拟器中

var ddex2 = Java.openClassFile("/data/local/tmp/dd");
    Java.perform(function(){

        ddex2.load();
        var DecodeUtils = Java.use("com.example.myapplication.DecodeUtils");
        console.log("DecodeUtils.decode_p:", DecodeUtils.decode_p());
        console.log("r to hex", DecodeUtils.r_to_hex());
var a = Java.use("com.tlamb96.kgbmessenger.b.a");
     // hook 构造函数用$init
     a.$init.implementation = function(i,str,str2,z){
         this.$init(i,str,str2,z);
         console.log("a.$init:",i,str,str2,z);
         print_stack();
     };

hook 在java层的构造函数需要前面加$init

0x8 hook so层

function hook_native() {
    //获取模块的基址
    var base_myjni = Module.findBaseAddress("libmyjni.so");
    if (base_myjni) {
        //获取模块的导出函数
        var n2 = Module.findExportByName("libmyjni.so", "n2");
        //thumb的函数,0x000011F8, 实际地址0xdba461f9
        console.log("base_myjni:", base_myjni, "n2:", n2);
        //hook模块的导出函数
        Interceptor.attach(n2, {
            onEnter: function (args) {
                console.log("n2 onEnter:", args[0], args[1], args[2]);
            }, onLeave: function (retval) {

            }
        });
    }
}

Interceptor.attach(target, callbacks)
在target指定的位置进行函数调用拦截,target是一个NativePointer参数,用来指定你想要拦截的函数的地址。callbacks参数是一个对象:
onEnter: function(args): 被拦截函数调用之前回调,其中原始函数的 参数使用args数组(NativePointer对象数组)来表示,可以在这里修改函数的调用参数。
onLeave: function(retval): 被拦截函数调用之后回调,其中retval表示原始函数的返回值,retval是从NativePointer继承来的,是对原始返回值的一个封装,可以使用retval.replace(1337)调用来修改返回值的内容。注意:retval对象只在 onLeave函数作用域范围内有效,因此如果你要保存这个对象以备后续使用的话,一定要使用深拷贝来保存对象,比如:ptr(retval.toString())

0x9 hook libc函数

function hook_libc() {
    //hook libc的函数
    var strcmp = Module.findExportByName("libc.so", "strcmp");
    console.log("strcmp:", strcmp);
    Interceptor.attach(strcmp, {
        onEnter: function (args) {
            var str_2 = ptr(args[1]).readCString();
            if (str_2 == "EoPAoY62@ElRD") {
                console.log("strcmp:", ptr(args[0]).readCString(),
                    ptr(args[1]).readCString());
            }
        }, onLeave: function (retval) {
        }
    });

}

0x10 frida api进行读写

function write_reg_dat() {

    //frida 的api来写文件
    var file = new File("/sdcard/reg.dat", "w");
    file.write("EoPAoY62@ElRD");
    file.flush();
    file.close();
}

0x11 把C函数定义为NativeFunction来写文件

function write_reg_dat2() {

    //把C函数定义为NativeFunction来写文件
    var addr_fopen = Module.findExportByName("libc.so", "fopen");
    var addr_fputs = Module.findExportByName("libc.so", "fputs");
    var addr_fclose = Module.findExportByName("libc.so", "fclose");

    console.log("addr_fopen:", addr_fopen, "addr_fputs:", addr_fputs, "addr_fclose:", addr_fclose);
    var fopen = new NativeFunction(addr_fopen, "pointer", ["pointer", "pointer"]);
    var fputs = new NativeFunction(addr_fputs, "int", ["pointer", "pointer"]);
    var fclose = new NativeFunction(addr_fclose, "int", ["pointer"]);

    var filename = Memory.allocUtf8String("/sdcard/reg.dat");
    var open_mode = Memory.allocUtf8String("w+");
    var file = fopen(filename, open_mode);
    console.log("fopen file:", file);

    var buffer = Memory.allocUtf8String("EoPAoY62@ElRD");
    var ret = fputs(buffer, file);
    console.log("fputs ret:", ret);

    fclose(file);
}

0x12 hook_native

function hook_native() {
    var base_hello_jni = Module.findBaseAddress("libhello-jni.so");
    if (base_hello_jni) {
        //ollvm默认的字符串混淆,静态的时候没法看见字符串
        //执行起来之后,先调用.init_array里面的函数来解密字符串
        //解密完之后,内存中的字符串就是明文状态了。
        var addr_37070 = base_hello_jni.add(0x37070);
        console.log("addr_37070:", ptr(addr_37070).readCString());

        var addr_37080 = base_hello_jni.add(0x37080);
        console.log("addr_37080:", ptr(addr_37080).readCString());
    }
}

hook so的时候加地址使用.add

0x12 hook_RegisterNatives

function hook_libart() {
    var module_libart = Process.findModuleByName("libart.so");
    var symbols = module_libart.enumerateSymbols();     //枚举模块的符号
    var addr_RegisterNatives = null;

    for (var i = 0; i < symbols.length; i++) {
        var name = symbols[i].name;
        if (name.indexOf("art") >= 0) {
            if ((name.indexOf("CheckJNI") == -1) && (name.indexOf("JNI") >= 0)) {
               if (name.indexOf("RegisterNatives") >= 0) {
                    console.log(name);
                    addr_RegisterNatives = symbols[i].address;
                }
            }
        }
    }

    if (addr_RegisterNatives) {
        Interceptor.attach(addr_RegisterNatives, {
            onEnter: function (args) {
                console.log("addr_RegisterNatives:", hexdump(args[2]));
                console.log("addr_RegisterNatives name:", ptr(args[2]).readPointer().readCString())
                console.log("addr_RegisterNatives sig:", ptr(args[2]).add(Process.pointerSize).readPointer().readCString());
            }, onLeave: function (retval) {

            }
        });
    }
}

hexdump 16进制打印

readPointer() 指定要读取的指针的地址

0x13 inline_hook

function inline_hook() {
    var base_hello_jni = Module.findBaseAddress("libhello-jni.so");
    console.log("base_hello_jni:", base_hello_jni);
    if (base_hello_jni) {
        console.log(base_hello_jni);
        //inline hook
        var addr_07320 = base_hello_jni.add(0x07320);
        Interceptor.attach(addr_07320, {
            onEnter: function (args) {
                console.log("addr_07320 x13:", this.context.x13);
            }, onLeave: function (retval) {
            }
        });
    }
}

inline_hook 和上面的hook一样 this.context 后面跟的是寄存器 代表程序某个位置时某个寄存器的值

0x14 hook_dlopen

function hook_dlopen() {
    var dlopen = Module.findExportByName(null, "dlopen");
    Interceptor.attach(dlopen, {
        onEnter: function (args) {
            this.call_hook = false;
            var so_name = ptr(args[0]).readCString();
            if (so_name.indexOf("libhello-jni.so") >= 0) {
                console.log("dlopen:", ptr(args[0]).readCString());
                this.call_hook = true;
            }

        }, onLeave: function (retval) {
            if (this.call_hook) {
                inline_hook();
            }
        }
    });
    // 高版本Android系统使用android_dlopen_ext
    var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
    Interceptor.attach(android_dlopen_ext, {
        onEnter: function (args) {
            this.call_hook = false;
            var so_name = ptr(args[0]).readCString();
            if (so_name.indexOf("libhello-jni.so") >= 0) {
                console.log("android_dlopen_ext:", ptr(args[0]).readCString());
                this.call_hook = true;
            }

        }, onLeave: function (retval) {
            if (this.call_hook) {
                inline_hook();
            }
        }
    });
}

因为hook动态注册so时 还没加载so就frida注入了 所以需要先hook dlopen运行它加载后判断一下再hook,安卓8.0以下hook dlopen,8.0以上hook android_dlopen_ext

0x15 笔记未完待续..


文章作者: Blue
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Blue !
评论
  目录