记录一些日常使用frida经常会用到的一些小方法

整理一下之前的学习的一些常用frida的技巧,以备哪天快速查找。

  • 常规的java层的函数hook
1
2
3
var manActivity=Java.use("com.kanxue.algorithmbase.MainActivity");
var res= manActivity.encodeFromJni_71(input)
console.log("input:",input,"output:",res);
  • 主动调用函数
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//主动调用静态函数
var FridaActivity2 = Java.use("com.kanxue.algorithmbase.MainActivity");
FridaActivity2.setStatic_bool_var(); 
//主动调用非静态函数
Java.choose("com.example.androiddemo.Activity.FridaActivity2", {
  onMatch: function (instance) {
    instance.setBool_var();
  },
  onComplete: function () {
  }
});
  • 主动设置成员变量
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var FridaActivity3 = Java.use("com.example.androiddemo.Activity.FridaActivity3");
//设置非静态成员变量的值
FridaActivity3.static_bool_var.value = true;
console.log(FridaActivity3.static_bool_var.value);
Java.choose("com.example.androiddemo.Activity.FridaActivity3", {
  onMatch: function (instance) {
  //设置非静态成员变量的值
  instance.bool_var.value = true;
  //设置有相同函数名的成员变量的值
  instance._same_name_bool_var.value = true;
  console.log(instance.bool_var.value, instance._same_name_bool_var.value);
  },
  onComplete: function () {
    }
});
  • hook内部类
1
2
3
4
5
var InnerClasses = Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses");
console.log(InnerClasses);
InnerClasses.check1.implementation = function () {
    return true;
};
  • 根据条件判断动态hook多个函数
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var class_name = "com.example.androiddemo.Activity.FridaActivity4$InnerClasses";
var InnerClasses = Java.use(class_name);
var all_methods = InnerClasses.class.getDeclaredMethods();
for (var i = 0; i < all_methods.length; i++) {
  var method = (all_methods[i]);
  var methodStr = method.toString();
  var substring = methodStr.substr(methodStr.indexOf(class_name) + class_name.length + 1);
  var methodname = substring.substr(0, substring.indexOf("("));
  console.log(methodname);
  InnerClasses[methodname].implementation = function () {
    console.log("hook_mul_function:", this);
    return true;
  }
}
  • interface中的函数进行hook。需要先切换classloader
 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
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");
console.log(DynamicCheck);
DynamicCheck.check.implementation = function () {
  console.log("DynamicCheck.check");
  return true;
}
  • frida动态加载dex然后再调用dex中的函数
1
2
3
4
var ddex2 = Java.openClassFile("/data/local/tmp/ddex2.dex");
ddex2.load();
var DecodeUtils = Java.use("com.example.androiddemo.DecodeUtils");
console.log("DecodeUtils.decode_p:", DecodeUtils.decode_p());
  • hook构造函数
1
2
3
4
5
6
7
var a = Java.use("com.tlamb96.kgbmessenger.b.a");
  //hook 构造函数
  a.$init.implementation = function (i, str, str2, z) {
  this.$init(i, str, str2, z);
  console.log("a.$init:", i, str, str2, z);
  print_stack();       //打印了调用栈
};
  • 打印java堆栈
1
2
3
4
5
6
7
8
9
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();
    });
}
  • 调用NativeFunction来写入文件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
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);
}
  • 将指针以字符串的方式打印
1
2
3
4
5
function print_string(addr) {
    var base_hello_jni = Module.findBaseAddress("libhello-jni.so");
    var addr_str = base_hello_jni.add(addr);
    console.log("addr:", addr, " ", ptr(addr_str).readCString());
}
  • 延时hook。当用frida来启动应用时。hook的so还没有加载。所以要延时到加载完这个so后。才能hook
 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
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获取时间的函数。并且替换函数内容
 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
