LSPatch 是怎么把 Xposed 塞进 APK 的
修补不是加壳:它到底改了什么
LSPatch 的核心是在 APK 里嵌入一套完整的 LSPosed 运行时,同时改写 Manifest 让系统启动应用时先走自己的引导逻辑。整个过程可以拆成五步。
第一步:Manifest 分析与改写
APK 其实就是一个 zip 包,里面的 AndroidManifest.xml 经过二进制编码。LSPatch 首先解压 APK,解析 Manifest:
- 找到
application节点 - 读取原应用声明的
android:appComponentFactory - 如果原应用没声明或者声明了系统默认的,替换为 LSPatch 自己的 factory
- 如果原应用已经声明了自定义 factory(比如有些加固方案会加),记录下来后续做链式转发
AppComponentFactory 是 Android 框架提供的一个钩子点——系统实例化 Activity、Service、ContentProvider、BroadcastReceiver 时,会先交给这个 factory 创建。LSPatch 就是在这个时机把自己的运行时初始化好。
第二步:AppComponentFactory 替换
替换后的 factory 类会先执行自己的 instantiateApplication——在应用的 Application.onCreate 之前,完成 LSPosed 核心的加载:
- 加载嵌入的 dex 文件
- 加载 native so(liblspatch.so 等)
- 初始化 Hook 框架(YAHFA 或 SandHook)
- 扫描并加载模块
- 然后再调用原应用的 factory 继续正常流程
原应用感知不到这些,它的生命周期回调会在 LSPosed 环境里执行。
第三步:dex 注入
LSPatch 在 APK 的 assets/lspatch/ 目录下(或直接 classes*.dex 追加)塞入自己的几个 dex 文件:
- 引导类(Bootstrap):在 factory 替换时机最先加载
- 加载器(Loader):负责找到并加载模块
- Xposed API 实现:hook 框架和 API 桥接
注入位置取决于修补模式:
- 本地模式:运行时从 LSPatch Manager 拉取模块列表并加载
- 便携模式:模块的 dex 已经打包进 APK,直接按清单加载
第四步:native so 注入
LSPosed 的核心 Hook 逻辑是 native 层完成的(YAHFA 或 SandHook),需要把对应的 .so 文件按 ABI 拷贝进 APK 的 lib/<abi>/ 目录:
liblspatch.so:加载器- 模块声明的 so:按需拷贝
多 ABI 的应用(arm64-v8a + armeabi-v7a 同时支持)需要对每个 ABI 都注入一遍。
第五步:重签名
改了 APK 之后签名一定会失效。LSPatch 自动生成一个新签名,用它给修改后的 APK 重新签名。签名算法默认使用 V2(Android 7.0+ 强制要求),部分场景会同时生成 V1 签名以兼容旧系统。
签名变了意味着:任何依赖签名校验的应用都会检测到异常,包括但不限于:
- 微信/支付宝(用于应用间通信校验)
- 银行类应用(安全校验)
- 正版游戏(服务端校验签名)
- 企业加固的应用(加壳层会校验自身签名)
运行时发生了什么
打开修补后的应用时:
系统 → AppComponentFactory.instantiateApplication()
→ LSPatch Bootstrap 加载
→ LSPosed 核心初始化
→ Hook 框架准备就绪
→ 扫描模块清单
→ 逐个加载模块(Xposed API 注入完成)
→ 原应用 Application.onCreate()
→ 模块开始 hook 目标方法
整个过程在应用进程内部完成,不涉及任何系统级改动,这也是补丁方案能做到免 Root 的根本原因。