首页
社区
课程
招聘
[原创]绕过bilibili frida反调试
发表于: 2023-4-29 15:51 61623

[原创]绕过bilibili frida反调试

2023-4-29 15:51
61623

原创文章,首发至博客http://t.csdn.cn/Pd9aL

文章仅供思路参考,请勿用作非法攻击

使用frida以spawn模式启动应用,frida进程直接被杀掉了

我需要知道是那个so在检测frida,可以hook dlopen看一下so的加载流程

由so的加载流程可知,当libmsaoaidsec.so被加载之后,frida进程就被杀掉了,因此监测点在libmsaoaidsec.so中。

如果有了解过so的加载流程,那么就会知道linker会先对so进行加载与链接,然后调用so的.init_proc函数,接着调用.init_array中的函数,最后才是JNI_OnLoad函数,所以我需要先确定检测点大概在哪个函数中。

使用frida hook JNI_OnLoad函数,如果调用了该函数就输出一行日志,如果没有日志输出,那么就说明检测点在.init_xxx函数中,注入的时机可以选择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函数刚刚调用的时候,在这个时机点可以注入我想要的代码,具体实现如下:

在获取了一个非常早的注入时机之后,就可以定位具体的frida检测点了。网上对frida的检测通常会使用openat、open、strstr、pthread_create、snprintf、sprintf、readlinkat等一系列函数,从这里下手是一个不错的选择。

我对pthread_create函数进行hook,打印一下新线程要执行的函数地址

这里面有两个线程是libmsaoaidsec.so创建的,对应的函数偏移分别是0x11129和0x10975

这两个函数都检测了frida,想要了解具体检测方法的可以自己看看,这里不再深入。

绕过的方法很简单,直接nop掉pthread_create或者替换检测函数的代码逻辑都可以,我是直接把pthread_create函数nop掉了,下面是完整代码。

至此,frida检测也就成功绕过了。

 
 
 
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);
                }
            }
        }
    );
}
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);
                }
            }
        }
    );
}
 
 
 
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")
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")
 
 
 
 
 
 
 
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")
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);

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 62
支持
分享
打赏 + 20.00雪花
打赏次数 1 雪花 + 20.00
 
最新回复 (74)
雪    币: 1692
活跃值: (2292)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
大佬牛逼。现在加固的壳脱壳搞不定,frida调试也搞不定。希望多出点frida过反调试的文章
2023-4-29 17:30
3
雪    币: 685
活跃值: (1318)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
也不是大佬,感谢支持
2023-4-29 18:30
1
雪    币: 3181
活跃值: (1796)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
思路不错。
2023-4-29 21:38
0
雪    币: 905
活跃值: (1042)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
好文好思路,学习了
2023-4-30 13:27
0
雪    币: 3059
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
好文
2023-4-30 16:24
1
雪    币: 353
活跃值: (845)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
大佬,new ThumbWriter未定义咋处理?
2023-5-3 12:49
0
雪    币: 2159
活跃值: (4097)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
8
666
2023-5-3 13:08
0
雪    币: 685
活跃值: (1318)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
Abelly 大佬,new ThumbWriter未定义咋处理?
不应该呀,是不是你的frida版本太低了?
2023-5-3 20:04
0
雪    币: 324
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
大佬牛逼
2023-5-4 11:57
0
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
找注入点的操作实在太6了,学习了
2023-5-4 18:35
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
mark
2023-5-4 23:23
0
雪    币: 237
活跃值: (258)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13

大佬,我想问下前边找的  对应的函数偏移分别是0x11129和0x10975,为啥后边

nop(module.base.add(0x10AE4))

nop(module.base.add(0x113F8))

这俩地址

最后于 2023-5-5 13:55 被puppet_w编辑 ,原因:
2023-5-5 13:54
0
雪    币: 685
活跃值: (1318)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
puppet_w 大佬,我想问下前边找的  对应的函数偏移分别是0x11129和0x10975,为啥后边nop(module.base.add(0x10AE4))nop(module ...
0x11129和0x10975是线程需要执行的函数的地址,也就是pthread_create函数的第三个参数,0x10AE4和0x113F8是pthread_create函数被调用的地址。
2023-5-5 14:08
1
雪    币: 237
活跃值: (258)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
马到成功* 0x11129和0x10975是线程需要执行的函数的地址,也就是pthread_create函数的第三个参数,0x10AE4和0x113F8是pthread_create函数被调用的地址。

我看10776  10ad0地址好像也有调用pthread_create,,对吗


2023-5-5 14:26
0
雪    币: 221
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
16
问下大佬,nop的这两个地址是怎么算出来的,0x10AE4和0x113F8
2023-5-5 16:00
0
雪    币: 33
活跃值: (1476)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
精彩
2023-5-5 16:40
0
雪    币: 685
活跃值: (1318)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
puppet_w 我看10776  10ad0地址好像也有调用pthread_create,,对吗
并不是每个线程都是检测frida的
2023-5-5 16:42
0
雪    币: 685
活跃值: (1318)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
lamorm 问下大佬,nop的这两个地址是怎么算出来的,0x10AE4和0x113F8
根据交叉引用,找到检测frida的函数的调用处
2023-5-5 16:42
0
雪    币: 109
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20

bilibili 是32位的   如果其他app是64位的地址是

 nop(module.base.add(0x1A858));
 nop(module.base.add(0x1B8A8));


且nop 方法要改为Arm64Writer  会报找不到ThumbWriter的问题  且cw.putNop()要变成四个


function nop(addr) {
    Memory.patchCode(ptr(addr), 4,
            code=>  {
        const cw = new Arm64Writer(code, { pc: ptr(addr) });
        // const cw = new ThumbWriter(code, { pc: ptr(addr) });
        cw.putNop();
        cw.putNop();
        cw.putNop();
        cw.putNop();
        cw.flush();
    });
}


而且64位的还可以hook  strstr  把frida  osedBridge之类的一大堆都过滤掉也可解决

最后于 2023-5-6 16:29 被萌木盖编辑 ,原因: 乱码了
2023-5-5 19:27
5
雪    币: 12
活跃值: (113)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
mark
2023-5-6 10:13
0
雪    币: 109
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
22
Abelly 大佬,new ThumbWriter未定义咋处理?
看我上条评论
2023-5-6 16:10
0
雪    币: 861
活跃值: (69)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
mark
2023-5-8 14:25
0
雪    币: 8447
活跃值: (5041)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
24
mark了,又学到一个linker里的hook点
2023-5-8 16:27
0
雪    币: 202
活跃值: (259)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
学习了,又涨新知识 了
2023-5-9 18:04
0
游客
登录 | 注册 方可回帖
返回
//