某邦企业壳frida检测绕过

某企业壳frida检测绕过尝试

遇见个汽车app 是个企业壳 有frida检测,导致无法注入,本文记录下绕过的过程(使用的frida版本葫芦嗒)

通过查壳发现,这是某企业壳 知其特点检测主要是在dexhelp这个so文件中,也就省去了定位检测位置这一步

尝试hook pthread_create 定位线程 通过杀线程方法干掉他

1

2

3

4

5

6

7

8

9

10

11

function hook_pthread_create(){

    var pthread_create_addr = Module.findExportByName("libc.so", "pthread_create");

    console.log("pthread_create_addr: ", pthread_create_addr);

    Interceptor.attach(pthread_create_addr,{

        onEnter:function(args){

            console.log(args[2], Process.findModuleByAddress(args[2]).name);

        },onLeave:function(retval){

        }

    });

}

hook_pthread_create();

发现没啥用 应该是检测到 pthread_create 被hook了 既然pthread_create 被检测了 那么是否还有其他方法定位线程呢,于是乎 我打开了逆向小助手 gpt 首先我去问了下pthread_create 实现原理 gpt 给出了这个回答

然后 我又去问了gpt hook pthread_create 被检测到了 该怎么办 他建议我去hook 其他相关函数 比如pthread_join clone 通过gpt给出的答案 pthread_create 的实现会调用 clone 系统调用来创建新线程

他既然检测 pthread_create 函数头被hook 那clone函数应该没有把 通过hook clone函数 得到线程相关信息然后去nop 干掉线程 是不是 也能一把梭了 说干就干

首先 我去hook dlopen 在打开dexhelp这个so的时候 去hook下jnionload 看看它做手脚的地方是否在init里面 发现不是 那我只需要去hook clone函数 打印出相关线程信息 然后 加载这个so的时候 nop 掉它 测试是否能绕过即可

于是开始写hook 首先 找gpt要了一份 clone实现创建线程的例子

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

#define _GNU_SOURCE

#include <sched.h>

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#define STACK_SIZE 1024*1024  // 分配线程栈空间

// 子线程函数

int thread_func(void *arg) {

    printf("Hello from the new thread!\n");

    return 0;

}

int main() {

    char *stack;  // 存放线程栈的空间

    char *stackTop;

    // 为线程分配栈

    stack = malloc(STACK_SIZE);

    if (stack == NULL) {

        perror("malloc");

        exit(1);

    }

    stackTop = stack + STACK_SIZE;  // 设置栈顶

    // 使用 clone 创建新线程

    int pid = clone(thread_func, stackTop, SIGCHLD, NULL);  // 子进程退出时会发出 SIGCHLD 信号

    if (pid == -1) {

        perror("clone");

        exit(1);

    }

    // 等待线程结束

    printf("Waiting for the thread to finish...\n");

    waitpid(pid, NULL, 0);

    free(stack);  // 释放栈空间

    return 0;

}

传进去第一个参数是 子线程函数 于是乎 嘎嘎嘎hook 并且打印 结果发现全是libc.so 这是咋回事呢 看来还得好好学习 于是乎 我拿了一份libc.so ida打开它 看pthread_create 如何 去调用clone函数创建线程的

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

// Hook clone 系统调用

Interceptor.attach(Module.findExportByName(null, 'clone'), {

    onEnter: function (args) {

        // 获取线程函数的地址(即第一个参数)

        var thread_func = args[0];

        // 打印线程函数地址

        console.log('Thread function address: ' + thread_func);

        // 获取线程函数所在模块(.so 文件)

        var module = Process.findModuleByAddress(thread_func);

        if (module) {

            console.log('Thread function is located in module: ' + module.name);

        } else {

            console.log('Thread function is not in a loaded module or location could not be determined.');

        }

    },

    onLeave: function (retval) {

        // 可以在这里修改 clone 的返回值(如需要)

    }

});

输出

Thread function address: 0x749b4140dc

Thread function is located in module: libc.so

Thread function address: 0x749b4140dc

Thread function is located in module: libc.so

Thread function address: 0x749b4140dc

Thread function is located in module: libc.so

在上诉 clone hook处 我打印了下堆栈 看下哪里调用了 代码和hook 结果如下

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

Interceptor.attach(Module.findExportByName(null, 'clone'), {

    onEnter: function (args) {

        // 获取线程函数地址

        var thread_func = args[0];

        // 尝试获取线程函数所在模块

        var module = Process.findModuleByAddress(thread_func);

        if (module) {

            console.log('Thread function is located in module: ' + module.name);

        } else {

        }

        // 打印调用栈

        console.log('Backtrace:');

        console.log(Thread.backtrace(this.context, Backtracer.ACCURATE)

            .map(DebugSymbol.fromAddress).join('\n'));

    },

    onLeave: function (retval) {

        // 返回值处理(如果需要)

    }

});

结果

Thread function is located in module: libc.so

Backtrace:

0x749b413e40 libc.so!pthread_create+0x27c

然后 IDA跳转到pthread_create+0x27c 此处 调用了函数E6850 于是进去瞧一瞧 发现是DCQ数据

继续使用frida hook 读取下 结果是clone 也就说这里调用了clone函数

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

Interceptor.attach(Module.findExportByName(null, 'clone'), {

    onEnter: function (args) {

        // 获取线程函数地址

        var thread_func = args[0];

        // 尝试获取线程函数所在模块

        var module = Process.findModuleByAddress(thread_func);

        if (module) {

            console.log('Thread function is located in module: ' + module.name);

            const address = module.base.add(0xF06E8);

            const value = Memory.readU64(address);

            const symbol = DebugSymbol.fromAddress(ptr(value));

            console.log("name",symbol.name)

        } else {

        }

        // 打印调用栈

    },

    onLeave: function (retval) {

        // 返回值处理(如果需要)

    }

});

结果 clone

观察 pthread_create 函数的传参走向 也就是 a3

此处的 E6850是clone 而 通过 pthread_create 函数创建线程传递的 线程函数 就是 v50 而clone函数的第四个参数 v27 + 96 是所需要的线程函数 这样 就可以去试试 写一下hook clone代码了

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

var clone = Module.findExportByName('libc.so', 'clone');

Interceptor.attach(clone, {

    onEnter: function(args) {

        // args[3] 子线程的栈地址。如果这个值为 0,可能意味着没有指定栈地址

        if(args[3] != 0){

            var addr = args[3].add(96).readPointer()

            var so_name = Process.findModuleByAddress(addr).name;

            var so_base = Module.getBaseAddress(so_name);

            var offset = (addr - so_base);

            console.log("===============>", so_name, addr,offset, offset.toString(16));

        }

    },

    onLeave: function(retval) {

    }

});

然后运行后发现 非常阔以 打印出来了我们所需要的参数 非常nice

最后 我们 去给他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

function hook_dlopen(so_name) {

    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(path)

                if (path.indexOf(so_name) !== -1) {

                    this.match = true

                }

            }

        },

        onLeave: function (retval) {

            if (this.match) {

                console.log(so_name, "加载成功");

                var base = Module.findBaseAddress("libDexHelper.so")

                patch_func_nop(base.add(322008));

                patch_func_nop(base.add(308756));

            }

        }

    });

}

function patch_func_nop(addr) {

    Memory.patchCode(addr, 8, function (code) {

        code.writeByteArray([0xE0, 0x03, 0x00, 0xAA]);

        code.writeByteArray([0xC0, 0x03, 0x5F, 0xD6]);

        console.log("patch code at " + addr)

    });

}

hook_dlopen("libDexHelper.so")

最后 看结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值