本文是对于了版本7.26.1,以及版本7.76.0的frida检测进行的分析研究以及绕过
bilibili的旧版本frida检测

可以看到按照Spawn的方式启动的时候,直接frida就被检测了。我们按照 hook dlopen去查看可能出现的对应frida检测的so文件。

可以看到的是libmsaoaidsec.so文件,在dlopen了之后,frida就被检测到了,所以大概率的可能是在libmsaoaidsec.so进行的frida检测。在这里之前,我们需要知道是在哪进行HOOK是最为有用的
这里我们可以通过在dlopen结束之后,去HOOK JNI_Onload函数,去判断检测函数在JNI_Onload之前还是之后,我们通过IDA可以去查看JNI_Onload的地址。这里是在JNI_Onload之前出现的frida检测。

我们通过HOOK 进程创建,来看看对于frida检测的线程是在哪里启动的。在复现过程中,原作者使用了hook _system_property_get函数,这里是 init_proc函数较早的位置,这里涉及到了安卓源码中dlopen和.init_xx函数的执行流程比较,在我的so文件执行流程的过程中有细节分析。


由于我们知道,frida检测的是在JNI_Onload函数之前,那么我们就要在init_proc的越早的地方可以进行HOOK,我们HOOK的地方就是线程创建的位置pthread_create。
在这里我们通过去HOOK dlopen的位置,通过dlopen的位置去HOOK system_property_get 当参数是ro.build.version.sdk然后去hook pthread_create
dlopen ———>system_property_get————>pthread_create

这里去比较了对应所以由pthread_create 创建的线程,当对应的线程的地址在libmsaoaidsec.so的地址区域内的时候,打印对应的地址以及偏移。可以看到这里有两个线程出现了
我们可以去通过IDA看看



这些位置的像出现的 strcmp openat strstr.......很多的frida的检测,我们交叉引用一下看看pthread_create,然后直接实现NOP就可以了



这里就绕过frida了,或者通过直接在IDA中去patch掉上面两个位置的pthread_create,然后把补丁之后的so再放到APK中也可以。
参考文章:[原创]绕过bilibili frida反调试-Android安全-看雪-安全社区|安全招聘|kanxue.com
7.26.1:

在高一点的版本上面,pthread_create函数是被隐藏了的
7.76.0: 
但是其实我们通过之前的方法也能看到对应的pthead_create创建线程的位置

这里可以看到在libmsaoaidsec.so中创建了三个新的线程,这里多半也就是进行frida检测的位置的了
同时这里我们进行HOOK的检测frida线程在哪的时候,也是在system_property_get的函数的位置进行HOOK的,但是实际上这里的位置也已经被混淆了,但是这个函数没有被混淆,可以直接在导入表里面找到的,那么我们就去交叉引用看看在哪引用的


其实是能够发现还是在init_proc的sub_123F0函数的位置的

但是这里去判断参数的为"ro.build.version.sdk"已经被混淆了,但是我们既然能通过这个代码找到对应的线程,说明实际上还是去执行了 **_system_property_get("ro.build.version.sdk")**这个函数的,而且既然代码可以直接检测得到frida检测的线程的地址,那么说明检测点还是再_system_property_get("ro.build.version.sdk")之前的。
我们同样按照交叉引用看看pthread_create 被混淆成了什么



其实通过参数的形式,我们就可以判断大概率就是被混淆了的pthead_create函数
按照之前旧版本的frida检测,我们的反检测是通过NOP掉对应的frida检测线程,在7.26.1中frida检测是有两个线程的,而在7.76.0中,这里的frida检测有了三个线程,那么我们也可以对于这里的三个线程进行NOP
这里按照最原始的方法,不去NOP掉pthead_create函数,而是去patch掉对应的frida函数。以及其中的NOP的实际,我选择的位置是在判断到进入libmsaoaidsec.so的时候,并且开始进行frida检测线程创建的pthead_create函数时期


可以看到是直接绕过了frida检测的位置的。并且我写的一个frida打印函数也是成功执行了
绕过最新版bilibili app反frida机制-Android安全-看雪-安全社区|安全招聘|kanxue.com
在这一篇文章中,作者并没有去实现正面对抗,而且取巧绕过了,通过的方式就是在HOOK dlsym函数,在进入libmsaoaidsec.so之后去HOOK dlsym 判断调用pthead_create函数的次数,在前两次进行调用pthead_create函数时,去调用fake_pthead_create函数,从而实现frida线程不启动,达成绕过。
以下是取巧绕过的代码(复制于上面的网址):

