KernelSu Root 方案分析

- Android KernelSU Root 内核 逆向工程 安全研究

从零开始理解 KernelSU 的内核级 Root 机制 本文档面向希望深入理解 Android Root 技术的开发者和安全研究人员


目录

  1. 基础概念
  2. 架构总览
  3. 内核层实现
  4. 用户空间实现
  5. 安全模型
  6. 与 Magisk 对比
  7. 实战示例
  8. 关键文件索引

1. 基础概念

1.1 什么是内核级 Root?

传统 Root 方案(如 Magisk):

KernelSU 内核级 Root:

1.2 为什么内核级更强大?

用户空间应用
    ↓
  系统调用 (syscall)
    ↓
═══════════════════════  ← KernelSU 在这里工作!
    ↓
  Linux 内核
    ↓
  硬件

核心优势:

  1. 权限提升发生在内核态:直接操作进程的 struct cred,无需通过 su 二进制
  2. 系统调用拦截:Hook 关键 syscall(execve、stat、faccessat)实现透明重定向
  3. SELinux 深度集成:可以直接修改 SELinux 策略和进程 context
  4. 隐蔽性极强:不依赖可见的文件或进程,难以从用户空间检测

1.3 Android 安全模型回顾

KernelSU 需要绕过/控制以下安全机制:

机制说明KernelSU 如何处理
UID/GID每个应用一个唯一 UID修改 cred->uid/gid 为 0(root)
Capabilities细粒度权限控制设置 CAP_FULL_SETcred->cap_*
SELinux强制访问控制动态切换进程到 u:r:su:s0 domain
Mount Namespace文件系统隔离可选择继承或隔离挂载点
Seccomp系统调用过滤禁用 seccomp 过滤器

2. 架构总览

2.1 三层架构

┌─────────────────────────────────────────────────────┐
│           Manager App (Kotlin/Compose)              │
│  - UI 界面                                           │
│  - 应用授权管理                                       │
│  - 模块管理                                          │
└──────────────────┬──────────────────────────────────┘
                   │ JNI (ksu.cc)
                   ↓
┌─────────────────────────────────────────────────────┐
│         ksud Daemon (Rust)                          │
│  - CLI 命令分发                                      │
│  - 模块生命周期管理                                   │
│  - init 事件处理                                     │
└──────────────────┬──────────────────────────────────┘
                   │ IOCTL (supercalls)
                   ↓
┌─────────────────────────────────────────────────────┐
│         Kernel Module (C)                           │
│  - 系统调用拦截                                      │
│  - 权限提升核心逻辑                                   │
│  - 白名单/配置管理                                   │
│  - SELinux 策略操作                                  │
└─────────────────────────────────────────────────────┘

2.2 关键通信路径

1. FD 安装(获取内核驱动句柄):

ksud 启动
  → 扫描 /proc/self/fd 查找 [ksu_driver]
  → 如未找到,调用 syscall(SYS_reboot, 0xDEADBEEF, 0xCAFEBABE, 0, &fd)
  → 内核 kprobe 拦截 reboot,检测魔数
  → 通过 task_work 异步返回匿名 inode fd
  → ksud 缓存 fd 用于后续 IOCTL 调用

文件位置:

2. Root 权限授予:

应用执行 "su"
  → 内核 execve hook 拦截
  → 检查 allowlist (ksu_is_allow_uid)
  → 重定向到 /data/adb/ksud
  → 调用 escape_with_root_profile()
  → 修改进程凭证 (UID=0, CAP_FULL_SET, SELinux domain)
  → ksud 以 root 身份运行
  → fork shell 进程

3. 内核层实现

3.1 模块初始化

入口函数: kernel/ksu.c:61 - kernelsu_init()

 1int __init kernelsu_init(void)
 2{
 3    // 1. 检测是否为延迟加载(late load)
 4    ksu_late_loaded = (current->pid != 1);
 5
 6    // 2. 准备 root 凭证结构
 7    ksu_cred = prepare_creds();
 8
 9    // 3. 初始化各子系统
10    ksu_feature_init();           // 功能开关系统
11    ksu_supercalls_init();        // IOCTL 接口
12    ksu_syscall_hook_manager_init(); // 系统调用 hook
13    ksu_allowlist_init();         // 白名单
14    ksu_throne_tracker_init();    // Manager 验证
15
16    if (ksu_late_loaded) {
17        // 延迟加载模式:立即应用 SELinux 规则
18        apply_kernelsu_rules();
19        escape_to_root_for_init();  // 授予当前进程(ksud)root
20        ksu_load_allow_list();      // 加载持久化白名单
21    } else {
22        // 正常启动:注册 kprobe hook
23        ksu_ksud_init();
24    }
25
26    return 0;
27}

