Skip to content
This repository was archived by the owner on Oct 3, 2026. It is now read-only.

Releases: hmascs/KSuRoot

KSuRoot 4.1.2 —— 从镜像读 vr.ko 标记偏移 + 导入完整刷机包

Choose a tag to compare

@hmascs hmascs released this 02 Oct 08:20

KSuRoot 4.1.2 —— 从镜像读 vr.ko 标记偏移 + 导入完整刷机包

versionCode = 412 · versionName = 4.1.2 · AOSP testkey 签名(a40da80a…5dc,可直接覆盖 4.1.1 原地升级)
上一个正式版本:4.1.1
单测 41 个类 / 417 个用例 · 0 失败(1 条环境门控跳过)


一、vr.ko 的标记偏移:从「赌一个」变成「读出来」

vr.ko 会给来自 app 的 task 打两个标记字节,该 task 一旦持有 euid 0,
sys_exit 探针就把它杀掉 —— 提权看着成功,子进程随即被杀,日志里一切正常。

要抹掉那两个字节,就得知道它们在哪个偏移。而那是编译期烤进载荷、patch 不了的。
麻烦在于它有 0x04 / 0x06 两种取值 —— 而且同一台设备的两份 vr.ko 就各一种:

路径 vermagic tag A
lib/modules/vr.ko …aarch64 vivo 0x04
lib/modules/6.1-gki/vr.ko …aarch64 0x06

两份的 srcversion 完全相同(同一份源码编的),差别只在编译配置。

这台机器实际加载的那份 vr.ko,就在 vendor_boot.img 里。 所以:

  • 蓝厂方案现在要求你提供 vendor_boot.img —— 应用从里面那份平铺的
    lib/modules/vr.ko(按 Android 的 modprobe 查找顺序,uname -r 是完整串而非
    6.1-gki,命中的就是平铺那份)反汇编出真正的偏移;
  • 然后改写载荷里那个值,而不是"对不上就停下";
  • 通用方案不需要它:通用方案不做 vr.ko 绕过,也就没有这个偏移要定。

界面上会直接把结论摊开:本机 vr.ko tag A = 0x04 · 已改写载荷 3 处。

二、四份自带/自编库强制配自己的档位

打补丁是「拿档位里的旧值去 .so 里找字面量」,所以库与档位必须同源。
而"选哪份库"按结构体族走、"选哪一档"按三级路由(内核串)走 —— 两条路会选岔:

  • X100 Pro 6.1.145:库是 libbaseline_6_1.so(旧值来自 tokay target.h),
    档位却命中上游档 up-6-1-145-…(旧值来自 GhostLock offsets.h)→ 26 项一处没匹配上
  • 本机 PD2463 6.6.89:库是 libbs.so(旧值来自 PD2520 target.h),
    档位命中 up-6-6-89-…-vivo → 25 项一处没匹配上

两次的产物都只是原样拷贝,装到机器上必然失败 —— 而界面显示的是"跑完了"。

现在四份库全部强制配对,选岔了由零命中闸门当场拦下:

库 配到
libbaseline_6_1.so baseline-6-1-tokay
libbaseline_6_12.so baseline-6-12-honor
libbs.so PD2520-BP2A.250605.031.A3
libionstack.so IONSTACK-P10-CP2A.260605.012

三、导入完整刷机包

载荷构建页新增入口:直接选你下载的 OTA zip 或 fastboot tgz,
它自己把 boot 和 vendor_boot 一起取出来 —— 不用你先解压,也不用手动提取。

  • OTA zip:认 payload.bin,支持 REPLACE / REPLACE_XZ / REPLACE_ZSTD / REPLACE_BZ / ZERO / DISCARD,ZIP64 也认
  • fastboot tgz:流式解析 gzip + tar,只把需要的那一个文件读出来

实测:真实的 6.5 GB 完整包上跑通,boot / vendor_boot 与独立参考实现
(Python + zstd CLI)逐字节一致。

⚠️ 代价要说明白:完整包要整份拷进应用缓存才能随机读(ZIP 中央目录在包尾,
而 SAF 的 uri 变不成 File)。6.5 GB 的包就要拷 6.5 GB —— 空间不够会当场拒绝
并说清差多少,抽完立刻删缓存(失败路径也删)。

四、本版修掉的其它问题

  • 蓝厂方案被自己的闸门 100% 拦死:构建开始时重建状态时把 vendorBootName 清成了 "",
    而闸门正是拿它判的 → 选不选 vendor_boot 都被拦。现在状态重置用 copy 保留输入,
    且判据改用真正的输入句柄,不再拿展示名当控制变量。
  • payloadSource 两份来源不同步:Compose 状态与持久化偏好各一份,
    而真正决定装哪份载荷的是偏好。构建自动落库那条路径只写了偏好 →
    界面高亮「内置」,点安装装的却是刚构建的自定义载荷。
  • 移交 root 那一串弹窗统一到 miuix(确认 / 进行中 / 结果 / 选管理器)。
    它们原来还是 Material3 AlertDialog;换成 miuix OverlayDialog 时
    必须放进 Scaffold 里 —— miuix 的 Overlay 组件依赖 Scaffold 提供的
    CompositionLocal,放在外面根本不渲染(表现就是"点了没反应")。
  • KallsymsFinder.kt 里有个裸 NUL 字节(注释里想写 x\0,写进了真的 0x00)→
    grep 把整个 1161 行文件当二进制跳过。

五、边界(不掩饰)

  1. 「抹标记」这一步仍然没有在任何真机上跑过。 vr detag 只证明代码编进去了,
    不证明它抹对了、更不证明抹完就不被杀 —— 三族基线一律仍标 beta。
  2. 整包导入没在真机跑过(只做了编译 + 单测 + 在真实包上的离线验证)。
  3. fastboot tgz 没有厂商真包样本:成功路径是用 GNU tar 现场造包验证的,
    错误路径用了真实 tar.gz。
  4. 0x04 / 0x06 由什么决定还没查清:目前只有"vermagic 里含 vivo"这条
    5 样本的相关性,因果未查明。所以别把它当规律用。
  5. 第三方载荷的许可证正文仍未补齐:随包 127 份 .so 来自多个上游仓库,
    登记表里逐条署了名(source 字段写明仓库与文件名),但许可证正文只带了
    GhostLock 的 Apache-2.0。其中一份来自
    qsvggff-spec/oppo-A5-PRO-5G-CVE-2026-43499(MIT,
    与包内 libksu_oppo_oppoa5pro5gcve202643499_any_d77f.so sha256 完全相同)——
    那个仓库是失败研究的归档,作者自己的结论是「利用链无法收敛」。
    该载荷仍在软件中(可供对照与研究),但不建议作为提权载荷使用,
    列表里会标红说明原因。

KSuRoot 4.1.1 —— 零命中闸门 + 动态库库房 + 滑动删除

Choose a tag to compare

@hmascs hmascs released this 01 Oct 13:27

KSuRoot 4.1.1 —— 零命中闸门 + 动态库库房 + 滑动删除

versionCode = 411 · versionName = 4.1.1 · AOSP testkey 签名(a40da80a…5dc,可直接覆盖 4.1.0 原地升级)
上一个正式版本:4.1.0(18 个提交之前)
单测 39 个类 / 398 个用例 · 0 失败(1 条环境门控跳过)· 全矩阵 14/14 blocked = false


〇、先说最要紧的一条:6.1 上「看着跑完了,其实一行都没改」

用 X100 Pro(6.1.145)构建时,界面给的是:

偏移解析: 28 / 28 项
需要改写: 26 项 · 校验通过: 0 项
该动态库未引用 26 项偏移

