立即注册,突破游客限制,与技术大牛交流切磋,畅享海量资源,让你的技术之路不再孤单!
您需要 登录 才可以下载或查看,没有账号?立即注册
×
问题说明
截止到2024年5月1日,B站最新版的安卓APP(7.76.0)有反Frida机制,不管是spawn还是attach,都无法注入frida,如下图所示。本文介绍一下如何绕过它
方法 (定位检测点):
检测Frida的机制一般在Native层实现,通常会创建几个线程轮询检测。首先要知道检测机制是由哪个so实现的,通过hook android_dlopen_ext函数,观察加载到哪个so的时候,触发反调试进程终止即可。最终可以定位到检测点在libmsaoaidsec.so中。
- 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)
-
- }
-
- },
-
- }
-
- )
复制代码
对抗(绕过检测点):
使用IDA载入libmsaoaidsec.so,发现没有导入pthread_create符号
使用Frida脚本尝试HOOK pthread_create 函数,也没有找到来自libmsaoaidsec.so的调用
- 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))
-
- }
-
- },
-
- }
-
- )
-
复制代码 分析
尽管表现有点奇怪,但它一定会调用pthread_create创建检测线程。所以尝试hook dlsym函数,在加载libmsaoaidsec.so之前挂钩dlsym函数,代码如下
- 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()
-
- // const module = Process.findModuleByAddress(ptr(this.returnAddress))
-
- 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()
复制代码 在加载libmsaoaidsec.so后,调用了2次dlsym获取pthread_create函数,然后进程就终止了。证明它确实会调用pthread_create,只是调用方式不是直接调用,可能采取了一些对抗手段。
绕过
它应该是使用了一些反hook的手段,没有必要和它正面对抗。简单描述一下我的绕过策略,创建一个fake_pthread_create函数,它只有一条ret汇编指令,然后hook来自libmsaoaidsec.so的前2次对dlsym的调用,返回fake_pthread_create函数的地址,这样就达成了欺骗它调用fake_pthread_create函数的目的。最终代码
如下:
- function create_fake_pthread_create() {
-
- const fake_pthread_create = Memory.alloc(4096)
-
- Memory.protect(fake_pthread_create, 4096, "rwx")
-
- Memory.patchCode(fake_pthread_create, 4096, code => {
-
- const cw = new Arm64Writer(code, { pc: ptr(fake_pthread_create) })
-
- cw.putRet()
-
- })
-
- return fake_pthread_create
-
- }
-
-
-
- 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++
-
- }
-
- },
-
- onLeave: function(retval) {
-
- if (count == 1) {
-
- retval.replace(fake_pthread_create)
-
- }
-
- else if (count == 2) {
-
- retval.replace(fake_pthread_create)
-
- // 完成2次替换, 停止hook dlsym
-
- interceptor.detach()
-
- }
-
- }
-
- }
-
- )
-
- 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
-
- }
-
-
-
- // 创建虚假pthread_create
-
- var fake_pthread_create = create_fake_pthread_create()
-
- var dlopen_interceptor = hook_dlopen()
复制代码 执行frida -U -f tv.danmaku.bili -l bypass.js后即可绕过反frida机制
|