这篇文章上次修改于 510 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

前言

尝试站在syscall的视角看root检查,但是eBPF

环境

目标是com.starbucks.cn,使用DirtyPipe-Android提权+卸载magisk后,APP还是能发现root

尝试在estrace基础上做修改,实现root bypass

效果:

记录

使用estraceexecve追踪,会得到这样的日志:

syscall_08:37:18 [om.starbucks.cn] type:1 pid:25310 tid:25310 nr:execve {"lr":"0x7dd9e9ebc8","pc":"0x7dd9ee9498","sp":"0x7fd0983a00","x0":"0xb400007f6682a268","x1":"0xb400007f6682a230","x2":"0xb400007f6680b288"}
syscall_08:37:18 [om.starbucks.cn] type:2 pid:25310 tid:25310 nr:execve arg_index:0 arg_str:/system/bin/sh
syscall_08:37:18 [om.starbucks.cn] type:2 pid:25310 tid:25310 nr:execve arg_index:1 arg_str:sh
syscall_08:37:18 [om.starbucks.cn] type:2 pid:25310 tid:25310 nr:execve arg_index:1 arg_str:-c
syscall_08:37:18 [om.starbucks.cn] type:2 pid:25310 tid:25310 nr:execve arg_index:1 arg_str:which su
syscall_08:37:18 [om.starbucks.cn] type:2 pid:25310 tid:25310 nr:execve arg_index:2 arg_str:PATH=/dev/.magisk:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin
syscall_08:37:18 [om.starbucks.cn] type:2 pid:25310 tid:25310 nr:execve arg_index:2 arg_str:ANDROID_BOOTLOGO=1
syscall_08:37:18 [om.starbucks.cn] type:2 pid:25310 tid:25310 nr:execve arg_index:2 arg_str:ANDROID_ROOT=/system
syscall_08:37:18 [om.starbucks.cn] type:2 pid:25310 tid:25310 nr:execve arg_index:2 arg_str:ANDROID_ASSETS=/system/app
syscall_08:37:18 [om.starbucks.cn] type:2 pid:25310 tid:25310 nr:execve arg_index:2 arg_str:ANDROID_DATA=/data
syscall_08:37:18 [om.starbucks.cn] type:2 pid:25310 tid:25310 nr:execve arg_index:2 arg_str:ANDROID_STORAGE=/storage

...

syscall_08:37:18 [bucks.cn:remote] type:1 pid:25552 tid:25552 nr:execve {"lr":"0x7dd9e9ebc8","pc":"0x7dd9ee9498","sp":"0x7fd09833a0","x0":"0x7c9c2c2b40","x1":"0x7cb1922160","x2":"0x7fd0986ae0"}
syscall_08:37:18 [bucks.cn:remote] type:2 pid:25552 tid:25552 nr:execve arg_index:0 arg_str:/system/bin/sh
syscall_08:37:18 [bucks.cn:remote] type:2 pid:25552 tid:25552 nr:execve arg_index:1 arg_str:sh
syscall_08:37:18 [bucks.cn:remote] type:2 pid:25552 tid:25552 nr:execve arg_index:1 arg_str:-c
syscall_08:37:18 [bucks.cn:remote] type:2 pid:25552 tid:25552 nr:execve arg_index:1 arg_str:mount
syscall_08:37:18 [bucks.cn:remote] type:2 pid:25552 tid:25552 nr:execve arg_index:2 arg_str:PATH=/dev/.magisk:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin
syscall_08:37:18 [bucks.cn:remote] type:2 pid:25552 tid:25552 nr:execve arg_index:2 arg_str:ANDROID_BOOTLOGO=1
syscall_08:37:18 [bucks.cn:remote] type:2 pid:25552 tid:25552 nr:execve arg_index:2 arg_str:ANDROID_ROOT=/system
syscall_08:37:18 [bucks.cn:remote] type:2 pid:25552 tid:25552 nr:execve arg_index:2 arg_str:ANDROID_ASSETS=/system/app
syscall_08:37:18 [bucks.cn:remote] type:2 pid:25552 tid:25552 nr:execve arg_index:2 arg_str:ANDROID_DATA=/data
syscall_08:37:18 [bucks.cn:remote] type:2 pid:25552 tid:25552 nr:execve arg_index:2 arg_str:ANDROID_STORAGE=/storage

可以推测which su是在检查root,而mount则是检查magisk

Q: 为什么mount可以用来检查magisk

A: 如下:

