0%

绕过libmsaoaidsec.so的frida检测

绕过libmsaoaidsec.so的frida检测

学习文章:https://bbs.kanxue.com/thread-280754.htm

根据大佬的文章,复现一次libmsaoaidsec.so frida检测的绕过

首先是hook一下dlopen,查看程序是在哪里退出的,很显然是 libmsaoaidsec.so

image-20250704145839563

可以看到只执行了 libmsaoaidsec.so 中的onEnter,说明JNI_onload方法还没有执行,执行方法可能就在 init 或者initarray方法内,搜索发现,只有一个 init_proc 的方法。这个时候可以用 strace 来看一下具体在哪个地址退出的。在 init 方法执行之前堵塞程序十秒,进行strace操作

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 ishook = false;
function hook_dlopen() {
Interceptor.attach(Module.findExportByName(null, 'android_dlopen_ext'), {
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr !== null) {
this.path = ptr(pathptr).readCString();
console.log("onEnter: " + this.path);
if (this.path.indexOf("libmsaoaidsec.so") != -1) {
ishook = true;
console.log("进入休眠10s")
Java.perform(function (){
var System = Java.use('java.lang.System');
System.currentTimeMillis();
var start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 10000) {}
console.log("休眠结束")
})
}
}
},
onLeave: function (retval) {
console.log("onLeave: " + this.path);
}
})
}
1
strace -e trace=process -i -f -p <PID>

输出结果如下,可以看到有 exit_group 执行,再找一下执行的地址 7f46fba008

image-20250702143357107

找到退出之后的新PID

1
cat /proc/<PID>/maps

发现 7f46fba008 地址并没有对应的 so ,那么代码很有可能是动态执行的

再执行

1
strace -e trace=process,memory -i -f -p <PID>

mmap申请的内存正好包含下面的退出方法

image-20250704095026555

再去找maps文件发现mmap在libc.so中

image-20250704095032175

image-20250704095020531

hook一下 mmap 方法,打印堆栈

1
2
3
4
5
6
7
8
9
10
11
12
13
function hook_mmap() {
var mmap = Module.findExportByName('libc.so','mmap');
console.log("mmap: ", mmap)
Interceptor.attach(mmap, {
onEnter: function (args) {
console.log("mmap onEnter");
console.log(Thread.backtrace(this.context, Backtracer.FUZZY).map(DebugSymbol.fromAddress).join("\n") + '\n');
},
onLeave: function (retval) {
console.log("mmap onLeave");
}
});
}

image-20250704100039984

顺着堆栈开始找 0x17fcc

找到了这个方法

image-20250704151053876

这个方法是创建了一个新线程执行 sub_175F8 函数,返回值是创建结果,我的思路是让其成功创建线程,然后直接 request掉 sub_175F8 方法,而且这个方法是个void方法,不需要考虑返回值的问题

image-20250704151117659

image-20250704151334970

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
65
66
67
68
69
70
71
var ishook = false;
function hook_dlopen() {
Interceptor.attach(Module.findExportByName(null, 'android_dlopen_ext'), {
onEnter: function (args) {
var pathptr = args[0];
if (pathptr !== undefined && pathptr !== null) {
this.path = ptr(pathptr).readCString();
console.log("onEnter: " + this.path);
if (this.path.indexOf("libmsaoaidsec.so") != -1) {
ishook = true;
// console.log("进入休眠10s")
// Java.perform(function (){
// var System = Java.use('java.lang.System');
// System.currentTimeMillis();
// var start = System.currentTimeMillis();
// while (System.currentTimeMillis() - start < 10000) {}
// console.log("休眠结束")
// })
// hook_mmap();
hook_sub_E338();
}
}
},
onLeave: function (retval) {
console.log("onLeave: " + this.path);
}
})
}
// 通过hook dlopen,定位到程序在libmsaoaidsec.so中崩溃,
// 因为没有输出onLeave,说明so还没有加载完全,执行时机在JNI_OnLoad之前


function hook_sub_E338() {
var call_constructors = null;
Process.getModuleByName("linker64").enumerateSymbols().forEach(function (symbol) {
if (symbol.name.indexOf('call_constructors') != -1) {
call_constructors = symbol.address;
console.log("call constructors: ", call_constructors)
}
})
Interceptor.attach(call_constructors, {
onEnter: function (args) {
if (ishook) {
var Addr = Module.findBaseAddress('libmsaoaidsec.so');
console.log("Addr: ", Addr)
var f1 = Addr.add(0x175F8);
Interceptor.replace(f1, new NativeCallback(function () {}, 'void', ['pointer']))
// var f1 = Addr.add(0x17FA0);
// Interceptor.attach(f1, )
ishook = false;
}
},
onLeave: function (retval) { }
})
}

hook_dlopen();

function hook_mmap() {
var mmap = Module.findExportByName('libc.so','mmap');
console.log("mmap: ", mmap)
Interceptor.attach(mmap, {
onEnter: function (args) {
console.log("mmap onEnter");
console.log(Thread.backtrace(this.context, Backtracer.FUZZY).map(DebugSymbol.fromAddress).join("\n") + '\n');
},
onLeave: function (retval) {
console.log("mmap onLeave");
}
});
}

也是成功了

image-20250704153700646

再试试hook sub_17FA0 方法,这个有一个int返回值,创建成功是返回0,int类型的返回值就不需要使用jni函数转类型了,直接返回0就行。可以看到依旧可以成功注入

image-20250709150123707

继续往上找进行置空也是可以的,但是越往上越容易出问题,因为可能不止光进行了检测退出这个这个操作。