首页
论坛
课程
招聘
[原创]分享一个Android通用svc跟踪以及hook方案——Frida-Seccomp
2022-3-11 19:32 25626

[原创]分享一个Android通用svc跟踪以及hook方案——Frida-Seccomp

2022-3-11 19:32
25626

一个Android通用svc跟踪以及hook方案——Frida-Seccomp

暂时只支持ARM64,ARM32的逻辑也是一样的,有兴趣的大佬可以自行更改哈。

效果:

对 openat进行跟踪

对 recvfrom进行跟踪


在这里感谢珍惜大佬介绍的seccomp机制,推荐一波珍惜大佬的课程能学到很多有趣的骚操作。

什么是seccomp

seccomp沙箱机制介绍文章
seccomp 是 Linux 内核提供的一种应用程序沙箱机制,主要通过限制进程的系统调用来完成部分沙箱隔离功能。seccomp-bpf 是 seccomp 的一个扩展,它可以通过配置来允许应用程序调用其他的系统调用。

如何和frida结合

基本原理

1
2
3
4
5
6
7
8
这是一个bpf规则:
struct sock_filter filter[] = {
        BPF_STMT(BPF_LD + BPF_W + BPF_ABS,
                 (offsetof(struct seccomp_data, nr))),
        BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1),
        BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRAP),
        BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
};

seccomp的具体用法可以参考「什么是seccomp」中的seccomp介绍文章。当返回规则设置为「SECCOMP_RET_TRAP」,目标系统调用时seccomp会产生一个SIGSYS系统信号并软中断,这时就可以通过捕获这个SIGSYS信号获得svc调用和打印具体参数。

如何脚本化安装seccomp规则呢

这里使用Frida的API「CModule」,CModule提供强大的动态编译功能可以让你在JS中写C,
frida文档中的示例

1
2
3
4
5
6
7
8
const cm = new CModule(`
#include <stdio.h>
void hello(void) {
  printf("Hello World from CModule\\n");
}
`);
const hello = new NativeFunction(cm.hello, 'void', []);
hello();

如何捕获异常

使用Frida的API「Process.setExceptionHandler」即可捕获异常并在自己写的回调中进行数据处理。
数据处理的逻辑解释写在注释里啦。

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
// 异常处理
    Process.setExceptionHandler(function (details) {
        const current_off = details.context.pc - 4;
        // 判断是否是seccomp导致的异常 读取opcode 010000d4 == svc 0
        if (details.message == "system error" && details.type == "system" && hex(ptr(current_off).readByteArray(4)) == "010000d4") {
            // 上锁避免多线程问题
            lock(syscall_thread_ptr)
            // 获取x8寄存器中的调用号
            const nr = details.context.x8.toString(10);
            let loginfo = "\n=================="
            loginfo += `\nSVC[${syscalls[nr][1]}|${nr}] ==> PC:${addrToString(current_off)} P${Process.id}-T${Process.getCurrentThreadId()}`
            // 构造线程syscall调用参数
            const args = Memory.alloc(7 * 8)
            args.writePointer(details.context.x8)
            let args_reg_arr = {}
            for (let index = 0; index < 6; index++) {
                eval(`args.add(8 * (index + 1)).writePointer(details.context.x${index})`)
                eval(`args_reg_arr["arg${index}"] = details.context.x${index}`)
            }
            // 获取手动堆栈信息
            loginfo += "\n" + stacktrace(ptr(current_off), details.context.fp, details.context.sp).map(addrToString).join('\n')
            // 打印传参
            loginfo += "\nargs = " + JSON.stringify(args_reg_arr)
            // 调用线程syscall 赋值x0寄存器
            details.context.x0 = call_task(syscall_thread_ptr, args, 0)
            loginfo += "\nret = " + details.context.x0.toString()
            // 打印信息
            call_thread_log(loginfo)
            // 解锁
            unlock(syscall_thread_ptr)
            return true;
        }
        return false;
    })

还有什么坑

1.syscall调用resume

问题描述

根据Frida文档介绍「setExceptionHandler」捕获异常后只需要让回调返回true就会resume原本的线程,但是其只是跳过了svc指令继续执行,实际上并不会执行svc,这时候如果不执行syscall轻则导致APP数据异常,重则导致APP直接崩溃。所以在异常的回调中需要手动调用了syscall并赋值给x0。
但这时候会发生个新的问题,因为在主线程开启seccomp后,主线程和其后创建出来的线程都会被seccomp规则约束,在异常处理函数直接调用syscall同样会被seccomp约束再次抛出异常,就形成了”死锁“了。

如何解决

可以注意到上面“死锁”部分描述,那我们在主线程被约束前,提前创建一个线程,这个线程就是不被约束的,同时受到线程池启发,我们让这个syscall线程循环接受任务,就能完成在一个没有约束的线程里进行syscall调用。

2.堆栈回溯

问题描述

直接使用Frida的API「Thread.backtrace」很容易导致崩溃,原因可能是seccomp规则或者「prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)」导致的权限收紧和Frida实现堆栈回溯功能冲突。

如何解决