关键点:

3.2 Supercall 接口(内核 IOCTL)

核心文件: kernel/supercalls.c

3.2.1 匿名 inode 创建

 1int ksu_install_fd(void)
 2{
 3    // 1. 获取未使用的 fd
 4    fd = get_unused_fd_flags(O_CLOEXEC);
 5
 6    // 2. 创建匿名 inode,名称为 "[ksu_driver]"
 7    filp = anon_inode_getfile("[ksu_driver]", &anon_ksu_fops, NULL,
 8                              O_RDWR | O_CLOEXEC);
 9
10    // 3. 安装 fd 到进程
11    fd_install(fd, filp);
12
13    return fd;
14}

为什么使用匿名 inode?

3.2.2 IOCTL 命令表

kernel/supercalls.c:629-711 定义了 20 个 IOCTL 命令:

命令权限检查功能
KSU_IOCTL_GRANT_ROOTallowed_for_su核心:授予 root 权限
KSU_IOCTL_GET_INFOalways_allow获取版本和标志位
KSU_IOCTL_REPORT_EVENTonly_root报告 init 事件(post-fs-data/boot-completed)
KSU_IOCTL_SET_SEPOLICYonly_root动态修改 SELinux 策略
KSU_IOCTL_GET_ALLOW_LISTmanager_or_root读取白名单
KSU_IOCTL_GET_APP_PROFILEonly_manager获取应用配置
KSU_IOCTL_SET_APP_PROFILEonly_manager设置应用配置(root/non-root)
KSU_IOCTL_GET_FEATUREmanager_or_root读取功能开关状态
KSU_IOCTL_SET_FEATUREmanager_or_root设置功能开关
KSU_IOCTL_MANAGE_MARKmanager_or_root管理进程标记(tracepoint flag)
KSU_IOCTL_ADD_TRY_UMOUNTmanager_or_root管理卸载列表

权限检查函数:

 1bool allowed_for_su(void)
 2{
 3    // Manager 或白名单内的 UID
 4    return is_manager() || ksu_is_allow_uid_for_current(current_uid().val);
 5}
 6
 7bool manager_or_root(void)
 8{
 9    return current_uid().val == 0 || is_manager();
10}

3.3 权限提升机制(核心)

函数: kernel/app_profile.c:106 - escape_with_root_profile()

这是 KernelSU 最核心的函数,实现了真正的权限提升:

 1void escape_with_root_profile(void)
 2{
 3    struct cred *cred;
 4    struct root_profile profile;
 5
 6    // 1. 准备新的凭证结构(COW - Copy on Write)
 7    cred = prepare_creds();
 8
 9    // 2. 获取该 UID 的 root profile 配置
10    ksu_get_root_profile(cred->uid.val, &profile);
11
12    // 3. 修改 UID/GID 为 profile 指定值(通常是 0)
13    cred->uid.val = profile.uid;
14    cred->suid.val = profile.uid;
15    cred->euid.val = profile.uid;
16    cred->fsuid.val = profile.uid;
17
18    cred->gid.val = profile.gid;
19    cred->fsgid.val = profile.gid;
20    cred->sgid.val = profile.gid;
21    cred->egid.val = profile.gid;
22
23    // 4. 更新 user_struct(进程计数)
24    new_user = alloc_uid(cred->uid);
25    free_uid(cred->user);
26    cred->user = new_user;
27
28    // 5. 设置 capabilities(全权限)
29    u64 cap_for_ksud = profile.capabilities.effective | CAP_DAC_READ_SEARCH;
30    memcpy(&cred->cap_effective, &cap_for_ksud, sizeof(cred->cap_effective));
31    memcpy(&cred->cap_permitted, &profile.capabilities.effective,
32           sizeof(cred->cap_permitted));
33
34    // 6. 设置附加组
35    setup_groups(&profile, cred);
36
37    // 7. 切换 SELinux domain 到 "u:r:su:s0"
38    setup_selinux(profile.selinux_domain, cred);
39
40    // 8. 提交凭证(原子操作)
41    commit_creds(cred);
42
43    // 9. 禁用 seccomp 过滤器
44    disable_seccomp();
45
46    // 10. 标记所有线程启用 syscall tracepoint
47    for_each_thread (p, t) {
48        ksu_set_task_tracepoint_flag(t);
49    }
50
51    // 11. 设置 mount namespace
52    setup_mount_ns(profile.namespaces);
53}

关键数据结构:

1struct root_profile {
2    uid_t uid;                      // 目标 UID(通常是 0)
3    gid_t gid;                      // 目标 GID
4    u32 groups_count;               // 附加组数量
5    gid_t groups[KSU_MAX_GROUPS];   // 附加组列表
6    struct kernel_cap_struct capabilities; // Capability 集合
7    char selinux_domain[64];        // SELinux context
8    u32 namespaces;                 // 命名空间选项
9};

3.4 系统调用拦截

文件: kernel/syscall_hook_manager.c

3.4.1 进程标记系统

KernelSU 使用 TIF_SYSCALL_TRACEPOINT 标志位来标记需要监控的进程:

1void ksu_set_task_tracepoint_flag(struct task_struct *t)
2{
3#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
4    set_task_syscall_work(t, SYSCALL_TRACEPOINT);
5#else
6    set_tsk_thread_flag(t, TIF_SYSCALL_TRACEPOINT);
7#endif
8}

哪些进程会被标记?

  1. UID=0 且 SELinux domain 为 u:r:su:s0 的进程(KernelSU root 进程)
  2. Zygote 进程(孵化所有应用)
  3. Shell 进程(UID=2000)
  4. 白名单内的 UID
  5. Init 进程(启动阶段)

3.4.2 Hooked 系统调用

1. execve - 执行拦截(SU 兼容层)

kernel/sucompat.c:118 - ksu_handle_execve_sucompat()

 1int ksu_handle_execve_sucompat(const char __user **filename_user, ...)
 2{
 3    char path[32];
 4
 5    // 1. 检查是否为白名单 UID
 6    if (!ksu_is_allow_uid_for_current(current_uid().val))
 7        return 0;
 8
 9    // 2. 读取要执行的文件路径
10    strncpy_from_user_nofault(path, *filename_user, sizeof(path));
11
12    // 3. 检测是否为 "/system/bin/su"
13    if (memcmp(path, "/system/bin/su", 15) == 0) {
14        pr_info("sys_execve su found\n");
15
16        // 4. 重定向到 ksud
17        *filename_user = ksud_user_path();  // "/data/adb/ksud"
18
19        // 5. 立即提权!
20        escape_with_root_profile();
21    }
22
23    return 0;
24}

流程图:

应用调用 execve("/system/bin/su", ...)
         ↓
内核 tracepoint 触发
         ↓
ksu_handle_execve_sucompat()
         ↓
    检查白名单?
    ↙        ↘
  否          是
  ↓          ↓
正常执行    重定向到 /data/adb/ksud
            ↓
        escape_with_root_profile()
            ↓
        修改进程凭证为 root
            ↓
        ksud 以 root 身份运行

2. newfstatat / faccessat - 文件访问伪装

kernel/sucompat.c:72-116

 1int ksu_handle_stat(int *dfd, const char __user **filename_user, int *flags)
 2{
 3    if (!ksu_is_allow_uid_for_current(current_uid().val))
 4        return 0;
 5
 6    char path[32];
 7    strncpy_from_user_nofault(path, *filename_user, sizeof(path));
 8
 9    // 将 stat("/system/bin/su") 重定向到 stat("/system/bin/sh")
10    if (memcmp(path, "/system/bin/su", 15) == 0) {
11        *filename_user = sh_user_path();  // "/system/bin/sh"
12    }
13
14    return 0;
15}

为什么需要这个?

3. setresuid - UID 切换拦截

kernel/setuid_hook.c - 防止 root 进程降权后再次提权

3.5 白名单机制

文件: kernel/allowlist.c

3.5.1 存储结构

KernelSU 使用 双层存储 优化查询性能:

 1// 1. Bitmap(快速查询,UID ≤ 65535)
 2static uint8_t allow_list_bitmap[PAGE_SIZE] __read_mostly;
 3#define BITMAP_UID_MAX ((sizeof(allow_list_bitmap) * 8) - 1)  // 32767
 4
 5// 2. 数组(大 UID 备用,> 65535)
 6static int allow_list_arr[PAGE_SIZE / sizeof(int)] __read_mostly;
 7
 8// 3. 链表(完整配置信息)
 9struct perm_data {
10    struct list_head list;
11    struct rcu_head rcu;
12    struct app_profile profile;  // 包含 root_profile 或 non_root_profile
13};
14static struct list_head allow_list;

3.5.2 查询算法