同样也可以实现绕过,不过,我们其实能知道,最开始的时候,其实是发现在libmsaoaidsec.so一共是开启了三个线程的,其实我觉得这里可以把count设置到三
这样我尝试过,也能实现绕过的。
function
hook_dlopen(soName =
''
) {
Interceptor.attach(Module.findExportByName(
null
,
"android_dlopen_ext"
), {
onEnter:
function
(args) {
var
pathptr = args[0];
if
(pathptr) {
var
path = ptr(pathptr).readCString();
console.log(
"Loading: "
+ path);
if
(path.indexOf(soName) >= 0) {
console.log(
"Already loading: "
+ soName);
}
}
}
});
}
setImmediate(hook_dlopen,
"libmsaoaidsec.so"
);
function
hook_dlopen(soName =
''
) {
Interceptor.attach(Module.findExportByName(
null
,
"android_dlopen_ext"
), {
onEnter:
function
(args) {
var
pathptr = args[0];
if
(pathptr) {
var
path = ptr(pathptr).readCString();
console.log(
"Loading: "
+ path);
if
(path.indexOf(soName) >= 0) {
console.log(
"Already loading: "
+ soName);
}
}
}
});
}
setImmediate(hook_dlopen,
"libmsaoaidsec.so"
);
function
hook_system_property_get() {
var
system_property_get_addr = Module.findExportByName(
null
,
"__system_property_get"
);
if
(!system_property_get_addr) {
console.log(
"__system_property_get not found"
);
return
;
}
Interceptor.attach(system_property_get_addr, {
onEnter:
function
(args) {
var
nameptr = args[0];
if
(nameptr) {
var
name = ptr(nameptr).readCString();
if
(name.indexOf(
"ro.build.version.sdk"
) >= 0) {
console.log(
"Found ro.build.version.sdk, need to patch"
);
}
}
}
});
}
function
hook_system_property_get() {
var
system_property_get_addr = Module.findExportByName(
null
,
"__system_property_get"
);
if
(!system_property_get_addr) {
console.log(
"__system_property_get not found"
);
return
;
}
Interceptor.attach(system_property_get_addr, {
onEnter:
function
(args) {
var
nameptr = args[0];
if
(nameptr) {
var
name = ptr(nameptr).readCString();
if
(name.indexOf(
"ro.build.version.sdk"
) >= 0) {
console.log(
"Found ro.build.version.sdk, need to patch"
);
}
}
}
});
}
function
hook_pthread_create() {
var
pthread_create = Module.findExportByName(
"libc.so"
,
"pthread_create"
);
var
libmsaoaidsec = Process.findModuleByName(
"libmsaoaidsec.so"
);
if
(!libmsaoaidsec) {
console.log(
"libmsaoaidsec.so not found"
);
return
;
}
console.log(
"libmsaoaidsec.so base: "
+ libmsaoaidsec.base);
if
(!pthread_create) {
console.log(
"pthread_create not found"
);
return
;
}
Interceptor.attach(pthread_create, {
onEnter:
function
(args) {
var
thread_ptr = args[2];
if
(thread_ptr.compare(libmsaoaidsec.base) < 0 || thread_ptr.compare(libmsaoaidsec.base.add(libmsaoaidsec.size)) >= 0) {
console.log(
"pthread_create other thread: "
+ thread_ptr);
}
else
{
console.log(
"pthread_create libmsaoaidsec.so thread: "
+ thread_ptr +
" offset: "
+ thread_ptr.sub(libmsaoaidsec.base));
}
},
onLeave:
function
(retval) {}
});
}
function
hook_pthread_create() {
var
pthread_create = Module.findExportByName(
"libc.so"
,
"pthread_create"
);
var
libmsaoaidsec = Process.findModuleByName(
"libmsaoaidsec.so"
);
if
(!libmsaoaidsec) {
console.log(
"libmsaoaidsec.so not found"
);
return
;
}
console.log(
"libmsaoaidsec.so base: "
+ libmsaoaidsec.base);
if
(!pthread_create) {
console.log(
"pthread_create not found"
);
return
;
}
Interceptor.attach(pthread_create, {
onEnter:
function
(args) {
var
thread_ptr = args[2];
if
(thread_ptr.compare(libmsaoaidsec.base) < 0 || thread_ptr.compare(libmsaoaidsec.base.add(libmsaoaidsec.size)) >= 0) {
console.log(
"pthread_create other thread: "
+ thread_ptr);
}
else
{
console.log(
"pthread_create libmsaoaidsec.so thread: "
+ thread_ptr +
" offset: "
+ thread_ptr.sub(libmsaoaidsec.base));
}
},
onLeave:
function
(retval) {}
});
}
function
hook_dlopen(soName =
''
) {
Interceptor.attach(Module.findExportByName(
null
,
"android_dlopen_ext"
), {
onEnter:
function
(args) {
var
pathptr = args[0];
if
(pathptr) {
var
path = ptr(pathptr).readCString();
console.log(
"Loading: "
+ path);
if
(path.indexOf(soName) >= 0) {
console.log(
"Already loading: "
+ soName);
hook_system_property_get();
}
}
}
});
}
function
hook_system_property_get() {
var
system_property_get_addr = Module.findExportByName(
null
,
"__system_property_get"
);
if
(!system_property_get_addr) {
console.log(
"__system_property_get not found"
);
return
;
}
Interceptor.attach(system_property_get_addr, {
onEnter:
function
(args) {
var
nameptr = args[0];
if
(nameptr) {
var
name = ptr(nameptr).readCString();
if
(name.indexOf(
"ro.build.version.sdk"
) >= 0) {
console.log(
"Found ro.build.version.sdk, need to patch"
);
hook_pthread_create();
}
}
}
});
}
function
hook_pthread_create() {
var
pthread_create = Module.findExportByName(
"libc.so"
,
"pthread_create"
);
var
libmsaoaidsec = Process.findModuleByName(
"libmsaoaidsec.so"
);
if
(!libmsaoaidsec) {
console.log(
"libmsaoaidsec.so not found"
);
return
;
}
console.log(
"libmsaoaidsec.so base: "
+ libmsaoaidsec.base);
if
(!pthread_create) {
console.log(
"pthread_create not found"
);
return
;
}
Interceptor.attach(pthread_create, {
onEnter:
function
(args) {
var
thread_ptr = args[2];
if
(thread_ptr.compare(libmsaoaidsec.base) < 0 || thread_ptr.compare(libmsaoaidsec.base.add(libmsaoaidsec.size)) >= 0) {
console.log(
"pthread_create other thread: "
+ thread_ptr);
}
else
{
console.log(
"pthread_create libmsaoaidsec.so thread: "
+ thread_ptr +
" offset: "
+ thread_ptr.sub(libmsaoaidsec.base));
}
},
onLeave:
function
(retval) {}
});
}
function
nop_code(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_code(module.base.add(0x010AE4))
nop_code(module.base.add(0x113F8))
}
setImmediate(hook_dlopen,
"libmsaoaidsec.so"
);
function
hook_dlopen(soName =
''
) {
Interceptor.attach(Module.findExportByName(
null
,
"android_dlopen_ext"
), {
onEnter:
function
(args) {
var
pathptr = args[0];
if
(pathptr) {
var
path = ptr(pathptr).readCString();
console.log(
"Loading: "
+ path);
if
(path.indexOf(soName) >= 0) {
console.log(
"Already loading: "
+ soName);
hook_system_property_get();
}
}
}
});
}
function
hook_system_property_get() {
var
system_property_get_addr = Module.findExportByName(
null
,
"__system_property_get"
);
if
(!system_property_get_addr) {
console.log(
"__system_property_get not found"
);
return
;
}
Interceptor.attach(system_property_get_addr, {
onEnter:
function
(args) {
var
nameptr = args[0];
if
(nameptr) {
var
name = ptr(nameptr).readCString();
if
(name.indexOf(
"ro.build.version.sdk"
) >= 0) {
console.log(
"Found ro.build.version.sdk, need to patch"
);
hook_pthread_create();
}
}
}
});
}
function
hook_pthread_create() {
var
pthread_create = Module.findExportByName(
"libc.so"
,
"pthread_create"
);
var
libmsaoaidsec = Process.findModuleByName(
"libmsaoaidsec.so"
);
if
(!libmsaoaidsec) {
console.log(
"libmsaoaidsec.so not found"
);
return
;
}
console.log(
"libmsaoaidsec.so base: "
+ libmsaoaidsec.base);
if
(!pthread_create) {
console.log(
"pthread_create not found"
);
return
;
}
Interceptor.attach(pthread_create, {
onEnter:
function
(args) {
var
thread_ptr = args[2];
if
(thread_ptr.compare(libmsaoaidsec.base) < 0 || thread_ptr.compare(libmsaoaidsec.base.add(libmsaoaidsec.size)) >= 0) {
console.log(
"pthread_create other thread: "
+ thread_ptr);
}
else
{
console.log(
"pthread_create libmsaoaidsec.so thread: "
+ thread_ptr +
" offset: "
+ thread_ptr.sub(libmsaoaidsec.base));
}
},
onLeave:
function
(retval) {}
});
}
function
nop_code(addr)
{
Memory.patchCode(ptr(addr),4,code => {
const cw =
new
ThumbWriter(code,{pc:ptr(addr)});
cw.putNop();
cw.putNop();
cw.flush();
})
}
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!