校验通过: 0 不是「没什么可改」,是「一个都没找到」。 根因是两条独立的路选岔了:

选什么 按什么选 6.1.145 上选到 旧值来自
基础库 结构体族 F6_1 libbaseline_6_1.so baseline-6.1-tokay/target.h
档位 三级路由(内核串) up-6-1-145-… GhostLock 的 offsets.h

打补丁的方式是「拿档位里的旧值去 .so 里找字面量」。两套旧值毫无交集,于是 26 项一处都对不上,产物等于把基础库原样拷贝了一份 —— 装到机器上必然失败,而界面看起来是"跑完了"。

为什么原来的硬闸门没拦住:hasFailures 的判据是 changed && !ok && !absent —— absent 被明确排除在外。那个理由("老版本 .so 可能没有对应代码路径")对个别键成立,对"全部键都 absent"不成立。

修法两条:

  1. 库与档位强制同源 —— 自编族基线必须配它自己的档(baseline-6-1-tokay / baseline-6-12-honor),上游 up-* 档只适用于上游那份 .so。
  2. 零命中硬闸门 —— 只要偏移规格一条都没落到站点上就停止打包。基址那条不计入:它即使全不匹配也常常会变,会把"一条偏移都没改"掩盖过去。

回归用例 BaselineLibraryPairingTest(4 条),其中一条直接断言两套旧值没有交集 —— 把"为什么必须配对"变成可执行的事实。


一、动态库:导入之后「点了没用」

# 缺陷 后果
1 「载荷构建 → 用作载荷」用的是内存里的产物;进程被回收后 outputLibrary 为 null,旧代码是 ?: return 点了什么都不发生 —— 没 Toast、没报错、按钮不变
2 PayloadStaging 缓存键是「同名 + 同长度」,而自定义载荷在私有目录里固定叫 payload.so 换一份字节数恰好相同的载荷 → 静默复用上一份
3 shizukuStage 缓存键只有长度 同一个坑在 Shizuku 路径上又踩一次

第 2、3 条最阴:它们不报错,只是加载了错的载荷。 现在缓存键改成内容哈希 / 逐字节比对。


二、动态库库房:Download/动态库/<机型>/<文件名>.so

  • 库房(用户可见、可自己整理):Download/动态库/<机型>/<文件名>.so
  • 活动副本(真正被加载的那份):files/active_payload/payload.so
  • 界面新增按机型分组的库房列表,每份可直接「使用」设为当前,左右滑动删除
  • 同名但内容不同的两份不会互相覆盖(自动加哈希后缀)
  • 删掉当前生效那条时会真正激活下一条(旧写法只改 id 不拷文件,会留下"界面说当前、实际没有活动副本"的自相矛盾状态)

为什么库房那份不能直接 dlopen:分区存储下应用只能读自己经 MediaStore 创建的那批文件;
而且 /storage 是 FUSE(u:object_r:fuse:s0),非 untrusted_app 的域根本读不到 ——
这一条是在 pm install 时被 SELinux 当场拦出来的(avc: denied { read } ... tclass=file)。
所以库房负责"让用户看得见、管得住",私有副本负责"一定能被加载"。

⚠️ 搜寻边界(如实说):库房不能自动扫描 Download/动态库/ 里你自己丢进去的文件 ——
分区存储不允许应用读取别的应用(包括文件管理器)创建的下载文件。
条目只有两个来源:本应用写进去的、以及你通过系统选择器显式授权的那一个。

滑动删除踩到的两个坑

  1. 最后一条永远删不掉:items.forEach 没有 key(),Compose 只能按位置复用;而手势的 pointerInput(enabled, triggerPx) 两个 key 换数据时都不变,于是手势块从不重启,一直握着第一次组合时捕获的 onDelete(指向已经删掉的条目)。修法两处缺一不可:key(entry.id) + rememberUpdatedState(onDelete)。
  2. 删除底色不统一:之前是硬编码红 + 直角 + 文字随方向左右跳。现在用主题 error 色、与行同一个圆角常量、同高同内边距、图标 + 文字垂直居中,红底不透明度跟着滑动进度长出来。

手势没有用 detectHorizontalDragGestures,而是沿用本工程在底栏滑块上验证过的写法 —— 本机系统 touchSlop 实测约 75px(≈19dp),且它的回调只给越过阈值之后的增量,那段距离会被永久丢掉(表现为"开头要空拖一小段才动")。这里是自定义 4dp 阈值 + 位移从按下点起算,并且在阈值之内一个事件都不消费,所以行内的「使用」按钮照常能点。


三、vr.ko 标记偏移分族

内核族 tag A tag B 样本
6.1 0x04 0x2c X100 Pro (PD2324) · 6.1.145
6.6 0x06 0x2c 本机 PD2463 · 6.6.89
6.12 0x06 0x2c iQOO 15 (PD2505) · 6.12.58

6.1 与 6.6 只差半代,tag A 就挪了 2 个字节 —— 而这个值编译期烤死、patch 改不了。填错的表现是"真机上标记一个字节都没抹掉,而自检报成功"。

  • VR_TAG_A_OFF 由单一常量改为分族,新增 tagAOffForSeries() / tagAOffForRelease(),认不出返回 null,不猜
  • 早先那段「跨内核版本未经证实、假定相同、从未验证」的结论留档保留(它当时是对的,而且明确把"假定"标了出来),但结论已随实测更新

顺带说一个被实测否掉的想法:曾加 add#0x4 计数想"分族把 tag A 也数上"。
add #0x4 是极常见指令 —— 89 份没有绕过的载荷里 86 份命中,放出来只会误导。
换成正确的指令形态(ldrb/strb 的立即数)再测,仍然 19/25 命中负例。
所以 tag A 只能当声明,不能当判据:判定继续只用「tag B + 清 0x400」(37/37 与 0/89)。


四、这一版包含的其余修复(4.1.0 之后累积)

  • 6.4+ 内核整档失败的总根源:kallsyms 偏移表定位用了负数取模(Python 语义直译)
  • 偏移表判据从「前三项单调」换成查表的形状 —— 单调几乎没有区分度
  • BASELINE_6_12.imageBase 填成目标基址 → 绝对地址形式的构造点全部漏改(39 处 → 9 处)
  • 符号对不齐时只置空产物、gate 仍是 Proceed → blocked=false 且产物 0 B,UI 不弹阻断框
  • FopsSlot 的 fallback 从来没被用上
  • 6.12 真正跑通:ashmem 在 6.12 变成 Rust 实现、符号名全 mangled → 改成运行时从 miscdevice 的 fops 槽读出来
  • 6.1 / 6.12 在通用 / 蓝厂两个方案下都可用(四个组合各 16 / 16 / 13 / 13 档)

五、边界(不掩饰)

  1. 偏移是实测的,「抹标记」这一步没在任何真机上跑过。 vr detag 只证明代码编进去了,不证明它抹对了、更不证明抹完就不被杀 —— 所以三族基线一律仍标 beta。
  2. 库房不能自动扫描 Download/动态库/ 里外部添加的文件(分区存储限制,见上)。
  3. 安装包与源码归档:本 Release 提供已签名 APK;源码归档由 GitHub 依据 tag 自动生成。
  4. 有一份随包载荷标了「不建议使用」。 libksu_oppo_oppoa5pro5gcve202643499_any_d77f.so(OPPO A5 Pro 5G)与上游仓库 qsvggff-spec/oppo-A5-PRO-5G-CVE-2026-43499 的 preload-tokay-PKP110.so sha256 完全相同 —— 而那个仓库是失败研究的归档,作者自己的结论是「利用链无法收敛:三条 KASLR 泄露路线全堵死」(并注明 iQOO Neo9s PRO / Z10x / vivo X Fold5 的独立研究结论相同)。
    它仍然留在软件里(仍可选取,供对照与研究),但不建议作为提权载荷使用 —— 列表里会直接标红写明原因,点选时会先弹一次确认。