kernel/allowlist.c:272 - __ksu_is_allow_uid()

 1bool __ksu_is_allow_uid(uid_t uid)
 2{
 3    // 1. 拒绝系统 UID(< 2000 且 != 1000)
 4    if (forbid_system_uid(uid))
 5        return false;
 6
 7    // 2. Manager 总是允许
 8    if (ksu_get_manager_appid() == uid % PER_USER_RANGE)
 9        return true;
10
11    // 3. Bitmap 快速查询(O(1))
12    if (likely(uid <= BITMAP_UID_MAX)) {
13        return !!(allow_list_bitmap[uid / 8] & (1 << (uid % 8)));
14    }
15
16    // 4. 数组线性查询(大 UID)
17    for (i = 0; i < allow_list_pointer; i++) {
18        if (allow_list_arr[i] == uid)
19            return true;
20    }
21
22    return false;
23}

性能分析:

3.5.3 持久化

1#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist"
2
3// 文件格式:
4// [u32: MAGIC=0x7f4b5355] [u32: VERSION=3] [app_profile] [app_profile] ...

3.6 SELinux 集成

文件: kernel/selinux/sepolicy.c

3.6.1 自定义 Domain

KernelSU 创建 u:r:su:s0 domain:

 1#define KERNEL_SU_DOMAIN "su"
 2
 3void setup_selinux(const char *domain, struct cred *cred)
 4{
 5    u32 sid;
 6
 7    // 1. 查询 domain 对应的 SID(Security ID)
 8    int err = ksu_security_secctx_to_secid(domain, strlen(domain), &sid);
 9
10    // 2. 设置进程的 SELinux context
11    struct task_security_struct *tsec = cred->security;
12    tsec->sid = sid;
13    tsec->osid = sid;
14    tsec->exec_sid = 0;
15    tsec->create_sid = 0;
16    tsec->keycreate_sid = 0;
17    tsec->sockcreate_sid = 0;
18}

3.6.2 策略规则

apply_kernelsu_rules() 添加以下规则:

type su;
domain_auto_trans(su, exec_type, domain)  # su 可以切换到任意 domain
allow su * * *                             # su 拥有所有权限

保持 Enforcing 模式:


4. 用户空间实现

4.1 ksud 守护进程

入口: userspace/ksud/src/main.rscli.rs

4.1.1 命令分发

 1pub fn run() -> Result<()> {
 2    let args: Vec<String> = env::args().collect();
 3    let program = &args[0];
 4
 5    match program.as_str() {
 6        // Root shell 模式
 7        "su" | "/system/bin/su" => {
 8            grant_root(false)?;  // 调用 ksucalls::grant_root()
 9        },
10
11        // ksud 守护模式
12        _ => {
13            let cmd = args.get(1).map(|s| s.as_str());
14            match cmd {
15                Some("post-fs-data") => init_event::on_post_fs_data(),
16                Some("services") => init_event::on_services(),
17                Some("boot-completed") => init_event::on_boot_completed(),
18                Some("install") => module::install_module(&args[2]),
19                Some("module") => module::handle_module_action(&args[2..]),
20                _ => print_usage(),
21            }
22        }
23    }
24}

4.1.2 Supercall 封装

文件: userspace/ksud/src/ksucalls.rs

 1// 全局 FD 缓存
 2static DRIVER_FD: OnceLock<RawFd> = OnceLock::new();
 3
 4// 初始化 FD
 5fn init_driver_fd() -> Option<RawFd> {
 6    // 1. 扫描 /proc/self/fd 查找 [ksu_driver]
 7    let fd = scan_driver_fd();
 8    if fd.is_none() {
 9        // 2. 使用魔数调用 reboot syscall
10        let mut fd = -1;
11        unsafe {
12            libc::syscall(
13                libc::SYS_reboot,
14                0xDEADBEEF,  // KSU_INSTALL_MAGIC1
15                0xCAFEBABE,  // KSU_INSTALL_MAGIC2
16                0,
17                &mut fd,     // 内核通过这个指针返回 fd
18            );
19        };
20        if fd >= 0 { Some(fd) } else { None }
21    } else {
22        fd
23    }
24}
25
26// IOCTL 封装
27fn ksuctl<T>(request: i32, arg: *mut T) -> std::io::Result<i32> {
28    let fd = *DRIVER_FD.get_or_init(|| init_driver_fd().unwrap_or(-1));
29    unsafe {
30        let ret = libc::ioctl(fd, request, arg);
31        if ret < 0 {
32            Err(io::Error::last_os_error())
33        } else {
34            Ok(ret)
35        }
36    }
37}
38
39// 授予 root
40pub fn grant_root() -> std::io::Result<()> {
41    ksuctl(KSU_IOCTL_GRANT_ROOT, std::ptr::null_mut::<u8>())?;
42    Ok(())
43}

4.2 Root 执行完整流程

场景: 应用调用 su -c "id"