function hook_gettimeofday() {
    var addr_gettimeofday = Module.findExportByName(null, "gettimeofday");
    var gettimeofday = new NativeFunction(addr_gettimeofday, "int", ["pointer", "pointer"]);

    var source = [
        'struct timeval {',
        '    int tv_sec;',
        '    int tv_usec;',
        '};',
        'void modify_time(struct timeval* tv, int tv_sec, int tv_usec) {',
        '  tv->tv_sec = tv_sec;',
        '  tv->tv_usec = tv_usec;',
        '}',
    ].join('\n');

    var cm = new CModule(source);
    var modify_time = new NativeFunction(cm.modify_time, 'void', ["pointer", "int", "int"]);

    Interceptor.replace(addr_gettimeofday, new NativeCallback(function (ptr_tz, ptr_tzp) {

        var result = gettimeofday(ptr_tz, ptr_tzp);
        if (result == 0) {
            console.log("hook gettimeofday:", ptr_tz, ptr_tzp, result);
            //modify_time(ptr_tz, 0xAAAA, 0xBBBB);
            var t = new Int32Array(ArrayBuffer.wrap(ptr_tz, 8));
            t[0] = 0xAAAA;
            t[1] = 0xBBBB;
            console.log(hexdump(ptr_tz));
        }
        return result;
    }, "int", ["pointer", "pointer"]));
}
  • frida打patch补丁。可以用来搞反调试的
 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
48
49
50
51
52
53
54
55
56
function dis(address, number) {
    for (var i = 0; i < number; i++) {
        var ins = Instruction.parse(address);
        console.log("address:" + address + "--dis:" + ins.toString());
        address = ins.next;
    }
}

//libc->strstr()
function hook() {
//call_function("DT_INIT", init_func_, get_realpath());
    var linkermodule = Process.getModuleByName("linker");
    var call_function_addr = null;
    var symbols = linkermodule.enumerateSymbols();
    for (var i = 0; i < symbols.length; i++) {
        var symbol = symbols[i];
        //LogPrint(linkername + "->" + symbol.name + "---" + symbol.address);
        if (symbol.name.indexOf("__dl__ZL13call_functionPKcPFviPPcS2_ES0_") != -1) {
            call_function_addr = symbol.address;
            //LogPrint("linker->" + symbol.name + "---" + symbol.address)

        }
    }
    Interceptor.attach(call_function_addr, {
        onEnter: function (args) {
            var type = ptr(args[0]).readUtf8String();
            var address = args[1];
            var sopath = ptr(args[2]).readUtf8String();
            console.log("loadso:" + sopath + "--addr:" + address + "--type:" + type);
            if (sopath.indexOf("libnative-lib.so") != -1) {
                var libnativemodule = Process.getModuleByName("libnative-lib.so");
                var base = libnativemodule.base;
                dis(base.add(0x8D8E).add(1), 10);
                var patchaddr = base.add(0x8d96);
                Memory.patchCode(patchaddr, 4, patchaddr => {
                    var cw = new ThumbWriter(patchaddr);
                    cw.putNop();
                    cw = new ThumbWriter(patchaddr.add(0x2));
                    cw.putNop();
                    cw.flush();
                });
                /*                Memory.protect(base.add(0x8d96),4,'rwx');
                                base.add(0x8d96).writeByteArray([0x00,0xbf,0x00,0xbf]);*/
                console.log("+++++++++++++++++++++++")
                dis(base.add(0x8D8E).add(1), 10);
                console.log("----------------------")

                dis(base.add(0x8E6E).add(1), 10);
                Memory.protect(base.add(0x8E78), 4, 'rwx');
                base.add(0x8E78).writeByteArray([0x00, 0xbf, 0x00, 0xbf]);
                console.log("+++++++++++++++++++++++")
                dis(base.add(0x8E6E).add(1), 10);
            }
        }
    })
}
  • 用stalker来trace
 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