KSuRoot 4.1.0 —— 蓝厂 vr.ko 反 root 实装 + 「解析完整包链接」

Choose a tag to compare

@hmascs hmascs released this 25 Sep 03:27

KSuRoot 4.1.0 —— 蓝厂 vr.ko 反 root 实装 + 「解析完整包链接」

versionCode = 410 · versionName = 4.1.0 · AOSP testkey 签名(a40da80a…5dc,可原地升级)
上一个正式版本:4.0.0
编译:debug / release 双变体通过 · 单测 362 条 0 失败(1 条环境门控跳过)· 0 警告


〇、先看这一条:4.0.0 的包不含蓝厂绕过

KSuRoot-4.0.0.apk 打包于 03:55,而蓝厂 vr.ko 那批改动落在 04:32 之后。
所以:

4.1.0 才是第一个真正带上 vr.ko 反 root 绕过的正式版本。


一、蓝厂 vr.ko 反 root 实装

1.1 两份自编族基线:从「没有」到「有」

文件 旧 新 strings -a | grep -c "vr detag"
libbaseline_6_1.so 135184 B 175792 B 0 → 2
libbaseline_6_12.so 135184 B 175776 B 0 → 2

重编时发现并修掉两个独立缺陷:

  1. 不带 vr.ko 抹标记 —— 这是任务书里点名的那一个;
  2. 旧产物根本 load 不起来(任务书里没有)—— 旧构建只编了
    fops.c main.c pipe.c posture.c preload.c slide.c util.c,没编 root.c / io_daemon.c,
    也没提供 wallpaper_blob.S 需要的素材。后果是 install_android_root /
    io_daemon_main / embedded_wallpaper_start/_end 成了指向 UND 的动态重定位 ——
    这份 .so 连 dlopen 都过不去。判定依据是 readelf -sW … | awk '$4=="FILE"' 的
    文件符号表对比。

修完之后:NEEDED 只剩 libdl.so / libc.so,STT_FILE 里出现了 root.c / io_daemon.c。

⚠️ 上表是源码树里的尺寸。 APK 里装的那两份更小(154872 B / 154856 B)——
release 构建会走 AGP 的 native 符号剥离。剥离不影响 vr detag,
已从成品包里取出来复核过:vr detag 仍是 2。
别拿这两个数字对不上当成构建出错。

1.2 能力与闸门成对出现

按任务书 §4 的结论,Kotlin 侧写不了内核内存 —— 所以实装落点在载荷的 C 代码里
(pipe_phys_write_data / pipe_write64 那段),Kotlin 只做校验与呈现:

层 文件 作用
能力 载荷 .so 里的 patch_task_vr_tag(已内联进 install_android_root) 先清 thread_info.flags 的 0x400,再逐字节清 task+0x06 / task+0x2c 两个标记,最后回读自证
校验 com.kernelpack.vivo.VrKoPayloadCheck 只读字节,判定"这份载荷带没带绕过"
闸门 com.kernelpack.vivo.VrKoPayloadGate 只对蓝厂方案生效;通用方案短路,一次 ELF 解析都不做