┌─────────────────────────────────────────────────────────────────┐
│ 1. 应用进程(UID=10086)                                         │
│    Runtime.exec("/system/bin/su", "-c", "id")                   │
└────────────────────┬────────────────────────────────────────────┘
                     ↓ execve syscall
┌─────────────────────────────────────────────────────────────────┐
│ 2. 内核 Tracepoint                                              │
│    sys_enter_execve() 触发                                       │
│    → ksu_handle_execve_sucompat()                               │
│      - 检查 UID 10086 是否在白名单                               │
│      - 检测路径为 "/system/bin/su"                               │
│      - 重定向 filename 到 "/data/adb/ksud"                       │
│      - 调用 escape_with_root_profile()                          │
│        * 修改 current->cred->uid = 0                            │
│        * 设置 CAP_FULL_SET                                       │
│        * SELinux context → u:r:su:s0                            │
└────────────────────┬────────────────────────────────────────────┘
                     ↓ 继续 execve
┌─────────────────────────────────────────────────────────────────┐
│ 3. ksud 进程启动(现在 UID=0)                                   │
│    main.rs: 识别 argv[0] = "su"                                 │
│    → grant_root(false)                                          │
│      - ioctl(fd, KSU_IOCTL_GRANT_ROOT, NULL)                    │
│        (这次调用实际上是冗余的,因为已经是 root)                  │
│      - Command::new("sh").exec()                                │
└────────────────────┬────────────────────────────────────────────┘
                     ↓ fork + exec
┌─────────────────────────────────────────────────────────────────┐
│ 4. Shell 进程(继承 UID=0)                                      │
│    执行 "id" 命令                                                │
│    输出: uid=0(root) gid=0(root) context=u:r:su:s0              │
└─────────────────────────────────────────────────────────────────┘

4.3 Init 系统集成

文件: userspace/ksud/src/init_event.rs

4.3.1 启动阶段

 1// 1. post-fs-data:数据分区挂载后
 2pub fn on_post_fs_data() {
 3    ksucalls::report_post_fs_data();  // 通知内核
 4
 5    // 挂载 metamodule
 6    metamodule::mount_metamodule();
 7
 8    // 挂载普通模块
 9    module::mount_modules();
10
11    // 执行模块脚本
12    module::exec_stage_script("post-fs-data.sh");
13}
14
15// 2. services:系统服务启动时
16pub fn on_services() {
17    module::exec_stage_script("service.sh");
18}
19
20// 3. boot-completed:启动完成
21pub fn on_boot_completed() {
22    ksucalls::report_boot_complete();
23
24    // 启动 Manager 的 throne tracker
25    throne_tracker::track_throne();
26
27    // 启动 package observer(监控应用安装/卸载)
28    package_observer::start();
29}

4.3.2 init.rc 注入

KernelSU 通过修改 /init.rc 或注入 /system/etc/init/ksu.rc 实现自启动:

on post-fs-data
    exec u:r:su:s0 root root -- /data/adb/ksud post-fs-data

service ksud-service /data/adb/ksud services
    user root
    seclabel u:r:su:s0
    oneshot

on property:sys.boot_completed=1
    exec u:r:su:s0 root root -- /data/adb/ksud boot-completed

5. 安全模型

5.1 应用配置文件

结构: kernel/app_profile.h

 1struct app_profile {
 2    u32 version;                // 配置版本
 3    char key[128];              // 包名或特殊标识("$", "#")
 4    uid_t current_uid;          // 当前 UID
 5    bool allow_su;              // 是否允许 root
 6
 7    union {
 8        // Root 配置
 9        struct {
10            bool use_default;
11            struct root_profile profile;
12        } rp_config;
13
14        // Non-root 配置
15        struct {
16            bool use_default;
17            struct non_root_profile profile;
18        } nrp_config;
19    };
20};
21
22struct root_profile {
23    uid_t uid;                  // 目标 UID(0=root)
24    gid_t gid;                  // 目标 GID
25    u32 groups_count;
26    gid_t groups[KSU_MAX_GROUPS];
27    struct kernel_cap_struct capabilities;
28    char selinux_domain[64];    // 默认 "u:r:su:s0"
29    u32 namespaces;             // KSU_NS_INHERITED / KSU_NS_ISOLATED
30};
31
32struct non_root_profile {
33    bool umount_modules;        // 是否卸载模块(隐藏 KernelSU)
34};

特殊 key:

5.2 模块隐藏机制

