想要使用Seccomp 来查看某个apk的syscall日志, 发现apk本身有反Seccomp机制, 设置PR_SET_NO_NEW_PRIVS 就闪退了.后续更无法使用 prctl PR_SET_SECCOMP, SECCOMP_MODE_FILTER

只好从内核层直接输入日志.

烧录内核的步骤主要参考:

https://blog.lleavesg.top/article/pixel5-kernel-build

https://github.com/zhanghecn/luckzh_android_flash_notes/blob/main/doc/note3-kernel/index.md

可以成功烧录内核. 主要的注意点就是: 解压原始boot.img的得到的boot.img-ramdisk.cpio.lz4 并将其放入android-kernel目录中. 再打包重新烧录 boot.img 和vendor_boot.img两个分区即可.

1.取消PR_SET_NO_NEW_PRIVS 设置后status状态值

这个修改比较简单,把文件fs/proc/array.c 里设置NoNewPrivs写死0即可.

1
2
3
4
static inline void task_seccomp(struct seq_file *m, struct task_struct *p)
{
seq_put_decimal_ull(m, "NoNewPrivs:\t", 0);//task_no_new_privs(p)

编译烧录之后,开启PR_SET_NO_NEW_PRIVS ,apk就检测不到状态了. 但是设置了PR_SET_SECCOMP仍然闪退. 因此需要在kernel里分析是调用了哪些syscall之后退出,就可以反推出检测逻辑.

2.增加syscall日志

kernel的syscall调用非常频繁,如果不过滤直接开printk, 日志就太多了. 因此只能过滤一下我们关心的.

安卓为每个apk分配了一个user,按照userid来过滤是个很好的方案. 查询到apk的userid之后,设置过滤如下即可只过滤当前apk的日志.

比如openat时加入日志:

1
2
3
4
5
6
7
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{

if(current_cred()->uid.val == 10411)
{
printk(DEBUG_TAG_KERNEL" %d-%d(uid=%d) open file %s\n",current->pid,current->tgid,current_cred()->uid,tmp->iname);
}

其他的系统调用可以按照类似修改.

3.增加userid可修改.

apk不卸载重装,userid是不会变的, 但是写死userid到代码里总不是一个好的方案. 因此需要userid能在应用层指定.

因此GPT给出的方案是使用debugfs来增加一个文件, 使用adb 可以写入这个userid值, kenrel检测到修改后更新这个userid.

基本代码如下:

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
int  DEBUG_USER_APP_USERID =0;
#define BUF_SIZE 100
static char debug_buf[BUF_SIZE];
static struct dentry *dir, *file;
static struct dentry *dir, *file;
static ssize_t debugfs_read(struct file *filp, char __user *buffer, size_t len, loff_t *offset) {
return simple_read_from_buffer(buffer, len, offset, debug_buf, strlen(debug_buf));
}
static ssize_t debugfs_write(struct file *filp, const char __user *buffer, size_t len, loff_t *offset) {
int num = 0;
int i = 0;
if (len > BUF_SIZE - 1)
return -EINVAL;
if (copy_from_user(debug_buf, buffer, len))
return -EFAULT;
debug_buf[len] = '\0';
//转换成整数

while (debug_buf[i] != '\0') {
if(debug_buf[i] >= '0' && debug_buf[i] <= '9')
{
num = num * 10 + debug_buf[i] - '0';
}
i++;
}
if(num > 10000)
{
DEBUG_USER_APP_USERID = num;
}
return len;
}
static const struct file_operations fops = {
.read = debugfs_read,
.write = debugfs_write,
};
static int __init debugfs_init(void) {
dir = debugfs_create_dir("my_debug", NULL);
if (!dir)
return -ENOMEM;
file = debugfs_create_file("debug_user_app_userid", 0666, dir, NULL, &fops);
if (!file) {
debugfs_remove(dir);
return -ENOMEM;
}
return 0;
}

为了简单,没必要单独写驱动, 可以放到kernel/configs.c 文件里,本身这个模块功能简单,不到一百行代码.

修改监控userid的方法也简单了.

1
2
3
redfin:/sys/kernel/debug/my_debug # echo 10144 > debug_user_app_userid
redfin:/sys/kernel/debug/my_debug # cat debug_user_app_userid
10144