48
49
50
51
52
function hook_native(){
    var base_addr=Module.getBaseAddress("libnative-lib.so");
    var encodeFromJni_71=base_addr.add(0x156B4);
    Interceptor.attach(encodeFromJni_71,{
        onEnter:function(args){
            this.tid=Process.getCurrentThreadId();
            console.log("enter encodeFromJni_71 tid:",this.tid);
            Stalker.follow(this.tid, {
                events: {
                    call: true, // CALL instructions: yes please
                    // Other events:
                    ret: false, // RET instructions
                    exec: false, // all instructions: not recommended as it's
                                 //                   a lot of data
                    block: false, // block executed: coarse execution trace
                    compile: false // block compiled: useful for coverage
                },
                onCallSummary:function(summary){        //调用的地址和调用的次数
                    for(var iter in summary){
                        var module= Process.getModuleByAddress(ptr(iter))
                        if(module.name.indexOf("libnative-lib.so")!=-1){
                            console.log(ptr(iter).sub(module.base));
                        }
                    }
                },
                onReceive:function(events){             //调用的流程,地址1是哪里发生的调用。地址2是调用到了哪里
                    console.log("enter onReceive")
                    var eventsData=Stalker.parse(events,{
                        annotate: true,
                        stringify: true
                    });
                    for(var idx in eventsData){
                        var dataSp=eventsData[idx];
                        var addr1=dataSp[1];
                        var addr2=dataSp[2];
                        try{
                            var module1=Process.getModuleByAddress(ptr(addr1));
                            if(module1.name.indexOf("libnative-lib.so")!=-1){
                                var module2=Process.getModuleByAddress(ptr(addr2));
                                console.log(dataSp[0],module1.name,addr1,module2.name,addr2);
                            }
                        }catch(err){
                            console.log(dataSp);
                        }
                    }
                }
            })
        },onLeave(retval){
            Stalker.unfollow(this.tid);
        }
    })
}
  • 比较通用的native函数hook打印
 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
//打印参数
function hexdumpMem(addr){
    if(Process.findRangeByAddress(addr)){
        return hexdump(ptr(addr),{length:0x40})+"\r\n"
    }else{
        return ptr(addr)+"\r\n";
    }
}
//比较通用的hook地址并且打印5个参数。如果参数是地址就打印下内存信息
function nativeHookFunction(addr){
    var base_addr=Module.getBaseAddress("libnative-lib.so");
    var hook_addr=base_addr.add(addr);
    Interceptor.attach(hook_addr,{
        onEnter:function(args){
            this.logs=[];
            this.logs.push("call",addr);
            this.arg0=args[0];
            this.arg1=args[1];
            this.arg2=args[2];
            this.arg3=args[3];
            this.arg4=args[4];
            this.arg5=args[5];
            this.logs.push("arg0:",hexdumpMem(this.arg0));
            this.logs.push("arg1:",hexdumpMem(this.arg1));
            this.logs.push("arg2:",hexdumpMem(this.arg2));
            this.logs.push("arg3:",hexdumpMem(this.arg3));
            this.logs.push("arg4:",hexdumpMem(this.arg4));
            this.logs.push("arg5:",hexdumpMem(this.arg5));
        },onLeave:function(retval){
            this.logs.push("arg0 leave:",hexdumpMem(this.arg0));
            this.logs.push("arg1 leave:",hexdumpMem(this.arg1));
            this.logs.push("arg2 leave:",hexdumpMem(this.arg2));
            this.logs.push("arg3 leave:",hexdumpMem(this.arg3));
            this.logs.push("arg4 leave:",hexdumpMem(this.arg4));
            this.logs.push("arg5 leave:",hexdumpMem(this.arg5));
            this.logs.push("retval leave:",hexdumpMem(retval));
            console.log(this.logs);
        }
    })
}
  • Frida打印java中的byte数组
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
function Bytes2HexString(arrBytes) {
    var str = "";
    for (var i = 0; i < arrBytes.length; i++) {
        var tmp;
        var num = arrBytes[i];
        if (num < 0) {
            //此处填坑,当byte因为符合位导致数值为负时候,需要对数据进行处理
            tmp = (255 + num + 1).toString(16);
        } else {
            tmp = num.toString(16);
        }
        if (tmp.length === 1) {
            tmp = "0" + tmp;
        }
        str += tmp;
    }
    return str;
}