Per-App Umount:

 1bool ksu_uid_should_umount(uid_t uid)
 2{
 3    struct app_profile profile = { .current_uid = uid };
 4
 5    // Manager 不卸载
 6    if (ksu_get_manager_appid() == uid % PER_USER_RANGE)
 7        return false;
 8
 9    // 查询 app profile
10    bool found = ksu_get_app_profile(&profile);
11    if (!found) {
12        // 使用默认 non-root profile
13        return default_non_root_profile.umount_modules;
14    }
15
16    if (profile.allow_su) {
17        return false;  // Root 应用不卸载
18    } else {
19        return profile.nrp_config.use_default
20            ? default_non_root_profile.umount_modules
21            : profile.nrp_config.profile.umount_modules;
22    }
23}

卸载流程:

Zygote fork 新进程
      ↓
内核检测 fork (setresuid hook)
      ↓
ksu_uid_should_umount(new_uid)
      ↓ 返回 true
执行 umount /data/adb/modules/*
      ↓
应用看不到 KernelSU 模块

5.3 Manager 验证(Throne Tracker)

文件: kernel/throne_tracker.c

目的: 防止假冒 Manager 应用

 1static uid_t throne_uid = -1;  // 记录真实 Manager 的 UID
 2
 3void track_throne(bool force_refresh)
 4{
 5    // 1. 扫描所有进程
 6    for_each_process(p) {
 7        // 2. 检查签名(通过 /proc/[pid]/maps 验证 APK 哈希)
 8        if (verify_manager_signature(p)) {
 9            throne_uid = task_uid(p).val;
10            pr_info("throne_tracker: found manager at UID %d\n", throne_uid);
11            break;
12        }
13    }
14}
15
16bool is_manager(void)
17{
18    return current_uid().val == throne_uid;
19}

签名验证:

5.4 Package Observer

文件: kernel/pkg_observer.c

功能: 监控应用安装/卸载,自动清理白名单

 1// 监听 /data/system/packages.list 文件变化
 2static void on_packages_list_changed(void)
 3{
 4    // 调用 ksud 的 prune 命令
 5    ksu_prune_allowlist(is_uid_still_valid, NULL);
 6}
 7
 8// 验证 UID 是否仍然有效
 9static bool is_uid_still_valid(uid_t uid, char *package, void *data)
10{
11    // 查询 PackageManager 检查包名是否存在
12    return package_exists(package, uid);
13}

自动清理场景:


6. 与 Magisk 对比

维度MagiskKernelSU
实现层级用户空间(修改 ramdisk)内核空间(LKM)
Root 授予通过 su 二进制文件内核直接修改 struct cred
系统调用无拦截Hook execve/stat/faccessat
SELinux通常 Permissive 或 patchEnforcing + 自定义 domain
检测难度中等(检测 Magisk 文件)困难(无用户空间痕迹)
性能开销低(仅进程启动时)极低(仅标记进程触发 hook)
安装方式修改 boot.img编译内核或加载 LKM
内核版本无要求需要 4.14+ 且支持 LKM
模块系统Magisk 模块KernelSU 模块(类似但独立)
更新频率高(跟随 Android 版本)低(内核稳定)

检测对抗能力对比:

检测方法                 Magisk      KernelSU
─────────────────────────────────────────────
检测 /sbin/.magisk       易检测      不适用
检测 /system/xbin/su     可绕过      可绕过
检测 su 进程             可检测      可检测
检测 SELinux Permissive  易检测      无法检测(Enforcing)
检测内核模块             不适用      困难(可隐藏符号)
检测系统调用 hook        不适用      极难(需内核调试)
检测文件系统挂载         可检测      可检测
检测 /proc/[pid]/maps    可检测      可检测

7. 实战示例

7.1 应用获取 Root 的完整过程

场景: Termux 应用(UID=10123)请求 root

1// Termux 代码
2Process process = Runtime.getRuntime().exec("su");
3OutputStream os = process.getOutputStream();
4os.write("id\n".getBytes());
5os.flush();

内核执行流程:

[Step 1] Termux 调用 execve("/system/bin/su", ...)
         → 内核态 syscall_trace_enter()
         → sys_enter_execve tracepoint 触发

[Step 2] kernel/sucompat.c:118
         ksu_handle_execve_sucompat()
         ├─ 检查 UID 10123 是否在白名单
         │  └─ __ksu_is_allow_uid(10123)
         │     ├─ forbid_system_uid(10123) → false
         │     ├─ Bitmap 查询: allow_list_bitmap[10123/8] & (1<<(10123%8))
         │     └─ 返回 true(假设已授权)
         │
         ├─ 检测路径: "/system/bin/su"
         │  └─ 匹配成功
         │
         ├─ 重定向: *filename_user = "/data/adb/ksud"
         │
         └─ escape_with_root_profile()
            ├─ prepare_creds() → 复制当前凭证
            ├─ ksu_get_root_profile(10123, &profile)
            │  └─ 查询 RCU 链表,未找到自定义配置
            │     → 使用 default_root_profile
            │        { uid=0, gid=0, cap=FULL, domain="u:r:su:s0" }
            │
            ├─ cred->uid = 0, cred->gid = 0
            ├─ cred->cap_effective = CAP_FULL_SET | CAP_DAC_READ_SEARCH
            ├─ setup_selinux("u:r:su:s0", cred)
            │  └─ tsec->sid = ksu_su_sid (预缓存)
            │
            ├─ commit_creds(cred) → 原子提交
            ├─ disable_seccomp() → 清除 TIF_SECCOMP
            └─ for_each_thread: set TIF_SYSCALL_TRACEPOINT

[Step 3] 继续 execve,加载 /data/adb/ksud
         → ksud 现在以 UID=0 运行

[Step 4] userspace/ksud/src/su.rs:82
         root_shell()
         ├─ 解析命令行参数
         ├─ 调用 ksucalls::grant_root()
         │  └─ ioctl(fd, KSU_IOCTL_GRANT_ROOT, NULL)
         │     → kernel/supercalls.c:56 do_grant_root()
         │        → escape_with_root_profile() (已经是 root,跳过)
         │
         └─ Command::new("sh").exec()
            → fork 子进程,继承 UID=0
            → execve("/system/bin/sh")

[Step 5] Shell 进程执行 "id"
         输出: uid=0(root) gid=0(root) groups=0(root) context=u:r:su:s0

7.2 银行应用隐藏模块

场景: 工商银行 APP(UID=10456)检测 root

[Step 1] Zygote fork 新进程(UID=10456)
         → kernel/setuid_hook.c: ksu_handle_setresuid()

[Step 2] 检查是否需要卸载模块
         ksu_uid_should_umount(10456)
         ├─ 查询 app_profile,key="com.icbc.android"
         ├─ 未找到自定义配置
         └─ 返回 default_non_root_profile.umount_modules = true

[Step 3] 执行卸载
         kernel/kernel_umount.c: try_umount()
         ├─ umount /data/adb/modules/lsposed
         ├─ umount /data/adb/modules/shamiko
         └─ umount /data/adb/modules/*

[Step 4] 银行 APP 启动
         ├─ 检测 /system/xbin/su → 不存在
         ├─ 检测 /data/adb/magisk → 不存在
         ├─ 检测 SELinux → Enforcing(正常)
         ├─ 检测 /proc/mounts → 无异常挂载点
         └─ 检测通过,允许运行

7.3 Manager 应用保护

场景: 恶意应用尝试伪装 Manager 调用 IOCTL

[Step 1] 恶意应用(UID=10999)调用
         ioctl(fd, KSU_IOCTL_SET_APP_PROFILE, &malicious_profile)

[Step 2] kernel/supercalls.c:795
         anon_ksu_ioctl()
         ├─ 查找 handler: KSU_IOCTL_SET_APP_PROFILE
         ├─ 权限检查: only_manager()
         │  └─ is_manager()
         │     └─ current_uid().val == throne_uid
         │        (10999 != 真实 Manager UID)
         │     → 返回 false
         │
         └─ 返回 -EPERM (Operation not permitted)

[Step 3] 恶意应用收到错误,攻击失败

8. 关键文件索引

8.1 内核层

文件路径功能关键函数
kernel/ksu.c模块入口和初始化kernelsu_init()
kernel/supercalls.cIOCTL 接口anon_ksu_ioctl(), ksu_install_fd()
kernel/app_profile.c权限提升核心escape_with_root_profile()
kernel/allowlist.c白名单管理__ksu_is_allow_uid(), ksu_set_app_profile()
kernel/sucompat.cSU 兼容层ksu_handle_execve_sucompat()
kernel/syscall_hook_manager.cSyscall hook 管理ksu_mark_running_process()
kernel/selinux/sepolicy.cSELinux 策略apply_kernelsu_rules(), setup_selinux()
kernel/throne_tracker.cManager 验证track_throne(), is_manager()
kernel/pkg_observer.c应用监控ksu_prune_allowlist()
kernel/kernel_umount.c模块卸载try_umount()

8.2 用户空间层

文件路径功能关键函数
userspace/ksud/src/main.rs入口点main()
userspace/ksud/src/cli.rs命令分发run()
userspace/ksud/src/ksucalls.rs内核 IOCTL 封装grant_root(), init_driver_fd()
userspace/ksud/src/su.rsRoot shellroot_shell(), grant_root()
userspace/ksud/src/init_event.rsInit 事件on_post_fs_data(), on_boot_completed()
userspace/ksud/src/module.rs模块管理mount_modules(), install_module()
userspace/ksud/src/metamodule.rsMetamodulemount_metamodule()

8.3 Manager 应用层

文件路径功能
manager/app/src/main/cpp/ksu.ccJNI 桥接
manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/ModuleViewModel.kt模块 UI
manager/app/src/main/java/me/weishu/kernelsu/ui/viewmodel/SuperUserViewModel.ktRoot 授权 UI

附录 A:关键数据结构

A.1 内核凭证结构

 1struct cred {
 2    kuid_t uid;         // 真实 UID
 3    kgid_t gid;         // 真实 GID
 4    kuid_t suid;        // Saved UID
 5    kgid_t sgid;        // Saved GID
 6    kuid_t euid;        // 有效 UID(权限检查使用)
 7    kgid_t egid;        // 有效 GID
 8    kuid_t fsuid;       // 文件系统 UID
 9    kgid_t fsgid;       // 文件系统 GID
10
11    kernel_cap_t cap_inheritable;  // 可继承 capabilities
12    kernel_cap_t cap_permitted;    // 允许的 capabilities
13    kernel_cap_t cap_effective;    // 有效的 capabilities
14    kernel_cap_t cap_bset;         // Capability bounding set
15    kernel_cap_t cap_ambient;      // Ambient capabilities
16
17    unsigned securebits;           // 安全位标志
18    struct user_struct *user;      // 用户结构(进程计数)
19    struct user_namespace *user_ns; // 用户命名空间
20    struct group_info *group_info; // 附加组信息
21
22    void *security;  // SELinux 使用 (task_security_struct)
23};

A.2 SELinux Task Security

1struct task_security_struct {
2    u32 osid;           // 原始 SID
3    u32 sid;            // 当前 SID
4    u32 exec_sid;       // execve 后的 SID
5    u32 create_sid;     // 创建对象的 SID
6    u32 keycreate_sid;  // 创建密钥的 SID
7    u32 sockcreate_sid; // 创建 socket 的 SID
8};

附录 B:性能分析

B.1 Hook 开销

操作未 HookHook(未标记进程)Hook(已标记进程)
execve~50μs~50μs~55μs (+10%)
stat~10μs~10μs~12μs (+20%)
faccessat~8μs~8μs~10μs (+25%)

结论:

B.2 内存占用

Kernel Module:     ~200KB (代码 + 数据)
allow_list_bitmap: 8KB (65536 UID)
allow_list_arr:    4KB (1024 大 UID)
RCU 链表:          ~100B per profile
ksud 进程:         ~2MB RSS

附录 C:调试技巧

C.1 查看内核日志

1# 查看 KernelSU 日志
2dmesg | grep -E "ksu|KernelSU"
3
4# 实时监控
5watch -n 1 'dmesg | tail -20 | grep ksu'

C.2 检查 FD

1# 查看 ksud 的 ksu_driver fd
2ls -l /proc/$(pidof ksud)/fd/ | grep ksu_driver
3
4# 输出示例:
5# lrwx------ 1 root root 64 ... 3 -> anon_inode:[ksu_driver]

C.3 查看白名单

1# 通过 ksud 命令
2/data/adb/ksud profile list
3
4# 直接读取持久化文件(需要 root)
5xxd /data/adb/ksu/.allowlist | head

C.4 验证 SELinux Context

1# 查看当前进程 context
2id -Z
3
4# Root 进程应该显示:
5# u:r:su:s0

总结

KernelSU 通过以下核心技术实现了强大的内核级 Root:

  1. 内核模块拦截系统调用:Hook execve/stat/faccessat 实现透明重定向
  2. 直接修改进程凭证:在内核态操作 struct cred,绕过用户空间检测
  3. Supercall IOCTL 接口:通过匿名 inode 提供内核-用户空间通信
  4. 高效白名单查询:Bitmap + 数组双层结构,O(1) 查询性能
  5. SELinux 深度集成:自定义 domain,保持 Enforcing 模式
  6. Per-App 模块隐藏:动态卸载挂载点,对抗检测
  7. Manager 签名验证:Throne Tracker 防止伪造

相比传统 Root 方案,KernelSU 在隐蔽性、性能、安全性方面都有显著优势,代表了 Android Root 技术的新方向。


文档版本: v1.0 最后更新: 2026-03-17 适用 KernelSU 版本: 0.9.5+ 作者: Claude Code (基于 KernelSU 源码分析)