Xposed 是 Android 平台上的一个著名开源框架, 作者是 rovo89.Xposed 能够动态修改 Android 系统或者应用, 给了用户 DIY 系统或者应用的能力. Xposed 主要由两部分组成, Xposed 框架和 Xposed 模块. Xposed 框架提供 Java hook 的能力. Xposed 模块运行在 Xposed 框架上, 使用 Xposed 框架提供的 Java hook 能力动态修改系统或者目标应用.
Xposed 开源代码网址是 https://github.com/rovo89 .Xposed 代码工程结构如下图所示:
Xposed 安装时需要替换系统分区文件, 具体是使用修改后的 app_process 替换 Android 系统分区中的原生 app_process(art 虚拟机还会替换 libart.so). 下图中左半部分是 Android 应用正常启动流程; 右半部分是安装 Xposed 后, Andoid 应用启动流程.
使用 Xposed 的前提是手机需要 root.
依赖 root 权限替换系统分区文件是 Xposed 实现的一个路径. 是否存在其他实现路径?
Xposed 模块能正常运行在目标应用中, 这是目标. 通过分析 Xposed 的开源代码, 可以总结出下面结论. 在目标应用启动时, 能控制目标应用进程, 建立 Xposed 运行环境(主要指 Xposed 框架), 加载 Xposed 模块并启动 Xposed 模块, 这是 Xposed 模块能正常运行在目标应用中的核心逻辑.
一个第三方 Android 应用因为权限问题, 不能控制其他应用进程, 但是在其应用内部的任何操作是没有权限问题的, 因为都是运行在同一个 Linux 用户下. 如果 Android 应用能够提供一个沙箱, 双开其他 Android 类应用, 同时能提供 Java hook 能力, 就可以实现非 root 手机运行 Xposed, 这在技术上是可行的.
下面具体介绍应用双开和 Xposed 移植, 首先是整体框架图:
1. 应用双开
应用双开核心原理是利用沙箱技术虚拟化一个 Android 系统.
所谓 Android 虚拟化技术, 就是利用 Hook 技术和沙箱机制, 在一个 Android 应用中模拟出一个 Android 系统. 双开的应用运行在虚拟化出来的 Android 系统中, 与外部的 Android 系统完全隔离.
要想虚拟化一个 Android 系统出来, 首先要做到如下几点:
Application 运行环境构建及初始化
Android 四大组件生命周期管理
双开的 App 与 Android 系统的透明通信
IO 重定向
2. Xposed 移植
Xposed 框架移植涉及到两部分, 一部分是 Xposed 框架 C++ 部分的移植, 具体是 Java hook native 库 (libxposed_ dalvik.so 和 libxposed_art.so) 的移植; 一部分是 Xposed 框架 Java 部分的移植, 具体是 XposedBridge.jar 的移植.
移植 libxposed_dalvik.so 库相对简单, 原生的代码不需要修改, 编译后可直接使用. 移植 libxposed_art.so 相对复杂, 因为其部分实现是依赖于修改后的 libart.so. 移植 libxposed_art.so 需要实现一套新的 Java hook 机制. XposedBridge.jar 的移植主要整理出用于加载 Xposed 模块和启动 Xposed 模块的代码.
目前, 在 art 虚拟机上实现 Java hook 主要有两个方案, 一个是 inline hook, 一个是虚拟机方法替换.
art 虚拟机在加载一个类的时候会将类中方法解析成 ArtMethod 结构体, 结构体中保存着一些运行时的必要信息以及需要执行的指令指针地址. 这些指令指针地址为实现 Java hook 提供了条件.
Inline Hook 即内部跳转 Hook, 通过替换函数开始处的指令为跳转指令, 使得原函数跳转到自己的函数, 通常还会保留原函数的调用接口. 其缺点是无法对一些太短的函数 Hook. 下图是 inline hook 原理示意图:
虚拟机方法替换, 在 native 层将原方法的 ArtMethod 结构体替换成新方法的结构体, 执行原方法的时候便会执行到新方法的指令. 由于不同的版本 ArtMethod 结构体参数会不一样, 所以不同的版本有不同的实现, 下图是 Android6.0 版本的方法替换示例代码:
双开应用进程是双 Application 同时运行, 一个是 Host Application(第三方双开应用自己的 Application), 一个是双开应用的 Application. 我们可以在双开应用的 Application 启动之前, 通过 DexClassloader 将 XposedBridge.jar 包加载到进程中, 从而建立 Xposed 运行环境; 建立 Xposed 运行环境后, 通过 DexClassloader 加载 Xposed 模块并启动 Xposed 模块, 具体如下图所示:
总结
经过从技术角度的分析, 探讨了不 root 手机的情况下, 在 Android 应用中运行 Xposed 插件的技术实现路径. 在市场上, 已经出现了支持 Xposed 插件运行的应用 "分身大师 X 版", 其已实现在双开的应用中运行 Xposed 插件. 从该产品来看, 非 root 手机支持 Xposed 完全具有可行性
来源: https://juejin.im/post/5ae44593f265da0b7e0c070f