菜单

Stub APK 系统

相关源文件

本文档描述了 Magisk 中用于促进安全应用更新和实现应用隐藏机制的 Stub APK 系统。该系统允许 Magisk 在运行时动态加载完整的应用程序代码,同时保持最小的占用空间。有关应用如何隐藏自身以避免检测的信息,请参阅应用隐藏机制

概述

Stub APK 系统是 Magisk 架构中的关键组成部分,解决了两个主要挑战:

  1. 提供无缝的应用更新,无需完全重新安装
  2. 通过将已安装的 APK 与实际可执行代码分离,实现应用隐藏机制

该系统通过安装一个最小的“Stub”APK 来工作,该 APK 包含足够的代码,可以在运行时从存储在应用私有数据目录中的外部 APK 文件动态加载和执行完整的 Magisk 应用程序。

来源:app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java app/shared/src/main/java/com/topjohnwu/magisk/utils/DynamicClassLoader.java

关键组件

Stub APK 结构

Stub APK 包含最小的组件,这些组件实现 Android 的应用程序生命周期,同时将实际功能委托给动态加载的完整 APK。

来源:app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java app/shared/src/main/java/com/topjohnwu/magisk/utils/DynamicClassLoader.java

动态文件管理

Stub APK 系统管理应用程序数据目录中的两个关键 APK 文件:

  1. current.apk:当前激活的完整 Magisk 实现
  2. update.apk:一个待处理的更新,将在重启后替换当前实现

这些文件通过 StubApk 类中的实用方法进行管理

方法描述
current(Context)返回当前活动 APK 的文件引用
update(Context)返回待处理更新 APK 的文件引用
restartProcess(Activity)重启应用程序以应用更新

来源:app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java42-56

动态代码加载

Stub APK 系统的核心功能是通过自定义类加载器实现的,该加载器可以从外部 APK 文件加载类。

DynamicClassLoader

DynamicClassLoader 类扩展了 Android 的 BaseDexClassLoader 以实现自定义类加载行为

  1. 它从外部 APK 文件加载类
  2. 它实现了一个特定的类加载顺序,以优先加载某些来源
  3. 它为 root 服务提供了特殊处理

类加载顺序如下:

  1. 检查类是否已加载
  2. 尝试从引导类路径加载
  3. 尝试从当前 dex(外部 APK)加载
  4. 最后尝试从父类加载器加载

来源:app/shared/src/main/java/com/topjohnwu/magisk/utils/DynamicClassLoader.java23-46

资源加载

Stub APK 系统还负责动态加载外部 APK 中的资源

对于 Android 11+ (API 30+),系统使用 ResourcesLoader API,而较旧的 Android 版本则通过反射使用 addAssetPath 方法。

来源:app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java58-85 app/shared/src/main/java/com/topjohnwu/magisk/utils/DynamicClassLoader.java48-64

构建时组件生成

Stub APK 系统依赖于构建时代码生成,以创建具有混淆名称的必要组件,从而增强安全性并逃避检测。

组件生成过程

在构建过程中,会生成具有随机名称的几个关键组件:

  1. Android Manifest 中的组件占位符
  2. Stub 应用程序类
  3. 组件工厂类
  4. 加密资源

来源:buildSrc/src/main/java/Codegen.kt75-181 buildSrc/src/main/java/Codegen.kt185-229

Manifest 更新

构建系统会修改 Android Manifest 以包含用作占位符的随机化组件

  1. Content Provider
  2. Broadcast Receiver
  3. Activities
  4. 服务

manifest updater

  1. 生成带有占位符名称的组件条目
  2. 打乱组件顺序以增加变异性
  3. 插入自定义应用程序和组件工厂类

这种方法有助于 Magisk 逃避安全扫描器寻找特定组件签名的检测。

来源:buildSrc/src/main/java/Codegen.kt95-180 buildSrc/src/main/java/Codegen.kt185-228 buildSrc/src/main/java/Codegen.kt25-59

类名混淆

构建系统使用一种复杂的方法来生成随机但有效的 Java 类名

  1. 使用字符组合创建候选名称池
  2. 过滤掉 Java 关键字和可能引起问题的名称
  3. 确保与不区分大小写的文件系统兼容
  4. 生成看起来合法的包名和类名

随机化在 CI 构建中使用固定种子以保证可重现性,而在本地构建中使用随机种子以增加变异性。

来源:buildSrc/src/main/java/Codegen.kt185-228 buildSrc/src/main/java/Codegen.kt25-59

资源加密

为了保护敏感资源,Stub APK 系统在构建过程中加密资源文件

  1. 生成随机的 AES 加密密钥和初始化向量
  2. 使用 AES/CBC/PKCS5Padding 加密资源
  3. 将密钥、IV 和加密数据存储在 Java 类中

加密的资源将在运行时根据应用程序需要进行解密。

来源:buildSrc/src/main/java/Codegen.kt231-261

更新过程

Stub APK 系统为处理更新实现了特定的流程

  1. 新 APK 被下载并保存为应用数据目录中的 update.apk
  2. 应用程序进程被重启
  3. 重启后,Stub APK 检测到更新并将 current.apk 替换为 update.apk
  4. 应用程序使用来自更新的 current.apk 的新代码进行加载

restartProcess() 方法通过以下方式确保干净重启:

  1. 获取包的启动意图
  2. 完成所有活动
  3. 启动启动活动
  4. 退出运行时

来源:app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java87-93

组件映射与数据类

StubApk.Data 内部类管理关键的映射信息,将 Stub 组件连接到实际实现

  1. 维护 Stub 版本
  2. 保存真实组件类名到 Stub 组件名称的映射
  3. 存储 root 服务类的引用

这种映射允许 Stub APK 将功能委托给动态加载的 APK 中的正确实现类。

字段目的
STUB_VERSION跟踪 Stub 实现的版本
CLASS_COMPONENT_MAP将真实组件类名映射到 Stub 组件名称
ROOT_SERVICE指向 root 服务类的引用

来源:app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java95-119

平台兼容性

Stub APK 系统包含针对不同 Android 版本的特定处理

  1. 对于 Android N 及以上版本,为动态 APK 使用设备受保护的存储
  2. 对于 Android R 及以上版本,使用现代 ResourcesLoader API
  3. 对于旧版本,使用反射来添加资源路径

这些适应性确保 Stub APK 系统在不同 Android 版本上一致运行。

来源:app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java27-39 app/shared/src/main/java/com/topjohnwu/magisk/StubApk.java58-85