一款 Android DEX 注入工具,针对使用网易 X19 SDK 的游戏应用,通过多种方式将自定义 DEX 文件注入到目标应用的 app_ntp0/<版本>/.unzip/ 目录中,实现模块化扩展。
- 多种注入方式:支持 StartAnyWhere、CVE-2024-0044、Root 共五种注入路径
- 插件管理:通过 Content URI 导入/删除/查看模块(zip 格式,含
info.json) - 应用选择:长按包名输入框弹出已安装非系统应用列表
- 版本检测:自动检测目标应用
versionName_versionCode,支持手动覆盖 - 设备兼容性检测:根据 SDK 版本和安全补丁日期判断注入方式是否可用
- 权限管理:一键释放所有持久化 URI 权限
- 详细错误日志:注入失败时展示完整异常堆栈,支持复制到剪贴板
| 方式 | 名称 | 原理 | 系统要求 |
|---|---|---|---|
| StartAnyWhere (NgWebviewActivity) | 利用 Intent 重定向启动任意 Activity | 通过伪造 AccountAuthenticator 响应,以系统身份拉起目标应用的 NgWebviewActivity,携带 URI 授权 flags | Android 11-13,安全补丁 < 2023-03-01 |
| StartAnyWhere (AssistActivity) | 同上,目标改为腾讯 AssistActivity | 通过 PendingIntent + Bundle 传递授权参数 | 同上 |
| CVE-2024-0044 (pm install) | 利用 Shizuku 执行 pm install -i |
通过 Shizuku 以 shell 身份执行 pm install,使用伪造 installer 包名 mcinject 实现 run-as 效果 |
Android 12-14,安全补丁 < 2024-10-01 |
| CVE-2024-0044 (PackageInstaller) | 利用 Shizuku 直接调用 PackageInstaller API | 通过反射获取系统 IPackageManager → IPackageInstaller,经 ShizukuBinderWrapper 提权后静默安装 | 同上 |
| Root 注入 | 以 Root 身份直接替换 DEX | 通过 su 执行 shell 脚本,复制 DEX 并还原原文件权限/所有者/修改时间 |
设备已 Root |
WNLZ-Injector/
├── app/ # 主应用模块
│ ├── src/main/
│ │ ├── AndroidManifest.xml # 清单文件(声明 AuthService、ShizukuProvider)
│ │ ├── aidl/ # AIDL 接口定义(编译期关闭,仅用于参考)
│ │ │ └── android/content/
│ │ │ ├── IIntentReceiver.aidl
│ │ │ └── IIntentSender.aidl
│ │ ├── assets/
│ │ │ ├── cve-2024-0044.apk # CVE 注入所需辅助 APK
│ │ │ └── cve-2024-0044.apk.idsig # APK 签名方案 v4
│ │ ├── java/
│ │ │ ├── android/content/ # Kotlin 桩类(IIntentSender/IIntentReceiver)
│ │ │ │ └── pm/ # IPackageManager/IPackageInstaller/IPackageInstallerSession 桩
│ │ │ ├── com/cfks/startanywhere/ # StartAnyWhere 核心实现
│ │ │ │ ├── StartAnyWhere.java # Parcel 伪造 + 任意 Activity 启动
│ │ │ │ └── AuthService.java # AccountAuthenticator 服务
│ │ │ └── com/wunelezi/injector/ # 应用主包
│ │ │ ├── MainActivity.kt # 主界面 + 注入流程入口
│ │ │ ├── inject/ # 注入处理器
│ │ │ │ ├── CvePmHandler.kt # CVE-2024-0044 (pm install)
│ │ │ │ ├── CvePackageInstallerHandler.kt # CVE-2024-0044 (PackageInstaller)
│ │ │ │ ├── PackageInstallerShizuku.kt # Shizuku PackageInstaller 封装
│ │ │ │ ├── ShizukuExecutor.kt # Shizuku 命令执行器
│ │ │ │ └── DexDownloader.kt # DEX 下载/解压/写入
│ │ │ ├── model/ # 数据模型
│ │ │ │ ├── InjectionMethod.kt # 注入方式枚举(含设备兼容性判断)
│ │ │ │ ├── ModuleInfo.kt # 模块信息
│ │ │ │ ├── AppInfo.kt # 应用信息
│ │ │ │ ├── ImportResult.kt # 导入结果
│ │ │ │ └── LoadResult.kt # 加载结果
│ │ │ ├── util/ # 工具类
│ │ │ │ ├── PluginManager.kt # 插件管理(Content URI 方案)
│ │ │ │ └── UriHelper.kt # Content URI 读写工具
│ │ │ ├── adapter/ # RecyclerView 适配器
│ │ │ │ ├── AppAdapter.kt # 应用列表
│ │ │ │ ├── ModuleAdapter.kt # 模块列表(含批量选择删除)
│ │ │ │ └── MethodAdapter.kt # 注入方式列表
│ │ │ └── widget/
│ │ │ └── MethodSelectorView.kt # 注入方式选择组件
│ │ └── res/ # 资源文件
│ │ ├── layout/ # 布局
│ │ ├── values/strings.xml # 字符串(简体中文)
│ │ ├── xml/authenticator.xml # AccountAuthenticator 配置
│ │ └── ...
│ ├── build.gradle # 应用构建配置
│ ├── proguard-rules.pro # ProGuard 规则
│ └── release.jks # 签名密钥
├── hidden-api/ # 隐藏 API 桩模块(compileOnly)
│ └── src/main/java/
│ ├── android/content/pm/ # IPackageManager 等隐藏接口桩
│ ├── android/os/ServiceManager.java
│ └── com/android/modules/utils/ # ParceledListSlice 桩
├── scripts/
│ ├── install-hooks.sh # 安装 git hooks 脚本
│ └── pre-push # pre-push hook(禁止 push tag)
├── build.gradle # 根构建文件
├── settings.gradle # 项目设置
└── gradle.properties # Gradle 属性
利用 Android AccountAuthenticator 机制,通过 AuthService 注册一个自定义账号类型。StartAnyWhere.pullSpecialActivity() 方法手动构造 Parcel 数据,伪造一个包含目标 Intent 的 Bundle 响应,然后启动系统的 ChooseTypeAndAccountActivity。系统在调用 addAccount 时,AuthService 返回预制的 Bundle,其中包含的 Intent 被系统以自身身份启动,从而实现:
- 以系统身份拉起目标应用的指定 Activity
- Intent 中携带
FLAG_GRANT_READ/WRITE/PERSISTABLE_URI_PERMISSION,使目标应用获得对 DEX 文件 URI 的读写权限
利用 Android pm install -i <installer_package> 的 installer 身份伪造漏洞(CVE-2024-0044),通过 Shizuku 以 shell 身份执行安装命令,将 installer 包名设为 mcinject(目标应用的 run-as 包名),从而获得以目标应用身份执行命令的能力。之后将 DEX 文件复制到目标应用的 app_ntp0/<版本>/.unzip/ 目录。
PackageInstaller 变体则通过反射直接调用系统 IPackageManager.getPackageInstaller() → PackageInstaller,经 ShizukuBinderWrapper 包装后实现静默安装。
通过 su -c 执行 shell 脚本,直接将 DEX 文件复制到目标目录,并使用 stat/chmod/chown/touch 还原原文件的权限、所有者、用户组和修改时间,做到外观无痕。
采用纯 Content URI 方案,通过目标应用暴露的 content://com.netease.x19.widget_file_provider/widget_external_files/ 访问其 files 目录:
- 读取:从
plugins.txt获取 zip 名称列表,遍历每个 zip 读取info.json解析模块名和作者 - 导入:SAF 选择文件 → 通过 Content URI 写入为
UUID.zip→ 更新plugins.txt - 删除:从
plugins.txt移除条目 → 通过ContentResolver.delete删除 zip
| 项目 | 版本 |
|---|---|
| Android Gradle Plugin | 8.0.2 |
| Kotlin | 1.9.22 |
| compileSdk | 34 |
| minSdk | 24 |
| targetSdk | 34 |
| Java | 17 |
dev.rikka.shizuku:api:13.1.5+dev.rikka.shizuku:provider:13.1.5— Shizuku APIorg.lsposed.hiddenapibypass:hiddenapibypass:4.3— 隐藏 API 限制绕过hidden-api(本地模块,compileOnly)— 系统隐藏接口桩
- 项目使用阿里云 Maven 镜像,适合国内网络环境
build.gradle中aidl = false,避免 AIDL 生成的 Java 类与 Kotlin 桩类冲突- release 构建开启
minifyEnabled但关闭shrinkResources,防止authenticator.xml被误删 - ProGuard 规则保留了
rikka.shizuku.**、org.lsposed.hiddenapibypass.**、android.content.**等关键类
- 输入包名:在主界面输入目标应用包名,或长按输入框从应用列表选择
- 选择注入方式:点击注入方式卡片,在弹出列表中选择合适的方式(不支持的会标红)
- 注入:点击"注入"按钮,等待下载并写入 DEX 文件
- 管理模块:点击"注入模块"卡片,导入 zip 格式的插件模块(需包含
info.json) - 重启游戏:注入完成后重启目标游戏即可生效
菜单栏可设置自定义官包版本号(格式:版本名_版本号),留空则自动检测已安装应用的版本。当目标应用未安装或版本检测失败时可手动指定。
DEX 文件从 GitHub Releases 下载:
https://github.com/caofangkuai/WNLZ-Injector-dex/releases/download/<versionSegment>/dex.zip
其中 <versionSegment> 为 versionName_versionCode 格式。StartAnyWhere 方式还会通过 WebView 加载远程注入页面。
- 本仓库禁止打 tag,所有版本号在 commit 信息中描述(通过
scripts/pre-pushhook 拦截) - 字符串资源仅保留简体中文(
resConfigs "zh-rCN") - 签名配置统一使用
release.jks(debug 和 release 均使用同一签名)
本项目仅供学习和研究使用。