首页
社区
课程
招聘
[讨论] Magisk隐藏root的实现
发表于: 2018-10-22 11:18 39583

[讨论] Magisk隐藏root的实现

2018-10-22 11:18
39583

unmount前后,目标进程/proc/self/mounts文件内容的变化:


然后测试了下namespace相关的输出,shell 和root的mnt-namespace 是同一个:

所以在shell或者root中某一个终端隐藏su后,在其他终端也不能直接访问su了。

另外,查看过的所有进程的net-namespace都是同一个:

关于哪些进程使用同一个namespace的逻辑,本菜也不清楚从内核源码的哪部分看,有大佬了解这块的欢迎拍砖。

int main(int argc, char** argv) {
    DEBUG_PRINT("hideroot start\n");
    if (argc < 2) {
        DEBUG_PRINT("usage: ./hideroot {pid}\n");
        return 1;
    }

    pid_t target_pid = atoi(argv[1]);
    DEBUG_PRINT("target pid is %d\n", target_pid);

    // 1. 暂停目标进程
    kill(target_pid, SIGSTOP);

    // 2. 关联到目标进程的mnt-namespace
    DEBUG_PRINT("hideroot switch_mnt_ns\n");
    if (switch_mnt_ns(target_pid)) {
        DEBUG_PRINT("");
        return 1;
    }

    // 3. 卸载相关文件系统
    DEBUG_PRINT("hideroot read mounts\n");
    char buffer[256];
    char* line = NULL;
    struct vector mount_list;
    snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", target_pid);
    DEBUG_PRINT("hideroot init mount_list\n");
    vec_init(&mount_list);
    DEBUG_PRINT("hideroot read file\n");
    file_to_vector(buffer, &mount_list);

    DEBUG_PRINT("hideroot unmount dummy skeletons and /sbin links\n");
    // Unmount dummy skeletons and /sbin links
    vec_for_each(&mount_list, line) {
        if (strstr(line, "tmpfs /system/") || strstr(line, "tmpfs /vendor/") || strstr(line, "tmpfs /sbin")) {
            sscanf(line, "%*s %4096s", buffer);
            lazy_unmount(buffer);
        }
        free(line);
    }
    vec_destroy(&mount_list);

    // Re-read mount infos
    snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", target_pid);
    vec_init(&mount_list);
    file_to_vector(buffer, &mount_list);

    DEBUG_PRINT("hideroot unmount everything under /system, /vendor\n");
    // Unmount everything under /system, /vendor, and loop mounts
    vec_for_each(&mount_list, line) {
        if (strstr(line, "/dev/block/loop") || strstr(line, " /system/") || strstr(line, " /vendor/")) {
            sscanf(line, "%*s %4096s", buffer);
            lazy_unmount(buffer);
        }
        free(line);
    }
    vec_destroy(&mount_list);

exit:
    // 4. 目标进程继续运行
    kill(target_pid, SIGCONT);

    sleep(100);

    return 0;
}
switch_mnt_ns的实现如下:
int main(int argc, char** argv) {
    DEBUG_PRINT("hideroot start\n");
    if (argc < 2) {
        DEBUG_PRINT("usage: ./hideroot {pid}\n");
        return 1;
    }

    pid_t target_pid = atoi(argv[1]);
    DEBUG_PRINT("target pid is %d\n", target_pid);

    // 1. 暂停目标进程
    kill(target_pid, SIGSTOP);

    // 2. 关联到目标进程的mnt-namespace
    DEBUG_PRINT("hideroot switch_mnt_ns\n");
    if (switch_mnt_ns(target_pid)) {
        DEBUG_PRINT("");
        return 1;
    }

    // 3. 卸载相关文件系统
    DEBUG_PRINT("hideroot read mounts\n");
    char buffer[256];
    char* line = NULL;
    struct vector mount_list;
    snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", target_pid);
    DEBUG_PRINT("hideroot init mount_list\n");
    vec_init(&mount_list);
    DEBUG_PRINT("hideroot read file\n");
    file_to_vector(buffer, &mount_list);

    DEBUG_PRINT("hideroot unmount dummy skeletons and /sbin links\n");
    // Unmount dummy skeletons and /sbin links
    vec_for_each(&mount_list, line) {
        if (strstr(line, "tmpfs /system/") || strstr(line, "tmpfs /vendor/") || strstr(line, "tmpfs /sbin")) {
            sscanf(line, "%*s %4096s", buffer);
            lazy_unmount(buffer);
        }
        free(line);
    }
    vec_destroy(&mount_list);

    // Re-read mount infos
    snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", target_pid);
    vec_init(&mount_list);
    file_to_vector(buffer, &mount_list);

    DEBUG_PRINT("hideroot unmount everything under /system, /vendor\n");
    // Unmount everything under /system, /vendor, and loop mounts
    vec_for_each(&mount_list, line) {
        if (strstr(line, "/dev/block/loop") || strstr(line, " /system/") || strstr(line, " /vendor/")) {
            sscanf(line, "%*s %4096s", buffer);
            lazy_unmount(buffer);
        }
        free(line);
    }
    vec_destroy(&mount_list);

exit:
    // 4. 目标进程继续运行
    kill(target_pid, SIGCONT);

    sleep(100);

    return 0;
}
switch_mnt_ns的实现如下:
int switch_mnt_ns(int pid) {
    char mnt[32];
    snprintf(mnt, sizeof(mnt), "/proc/%d/ns/mnt", pid);
    if(access(mnt, R_OK) == -1) {
        DEBUG_PRINT("[switch_mnt_ns] %s can't access!", mnt);
        return 1;
    }

    int fd, ret;
    fd = open(mnt, O_RDONLY);
    if (fd < 0) {
        DEBUG_PRINT("[switch_mnt_ns] open %s failed!", mnt);
        return 1;
    }

    // setns的详细解释见 http://man7.org/linux/man-pages/man2/setns.2.html
    ret = setns(fd, 0);
    close(fd);
    return ret;
}
原理很简单,通过setns关联到目标进程,unmount掉一些文件系统。附件demo的测试输出:

unmount前后,目标进程/proc/self/mounts文件内容的变化:


然后测试了下namespace相关的输出,shell 和root的mnt-namespace 是同一个:


所以在shell或者root中某一个终端隐藏su后,在其他终端也不能直接访问su了。

另外,查看过的所有进程的net-namespace都是同一个:


关于哪些进程使用同一个namespace的逻辑,本菜也不清楚从内核源码的哪部分看,有大佬了解这块的欢迎拍砖。



[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 8
支持
分享
最新回复 (17)
雪    币: 368
活跃值: (431)
能力值: ( LV2,RANK:140 )
在线值:
发帖
回帖
粉丝
2
谢谢楼主分享,楼主好人
2018-10-22 14:23
0
雪    币: 53
活跃值: (280)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
Android app进程的父进程zygote进程启动后初始化阶段,会从其父进程(init: pid为1, init namespace为所有其他native service共享,如adbd[adb shell]、vold...) 的mount namespace中独立出来,形成新的namespace;此后,所有app进程由zygote fork出来后,会再次独立出来形成各自app的mount namespace,来实现android对存储的权限控制和隔离机制。

参考:
https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/java/com/android/internal/os/ZygoteInit.java
Zygote.nativeUnmountStorageOnInit();

https://android.googlesource.com/platform/frameworks/base/+/android-9.0.0_r12/core/jni/com_android_internal_os_Zygote.cpp
com_android_internal_os_Zygote_nativeUnmountStorageOnInit
MountEmulatedStorage
2018-10-22 14:45
0
雪    币: 1553
活跃值: (492)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
4
netsniffer Android app进程的父进程zygote进程启动后初始化阶段,会从其父进程(init: pid为1, init namespace为所有其他native service共享,如adbd[adb ...
感谢大佬指导!
2018-10-22 14:55
0
雪    币: 94
活跃值: (2397)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
mark
2018-10-22 20:15
0
雪    币: 76
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
马克
2018-10-23 09:14
0
雪    币: 174
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
mark
2018-10-23 19:53
1
雪    币: 43
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
多谢分享,3q
2019-4-19 14:24
0
雪    币: 199
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
mark
2019-4-25 17:01
0
雪    币: 15
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
学习了
2019-12-19 10:26
0
雪    币: 19
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
学习了
2019-12-19 14:28
0
雪    币: 231
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
学习了
2020-4-1 19:58
0
雪    币: 286
活跃值: (381)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
学习了
2020-4-2 18:07
0
雪    币: 244
活跃值: (266)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
supersu改SU  使得正常检查不到root,特定应用可以获取root
2020-5-7 12:55
0
雪    币: 244
活跃值: (266)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
学习了
2021-8-11 13:59
0
雪    币: 45
活跃值: (1369)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
收藏
2021-8-15 07:11
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
mark
2022-9-11 21:45
0
雪    币: 2714
活跃值: (1611)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
2022-9-12 09:23
0
游客
登录 | 注册 方可回帖
返回
//