自学内容网 自学内容网

绕过最新版bilibili app反frida机制

问题说明

截止到2024年5月1日,B站最新版的安卓APP(7.76.0)有反Frida机制,不管是spawn还是attach,都无法注入frida,如下图所示。本文介绍一下如何绕过它

 

方法

定位检测点

检测Frida的机制一般在Native层实现,通常会创建几个线程轮询检测。首先要知道检测机制是由哪个so实现的,通过hook android_dlopen_ext函数,观察加载到哪个so的时候,触发反调试进程终止即可。Frida脚本代码与输出如下,最终可以定位到检测点在libmsaoaidsec.so中。

1

2

3

4

5

6

7

8

9

10

11

var interceptor = 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)

                }

            },

        }

)

 

绕过检测点

对抗

使用IDA载入libmsaoaidsec.so,发现没有导入pthread_create符号

 

使用Frida脚本尝试HOOK pthread_create 函数,也没有找到来自libmsaoaidsec.so的调用

1

2

3

4

5

6

7

8

9

10

11

12

13

var interceptor = Interceptor.attach(Module.findExportByName(null, "pthread_create"),

        {

            onEnter: function (args) {

                var module = Process.findModuleByAddress(ptr(this.returnAddress))

                if (module != null) {

                    console.log("[pthread_create] called from", module.name)

                }

                else {

                    console.log("[pthread_create] called from", ptr(this.returnAddress))

                }

            },

        }

)

 

分析

尽管表现有点奇怪,但它一定会调用pthread_create创建检测线程。所以尝试hook dlsym函数,在加载libmsaoaidsec.so之前挂钩dlsym函数,代码如下

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_dlsym() {

    var count = 0

    console.log("=== HOOKING dlsym ===")

    var interceptor = Interceptor.attach(Module.findExportByName(null, "dlsym"),

        {

            onEnter: function (args) {

                const name = ptr(args[1]).readCString()

                // const module = Process.findModuleByAddress(ptr(this.returnAddress))

                console.log("[dlsym]", name)

                if (name == "pthread_create") {

                    count++

                }

            }

        }

    )

    return Interceptor

}

function hook_dlopen() {

    var interceptor = 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)

                    if (path.indexOf("libmsaoaidsec.so") > -1) {

                        hook_dlsym()

                    }

                }

            },

        }

    )

    return interceptor

}

var dlopen_interceptor = hook_dlopen()

输出如下,在加载libmsaoaidsec.so后,调用了2次dlsym获取pthread_create函数,然后进程就终止了。证明它确实会调用pthread_create,只是调用方式不是直接调用,可能采取了一些对抗手段。

 

绕过

它应该是使用了一些反hook的手段,没有必要和它正面对抗。简单描述一下我的绕过策略,创建一个fake_pthread_create函数,它只有一条ret汇编指令,然后hook来自libmsaoaidsec.so的前2次对dlsym的调用,返回fake_pthread_create函数的地址,这样就达成了欺骗它调用fake_pthread_create函数的目的。最终代码如下

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

function create_fake_pthread_create() {

    const fake_pthread_create = Memory.alloc(4096)

    Memory.protect(fake_pthread_create, 4096, "rwx")

    Memory.patchCode(fake_pthread_create, 4096, code => {

        const cw = new Arm64Writer(code, { pc: ptr(fake_pthread_create) })

        cw.putRet()

    })

    return fake_pthread_create

}

function hook_dlsym() {

    var count = 0

    console.log("=== HOOKING dlsym ===")

    var interceptor = Interceptor.attach(Module.findExportByName(null, "dlsym"),

        {

            onEnter: function (args) {

                const name = ptr(args[1]).readCString()

                console.log("[dlsym]", name)

                if (name == "pthread_create") {

                    count++

                }

            },

            onLeave: function(retval) {

                if (count == 1) {

                    retval.replace(fake_pthread_create)

                }

                else if (count == 2) {

                    retval.replace(fake_pthread_create)

                    // 完成2次替换, 停止hook dlsym

                    interceptor.detach()

                }

            }

        }

    )

    return Interceptor

}

function hook_dlopen() {

    var interceptor = 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)

                    if (path.indexOf("libmsaoaidsec.so") > -1) {

                        hook_dlsym()

                    }

                }

            }

        }

    )

    return interceptor

}

// 创建虚假pthread_create

var fake_pthread_create = create_fake_pthread_create()

var dlopen_interceptor = hook_dlopen()

执行frida -U -f tv.danmaku.bili -l bypass.js后即可绕过反frida机制,如下图所示

 


原文地址:https://blog.csdn.net/wei_java144/article/details/139179629

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!