一个由 adb 驱动的工具,可将一台原厂、引导加载程序已锁定的 Google Pixel 变成 KernelSU 已 root 的设备,而无需解锁引导加载程序或修改启动镜像。在主机端,它在设备上运行一个非特权用户态内核漏洞利用程序,以获得临时的内核读写能力,利用该原语修补 root 凭据,然后将 KernelSU 可加载内核模块(kernelsu.ko)延迟加载到正在运行的 GKI 内核中,并将控制权交给任何已安装的 KernelSU 管理器(KernelSU、KernelSU-Next、SukiSU 或其他变体)。它针对运行 GKI 6.1 和 6.6 内核的 Android 17 Pixel 设备,并通过 adb shell 驱动整个流程,以实现确定性排序和时间戳日志记录。
设备端负载是 CVE-2026-43499(“GhostLock”)的完整链式本地权限提升漏洞,这是 kernel/locking/rtmutex.c 中 futex/rtmutex 优先级继承栈释放后使用漏洞。在 requeue-PI 回滚路径上,remove_waiter() 清除的是 requeuer(current)而非实际 waiter 上的 pi_blocked_on,从而留下一个悬空指针,指向一个已释放的内核栈槽位,该槽位曾保存 rt_mutex_waiter。该漏洞可从普通非特权进程触发:
owner、waiter、consumer)构建一条 PI 链;waiter 在 FUTEX_WAIT_REQUEUE_PI 上挂起,主线程触发 FUTEX_CMP_REQUEUE_PI,consumer 发出的 sched_setattr 驱动回滚。pselect()/select()(或在某些 6.1 目标上通过 TCP_ZEROCOPY_RECEIVE 路径)重新占用,其 fd_set 字覆盖到 waiter 结构体上,写入一个伪造的扁平 rt_mutex_waiter,使悬空指针遍历攻击者控制的 rb-tree 和锁字段——这是一个单一受控指针写入原语。mm_struct/sk_buff/pipe_buffer 对象的 slab 页。ashmem_miscs[0].fops 覆盖为一个伪造的 file_operations,其每个槽位都指向一个真实的、原型兼容的内核函数(configfs_bin_write_iter、configfs_read_iter、copy_splice_read、ashmem_ioctl、noop_llseek 等),从而满足前向边缘 CFI,同时对 ashmem fd 的 read/write/splice 产生受限的内核读/写。pipe_buffer 结构体(通过 vmemmap↔直接映射转换将 page 指向任意目标,ops = anon_pipe_buf_ops,PIPE_BUF_FLAG_CAN_MERGE),因此对管道进行普通的 read()/write() 即可在任意内核地址之间移动字节——这是一个稳定的任意内核读/写。随后通过管道原语修补 root 和 SELinux 状态:root 子任务的 cred 被清零为 uid/gid 0 并具有完整能力集,其 SELinux osid/sid 被设置为 SECINITSID_KERNEL,seccomp 被清除,selinux_state.enforcing 被设置为 0。
漏洞利用链、KASLR 预言机和 KernelSnitch 侧信道源自 NebuSec 的 IonStack Part II — GhostLock 研究(NebuSec/CyberMeowfia PoC,Apache-2.0),此处针对 Pixel/aarch64 进行了改编。参见 署名与许可证。
该链中恰好有一个阶段可能导致内核崩溃:KASLR 偏移推导,它与其希望回收的页竞争。其他每个阶段都可安全重试,且内核文本基址在单次启动的生命周期内是固定的。主机流程基于此属性进行拆分:
KASLR_BASE 的情况下运行。伪造 waiter 写入将 random_table sysctl ctl_table.data 重新指向一个已知的内核文本指针;读取 /proc/sys/kernel/random/boot_id 通过 proc_do_uuid() 泄漏它,减去镜像偏移即可得到 _stext/KASLR 基址。restore_slide_boot_id() 修复被破坏的 ctl_table.data。由于竞争失败会重启设备,因此每次尝试前都会等待启动,并通过存活检查将设备消失归类为崩溃。成功后,设备日志输出 slide-kaslr-ok pid=<pid> base=<hex>,基址被固定到当前启动。KASLR_BASE=0x<base> 的情况下重新运行。此路径不会导致崩溃,并循环执行,直到 id 通过临时 su 报告 uid=0。/proc/sys/kernel/random/boot_id 与捕获时记录的启动进行比较;任何变化都会丢弃该基址并返回阶段 A。外层循环在多次重启之间重复 推导→重放。已连接设备在运行时根据 data/targets.json 进行解析;没有任何设备是硬编码的。发生两个独立的解析:
uname -r),要么来自匹配的目标条目,要么从发布字符串派生(例如 android14-6.1)。一个负载在多个设备上的复用源于 GKI/KMI 结构。同一 GKI 构建上的每台设备都运行字节完全相同的 vmlinux,并且结构体字段偏移(task_struct->cred、cred->uid 等)在 KMI 分支的生命周期内由 KMI 类型契约和 MODVERSIONS CRC 强制机制冻结。相比之下,绝对内核符号地址由链接器针对每个 ab<NNN> 构建决定,因此漏洞利用程序的固定偏移属于一个特定的 vmlinux;不同的内核镜像因此需要不同的负载,即使它们的 KMI 匹配。data/targets.json 精确地编码了这一点:许多设备去重到一个以内核镜像为键的负载,而不同的内核镜像则拥有自己的负载。
LKM 延迟加载需要支持可加载模块的 GKI 内核(5.10+)和 KMI 匹配的 .ko。KernelSU 内核模块通过在内核中验证管理器 APK 的 v2 签名块,并将签名证书的 SHA-256 与编译进 .ko 的 KSU_EXPECTED_SIZE/KSU_EXPECTED_HASH 对进行比较,来认证其管理器。因此,管理器发布版中附带的 kernelsu.ko 与该管理器的 APK 共享一个签名身份;不匹配的 ksud 会加载驱动程序,但永远不会设置管理器授权位,使设备没有可用的 root。
该流程遵循此绑定:它解析已安装管理器的 APK 路径(pm path <manager package>),拉取 APK,提取 lib/arm64-v8a/libksud.so 作为 ksud 二进制文件,如果未安装管理器则中止。在持有临时 root 的情况下,该 ksud 被暂存为 root 拥有的可执行文件,并作为 ksud late-load --kmi <kmi> --package-name <manager package> 调用。延迟加载检测当前 KMI,从其嵌入的资源中拉取 "{kmi}_kernelsu.ko",执行手动符号重定位(针对 /proc/kallsyms 解析每个 SHN_UNDEF 符号,将条目重写为 SHN_ABS),并对修补后的缓冲区调用 init_module(2)。然后它运行 init 会执行的其余启动管道(安装 ksud、restorecon、加载 sepolicy.rule 和 root 配置文件、运行 post-fs-data/阶段脚本、挂载模块覆盖层)。
延迟加载守护进程化,并在其 fork 的子进程中重新强制 SELinux,该子进程会拆除漏洞利用程序的临时 su 守护进程;因此验证不能通过 su 进行。相反,加载的驱动程序通过其系统调用接口直接查询,该接口可从普通 shell 无 root 访问:轮询 ksud debug version 并解析报告的内核版本。非空、非零的版本确认驱动程序已驻留并正在响应。驱动程序安装路径是 reboot(2) 魔术 → 安装 fd → KSU_IOCTL_GET_INFO 机制(reboot(0xDEADBEEF, 0xCAFEBABE, 0, &fd) 安装一个匿名的 [ksu_driver] fd;GET_INFO 返回 {version, flags, features, uapi_version}),并探测传统的 prctl(0xDEADBEEF, …) 通道作为回退。启动时运行的相同探测在模块已为当前启动驻留时短路整个流程。
漏洞利用程序将其临时 su 暂存在 /apex/com.android.virt/bin/su,位于 adbd 挂载命名空间内挂载在该 apex bin 目录上的 tmpfs 中,因为该目录在 shell PATH 中位于 /system/bin 之前——因此 adb shell 中的裸 su 在流程运行时到达临时 su。延迟加载随后拆除临时 su 守护进程(见 (e)),而不移除影子,这使裸 adb shell su 运行一个孤立的客户端,即使 root 正常工作,也会以 su: connect daemon: Permission denied 失败,并使 apex 的真实二进制文件(crosvm、virtmgr、vm 等)保持隐藏。一旦验证报告驱动程序存活,流程卸载暂存 tmpfs——通过 KernelSU 自己的 /system/bin/su,因为漏洞利用程序的守护进程已经消失——移除临时 su 客户端、套接字和日志,并报告普通 adb shell 现在解析到哪个 su。这是尽力而为的:失败时它警告手动 umount 命令而不是使运行失败,并且重启无论如何都会清除挂载。
adb,设备已授权(已启用 USB 调试)。kernelsu.ko 的来源。artifacts/exploits/ 中的预构建漏洞利用负载(参见构建负载)。# adb 上有一台设备;已安装管理器;负载已构建。
bin/pixel-ksu-root
驱动程序根据 data/targets.json 解析设备,运行两阶段 KASLR 流程,通过管理器派生的 ksud 延迟加载模块,并通过驱动程序系统调用进行验证。如果设备无法解析负载、未安装管理器或验证从未报告驱动程序存活,则非零退出。
KASLR_BASE=0x<hex> — 在阶段 B 期间传递给设备负载,以针对固定的、已推导的每次启动基址进行重放。在阶段 A 期间未设置,以便负载自行推导基址。ANDROID_NDK_HOME — Android NDK 的路径,仅在构建负载时需要。API — 构建负载时 NDK 工具链的 Android API 级别(默认 35)。pixel-ksu-root/
├── bin/ 主机驱动入口点(adb 驱动流程)
├── data/
│ └── targets.json 设备→负载和设备→KMI 解析表
├── exploit/ 内置的 CVE-2026-43499 负载源码
│ ├── Makefile 按目标的 aarch64 NDK 构建
│ ├── src/ android15-6.6 基线源码集
│ │ ├── main.c slide.c fops.c pipe.c root.c preload.c util.c
│ │ ├── su_daemon.c 链生成的临时 su 辅助程序
│ │ ├── kernelsnitch/ Futex 哈希占用侧信道头文件
│ │ └── targets/ 按设备+构建版本的 target.h(内核偏移)
│ └── src/61/ android14-6.1 源码集(slide61.c、TCP 路由)
├── lib/ 主机端共享 shell/辅助函数
├── scripts/
│ └── build-payloads.sh 构建并去重负载集
├── artifacts/
│ └── exploits/ 构建的、去重的负载 .so 文件
└── docs/ 设计和分析笔记
scripts/build-payloads.sh 包装按目标的 exploit/Makefile,并将 data/targets.json 中命名的去重负载集输出到 artifacts/exploits/。它为每个唯一偏移组(从该组的 build_from 目标)构建一个 .so,而不是每台设备一个。
export ANDROID_NDK_HOME=/path/to/android-ndk # 必须包含 aarch64 NDK 工具链
scripts/build-payloads.sh # 构建 data/targets.json 中的每个负载
Makefile 从 ANDROID_NDK_HOME 选择 aarch64 NDK Clang 工具链,并一次编译一个目标;API(默认 35)选择 aarch64-linux-android<API>-clang 驱动程序。源码集按内核系列选择——android15-6.6 目标编译 src/ 基线,android14-6.1 目标编译 src/61/——每个目标的绝对内核偏移来自 src/targets/<codename>-<build>/target.h。要直接构建单个目标:
make -C exploit TARGET=husky-CP2A.260705.006
data/targets.json 列出了覆盖 18 款 Pixel 机型的 19 个设备/构建条目(bluejay 出现在两个固件构建上),分组为5 个内核偏移负载。选择基于内核镜像,因此共享 vmlinux 的设备去重到一个负载;不同的内核镜像则拥有自己的负载。
共享 android14-6.1-a 内核镜像(6.1.157-android14-11-gbd23337e42e7-ab14791245)的设备涵盖 Pixel 6/6 Pro/6a、7/7 Pro/7a、8/8 Pro 和 9/9 Pro/9 Pro XL/9 Pro Fold 系列;android14-6.1-b 和 android14-6.1-akita 隔离了同一 KMI 上内核构建或偏移不同的机型;android15-6.6 涵盖 Pixel 10 系列。
NebuSec/CyberMeowfia 仓库中以 Apache-2.0 发布;发现归功于 NebuSec 的 VEGA 工具,披露于 2026-07-07。exploit/ 树在 NebuSec 漏洞利用程序之上添加了 android14-6.1 和 android15-6.6 目标偏移以及 KernelSU 延迟加载守护进程;它不携带单独的许可证,并继承上游 Apache-2.0 条款。ksud 以及本工具延迟加载的管理器授权模型。exploit/ 下的内置源码保留其上游许可证(NebuSec 派生漏洞利用程序为 Apache-2.0)。本项目与管理器无关:它延迟加载已安装的任何 KernelSU 变体的管理器,不针对或捆绑任何特定分支。
ksud 延迟加载路径init_module 加载器和驱动程序检测apk_sign.rs| 负载 | KMI | 构建自 | 设备 |
|---|
android14-6.1-a | android14-6.1 | bluejay-CP2A.260705.006 | oriole、raven、bluejay (CP2A)、panther、cheetah、comet、shiba、husky、lynx、caiman |
android14-6.1-b | android14-6.1 | komodo-CP2A.260705.006 | komodo、tegu、tokay |
android14-6.1-akita | android14-6.1 | akita-CP2A.260805.005 | akita |
android14-6.1-cp1a | android14-6.1 | bluejay-CP1A.260405.005 | bluejay (CP1A) |
android15-6.6 | android15-6.6 | blazer-CP2A.260705.006 | frankel、blazer、mustang、rango |