KernelSU 旧内核适配指南:Linux 4.14 非 GKI 设备跑通 root 的完整四步走
【免费下载链接】KernelSUA Kernel based root solution for Android项目地址: https://gitcode.com/GitHub_Trending/ke/KernelSU
如果你手机的内核还是 Linux 4.14~5.10 这一段,装上 KernelSU 管理器却提示不受支持,先别下结论——非 GKI 设备照样可以通过旧内核适配拿到 root,代价是你得自己动手编译一整套内核。这篇文章按"能不能用、走哪条路、钩子写在哪、改完怎么验"四个问题展开,你可以对照着一步步做。
一、先判断你的设备值不值得动手
别急着改代码,连上手机先跑一条命令:
adb shell uname -r看输出前两位数字:
5.10及以上:属于 GKI 2.0 设备,有官方 boot 镜像,用不上本文;4.14~5.9:本文覆盖的范围。注意官方不会为非 GKI 设备出 boot 镜像(各家内核碎片化太严重),镜像只能自己编;4.14以下:理论可行,但要回移不少基础设施,不建议普通玩家尝试。
两个硬前提:
- 内核源码必须是开放的,而且你自己能编出一个能开机的内核。如果你从没成功编译过自己设备的内核,先解决这个,否则后面全是空谈;
- 你后续使用的 KernelSU 版本锁定在v0.9.5——自 v1.0 起官方放弃了对非 GKI 内核的支持,拿最新 tag 适配旧内核必卡。
两条路线怎么选
KernelSU 默认用 kprobe 机制做内核钩子,你走哪条集成路线取决于 kprobe 在你的内核里是否正常:
- kprobe 正常 → 走自动集成,源码树里加上代码就能跑,不用逐处打补丁;
- kprobe 不正常(常见原因是上游 bug 或内核太老)→ 必须手写钩子,也就是本文第三、四节的内容。
拿不准时可以事后验证:集成完如果手机开不了机,把对应版本ksu.c里的ksu_sucompat_init()和ksu_ksud_init()临时注释掉再编一版——能正常开机,说明问题就在 kprobe,转手动路线即可。
二、把 KernelSU 代码放进内核源码树
两条路线的第一步相同,都在你的内核源码根目录操作:
git clone https://gitcode.com/GitHub_Trending/ke/KernelSU KernelSU cd KernelSU git checkout v0.9.5 cd .. bash KernelSU/kernel/setup.sh v0.9.5这个脚本做的事其实就三件:把drivers/kernelsu软链指向仓库的 kernel 目录、往drivers/Makefile追加obj-$(CONFIG_KSU) += kernelsu/、在drivers/Kconfig里注册 Kconfig。脚本不放心就手动做这三步,效果一样;改乱了可以用--cleanup参数让脚本还原。
然后找到你设备的 defconfig(一般在arch/arm64/configs/你的设备代号_defconfig,部分厂商藏在vendor/子目录里),追加:
# KernelSU CONFIG_KSU=y CONFIG_KPROBES=y CONFIG_HAVE_KPROBES=y CONFIG_KPROBE_EVENTS=y两个高频坑:
- KPROBES 三项都写了 y 却仍不生效,优先检查
CONFIG_MODULES有没有开,kprobe 的依赖链最常断在这里; CONFIG_KSU开不起来时,看它的依赖项(KPROBES、EXT4_FS等),对照 kernel/Kconfig 逐项排查。
走 kprobe 路线的话到这里就结束
直接编译、刷机、验证。如果编译后手机无法启动,回到上一节的 kprobe 验证法,确认后转手动路线继续看第三节。
三、四个系统调用入口钩在哪里
手动路线的本质,是在几个系统调用的入口处插一段代码,让 KernelSU 有机会先于内核逻辑介入。一共四处:
- fs/open.c 的
do_faccessat——文件访问探测,root 检测类应用靠access()判断,钩在这里才能拦截; - fs/exec.c 的
do_execveat_common——进程执行入口,su 提权的核心; - fs/read_write.c 的
vfs_read——文件读取,用于改写特定文件的内容; - fs/stat.c 的
vfs_statx——文件属性查询,隐藏文件的 stat 结果。
四处写法完全同构,以 exec 为例:文件顶部声明开关变量和处理函数,函数入口调用处理函数:
/* fs/exec.c 顶部:声明开关与处理函数 */ #ifdef CONFIG_KSU extern bool ksu_execveat_hook __read_mostly; extern int ksu_handle_execveat(int *fd, struct filename **filename_ptr, void *argv, void *envp, int *flags); #endif static int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr argv, struct user_arg_ptr envp, int flags) { /* 入口处先问开关,打开就把参数交给 KernelSU,处理函数可原地改写参数 */ #ifdef CONFIG_KSU if (unlikely(ksu_execveat_hook)) ksu_handle_execveat(&fd, &filename, &argv, &envp, &flags); #endif return __do_execve_file(fd, filename, argv, envp, flags, NULL); }注意:传进去的全部是指针,处理函数靠修改指针指向的内容来"劫持"参数。你要是直接传值,编译不报错、运行也不报错,钩子就是死的。
版本差异:老内核去哪里找对应函数
上面四个名字是较新内核里的,你的内核版本低一档就要换位置:
- 内核里没有
vfs_statx时,改用同文件里的vfs_fstatat(见 fs/stat.c),钩子位置不变,只换函数名; - 4.17 之前的内核没有
do_faccessat,在 fs/open.c 里找到SYSCALL_DEFINE3(faccessat, ...)的定义,用同样方式插进去。
四、还有两处不做一定会卡住
📌 安全模式:防变砖的最后防线
万一刷入后 KernelSU 行为异常,靠长按音量下键进安全模式才能救回来。这个功能要钩输入事件,不补它,最后这条退路就是空的。往 drivers/input/input.c 的input_handle_event里插:
/* drivers/input/input.c:拦截输入事件,识别安全模式触发 */ #ifdef CONFIG_KSU extern bool ksu_input_hook __read_mostly; extern int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code, int *value); #endif static void input_handle_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { /* 开关打开时把事件交给 KernelSU 判断是否构成安全模式触发 */ #ifdef CONFIG_KSU if (unlikely(ksu_input_hook)) ksu_handle_input_handle_event(&type, &code, &value); #endif /* 原有事件分发逻辑保持不变 */ }注意:走手动集成路线时,defconfig 里必须关掉CONFIG_KPROBES。否则 kprobe 路线和手写钩子会同时拦截输入事件,开机时正常按一次音量下键都可能把你直接弹进安全模式。
两个小修补:pm 命令与卸载模块
pm命令老是执行失败的话,需要在 fs/devpts/inode.c 的devpts_get_priv()里加一行ksu_handle_devpts(dentry->d_inode)调用,处理 devpts 设备节点映射;- 想在旧内核上保留"卸载模块"能力,要把 5.9 内核的
path_umount回移到 fs/namespace.c。用不上就跳过,不影响基础 root。
五、刷入前必做的三项确认
编完先别急,按顺序做三件事:
- 用
fastboot boot boot-ksu.img先试启动。不写分区,重启即回退,有问题不用进恢复模式;镜像文件名以你内核的编译产物为准; - 开机后
adb shell su -c id,输出应为uid=0(root);再su -v确认能打印 KernelSU 版本信息; - 连续重启三到五次确认不闪退,同时看 logcat 里的
avc: denied——如果出现大量与 kernelsu 相关的 SELinux 拒绝记录,说明 sepolicy 规则没补全,回 manager 里补授权。
三项都过了再执行正式刷写。
六、动手前这四条避坑建议
- 版本先锁死:clone 完立即
git checkout v0.9.5,最新 tag 与旧内核适配不兼容,这是最常见的开坑原因; - defconfig 别抄错文件:
CONFIG_KSU=y和 KPROBES 相关配置必须写进你设备对应的那份 defconfig,改在通用模板里等于没改; - 给自己留退路:刷写前备份原始 boot 分区,并且永远先用
fastboot boot试跑一次再考虑正式写入; - 别在 4.14 以下硬耗:本方案只推荐 4.14~5.9 使用,再往下的内核要回移的东西多,时间成本大概率高于换一台 GKI 设备。
【免费下载链接】KernelSUA Kernel based root solution for Android项目地址: https://gitcode.com/GitHub_Trending/ke/KernelSU
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考