APP使用frida反调试检测绕过
一、环境
- bilibili 7.26.1
- arm
- frida 15.2.2(去除特征版本)
- pixel 6 android 12
二、正文
-
使用
frida以spawn模式启动应用,frida进程直接被杀掉了 -
我需要知道是那个
so在检测frida,可以hook dlopen看一下so的加载流程-
function hook_dlopen() { 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); } } } ); } -

-
-
由so的加载流程可知,当
libmsaoaidsec.so被加载之后,frida进程就被杀掉了- 因此监测点在
libmsaoaidsec.so中 - 如果有了解过so的加载流程,那么就会知道linker会先对so进行加载与链接
- 然后调用so的
.init_proc函数 - 接着调用
.init_array中的函数 - 最后才是
JNI_OnLoad函数
- 然后调用so的
- 所以我需要先确定检测点大概在哪个函数中
- 因此监测点在
-
使用
frida hook JNI_OnLoad函数-
如果调用了该函数就输出一行日志
-
如果没有日志输出,那么就说明检测点在
.init_xxx函数中- 注入的时机可以选择
dlopen加载libmsaoaidsec.so完成之后。
- 注入的时机可以选择
-
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) { this.is_can_hook = true; } } }, onLeave: function (retval) { if (this.is_can_hook) { hook_JNI_OnLoad() } } } ); } function hook_JNI_OnLoad(){ let module = Process.findModuleByName("libmsaoaidsec.so") Interceptor.attach(module.base.add(0xC6DC + 1), { onEnter(args){ console.log("call JNI_OnLoad") } }) } setImmediate(hook_dlopen, "libmsaoaidsec.so") -

-
-
并没有输出日志,那么说明检测的位置在
JNI_OnLoad函数之前- 所以我需要
hook .init_xxx的函数 - 但这里有一个问题
dlopen函数调用完成之后.init_xxx函数已经执行完成了- 这个时候不容易使用
frida进行hook 
- 这个问题其实很麻烦的,因为你想要
hook linker的call_function并不容易 - 这里面涉及到
linker的自举,我想到了一个取巧的办法,请看接下来的操作。
- 所以我需要
-
首先在
.init_proc函数中找一个调用了外部函数的位置,时机越早越好 -
我选择了
_system_property_get函数,接下来使用frida hook dlopen函数-
当加载
libmsaoaidsec.so时- 在
onEnter回调方法中hook _system_property_get函数,以"ro.build.version.sdk"字符串作为过滤器。
- 在
-
如果
_system_property_get函数被调用了 -
那么这个时候也就是
.init_proc函数刚刚调用的时候 -
在这个时机点可以注入我想要的代码,具体实现如下:
-
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 } } } } ); } setImmediate(hook_dlopen, "libmsaoaidsec.so")- 在获取了一个非常早的注入时机之后,就可以定位具体的frida检测点了。
- 网上对
frida的检测通常会使用openat、open、strstr、pthread_create、snprintf、sprintf、readlinkat等一系列函数,从这里下手是一个不错的选择。
-
-
-
我对
pthread_create函数进行hook,打印一下新线程要执行的函数地址-
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) } }) } -

-
-
这里面有两个线程是
libmsaoaidsec.so创建的,对应的函数偏移分别是0x11129和0x10975-
这两个函数都检测了
frida,想要了解具体检测方法的可以自己看看,这里不再深入 -
绕过的方法很简单,直接
nop掉pthread_create或者替换检测函数的代码逻辑都可以 -
我是直接把
pthread_create函数nop掉了,下面是完整代码。-
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")
-
-

-



浙公网安备 33010602011771号