某痛单词过frida检测
**小白第一次发帖,可能写的不太好,见谅**本文已同步到本人博客,本人博客为 `5Yaw5pyI5Y2a5a6i`
今天来给大家分享一个案例,某某单词`app`,由于该`app`有反调试,本文就介绍一下如何绕过他的反调试
---
## 参考资料
[绕过最新版bilibili app反frida机制 ](https://bbs.kanxue.com/thread-281584.htm)
[绕过bilibili frida反调试](https://bbs.kanxue.com/thread-277034.htm)
---
## 开始
检测Frida的机制一般在Native层实现,通常会创建几个线程轮询检测。首先要知道检测机制是由哪个so实现的,通过hook `android_dlopen_ext`函数,观察加载到哪个so的时候,触发反调试进程终止即可。下面我们来试一下
```javascript
Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
{
onEnter: function (args) {
var pathptr = args;
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
console.log("load " + path);
}
}
}
);
```

可以看到,在加载`libmsaoaidsec.so`后,`frida`挂掉了
现在直接注入我们的线程替换脚本,看看这个so加载的线程
```javascript
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整个流程如下
```bash
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`
```javascript
function locate_init() {
let r = null
Interceptor.attach(Module.findExportByName(null, "__system_property_get"),
{
onEnter: function (args) {
var name = args;
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;
if (pathptr !== undefined && pathptr != null) {
var path = ptr(pathptr).readCString();
if(path.search("libmsaoaidsec.so") != -1){
this.hook = true
locate_init()
}
}
}
}
);
```
输出如下,我们成功获取到了基址

那我们就`nop`上面提到的偏移量吧

完美绕过`frida`检测
---
## 完整代码
```javascript
function locate_init() {
let r = null
Interceptor.attach(Module.findExportByName(null, "__system_property_get"),
{
onEnter: function (args) {
var name = args;
if (name !== undefined && name != null) {
name = ptr(name).readCString();
//console.log(name)
if (name.indexOf("ro.build.version.sdk") >= 0) {
varr = 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;
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();
}
``` 我分析过不止一个App,确实有好多用到`libmsaoaidsec.so`来反Frida调试的。除了屏蔽它的检测线程,还可以直接把该so文件删掉。如果删掉之后App闪退的话,那就自己写一个假的so文件给它替换一下。(我当时试了可以,目前还没发现影响App的功能啥的)。
当然了,也能用IDA把`libmsaoaidsec.so` 的检测线程RET掉(打补丁),再替换回去试试看。这样就不用每次加载frida脚本去绕反调试了,稍微方便一点。
{:301_997:} 这么说 其实所有对 frida的检测和 xposed的检测都可以被 绕过 大佬,牛逼 厉害,学习了 清晰值得推荐 这个是真的厉害!
思路清晰明了 学习了! 感谢大佬分享,很好的思路
感谢分享,学习 思路清晰明了 学习了!