小黑盒 hook pthread_create 过frida检测

小黑盒抓包的时候,想用自吐加密算法查看用的是什么加密,发现frida做了检测,启动frida脚本就会提示程序终止

image-20240524101621104

image-20240524103012130

目前使用的frida版本是16.0.19,未作任何特征隐藏

常见的frida检测就那么几种,进程和端口检测等,我们先看下是否是在so中进行检测,这里我们尝试通过hook dlopen 函数,查看一下so加载流程,结果发现,加载到 libmsaoaidsec.so 时,frida被终止

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
Java.perform(function () {
// 通过查找dlopen,dlopen时打开so文件的通用方法
var dlopen = Module.findExportByName(null, "dlopen");
var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
// C语言hook的方法
// Interceptor.attach(dlopen,通用 将找到的函数名放进去
Interceptor.attach(dlopen, {
// 函数进去后,添加参数
onEnter: function (args) {
// 通过获取指针
var path_ptr = args[0];
var path = ptr(path_ptr).readCString();
console.log("[dlopen:]", path);
},
// 函数执行完之后
onLeave: function (retval) {

}
});

Interceptor.attach(android_dlopen_ext, {
onEnter: function (args) {
var path_ptr = args[0];
var path = ptr(path_ptr).readCString();
console.log("[dlopen_ext:]", path);
},
onLeave: function (retval) {

}
});
});

image-20240524110453007

由so的加载流程可知,当libmsaoaidsec.so被加载之后,frida进程就被杀掉了,因此监测点在libmsaoaidsec.so中。

如果有了解过so的加载流程,那么就会知道linker会先对so进行加载与链接,然后调用so的.init_proc函数,接着调用.init_array中的函数,最后才是JNI_OnLoad函数,所以我需要先确定检测点大概在哪个函数中。

还有一个思路就是,如果app开启了线程检测,就有一个线程循环检测是否有frida特征,我们也可以直接hook线程函数pthread_create使其返回为空

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function hook_pthread_create() {
var pt_create_func = Module.findExportByName("libc.so", 'pthread_create');
Interceptor.attach(pt_create_func, {
onEnter: function (args) {
// 是那个so文件调用我,创建线程
var so_name = Process.findModuleByAddress(args[2]).name;
if (so_name.indexOf("libmsaoaidsec.so") != -1) {
try {
Interceptor.replace(args[2], new NativeCallback(function () {
console.log('replace success');
return null;
}, 'void', ["void"]));
} catch (e) {
}
}
}, onLeave: function (retval) {
}
})
}

hook_pthread_create();

可以发现可以成功过掉frida检测,然后再将需要hook的脚本放下面

image-20240524151639365

哔哩哔哩nop掉pthread_create过frida检测

同样使用frida尝试打印so加载流程,发现也是在 libmsaoaidsec.so 加载后程序结束,然后尝试一下过小黑盒的方式看下能否过frida检测

image-20240524171918887

程序没有被终止,但是app也没打开,直接卡死在打开界面,那说明还是在pthread_create函数中进行检测

image-20240524172053735

我们打印一下新线程要执行的函数地址

1
2
3
4
5
6
7
8
9
function hook_pthread_create(){
``console.log(``"libmsaoaidsec.so --- "` `+` `Process.findModuleByName(``"libmsaoaidsec.so"``).base)
``Interceptor.attach(Module.findExportByName(``"libc.so"``, ``"pthread_create"``),{
``onEnter(args){
``let func_addr ``=` `args[``2``]
``console.log(``"The thread function address is "` `+` `func_addr)
``}
``})
}

image-20240524181828845

可以发现这里面有两个线程是libmsaoaidsec.so创建的,对应的函数偏移分别是0x11129和0x10975,这两个函数都检测了frida,绕过的方法很简单,直接nop掉pthread_create

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
57
58
59
60
61
62
63
64
function hook_dlopen(soName = '') {
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
{
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
if (path.indexOf(soName) >= 0) {
locate_init()
}
}
}
}
);
}

function locate_init() {
let secmodule = null
Interceptor.attach(Module.findExportByName(null, "__system_property_get"),
{
// _system_property_get("ro.build.version.sdk", v1);
onEnter: function (args) {
secmodule = Process.findModuleByName("libmsaoaidsec.so")
var name = args[0];
if (name !== undefined && name != null) {
name = ptr(name).readCString();
if (name.indexOf("ro.build.version.sdk") >= 0) {
// 这是.init_proc刚开始执行的地方,是一个比较早的时机点
// do something
// hook_pthread_create()
bypass()
}
}
}
}
);
}

function hook_pthread_create() {
console.log("libmsaoaidsec.so --- " + Process.findModuleByName("libmsaoaidsec.so").base)
Interceptor.attach(Module.findExportByName("libc.so", "pthread_create"), {
onEnter(args) {
let func_addr = args[2]
console.log("The thread function address is " + func_addr)
}
})
}

function nop(addr) {
Memory.patchCode(ptr(addr), 4, code => {
const cw = new ThumbWriter(code, { pc: ptr(addr) });
cw.putNop();
cw.putNop();
cw.flush();
});
}

function bypass(){
let module = Process.findModuleByName("libmsaoaidsec.so")
nop(module.base.add(0x10AE4))
nop(module.base.add(0x113F8))
}

setImmediate(hook_dlopen, "libmsaoaidsec.so")

最后呢,也是成功过掉检测

image-20240524182028106