233laoliu/mt6985-CVE-2026-43499
GitHub: 233laoliu/mt6985-CVE-2026-43499
记录了在vivo PD2241(MT6985/天玑9300)上适配CVE-2026-43499内核漏洞利用的失败过程,并留下了符号表、结构体偏移和编译脚本等可用资产。
Stars: 0 | Forks: 0
# CVE-2026-43499 失败记录:MT6985 适配尝试
## 背景
| 项目 | 值 |
|------|-----|
| 设备 | vivo PD2241 (Dimensity 9300 / MT6985), Android 15 |
| 固件 | PD2241_A_15.2.10.2.W10.V000L1 |
| 内核 | 5.15.178-android13-8-gfb31f5bdd612-dirty |
| Bootloader | **锁定** (`ro.boot.flash.locked=1`) |
| SELinux | **Enforcing** |
| panic_on_oops | **开启** → 任何内核 OOPS = 秒重启 |
| Exploit | [CyberMeowfia](https://github.com/NebuSec/CyberMeowfia) — CVE-2026-43499 (IonStack) |
| 源码树 | android_15.0_kernel_MT6985 (5.15.178) — 与设备版本不匹配 (源码是 android15 GKI, 设备跑 android13 GKI) |
## 做了哪些事
### 1. 源码分析 → 提取结构体偏移
从 `arch/arm64/include/asm/memory.h` + `include/linux/fs.h` + `android/abi_gki_aarch64.xml` 提取:
- **内存布局**: `KIMAGE_TEXT_BASE = 0xffffffc008000000`, `VA_BITS=39`, `DIRECT_MAP=256GB`
- **task_struct**: 36864 bits, 完全解析 (ABI XML `layout-offset-in-bits`)
- **file_operations**: 无 `iopoll` (android13 GKI), IOCTL=0x48, open=0x68
- **cred**: `atomic_t usage` = 4 字节, uid=0x04
- **struct page**: 64 字节, `slab_cache=0x18`
关键发现: **源码是 android15 GKI, 设备是 android13 GKI**——task_struct 偏移差了 0x40~0x88 字节,不能照抄源码。
### 2. 固件解包 → 提取符号
```
OTA zip (8.3GB)
→ payload.bin (8.2GB)
→ payload_dumper → boot.img (96MB, v4 header)
→ LZ4 解压 → Image (50MB ARM64)
→ kallsyms-finder → 187810 符号
```
从两版固件 (15.2.7.6 / 15.2.10.2) 中提取符号——同一个符号两版之间差了 10KB~200KB,**必须用对版本**。
### 3. 反汇编验证 → capstone 确认关键偏移
```
# rt_mutex_adjust_pi 中:
LDR x21, [x19, #0x8b0] → pi_blocked_on = 0x8b0 (android15 值, 非 frankel)
```
这确认了 task_struct 布局是 android15 分支,不是 frankel 的 android13。
### 4. 编译 → 能过
NDK r29, `make PROJECT=android_15.0_kernel_MT6985` → `preload.so` (150KB)。
### 5. 运行 → 反复崩溃
```
[+] preload starting pid=25414
[+] p0 profile ... 所有符号正确加载
[-] KernelSnitch mm_struct leak failed ← 有时没这条 (偶尔成功)
[+] slide child context route=pselect ← slide KASLR leak 子进程启动
[内核 panic] ← rt_mutex_adjust_prio_chain+0x1b0
```
崩溃指令 (capstone):
```
ldar w8, [x27] ; x27 = waiter->lock (从 [x28, #0x38] 加载)
; x27 值是垃圾 → 页表无映射 → translation fault
; → die() → panic → 重启
```
## 为什么失败
### 根因 1: KernelSnitch 在 MTK 上不可靠
KernelSnitch 是整套 exploit 的入口——它通过 futex 哈希桶的**时序差异**泄露 `mm_struct` 地址:
1. **碰撞检测**成功——低阈值下找到 5 个碰撞
2. **bruteforce 匹配**几乎总是失败——核心问题在:
```
MT6985 有 CONFIG_KASAN_HW_TAGS=y → 内核用 MTE 标签标记 slab 分配
mm_struct 的指针带了 KASAN tag → futex_hash 基于 tagged pointer 计算
但 bruteforce 扫描 direct map (untagged 地址) → 算出来的 hash 对不上
即使加上 MTE tag 遍历 (0-14 共 15 种), 在 VA_BITS=39 的系统上
tag 位 (bit56-59) 与符号扩展位重叠 → 有些 tag 组合产生无效地址 → 漏检
```
**Pixel 设备没有 KASAN_HW_TAGS,这个机制跑得通。MTK 不行。**
### 根因 2: `CONFIG_PANIC_ON_OOPS` 是杀手
```
Pixel: 内核 OOPS → dump_stack → 继续跑 → exploit 可重试
MT6985: 内核 OOPS → die() → panic() → 秒重启 → 无试错空间
π 链破坏稍有偏差就全盘崩,Pixel 上偏差了只是"这次没成功,换组地址再来"。
```
且 bootloader 锁定 (`flash.locked=1`) → 不能刷自定义内核去掉这个选项。
### 根因 3: 内核版本漂移
```
源码树: 5.15.178 android15 GKI
设备: 5.15.178-android13 (vivo vendor)
```
虽然大版本号都是 5.15.178,但 GKI 分支不同(android13 vs android15),task_struct/cred 等关键结构体布局不一致。反复在 frankel/android15 两套偏移之间切换,最终靠反汇编才锁定。
## 尝试过的调整 (全部没用)
| 改动 | 目的 | 结果 |
|------|------|------|
| `THRESHOLD_MULT` 10→5→3 | 降低碰撞检测阈值 | <5 假阳性太多 |
| `APPENDED_FUTEXES` 4096→8192 | 增大 hash 链差异 | 无效果 |
| `REPEAT_MEASUREMENT/AVERAGE` | 增加采样精度 | 无效果 |
| `MTE=1` | 让 bruteforce 遍历标签 | 更慢, 反而崩溃减少 |
| `MM_STRUCT_SZ` 0x500→0x400 | 修正 mm_struct 步长 | 必要, ABI 实际 992 字节 |
| `IDENTITY_END` 64GB→256GB | 扩大扫描范围 | 太慢 (MTE遍历), 仍然不匹配 |
| TASK offsets: android15↔frankel | 锁定正确偏移 | 反汇编确认 android15 |
| FOPS offsets: android15↔frankel | android13 无 iopoll | 用 frankel |
## target.h 现状
`exploit/targets/android_15.0_kernel_MT6985/target.h` 中:
| 类别 | 可信度 | 验证方式 |
|------|--------|----------|
| 内存布局 | **正确** | memory.h 计算 + kallsyms `_text` 验证 |
| 符号偏移 (22 个) | **正确** | 从 15.2.10.2 boot.img 提取 |
| task_struct 偏移 | **正确** | ABI XML + capstone 反汇编 (pi_blocked_on=0x8b0) |
| FOPS 偏移 | **正确** | ABI XML (android13 布局, 无 iopoll) |
| CRED 偏移 | **待验证** | ABI XML (可能有 vendor OEM 字段影响) |
**汇编能过, 跑得起来, 输在最后一公里。**
## 如果你要继续
### 必要条件 (缺一不可)
1. **去掉 `CONFIG_PANIC_ON_OOPS`** — 要么刷自定义内核 (需要解锁 bootloader), 要么找一台默认关闭此选项的 MT6985 设备
2. **解决 KernelSnitch** — 需要 MTK Dimensity 9300 的缓存时序标定, 或者在 exploit 中完全替换 KernelSnitch 为其他 mm_struct 泄露方式
### 可能的替代思路
- `/proc/self/pagemap` — 本设备已限制 (返回全零)
- MTK 特有的调试接口 (`/proc/mtk_*`) — 存在但需要进一步分析
- MTK 相机/GPU 驱动的 ioctl 漏洞 — 更简单的提权路径
- 等社区适配 MTK 变体
### 本仓库的残余价值
- `symbols/kallsyms_PD2241_15.2.10.2.txt` — 完整的 15.2.10.2 符号表, 后人可以直接用
- `device_config.txt` — 设备实际内核配置, 可以看到 vendor 改了什么
- `exploit/targets/android_15.0_kernel_MT6985/target.h` — 结构偏移已验证
- `scripts/server_compile.py` — 自动化编译, 改参数后重编很快
## 踩坑清单 (后人避坑用)
1. **文件在 Windows 上解压**: `tar -xf` 对大 zip 可能失败, 用 Python `zipfile` 或先手动解压
2. **payload_dumper 的 protobuf 版本冲突**: 生成的 `update_metadata_pb2.py` 要求 protobuf 5.x, 需要手动删除 `runtime_version` 导入行
3. **直接用 `./preload.so` 运行会 segfault**: 必须用 `/system/bin/linker64 /data/local/tmp/preload.so`
4. **ABI XML 比源码更准**: `layout-offset-in-bits` 是编译器算的, 比手工数 5000 字节准 100 倍
5. **GKI 分支影响 layout**: android13/14/15 的 task_struct 不同, 不能跨分支复制 offset
6. **固件版本不同则符号偏移不同**: 15.2.7.6 和 15.2.10.2 差了 10KB~200KB
7. **vivo vendor 加了大量 OEM 字段**: `CONFIG_ANDROID_VENDOR_OEM_DATA=y`, `CONFIG_SCHED_INFO=y`, `CONFIG_RSC_*` → 偏离标准 GKI
8. **前后端符号提取工具链**: `boot.img → kernel.bin → LZ4 解压 → Image → kallsyms-finder → 符号表`
## 时间线
```
07/28 下载 CyberMeowfia 仓库 + MT6985 源码
07/29 源码分析 (memory.h, fs.h, ABI XML, 各种 struct)
固件解包 (payload.bin → boot.img → Image)
符号提取 (kallsyms-finder → 187810 符号)
多轮编译 + 多轮崩溃 + 反汇编验证
5 次自动重试 → 全部失败
写成这篇
-------------------------------------------
总计: ~68M tokens, 0 root shells
```
*2026-07-29, 活着讲述了这个故事*
标签:Android系统, ARM64架构, 云资产清单, 内核漏洞, 客户端加密, 目录枚举, 移动安全, 逆向工具, 逆向工程