判据是两条组合:日志串 vr detag + 机器码特征(add #0x2c 且 AND ~0x400)。

全量 126 份载荷实测:

份数 命中判据
带绕过 36 36 / 36
不带 89 0 / 89(零假阳性)

任务书 §6.3 的建议是错的:它建议扫 movz / movk 找 0x2c 与 0x400。
实测 clang 折成的是 add 立即数与 AND 逻辑立即数 —— 照 movz 扫会漏判 36/36。
为此在 AArch64.kt 补了两个解码器(decodeAddImmediate / decodeLogicalImmediate)。

1.3 两份无源码载荷:降级标注(按你选的方案 A)

libksu_vivo_iqoo12_a15.so 与 libksu_vivo_iqooz95gvivot35grootghos_any_3cc6.so
没有源码、无法重编,所以不假装它们带绕过:vivoVrBypass = false →
载荷列表标红 + 选中时一次确认对话框(可以"仍要选用",但得先看过这句话)。


二、新增功能:「解析完整包链接」

载荷构建页的第三条路:粘一个完整包(OTA ZIP)直链,自动解出 boot.img 交给已有流程。

2.1 它不是"下载整个包"

完整包通常 4–8 GiB。实际网络代价:

取什么 大约
文件尾部(找 ZIP 中央目录) 64 KiB
ZIP 中央目录本体 几百 KiB
payload.bin 头 + 分区清单 24 B + 几百 KiB
boot 分区真正用到的那几块 ~64–96 MiB

实现方式:HTTP Range 请求 + 手工跟随重定向(厂商 CDN / GitHub Release 大量用 302)。

2.2 两种完整包形态都认

形态 识别 处理
A/B 完整包 包里有 payload.bin(必须是 Stored) 读 update_engine 清单,按 dst_extents 还原分区;支持 REPLACE / REPLACE_XZ / ZERO / DISCARD
recovery 风格 包里直接放 boot.img / init_boot.img Stored 原样落盘;Deflate 流式解压

2.3 出处分级(Apache-2.0)

com.kernelpack.ota 下的 5 个文件移植自
YuKongA/ghostlock-app 的 data/ota/:

文件 移植方式
XzDecoder.kt 逐字节原样(只改 package)
PayloadBinUtils.kt 逐字节原样(只改 package)
ZipCentralDirectory.kt 原实现 + 三处只加不改(改名 / 候选条目表 / 边界检查)
HttpRangeReader.kt 原实现 + probe()(原版拿不到"服务器支不支持 Range")+ readToFile()(流式落盘)
OtaPayloadExtractor.kt 见下 §四 的改动清单

许可证沿用 app/src/main/assets/GL_LICENSE_Apache2.txt。


三、其它打磨

  • 清掉构建里全部 5 条警告(1 条生产代码 + 4 条测试代码),现在编译 0 警告:
    • InstallViewModel.kt 的 Condition is always 'true'(similar 由 snapshot?.let{} 推出,
      顺序倒过来即消,语义不变);
    • 测试用例名里的半角引号 / **(会触发 Windows 路径警告);
    • 3 处多余的 !!(编译器对 JUnit 的 assertNotNull 有数据流支持)。
  • 载荷构建页的输入现在有两条互斥来源(content:// URI 与本地文件),
    ViewModel 里互斥赋值 —— 避免"界面写着 A、实际构建用的是 B"。
  • 解出的镜像放应用缓存目录,只保留最近一份(boot 镜像 96 MiB,堆着会被系统无预告清掉)。
  • 给 payload 操作长度加了上限闸(256 MiB),防 toInt() 溢出把"包有问题"伪装成"应用崩了"。

四、OtaPayloadExtractor 相对上游的改动(逐条)

  1. package 名;对象名不变;
  2. ZipFileUtils → ZipCentralDirectory;
  3. 去掉 REPLACE_BZ 支持 —— 它要 commons-compress,而现代 OTA 的 boot 分区用的是
    REPLACE / REPLACE_XZ。为几乎不会出现的旧操作类型引一个第三方依赖不值得;遇到时明确报错;
  4. 新增直取条目路径 —— recovery 风格完整包(国内厂商常见)里根本没有 payload.bin;
  5. xbl_config 改为可选(默认不取)—— 本工程走 kallsyms 扫符号,不需要物理加载地址,
    取它只是白白多下几十 MiB;
  6. 日志中文化,产物文件名前缀 ghostlock_ota_ → ksuroot_ota_。

五、没做的事(如实列出)

  1. 一次真机都没跑过。 这一条对所有 4.1.0 的内容都成立 ——
    包括 vr.ko 绕过本身。vr detag=2 只证明代码被编进去了,不证明它在真机上抹掉了标记。
  2. 没有验证过真实 OTA 的 REPLACE_XZ 操作是单块还是多块 —— 见下面第 3 条。
  3. 内置 XZ 解码器只支持单块流,这是上游的缺陷,没有修。
    实测:xz --block-size=16384 -9 产出的 5 块流,第 1 块 16384 字节完全正确,
    第 2 块从第 2 个字节起发散(期望 0356: KS,实得 00000000),随后抛
    XzException: match distance beyond decoded data。
    各块的 LZMA2 头解析(reset=3 / props=93 / packSize / 偏移)与 xz 侧完全一致,
    输入字节也一致 —— 问题在解码状态而非定位。
    没有去修:这是一段算术编码器,"差一位"和"完全正确"之间没有中间状态,
    在没有吃透它之前动手改,风险比不修大得多。
    处理方式:单块流已用 3 条真实 xz 向量逐字节验证(含 crc32 / crc64 两种 check);
    多块流由 XzDecoderTest 钉住"会抛异常"这一现状;OtaPayloadExtractor 把它翻成
    一句人能看懂的话。谁将来修它,那条测试会先红。
  4. REPLACE_BZ(bzip2)不支持 —— 理由见 §四.3。
  5. 没有下载整包的能力:服务器不支持 Range 时直接拒绝。这是有意的 ——
    不该在用户没同意的情况下下几个 GB。
  6. BundledPayloadImported.kt 是生成器产物:为加 vivoVrBypass 字段,
    生成器(载荷搜寻/gen_catalog.py)与产物两边都改了,但生成器没有重跑
    (重跑会把全部 83 条 imported 条目一起刷新,超出本次范围)。
  7. 任务书 §6.2 点名的 tokay-CP2A.260605.012/target.h 与它自己给的数字矛盾:
    该文件是 TASK_CRED_OFF 0x820(不是 0x838),且没有 TASK_PI_LOCK_OFF。
    配方用的是与旧构建现场 cmp 逐字节相同的 targets_6_1/tokay.h。
    这条需要人来确认哪份才权威。
  8. neutralize_vr() 全局关开关没做(Option B):它需要
    SYS_EXIT_TP_OFF / RVH_COMMIT_CREDS_TP_OFF,这两个偏移在 6.1 / 6.12 上
    没有可核实的来源,按"不许猜"的原则留空,只做 per-task 抹标记。
  9. 载荷列表里那两份无源码载荷是降级标注,不是修好了(见 §1.3)。

六、怎么自己复核

# 1. 编译 + 全部单测(会同步源码树,防止"编的是旧代码")
bash ksu-toolchain/compile_check.sh /绝对路径/merge-repo
#    期望:SCRIPT_RC=0 · 362 条 0 失败 · 0 警告

# 2. 两份族基线真的带上了绕过
strings -a merge-repo/app/src/main/jniLibs/arm64-v8a/libbaseline_6_1.so  | grep -c "vr detag"   # 2
strings -a merge-repo/app/src/main/jniLibs/arm64-v8a/libbaseline_6_12.so | grep -c "vr detag"   # 2

# 3. 旧产物为什么 load 不起来(对比用)
readelf -sW <旧.so> | awk '$4=="FILE"'      # 缺 root.c / io_daemon.c
readelf -dW <旧.so> | grep -E "UND|NEEDED"  # install_android_root 等是 UND

# 4. 出包
bash ksu-toolchain/package_beta.sh /绝对路径/merge-repo
#    脚本自带三道断言:versionCode == 410 · 签名 == testkey · 成品指纹比对

七、本轮改动的文件

新增(com.kernelpack.ota,5 个)
HttpRangeReader.kt · ZipCentralDirectory.kt · PayloadBinUtils.kt · XzDecoder.kt · OtaPayloadExtractor.kt

新增(单测 3 个)
ota/XzDecoderTest.kt · ota/XzVectors.kt(4 条真实 xz 向量)· ota/ZipCentralDirectoryTest.kt · ota/PayloadBinUtilsTest.kt

改动(生产代码)
PayloadBuilderViewModel.kt(新增 OtaLinkState + parseOtaLink() + 输入双来源)
MainActivity.kt(构建页第三个按钮 + 对话框 + 状态行)
res/values/strings.xml · res/values-zh-rCN/strings.xml(10 条新字符串)
InstallViewModel.kt(消警告)· app/build.gradle.kts(版本号)

改动(文档)
README.md · MODULE.md

改动(构建脚本)
ksu-toolchain/package_beta.sh(VERSION=4.1.0 / VCODE=410)

KSuRoot 4.0.0 —— 三族内核(6.1/6.6/6.12)+ GhostLock 50 档内核适配

Choose a tag to compare

@hmascs hmascs released this 24 Sep 19:58

KSuRoot 4.0.0 —— 三族内核(6.1 / 6.6 / 6.12)+ GhostLock 50 档内核适配

versionCode = 400 · versionName = 4.0.0 · AOSP testkey 签名(a40da80a…5dc,可原地升级)
上一个正式版本:3.2.0(2026-09-24)
编译:debug / release 双变体通过 · 单测 304 条 0 失败(1 条环境门控跳过)


一、这个版本做了什么

1. 内核覆盖:从「一条 6.6」到「三族 6.1 / 6.6 / 6.12」

3.2.0 实际只有 6.6 一条线。4.0.0 扩到三个结构体族,
而且不是靠"版本号外推" —— 每一族都有自己的基线库:

结构体族 pi_lock cred tasks 基线库 来源
6_1 0x924 0x838 0x550 libbaseline_6_1.so 自编(tokay target.h)
6_6 0x90C 0x820 0x550 libionstack.so / libbs.so 沿用
6_12 0x9EC 0x900 0x638 libbaseline_6_12.so 自编(GhostLock + 荣耀 BTF)

为什么必须按族选库:结构体偏移是编译期烤死的,patch 改不了。
拿 6.6 的库去打 6.1 的内核,符号就算全 patch 对,写进去的也是错位置的字段 ——
这比"符号对不上"隐蔽得多(符号对不上会报错,字段错位不会)。

6.1 的口径变更(留档):6.1 曾在 2026-09-12 被移出主线,理由是"它是 flat 形态
(88 字节 / task@0x30),与 6.6/6.12 的 nested(112 字节 / task@0x50)不是一套"。
这个理由本身是对的;变的是我们后来为 6.1 编出了专属基线,
于是"拿 6.6 的偏移硬打 6.1"这个危险不再存在。
⚠️ 两条要一起读:6.1 能进主线的唯一前提是它有自己的族基线 ——
那份基线若被拿掉,6.1 必须同时退回拒绝。

2. 登记档位 51(通用)+ 52(蓝厂)= 103 档

引入上游 ghostlock-app 源码登记的
50 个内核适配(每档 9 个符号地址 + 结构体族),"通用方案"从 1 档扩到 51 档;
蓝厂方案把这 51 档全部挂上 vr.ko 绕过 → 52 档。

⚠️ 这 50 档一律标 UPSTREAM_TARGET_H + beta:数据是真的(来自上游源码),
但我方未在真机上验证过
。界面上与实测档分开计数显示,不谎报验证状态。

3. 双向符号对齐闸门(新的安全闸)

打补丁只能改写基线 .so 里本来就有的字面量,所以"基线有哪些键"与
"boot.img 解出哪些键"必须双向对齐。原先的写法是
baseline.symbolOffsets[key] ?: continue(直接跳过)—— 于是"看起来支持、实际写错内存"。
现在 SymbolAlignment 对不齐就阻断打包。

4. 与 GhostLock 的 offsets.json 互通

采用它的 offsets.json 作为互通格式(字段命名与结构已逐键核对),
实现读 / 写 / 合并(三种冲突策略),往返不丢未知键 ——
别人文件里我们不认识的键原样保留,不会被静默丢掉。

5. 内置厂商载荷:39 → 122 条(126 个 .so)

新增并入批次 83 份:Pixel 6~11 全系、三星 Galaxy 全系、
OPPO / realme / 一加 / 华硕 / 魅族等。读不出内核版本的 77 份一律
kernelUnknown —— 只允许手动选择、绝不参与自动匹配(载荷靠编译期常量寻址内核符号,
拿错一份就是提权失败)。

6. 设置页新增「基线覆盖面」

把注册表真实覆盖面摊开给用户看,而不是让人猜:三个主线系列 × 两个方案各登记多少档
(实测 / beta 分开计数)· 上游清单对账(GhostLock 登记的 50 档 vs 我方登记,必须零差异)
· 偏移可信度直方图。

7. 其它

  • 删除孤儿库 libgl_universal.so(全工程 0 引用)与重复载荷 libksu_vivo_sixmodels_a.so
  • 单测 154 → 304 条

二、修掉的 bug:两处「基线 ABI 冲突」误报

实测 6.1.145 的 boot.img 时被拒,提示
「基线 ABI 档位是 GKI 6.6,而 boot.img 是 6.1」。根因有两层,
都是"两套东西对不上",而且都表现为同一句话,极易误判:

症状 根因 修法
第 1 层 两张表 路由查 BaselineRegistry.allEntries(103 档),打包却查 BaselineProfiles.byId(只有 2 档,都是 6.6)→ 查不到就兜底回落 PD2520 统一到 BaselineRegistry.byId / findByBytes(两个调用点都改)
第 2 层 两套词汇 上游档的 abi.kernelSeries 填的是三段小版本(6.6.118),而闸门比的是两段大系列(6.6)→ 50 档一档都构建不出来 拆开两个语义:路由键保留三段小版本,ABI 比较键压成两段

同源的第 3 处:lookup() / coverageReport() / availableLabels() 也只查那 2 档 ——
导致报缺文案会在明明有档位时说"没有基线"。已一并修正。

并且不再兜底猜系列:认不出基础 .so 就如实报缺并停止打包,
而不是"取第一档顶上" —— 那等于拿 6.6 的旧值去打 6.1 的库。

回归测试

新增 BaselineRoutingLookupTest(11 条),把两条不变量写成断言:

  1. 路由给出的每一个 profileId,byId 都必须能取到(防"两张表"再次分叉);
  2. 每一档都必须能通过 ABI 硬闸门(用它的真实内核串端到端跑一遍)——
    这条直接复现用户看到的那句「基线 ABI 冲突」,只不过是在单测里。

三、参考了 GhostLock 的哪些源码

上游仓库:YuKongA/ghostlock-app(Apache-2.0)。
本项目只取方法与数据,不复制其 C 代码;其许可证随包携带于
app/src/main/assets/GL_LICENSE_Apache2.txt。

上游路径 取用了什么 落在本项目哪里
src/kernels/<内核串>/offsets.h 50 个内核各自的 9 个符号地址 GhostLockKernelOffsets.KERNELS
src/kernels/offsets.h 3 个结构体族的字段偏移 GhostLockKernelOffsets.STRUCT_FAMILIES
src/core/main.c _RSO(field, fallback) 覆盖模型:运行时值 > 编译期基线 > 载荷兜底常量 UnifiedOffsetResolver
src/core/offsets_json.c / .h offsets.json 读写与字段命名 GhostLockOffsets · GhostLockOffsetsIo · MiniJsonCodec
src/core/runtime_struct_offsets.h 运行时结构体偏移键名 SymbolKeyMapping(上游 9 键 ↔ 我方 11 键)
src/core/target.h 目标描述形态 BaselineProfile / AbiProfile 字段对照
buildSrc/.../GenerateSupportedKernelsTask.kt 内核清单由扫描源码树生成 GhostLockKernelCatalog(50 条 + 出处标记)

反向核对:它的数据经我们独立验证过(4 处零差异)

不是"抄了就信":

上游数据 独立佐证 结果
STRUCT_OFFSETS_6_6 frankel-CP2A.260605.012/target.h 一致
STRUCT_OFFSETS_6_12 pyyyc 荣耀 YLP-W00 6.12.38 BTF 实测 offsets.json 15 字段 0 差异
编译期兜底常量(11 项) 荣耀 struct_fields 一致
STRUCT_OFFSETS_6_1 tokay-CP2A.260605.012/target.h 一致(pi_lock=0x924、compact_waiter=1)
手写档 PD2520 boxiaolanya2008 PD2520-BP2A.250605.031.A3/target.h 28/28 键 0 差异

明确没有引用(高风险,拒绝照搬)

  • libextract.so(3.88 MB Rust 黑盒):kallsyms 提取口径我方没审过,
    且具备 LZ4 重压缩回写 boot.img 的能力。在没验证其提取结果与我方口径一致之前,
    引入它等于把校验权外包 —— 不得用于生成可刷写产物。
  • libghostlock.so 的运行时架构:它是"1 份通用载荷 + 运行时读 json",
    与我方"编译期常量写进 .so"根本不同。我们只采用它的格式与覆盖模型,
    主线仍是直接写入 .so。

四、已知限制(如实说明)

  • 50 档上游内核 + 两份自编族基线均未在真机验证(一律标 beta)。
  • 6.12 基线的符号是 CROSS_REFERENCE(取自荣耀 YLP-W00 6.12.38,是别的机型)。
    构建时会被 boot.img 解析出的新值逐项改写,且 SymbolAlignment 保证改写不齐就阻断。
    结构体偏移才是编译期烤死、决定成败的那一半。
  • 蓝厂 vr.ko 绕过尚未接入提权路径:数据层(VrKoBypass,12 条单测)已完成,
    但"清零 0x28-0x2f"这一步需要在真机上先确认安全才敢接线。
  • offsets.json 导入目前是阶段 1(读取与呈现):UnifiedOffsetResolver
    的合并流水线已实现并有 10 条单测,但尚未接入构建路径。

五、发布资产

文件 内容
KSuRoot-4.0.0.apk 签名 APK(versionCode 400,AOSP testkey,可原地升级)
KSuRoot-4.0.0-source-full.zip 完整构建源码(含 UI 外壳、厂商载荷目录、全部 jniLibs)
KSuRoot-4.0.0-module-src.zip 仅构建与模块相关源码(com.kernelpack 载荷引擎 + 对接点 + 构建脚本 + 两份自编族基线)

单测:304 条 0 失败(./gradlew :app:testDebugUnitTest)。

KSuRoot 3.2.0 —— 39 份厂商载荷 + 硬闸门 + 移交 root + 安全补丁提示

Choose a tag to compare

@hmascs hmascs released this 24 Sep 04:33

⚠️ 温馨提示:蓝厂机型调度策略较为严格,提权时子进程易被系统回收。请先在「开发者选项」中开启「停止限制子进程」后再执行提权,成功率更高。

真实内核提权工具,请只在自有且愿意承担风险的设备上使用,动手前先备份数据。
覆盖安装即可(同签名),versionCode 320。


本版是两条开发线的合并版

3.2.0 = 「厂商载荷目录线」+「闸门/移交 root 线」双向合并后的第一个版本。
两条线此前都叫 3.1.1 但内容不同,因此合并版换了版本号以便区分。

一、新增:39 份厂商载荷内置 + 分级匹配

随包内置 39 份逐机型编译的载荷(libksu_*.so,小米 6 / vivo·iQOO 33):

  • 覆盖 6.6.30 / 6.6.57 / 6.6.89 / 6.6.127
  • 三级匹配:Exact(机型+内核+commit 全中)/ SameKernel(厂商小版本 OTA)/ SimilarDevice(同厂商同内核,仅建议、绝不自动选中)
  • 6.6.89 的三款(iQOO Neo10 Pro+ / iQOO 13 / Neo11)显式指向随包 libbs.so

二、新增:Android 安全补丁提示

  • 设备卡新增「Android 安全补丁」一行(原「系统 ABI」行位置)
  • 2026-06:黄色感叹号 —— 可能已合并幽灵锁修复,只提示、不限制、不冷却
  • 2026-07 及以后:红色感叹号 + 提权按钮上方常驻红字 + 弹窗确认键 10 秒冷却
  • 判据只有月份、没有官方补丁映射表,所以两级都只提示、不阻断

三、机型识别优化

厂商把「这台机器叫什么」放在哪个字段完全不统一,本版做了两件事:

  • 多源取市场名:17 个属性按可信度排序(ro.product.marketname 系列 → 厂商自定义)+ Settings.Global.device_name 兜底
  • 匹配改用全身份串:haystack 从「只有 Build.MODEL」改为 manufacturer+brand+model+device+product+board+市场名;
    vivo/iQOO 的 Build.MODEL 是型号代码(V2463A)而目录登记的是市场名(iqoo 13),原实现必然匹配不上
  • 取不到市场名时界面如实标注「(型号代码)」,不拿代号冒充名字

四、新增:移交 root

  • 每次打开、检测到 root 即弹框询问是否移交给 Root 管理器
  • 管理器二选一:KernelSU(me.weishu.kernelsu)/ SukiSU Ultra(com.sukisu.ultra)
  • root 探测含 /apex/com.android.virt/bin/su(载荷提权后的落点,置首位)
  • 载荷跑完自动重探;失败可展开逐条诊断并重试

五、新增:5.x 内核支持(beta)开关

设置 → 内核支持,默认关。关着时识别到 5.x 不采用五系方案并拦住引导开启。

内核支持口径:主线 6.6 / 6.12(两个方案都覆盖);5.x 测试;6.1 拒绝
(6.1 的 rt_mutex_waiter 是 flat 形态 88 字节,与 6.6/6.12 的 nested 112 字节不是一套)。

六、本版删除

  • 主页「工作原理」卡片
  • 日志翻译引擎整套(ExploitLogDigest 及其 13 个用例)—— 提权页现在只显示原始日志,
    不再有「原文/译文」切换;进度条由 16 级里程碑退回阶段制
  • 设置里的「日志详细显示」开关

七、本版修掉的 bug

  1. matchesModel 大小写 bug:MODEL_SEPARATOR 字符类只认小写,而 displayName 是 "iQOO 13",
    导致新增的 displayName 匹配静默失效(一条都命中不了且不报错)
  2. ro.vivo.product.model 实测是代号(PD2463)却被列为市场名候选 → 界面会把代号当设备名显示。已移出 + 加 looksLikeCode() 兜底
  3. su 候选路径缺 /product/bin/su 与 /apex/com.android.virt/bin/su → 真机上「有 root 却显示未检测到 root」
  4. 裸名 "su" 被当成"一定存在",报错理由掩盖真因
  5. Operation not permitted(late-load 最常见失败)被判成成功
  6. 提权页日志滚动只盯译文 → 切到原文后不再跟随
  7. 合并时 MainActivity 多出一个 } 导致整份文件塌掉;A 线删除的 DialogDimAmount 等被 git 干净应用而消失

八、签名

AOSP testkey(CN=Android,SHA-256 a40da80a…),与设备当前安装一致,可覆盖安装。

⚠️ testkey 是公开密钥,只保证兼容性、不提供身份保证。适合自用 / 内测。


验证情况

  • 单测 168 个(1 个环境门控跳过),debug + release 两变体均编译通过
  • 真机:pm install -r 通过,启动无崩溃
  • 源码:本 Release 对应分支 merge-3.2.0

已知局限(如实说明)

  • 6.12 声明支持但会明确报缺:代码路径已铺好(两个方案 × 两个主线系列),但没有 6.12 的偏移数据。补数据需要为该内核编译的载荷 .so,或用真实 6.12 boot.img 实测 —— 本版不会拿 6.6 的数值去凑
  • 移交 root 的完整流程未在真机点过,只验证到命令行层;且 late-load 成功信号很弱(成功 = 空输出 + rc 0),界面只报「已执行移交」并原样展示输出
  • 红色补丁档未在真机验证(本机补丁为 2026-06,走黄色分支)
  • 本机 vivo 属性里没有市场名(marketname/marketing_name 全空),因此设备卡仍显示型号代码并标注。要真正解决需一张「型号代码 → 市场名」映射表

KSuRoot 3.1.1 —— 移交 root + 5.x beta 开关 + 内核支持口径(主线 6.6/6.12)

Choose a tag to compare

@hmascs hmascs released this 12 Sep 12:20

⚠️ 温馨提示:蓝厂机型调度策略较为严格,提权时子进程易被系统回收。请先在「开发者选项」中开启「停止限制子进程」后再执行提权,成功率更高。

真实内核提权工具,请只在自有且愿意承担风险的设备上使用,动手前先备份数据。
覆盖安装即可(同签名),versionCode 311。


本次更新(相对 v3.0.2)

一、新增:移交 root

载荷拿到的 root 只活在当前进程里,进程一结束就没了。本版新增把它移交给常驻 Root 管理器的完整链路:

  • 每次打开软件、只要检测到 root 就弹框询问是否移交(主页最底部卡片可随时再进)
  • 管理器二选一:KernelSU(me.weishu.kernelsu)或 SukiSU Ultra(com.sukisu.ultra)
  • 执行 libksud.so late-load --allow-shell --package-name <包名>
  • 把「管理器没装」与「移交失败」分成两种结果 —— 这两种该给的建议完全不同(一个去装、一个查版本)
  • root 探测路径含 /apex/com.android.virt/bin/su(载荷提权后的落点,置于首位)
  • 载荷跑完自动重探 root,不需要手动点「重新检测」
  • 探测失败时可展开逐条诊断(哪条路径不存在 / 被拒绝 / 超时),并支持手动重试

⚠️ 移交没有在真机上点过完整流程,只验证了命令行层:
SukiSU 那条 late-load 实测 rc=0 且静默成功;不存在的包名 rc=1 并输出
kernelnosu: exec /data/adb/ksud failed。
另外 late-load 的成功信号很弱(成功 = 空输出 + rc 0),
所以界面只报「已执行移交」并原样展示输出,请自己去管理器里确认。

二、新增:5.x 内核支持(beta)开关

  • 位置:设置 → 内核支持,默认关
  • 关着时识别到 5.x → 不采用五系方案,构建被拦下并引导去开启
  • 开启前弹确认框说明风险;开启后构建仍带 [测试内核] 提示

三、内核支持口径

系列
主线 6.6 / 6.12 —— 「通用方案」与「vivo / iQOO 方案」都覆盖
测试 5.x(需开上面的 beta 开关)
拒绝 6.1 及其它 6.x 次版本 —— 明确拦下,不走 beta 开关

构建前先定版本与方案:读完 boot.img 即按实测内核版本选方案;版本认不出、5.x 开关没开、或强制指定与实测冲突,都在打补丁之前零成本拒绝。

⚠️ 6.12 声明支持,但当前会明确报缺:还没有为 6.12 登记偏移产物。
代码路径(两个方案 × 两个主线系列)已实装,补数据即可生效 —— 但那需要
为该内核编译的载荷 .so,或用真实 6.12 boot.img 实测。
本版不会拿 6.6 的数值去凑 6.12(那正是本项目两次布局勘误的同一种错)。

四、boot 镜像格式识别

  • AOSP boot v0~v4、vendor_boot(点名「内核不在这个文件里」并指路)、裸 Image / 压缩镜像
  • MTK / 高通 split 的启发式提示(输出一律带「疑似」,不假装是解析)

五、设置页重构

  • 去掉原先的大段正文说明与三个大按钮
  • 「内核系列」改为一行可点选;「忽略冲突」与「5.x 内核支持」合并进同一个「内核支持」分组
  • 详细说明移到做决定的地方(确认框 / 选择器),设置页只留短摘要
  • 全部改用与全页一致的 miuix 偏好行,不再各写一套

六、修掉的 bug

  1. su 候选路径缺料:真机上检测不到 root —— 可用 su 在 /product/bin/su,而候选只赌 /system/bin、/sbin
  2. 裸名 "su" 被无条件当作「存在」,等于假装它在,报出来的理由是「找不到可用的 su」,把真因盖住
  3. looksSuccessful 漏 not permitted:Operation not permitted(late-load 最常见失败)会被报成成功
  4. 强制指定未参与前置判定:boot.img 白解一遍才被内部闸门拒绝
  5. 阻断只标红不弹窗:违反 P1 定的规矩,已加分类阻断弹窗
  6. 进度框错用确认框正文(「正在执行」里写着「是否移交?」)
  7. e2e_check.sh 用旧快照覆盖 security 模块 → 两个变体都编不过,而检查脚本一直报成功
  8. KSU_TEST_BOOT_IMG 从未透传进测试 JVM → 那条端到端用例永远 SKIP

七、签名

设备上及本项目历史版本用的都是 AOSP testkey(CN=Android,SHA-256 a40da80a…)。
打包脚本原先用的自造密钥与之不一致,签出来无法原地升级(必须卸载重装、丢数据)——
已改用 testkey,pm install -r 实测通过。

⚠️ testkey 是公开密钥,只保证兼容性、不提供身份保证。适合自用 / 内测。

验证情况

  • 单测 136 个(1 个环境门控跳过),debug + release 两变体均编译通过
  • 真机原地升级:versionCode 310 → 311

KSuRoot 3.0.2 —— 看门狗 180 秒 + 内置动态库 v1.3.0

Choose a tag to compare

@hmascs hmascs released this 11 Sep 08:21

⚠️ 温馨提示:蓝厂机型调度策略较为严格,提权时子进程易被系统回收。请先在「开发者选项」中开启「停止限制子进程」后再执行提权,成功率更高。

本次更新

  1. 看门狗放宽至 180 秒:EXPLOIT_STALL_MILLIS = 180_000L,九个语言提示文案同步更新为 180 秒,慢速提权不再容易被误判「停滞」而中断。
  2. 内置动态库换回 v1.3.0:与官方 release v1.3.0 资产逐字节一致(sha256 8c3410cb…95d9,176544 字节);已确认 v1.3.0 与 v1.0.0 共用同一套偏移(ASHMEM_MISC_FOPS 0x226b4e8 / INIT_TASK 0x210e280,上游 PD2520 target.h 无改动),无需重新适配,直接替换即可。

覆盖安装即可(同签名),versionCode 302。

KSuRoot 3.0.1 —— 修掉「内置动态库」的真正卡点

Choose a tag to compare

@hmascs hmascs released this 10 Sep 20:09

KSuRoot 3.0.1

修掉「内置动态库不可用」的真正卡点 —— 一行多余的 chmod。
覆盖安装即可(同签名),versionCode 301。

⚠️ 真实内核提权工具,请只在自有且愿意承担风险的设备上使用,动手前先备份数据。


问题是什么

2.2.0 起,只要选择「内置动态库(libbs.so)」并点安装,安装链就会在刚打印完下面这行之后立刻断掉:

[+] 支持配置: fixed-bn-so
使用内置动态库:libbs.so
[-] chmod failed: EACCES (Permission denied)
[*] 安装失败

chmod failed: EACCES (Permission denied) 是 Android Os.chmod() 抛出的 ErrnoException 原文,来自 PayloadRepository.bundledPayloads() 里的一行:

Os.chmod(exploit.absolutePath, 0b100100100)   // 0444

为什么它会失败

内置载荷住在 applicationInfo.nativeLibraryDir。这个目录里的文件是安装器以 system 身份提取的:

/data/app/~~…/com.ting.root-…/lib/arm64/
-rwxr-xr-x system system 162328 libbs.so
-rwxr-xr-x system system  26024 libcve43499root.so

属主是 system,不是应用自己 —— 非属主执行 chmod,内核直接回 EACCES。而它本来就是 r-xr-xr-x:那次 chmod 纯属多余(载荷只被 LD_PRELOAD 映射,不需要额外权限),却因为没有兜异常把整条安装链打断了。

「自定义动态库」一直没这个问题,是因为那份文件由应用自己写进私有目录、属主是应用自己。

3.0.1 怎么修

新增 PayloadStaging,四个载荷入口(内置 / 自定义 / 下载 / KernelSU)与执行助手统一走它:

1. 已经够用(可读 / 可执行)→ 原样返回,一次 chmod 都不做     ← 本机走的就是这条
2. 不够用 → 先试就地 chmod(有些 ROM/分区允许)
3. 还不满足 → 复制到应用私有目录(一定能写)再补权限,并按「同名同长度」缓存复用
4. 全失败 → 返回原文件,交给调用方已有的 require 兜底

因为原生库本来就 -rwxr-xr-x、对应用世界可读,第一步的 canRead() 即为真 → chmod 那行再也不会被执行 → EACCES 在结构上不可能再出现。

顺带把另外两层也一起说清楚

「内置动态库不可用」其实是三层叠在一起,前两层是隐患,第三层才是卡住安装的那一步。三层现在都已处理:

层 问题 状态
打包 AGP 默认 strip jniLibs 里的 .so,libbs.so 162328 → 142848 字节,跑起来的其实是被二次加工过的二进制 已用 keepDebugSymbols 保住原件
版本 内置的是上游 v1.3.0 已固定为 v1.0.0(162328 字节,sha256 87bf839f…b861),慢但稳
chmod 原生库属主是 system → Os.chmod EACCES → 安装链中断(真凶) 3.0.1 修复

上一版(3.0)的发布说明把「内置动态库已修复」写在了前两层上,那是不完整的 —— 特此更正。

你可以自己核对

装完之后从 /data/app 把 base.apk 抠出来:

unzip -p base.apk lib/arm64-v8a/libbs.so | sha256sum
# 87bf839fc8524ed25831a22166ebc6cef898e7ddc77ce77736add5ca49b78b61

其它(与 3.0 相同)

  • 载荷构建页:boot.img → kallsyms → 偏移 → 打补丁的动态库;点构建先选方案(通用 / vivo·iQOO vr.ko 绕过);产物自动进 Download/ 与「自定义动态库」
  • 免 ADB:内核 6.6 及以上(6.6 / 6.12 已验证,6.7~6.11 同理);低于 6.6 才需要 Shizuku(ADB),设备信息里新增内核版本行与判定
  • 运行记录只记过程不判成败;日志支持一键复制与保存到指定目录
  • 液态玻璃悬浮底栏、MIUIX 卡片分组、版本号 3.0.1

Apache-2.0 · 仅供安全研究与学习,请仅在自有且受控的设备上使用。

KSuRoot 3.0 —— 载荷构建

Choose a tag to compare

@hmascs hmascs released this 10 Sep 17:41

⚠️ 本版已被 v3.0.1 取代。
下面「内置动态库」一节写的是版本与打包被 strip 两层原因,但那两层只是隐患 ——
真正卡住安装的那一步是第三层:原生库属主是 system,应用执行 Os.chmod 必回 EACCES,
安装链会在打印完「使用内置动态库:libbs.so」后立刻断掉([-] chmod failed: EACCES)。
本版仍带该问题,请直接使用 v3.0.1。


KSuRoot 3.0

基于 CVE-2026-43499(GhostLock) 的一键 KernelSU 提权工具 · 本版是「载荷构建」大版本

⚠️ 这是真实的内核提权工具。竞态未命中、偏移错误都可能触发 oops/panic,轻则进程被杀,重则内核卡死或设备重启。请只在你自己拥有、且愿意承担风险的设备上使用,使用前先备份数据。


一、这个版本最重要的三件事

1. 内置动态库终于「能用」了 —— 而且现在能自证

之前「内置动态库不可用」其实是两层原因叠在一起:

层 问题 本版处理
版本 内置的是上游 release v1.3.0 的 preload.so 换成 v1.0.0(162328 字节,SHA-256 87bf839f…b861)—— 提权速度稍慢但稳
打包 AGP 默认会 strip jniLibs 里的 .so:实测 libbs.so 被削成 142848 字节,执行载荷的 helper 也被削 用 keepDebugSymbols 逐个保住,逐字节保留原件

「打包被 strip」这层特别隐蔽:版本号看着是对的,但跑起来的其实是一份被二次加工过的二进制。现在装完可以自己核对 —— 从 /data/app 里把 base.apk 抠出来:

unzip -p base.apk lib/arm64-v8a/libbs.so | sha256sum
# 87bf839fc8524ed25831a22166ebc6cef898e7ddc77ce77736add5ca49b78b61

2. 新增「载荷构建」页 —— 换机型不用再重新编译

把这条链路整个搬到手机上:

本机 boot.img ──► 内核符号表(kallsyms) ──► 这条链需要的偏移 ──► 打好补丁的动态库
  • 点「开始构建」会先问用哪种方案(从下往上弹出):
    1. 通用方案(推荐) —— IonStack 上游分支,不含厂商适配,适用于大部分 GKI 6.6+ 设备
    2. vivo / iQOO(vr.ko 反 su 绕过) —— 额外做厂商反 root 绕过,蓝厂机型必须选这项
  • 产物自动做两件事,不用你再点:写进 /storage/emulated/0/Download/(走 MediaStore,不需要任何存储权限),并写入「自定义动态库」且把载荷源切过去
  • 界面上直接摊开「打的是哪一份库」:文件名 / 大小 / SHA-256 / 来源版本 —— 这条信息不该藏在代码里
  • 全程离线,构建日志实时上屏;算法是独立的纯 Kotlin 模块(com.kernelpack),原地改写常量、不增删一个字节,改完还会自己重扫一遍自证(旧值残留必须为 0)

通用方案的载荷是本项目真编译出来的:用原生 clang 交叉编译 IonStack 的 CVE-2026-43499/exploit(PROJECT=blazer-CP2A.260605.012),并用真机 boot.img 验证过补丁链 —— 一次构建会把基线里的 13 项偏移改写成你机器的实际值。

3. 免 ADB 的边界说清楚了

GhostLock 打的是 rt_mutex + pipe_buffer 这条链:

内核 免 ADB 提权
6.6 及以上(6.6 / 6.12 两系已验证,6.7~6.11 同理) ✅ 直接可用,不需要电脑、不需要 ADB
低于 6.6 ❌ 只能走 Shizuku(ADB)授权那条路

设备信息卡新增内核版本行,并直接给出判定(6.6.89 · 支持 GhostLock 免 ADB)。内核低于 6.6 时按「安装」会先弹提示:免 ADB 走不通、请在设置中打开 Shizuku 授权;确认按钮带 3 秒倒计时(期间只有取消可点),避免手快直接确认。


二、界面与体验

  • 运行记录不再判成败:蓝厂机型上「跑完了但没拿到 root」和「真的跑挂了」根本分不开,判定既不准也没意义。现在只保留「进行中 / 已记录」,图标与配色一律中性。是否真的装上,看主页 KernelSU 状态 —— 那是实测出来的,不是推断的。
  • 日志一键复制 + 保存到指定目录:安装页的实时日志、运行记录详情,两处都有这两个动作。出问题时直接复制贴群里/issue。
  • 关于页改为「关于 KSUroot」,补上本仓库地址与简介,版本号统一为 3.0。
  • 上一轮做的液态玻璃 UI(悬浮玻璃底栏 + 滑块折射、MIUIX 卡片分组)与内置库路由修复(此前用内置库点安装会被「定位到官方在线源」,因为判断里漏了载荷来源这一维)一并包含在本版。

三、升级与使用建议

  1. 覆盖安装即可(同签名),版本号 300 / 3.0。
  2. iQOO / vivo → 主页选内置动态库。
  3. 三星 → 主页选官方在线源(按机型与内核版本匹配)。
  4. 其它机型(内核 6.6+)→ 到载荷构建用本机 boot.img 生成载荷,产物会自动进入「自定义动态库」。
  5. minSdk 33(Android 13+),仅 arm64-v8a。

四、致谢与许可

Apache-2.0。仅供安全研究与学习,请仅在自有且受控的设备上使用。

KSuRoot 2.2.0 — CVE-2026-43499

Choose a tag to compare

@hmascs hmascs released this 14 Aug 10:52

KSuRoot 2.2.0

基于 CVE-2026-43499(GhostLock) 内核漏洞的一键 KernelSU 提权工具。同步 Root-My-Galaxy v0.2.6 主线更新,新增自定义动态库导入功能。

本次更新

  • 同步 Root-My-Galaxy v0.2.6 主线:Compose 界面、在线设备清单(schema v3)自动匹配、安装历史、主题多语言
  • 三种载荷来源主页切换:官方在线源 / 内置 libbs.so / 自定义导入,切换即时生效无需重启
  • 自定义导入动态库:ELF 魔数校验、SHA-256 指纹记录、256MB 大小限制、随时移除
  • 支持机型详情页:三星 11 组型号(含内核版本)/ iQOO 骁龙 8 至尊版 3 款
  • 安装确认文案随来源动态变化,本地载荷全程不联网

支持设备

  • 官方在线源(三星):Galaxy S25 全系、Z Fold 7、S24 系列、S23 Ultra、A56 5G、A36 5G(内核版本需完全一致)
  • 内置动态库(iQOO · 骁龙 8 至尊版):iQOO Neo 10 Pro+、iQOO Neo 11、iQOO 13

安装

下载下方 KSURoot-2.2.0-CVE43499.apk 直接安装(Android 13+ / minSdk 33)。


One-click KernelSU rooting based on CVE-2026-43499. Synced from Root-My-Galaxy v0.2.6 with custom payload (.so) import.

Mod by hmascs · Apache-2.0