手动实现堆栈回溯,原理是Arm64中每个函数都会在函数头部位置对x29、x30寄存器存入栈中,所以可以对x29不断读取往上回溯,最后得到完整的堆栈信息。
实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function stacktrace(pc, fp, sp) {
    let n = 0, stack_arr = [], fp_c = fp;
    stack_arr[n++] = pc;
    const mem_region = call_thread_read_maps(sp);
    while (n < MAX_STACK_TRACE_DEPTH) {
        if (parseInt(fp_c.toString()) < parseInt(sp.toString()) || fp_c < mem_region.start || fp_c > mem_region.end) {
            break
        }
        let next_fp = fp_c.readPointer()
        let lr = fp_c.add(8).readPointer()
        fp_c = next_fp
        stack_arr[n++] = lr
    }
    return stack_arr;
}

3.「Process.findModuleByAddress」「Process.enumerateModules」类的API导致崩溃或找不到Module信息

问题描述

疑似同坑2的原因

如何解决

在CModule中手动实现了通过地址查soinfo信息「base, size, soname」等

4.write调用约束下调用Frida的API「send」崩溃

问题描述

同坑2的原因

如何解决

直接改用syscall线程使用「__android_print_log」打印信息

还可以实现什么

在调用线程syscall前后可以更改传参、返回值、地址等更改,达到HOOK的效果

GITHUB

求star
https://github.com/Abbbbbi/Frida-Seccomp

如何使用

1
2
pip3 install frida
python3 multi_frida_seccomp.py

log信息可以在logcat过滤“seccomp”查看
同时也自动保存到了「包名_pid_时间戳」文件夹内(支持多进程)
图片描述


【看雪培训】《Adroid高级研修班》2022年春季班招生中!

最后于 2022-3-12 22:53 被阿碧编辑 ,原因:
收藏
点赞16
打赏
分享
打赏 + 55.00雪花
打赏次数 2 雪花 + 55.00
 
赞赏  Editor   +50.00 2022/04/07 恭喜您获得“雪花”奖励,安全圈有你而精彩!
赞赏  virjar   +5.00 2022/03/12 好文章值得赞赏
最新回复 (25)
雪    币: 2035
活跃值: 活跃值 (5471)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
珍惜Any 活跃值 1 2022-3-11 19:49
2
1
火钳刘明
雪    币: 14248
活跃值: 活跃值 (3262)
能力值: ( LV13,RANK:835 )
在线值:
发帖
回帖
粉丝
大帅锅 活跃值 4 2022-3-11 20:05
3
0
目测必火
雪    币: 9781
活跃值: 活跃值 (7245)
能力值: ( LV9,RANK:240 )
在线值:
发帖
回帖
粉丝
misskings 活跃值 4 2022-3-11 20:42
4
0
收藏收藏。
雪    币: 159
活跃值: 活跃值 (1929)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
huaerxiela 活跃值 2022-3-11 21:08
5
0

b哥牛批

最后于 2022-3-11 21:08 被huaerxiela编辑 ,原因:
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
憨豆爆发 活跃值 2022-3-11 21:15
6
0
6呀6呀  骚操作
雪    币: 1053
活跃值: 活跃值 (309)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
图灵真主护佑 活跃值 2022-3-12 09:19
7
0
niu bee 6666
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
qxpy 活跃值 2022-3-12 11:44
8
0
nbbbb
雪    币: 227
活跃值: 活跃值 (700)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
juziss 活跃值 2022-3-12 11:56
9
0
tql!!!
雪    币: 2656
活跃值: 活跃值 (859)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
VNRKDOEA 活跃值 2022-3-12 13:52
10
0
收藏=会了
雪    币: 94
活跃值: 活跃值 (469)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
wangzehua 活跃值 2022-3-12 15:00
11
0
看过=会了
雪    币: 113
活跃值: 活跃值 (456)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
koflfy 活跃值 1 2022-3-12 22:15
12
0
mark
雪    币: 5407
活跃值: 活跃值 (3912)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
GitRoy 活跃值 3 2022-3-12 23:39
13
0
mark
雪    币: 6642
活跃值: 活跃值 (2704)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
v0id_ 活跃值 2022-3-13 20:47
14
0
mark
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_zpajwtis 活跃值 2022-3-14 09:01
15
0
学习下
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_Then_580 活跃值 2022-3-14 14:42
16
0
你这个能hook  Android 下的 cat不
雪    币: 500
活跃值: 活跃值 (1082)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
阿碧 活跃值 2022-3-16 01:14
17
0
wx_Then_580 你这个能hook Android 下的 cat不
没太理解到意思
雪    币: 962
活跃值: 活跃值 (4194)
能力值: ( LV7,RANK:115 )
在线值:
发帖
回帖
粉丝
Ssssone 活跃值 2 2022-3-16 16:41
18
0
强!
雪    币: 201
活跃值: 活跃值 (82)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ldzspace 活跃值 2022-3-24 18:00
19
0
雪    币: 219
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
hubway 活跃值 2022-4-7 18:38
20
0
这个函数"call_read_maps"有个bug,函数结尾返回了局部变量指针地址
雪    币: 3815
活跃值: 活跃值 (2625)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
mb_aoooaosd 活跃值 2022-4-7 19:41
21
0
nnnnnnb
雪    币: 1732
活跃值: 活跃值 (255)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
iRabbit666 活跃值 2022-4-8 10:57
22
1
看了等于学会了
雪    币: 0
活跃值: 活跃值 (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
breakM 活跃值 2022-4-9 11:27
23
0
学习学习
雪    币: 179
活跃值: 活跃值 (206)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
pigging 活跃值 2022-4-9 20:32
24
0
留名!!
雪    币: 217
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_oowzftna 活跃值 2022-4-10 11:26
25
0
tql
游客
登录 | 注册 方可回帖
返回