1.先去Hook dlopen
functionhook_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);
}
}
}
);
}
hook_dlopen()
查看到是libmsaoaidsec.so进行到了最后一步,猜测是这个so进行了ptrace检测进程
第二步:
验证下是在jni_onload之前还是之后
如果调用了该函数就输出一行日志
如果没有日志输出,那么就说明检测点在.init_xxx
函数中。.init_xxx对应的是下面补充的的init()
注入的时机可以选择dlopen
加载libmsaoaidsec.so
完成之后
functionhook_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()
}
}
}
);
}
functionhook_JNI_OnLoad(){
letmodule = 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 pthread
方法,pthread
用于线程的创建、同步、管理和终止
如何过掉frida检测?
想法:直接nop掉pthread_create或者替换检测函数
上面看到三个地址
0x1c544,0x1b8d4,0x26e5c
直接去hook这个 18BD4,按住X进行多个循环引用
再次按住X进行引用
追踪到了init_proc这个地方
另外这个 hook
时机要早,因为这个函数的调用是通过 init_proc
调用的。通过调用比init_proc更早的来进行调用。
我们可以通过 hook call_constructors
这个, call_constructors
主要作用是执行那些需要在程序开始运行之前完成初始化的代码,hook 代码如下
var dlopen = Module.findExportByName(null, "dlopen");
var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
Interceptor.attach(dlopen, {
onEnter: function (args) {
var path_ptr = args[0];
var path = ptr(path_ptr).readCString();
console.log("[dlopen -> enter", path);
},
onLeave: function (retval) {
console.log("dlopen -> leave")
}
});
Interceptor.attach(android_dlopen_ext, {
onEnter: function (args) {
var path_ptr = args[0];
var path = ptr(path_ptr).readCString();
console.log("[android_dlopen_ext -> enter", path);
if (args[0].readCString() != null && args[0].readCString().indexOf("libmsaoaidsec.so") >= 0) {
hook_call_constructors()
}
},
onLeave: function (retval) {
console.log("android_dlopen_ext -> leave")
}
});
functionhook_call_constructors() {
var linker64_base_addr = Module.getBaseAddress("linker64")
var call_constructors_func_off =0xa128c
var call_constructors_func_addr = linker64_base_addr.add(call_constructors_func_off)
var listener = Interceptor.attach(call_constructors_func_addr, {
onEnter: function (args) {
console.log("call_constructors -> enter")
varmodule = Process.findModuleByName("libmsaoaidsec.so")
if (module != null) {
Interceptor.replace(module.base.add(0x1B924), newNativeCallback(function () {
console.log("替换成功")
}, "void", []))
listener.detach()
}
},
})
}
问题:
为什么要先hook dlopen再去Hook call_constructors
?
时机不对,call_constructors
是一个初始化函数,通常在库加载完成后会被调用。 如果直接Hook可能导致so没有被加载。所以如果是要Hook call_constructors
之前要Hook dlopen。 在 Android 上,android_dlopen_ext
有时会用来加载一些特定的系统库。通过 hook android_dlopen_ext
,可以在更高层次上监控到一些特定库(如 libmsaoaidsec.so
)的加载 。下图有补充加载so的流程,具体代码,就不跟了,之前也跟踪过。
上面这个方法是从Linker64里面寻找符号,将符号给替换掉
通过上述代码,发现豆瓣绕不过去,换下一个。
第二种方法:
首先在.init_proc
函数中找一个调用了外部函数的位置,时机越早越好。尝试去利用Hook。原因:
选择了_system_property_get
函数,接下来使用frida hook dlopen
函数
- 当加载
libmsaoaidsec.so
时 - 在回调方法中
hook _system_property_get
函数,以"ro.build.version.sdk
"字符串作为过滤器。 - 如果
_system_property_get
函数被调用了 - 那么这个时候也就是
.init_proc
函数刚刚调用的时候,比jni_onload加载进去的要早 - 如果
_system_property_get
函数被调用了,那么这个时候也就是.init_proc
函数刚刚调用的时候,在这个时机点可以注入我想要的代码,具体实现如上。
从init_proc里面寻找ro.build.version.sdk
sub_123F0找到了
尝试去利用
functionlocate_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()
}
}
}
}
);
functionnop_64(addr) {
Memory.protect(addr, 4 , 'rwx');
var w = new Arm64Writer(addr);
w.putRet();
w.flush();
w.dispose();
}
刚才这个尝试直接使用了 Module.findExportByName
来定位到需要 hook 的函数
补充:
Module.findExportByName
是 Frida 提供的一个非常强大的 API,它可以直接从已加载的模块中查找导出符号,并返回该符号对应的地址。不需要显式地从 linker64
或者其他模块开始查找符号。
直接hook这个,发现能绕过去
补充:
hook so的加载流程
在Hook so的时候,首先要知道so的加载流程
如果是hook jni_onload之前,就可以利用是init_proc还有call_constructors
换另外一种方法:
https://www.52pojie.cn/thread-1998228-1-1.html
如果是Hook jni_onload(梆梆)做校验,那就只能在这个地方搞了
https://bbs.kanxue.com/thread-284838.htm
可以大概看看这篇文章,也是hook东西的
参考文章:
https://bbs.kanxue.com/thread-277034.htm
https://www.52pojie.cn/thread-1998228-1-1.html
https://bbs.kanxue.com/thread-280754.htm
反思:
这个是在检测so的地方做文章,那么直接把 pthread_create 每次都替换掉不就行了
进行尝试
functionhook_pthread() {
var pthread_create_addr = Module.findExportByName(null, 'pthread_create');
console.log("pthread_create_addr,", pthread_create_addr);
var pthread_create = newNativeFunction(pthread_create_addr, "int", ["pointer", "pointer", "pointer", "pointer"]);
Interceptor.replace(pthread_create_addr, newNativeCallback(function (parg0, parg1, parg2, parg3) {
var so_name = Process.findModuleByAddress(parg2).name;
var so_path = Process.findModuleByAddress(parg2).path;
var so_base = Module.getBaseAddress(so_name);
var offset = parg2 - so_base;
console.log("so_name", so_name, "offset", offset, "path", so_path, "parg2", parg2);
varPC = 0;
if ((so_name.indexOf("libexec.so") > -1) || (so_name.indexOf("xxxx") > -1)) {
console.log("find thread func offset", so_name, offset);
if ((1 === offset)) {
console.log("anti bypass");
} elseif (1 === offset) {
console.log("anti bypass");
} elseif (1 === offset) {
console.log("anti bypass");
} elseif (1 === offset) {
console.log("anti bypass");
} elseif (1 === offset) {
console.log("anti bypass");
} elseif (1 === offset) {
console.log("anti bypass");
} elseif (1 === offset) {
console.log("anti bypass");
} else {
PC = pthread_create(parg0, parg1, parg2, parg3);
console.log("ordinary sequence", PC)
}
} else {
PC = pthread_create(parg0, parg1, parg2, parg3);
// console.log("ordinary sequence", PC)
}
return PC;
}, "int", ["pointer", "pointer", "pointer", "pointer"]))
}
hook_pthread();
没成功,后续再进行研究
原文始发于微信公众号(呼啦啦安全):过掉XXAPP frida检测
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论