xaga:/ $ mount | grep magisk
none on /dev/.magisk type tmpfs (rw,seclabel,relatime)
devpts on /dev/.magisk/.magisk/pts type devpts (rw,seclabel,nosuid,noexec,relatime,mode=600,ptmxmode=000)
none on /dev/.magisk type tmpfs (rw,seclabel,relatime)
devpts on /dev/.magisk/.magisk/pts type devpts (rw,seclabel,nosuid,noexec,relatime,mode=600,ptmxmode=000)

如果要使用eBPF的方案实现bypass,我们需要对比参数并对参数内容做出修改

estrace中添加下面这样的代码,以实现bypass(mount也是类似处理):

bool need_bypass_check = true;
char target[] = "which su";
for (int i = 0; i < sizeof(target); ++i) {
    if (data->arg_str[i] != target[i]) {
        need_bypass_check = false;
        break;
    }
}
if (need_bypass_check) {
    char fmt0[] = "execve call which su, lets bypass it, uid:%d\n";
    bpf_trace_printk(fmt0, sizeof(fmt0), uid);
    char placeholder[] = "which bb";
    bpf_probe_write_user((void*)addr, placeholder, sizeof(placeholder));
}

也就是比较execveargv中的参数有没有关键词,如果有,我们就把对应的参数修改为其他的,迫使命令执行得到原预期之外的结果

实际测试之后,发现APP还是崩溃了,但是确实多运行了一会儿

百思不得其解,因为estrace是基于uid进行过滤的,不过有没有可能某些检查方案所产生的进程不会归属于当前APP呢?

于是将uid过滤部分去除,再次运行estrace,这一次APP成功进入首页并且没有闪退

那么这次日志中多出来什么呢?如下:

syscall_10:32:07 [.apkwrapper.r.S] type:1 pid:20211 tid:20211 nr:execve {"lr":"0x7dd9e9ebc8","pc":"0x7dd9ee9498","sp":"0x7fd0984330","x0":"0x7dd9e34390","x1":"0x7fd09841a0","x2":"0x7fd0986ae0"}
syscall_10:32:07 [.apkwrapper.r.S] type:2 pid:20211 tid:20211 nr:execve arg_index:0 arg_str:/system/bin/sh
syscall_10:32:07 [.apkwrapper.r.S] type:2 pid:20211 tid:20211 nr:execve arg_index:1 arg_str:sh
syscall_10:32:07 [.apkwrapper.r.S] type:2 pid:20211 tid:20211 nr:execve arg_index:1 arg_str:-c
syscall_10:32:07 [.apkwrapper.r.S] type:2 pid:20211 tid:20211 nr:execve arg_index:1 arg_str:which su
syscall_10:32:07 [.apkwrapper.r.S] type:2 pid:20211 tid:20211 nr:execve arg_index:2 arg_str:PATH=/dev/.magisk:/apex/com.android.runtime/bin:/apex/com.android.art/bin:/system_ext/bin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin
syscall_10:32:07 [.apkwrapper.r.S] type:2 pid:20211 tid:20211 nr:execve arg_index:2 arg_str:ANDROID_BOOTLOGO=1
syscall_10:32:07 [.apkwrapper.r.S] type:2 pid:20211 tid:20211 nr:execve arg_index:2 arg_str:ANDROID_ROOT=/system
syscall_10:32:07 [.apkwrapper.r.S] type:2 pid:20211 tid:20211 nr:execve arg_index:2 arg_str:ANDROID_ASSETS=/system/app
syscall_10:32:07 [.apkwrapper.r.S] type:2 pid:20211 tid:20211 nr:execve arg_index:2 arg_str:ANDROID_DATA=/data
syscall_10:32:07 [.apkwrapper.r.S] type:2 pid:20211 tid:20211 nr:execve arg_index:2 arg_str:ANDROID_STORAGE=/storage

通过拼手速,终于发现了这个进程:

xaga:/ # ps -ef | grep apkwrapper                                                                                                     
u0_i9104     21022   759 7 18:34:17 ?     00:00:00 com.starbucks.cn:bbs:com.secneo.apkwrapper.r.S

这个进程的父进程是zygote64,查看AndroidManifest.xml发现原来是isolatedProcess

xaga:/ # ps -ef | grep zygote                                                                                                         
root           759     1 0 00:08:26 ?     00:00:20 zygote64

总结

  • APP检查root的方案是执行which su命令
  • APP检查magisk的方案是执行mount命令,看看是否存在magisk关键词
  • 在此案例中isolatedProcess的父进程是zygote64