整理一下之前的学习笔记。以及常用的一些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
5
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
36
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;
}