安卓的最新版B站APP(7.76.0)有反FRIDA机制,本文介绍一下如何绕过它
截止到2024年5月1日,B站最新版的安卓APP(7.76.0)有反Frida机制,不管是spawn还是attach,都无法注入frida,如下图所示。本文介绍一下如何绕过它

检测Frida的机制一般在Native层实现,通常会创建几个线程轮询检测。首先要知道检测机制是由哪个so实现的,通过hook android_dlopen_ext函数,观察加载到哪个so的时候,触发反调试进程终止即可。Frida脚本代码与输出如下,最终可以定位到检测点在libmsaoaidsec.so中。

使用IDA载入libmsaoaidsec.so,发现没有导入pthread_create符号

使用Frida脚本尝试HOOK pthread_create 函数,也没有找到来自libmsaoaidsec.so的调用

尽管表现有点奇怪,但它一定会调用pthread_create创建检测线程。所以尝试hook dlsym函数,在加载libmsaoaidsec.so之前挂钩dlsym函数,代码如下
输出如下,在加载libmsaoaidsec.so后,调用了2次dlsym获取pthread_create函数,然后进程就终止了。证明它确实会调用pthread_create,只是调用方式不是直接调用,可能采取了一些对抗手段。

它应该是使用了一些反hook的手段,没有必要和它正面对抗。简单描述一下我的绕过策略,创建一个fake_pthread_create函数,它只有一条ret汇编指令,然后hook来自libmsaoaidsec.so的前2次对dlsym的调用,返回fake_pthread_create函数的地址,这样就达成了欺骗它调用fake_pthread_create函数的目的。最终代码如下
执行frida -U -f tv.danmaku.bili -l bypass.js
后即可绕过反frida机制,如下图所示

代码也可从github下载,见引用[1]。
[1] fb8K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6V1k6r3c8V1K9r3@1I4x3U0x3@1i4K6u0r3j5Y4W2H3j5i4y4K6i4K6g2X3j5X3W2D9K9h3u0A6L8r3W2Q4x3V1j5`.
var
interceptor = 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();
console.log(
"[LOAD]"
, path)
}
},
}
)
var
interceptor = 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();
console.log(
"[LOAD]"
, path)
}
},
}
)
var
interceptor = Interceptor.attach(Module.findExportByName(
null
,
"pthread_create"
),
{
onEnter:
function
(args) {
var
module = Process.findModuleByAddress(ptr(
this
.returnAddress))
if
(module !=
null
) {
console.log(
"[pthread_create] called from"
, module.name)
}
else
{
console.log(
"[pthread_create] called from"
, ptr(
this
.returnAddress))
}
},
}
)
var
interceptor = Interceptor.attach(Module.findExportByName(
null
,
"pthread_create"
),
{
onEnter:
function
(args) {
var
module = Process.findModuleByAddress(ptr(
this
.returnAddress))
if
(module !=
null
) {
console.log(
"[pthread_create] called from"
, module.name)
}
else
{
console.log(
"[pthread_create] called from"
, ptr(
this
.returnAddress))
}
},
}
)
function
hook_dlsym() {
var
count = 0
console.log(
"=== HOOKING dlsym ==="
)
var
interceptor = Interceptor.attach(Module.findExportByName(
null
,
"dlsym"
),
{
onEnter:
function
(args) {
const name = ptr(args[1]).readCString()
console.log(
"[dlsym]"
, name)
if
(name ==
"pthread_create"
) {
count++
}
}
}
)
return
Interceptor
}
function
hook_dlopen() {
var
interceptor = 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();
console.log(
"[LOAD]"
, path)
if
(path.indexOf(
"libmsaoaidsec.so"
) > -1) {
hook_dlsym()
}
}
},
}
)
return
interceptor
}
var
dlopen_interceptor = hook_dlopen()
function
hook_dlsym() {
var
count = 0
console.log(
"=== HOOKING dlsym ==="
)
var
interceptor = Interceptor.attach(Module.findExportByName(
null
,
"dlsym"
),
{
onEnter:
function
(args) {
const name = ptr(args[1]).readCString()
console.log(
"[dlsym]"
, name)
if
(name ==
"pthread_create"
) {
count++
}
}
}
)
return
Interceptor
}
function
hook_dlopen() {
var
interceptor = 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();
console.log(
"[LOAD]"
, path)
if
(path.indexOf(
"libmsaoaidsec.so"
) > -1) {
hook_dlsym()
}
[培训]科锐逆向工程师培训第53期2025年7月8日开班!
最后于 2024-5-1 17:31
被天水姜伯约编辑
,原因: 第一次上传没写标题