今天来给大家分享一个案例,某某单词app
,由于该app
有反调试,本文就介绍一下如何绕过他的反调试
参考资料
绕过最新版bilibili app反frida机制
绕过bilibili frida反调试
开始
检测Frida的机制一般在Native层实现,通常会创建几个线程轮询检测。首先要知道检测机制是由哪个so实现的,通过hook android_dlopen_ext
函数,观察加载到哪个so的时候,触发反调试进程终止即可。下面我们来试一下
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);
}
}
}
);
可以看到,在加载libmsaoaidsec.so
后,frida
挂掉了
现在直接注入我们的线程替换脚本,看看这个so加载的线程
function check_pthread_create(name = null) {
var pthread_create_addr = Module.findExportByName(null, 'pthread_create');
var pthread_create = new NativeFunction(pthread_create_addr, "int", ["pointer", "pointer", "pointer", "pointer"]);
Interceptor.replace(pthread_create_addr, new NativeCallback(function (parg0, parg1, parg2, parg3) {
var module = Process.findModuleByAddress(parg2)
var so_base = module.base;
var off = "0x" + parg2.sub(so_base).toString(16)
var so_name = module.name;
console.log(so_name, off, parg3)
return pthread_create(parg0, parg1, parg2, parg3);
}, "int", ["pointer", "pointer", "pointer", "pointer"]))
}
setImmediate(check_pthread_create)
这里创建了三个线程,内存偏移量为0x1c544
,0x1b8d4
,0x26e5c
,注:画线的地方不是检测线程,请看清楚so名字
现在回去改dlopen
,如果这个so
一加载就nop
线程
结果不尽人意,这里获取不了libmsaoaidsec.so
的基址
因为安卓加载so整个流程如下
linker->init_proc ->JNI_OnLoad
从dlopen
获取基址,是要等jni
加载后的,但是现在jni
还没加载我们的frida
就被杀掉了,说明检测在init_proc
里,我们需要寻找一个合适的hook时机
现在我们打开ida
,把so拖进去,静态分析
这里我尝试过寻找发起线程的地方,但从导入函数并没有看到,pthread_create
相关字样,他应该是间接调用的,但是我们已经知道了线程的偏移量,所以这里不太重要了
接下来我们继续看init_proc
,这里被ollvm
混淆了,转成伪c
代码,通过交叉引用,可以得到他是先执行sub_123f0
可以看到sub_123f0
,_system_property_get
调用了一个ro.build.version.sdk
,这里我们从注入system_property_get
是个不错的选择,因为他是在init.proc
阶段执行的
现在我们去hook_system_property_get
function locate_init() {
let r = null
Interceptor.attach(Module.findExportByName(null, "__system_property_get"),
{
onEnter: function (args) {
var name = args[0];
if (name !== undefined && name != null) {
name = ptr(name).readCString();
console.log(name)
if (name.indexOf("ro.build.version.sdk") >= 0) {
console.log(Process.findModuleByName("libmsaoaidsec.so").base)
}
}
}
}
);
}
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.search("libmsaoaidsec.so") != -1){
this.hook = true
locate_init()
}
}
}
}
);
输出如下,我们成功获取到了基址
那我们就nop
上面提到的偏移量吧
完美绕过frida
检测
完整代码
function locate_init() {
let r = null
Interceptor.attach(Module.findExportByName(null, "__system_property_get"),
{
onEnter: function (args) {
var name = args[0];
if (name !== undefined && name != null) {
name = ptr(name).readCString();
//console.log(name)
if (name.indexOf("ro.build.version.sdk") >= 0) {
var r = Process.findModuleByName("libmsaoaidsec.so")
nop_64(r.base.add("0x1c544"))
nop_64(r.base.add("0x1b8d4"))
nop_64(r.base.add("0x26e5c"))
}
}
}
}
);
}
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.search("libmsaoaidsec.so") != -1){
this.hook = true
locate_init()
}
}
}
}
);
function nop_64(addr) {
Memory.protect(addr, 4 , 'rwx');
var w = new Arm64Writer(addr);
w.putRet();
w.flush();
w.dispose();
}