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

[原创]绕过bilibili frida反调试

2023-4-29 15:51
52402

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

 

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

环境

  • bilibili 7.26.1
  • arm
  • frida 15.2.2(去除特征版本)
  • pixel 6 android 12

正文

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

 

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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函数,所以我需要先确定检测点大概在哪个函数中。

 

使用frida hook JNI_OnLoad函数,如果调用了该函数就输出一行日志,如果没有日志输出,那么就说明检测点在.init_xxx函数中,注入的时机可以选择dlopen加载libmsaoaidsec.so完成之后。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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函数刚刚调用的时候,在这个时机点可以注入我想要的代码,具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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,打印一下新线程要执行的函数地址

1
2
3
4
5
6
7
8
9
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掉了,下面是完整代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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")

 

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


[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞60
打赏
分享
打赏 + 20.00雪花
打赏次数 1 雪花 + 20.00
 
最新回复 (71)
雪    币: 1488
活跃值: (2001)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
huluxia 2023-4-29 17:30
2
3
大佬牛逼。现在加固的壳脱壳搞不定,frida调试也搞不定。希望多出点frida过反调试的文章
雪    币: 705
活跃值: (933)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
马到成功* 2023-4-29 18:30
3
1
也不是大佬,感谢支持
雪    币: 3018
活跃值: (1453)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
MsScotch 2023-4-29 21:38
4
0
思路不错。
雪    币: 907
活跃值: (857)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
La0s 2023-4-30 13:27
5
0
好文好思路,学习了
雪    币: 19803
活跃值: (29410)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-4-30 16:24
6
1
好文
雪    币: 296
活跃值: (510)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Abelly 2023-5-3 12:49
7
0
大佬,new ThumbWriter未定义咋处理?
雪    币: 2113
活跃值: (3842)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
st0ne 1 2023-5-3 13:08
8
0
666
雪    币: 705
活跃值: (933)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
马到成功* 2023-5-3 20:04
9
0
Abelly 大佬,new ThumbWriter未定义咋处理?
不应该呀,是不是你的frida版本太低了?
雪    币: 320
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Losir 2023-5-4 11:57
10
0
大佬牛逼
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_水山 2023-5-4 18:35
11
0
找注入点的操作实在太6了,学习了
雪    币: 62
活跃值: (572)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
万里星河 2023-5-4 23:23
12
0
mark
雪    币: 237
活跃值: (238)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
puppet_w 2023-5-5 13:54
13
0

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

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

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

这俩地址

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

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


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

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