Android 插件化系列文章目录

【Android 插件化】插件化简介 ( 组件化与插件化 )
【Android 插件化】插件化原理 ( JVM 内存数据 | 类加载流程 )
【Android 插件化】插件化原理 ( 类加载器 )

【Android 插件化】“ 插桩式 “ 插件化框架 ( 原理与实现思路 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 类加载器创建 | 资源加载 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 注入上下文的使用 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 获取插件入口 Activity 组件 | 加载插件 Resources 资源 )
【Android 插件化】“ 插桩式 “ 插件化框架 ( 运行应用 | 代码整理 )

【Android 插件化】Hook 插件化框架 ( Hook 技术 | 代理模式 | 静态代理 | 动态代理 )
【Android 插件化】Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 )
【Android 插件化】Hook 插件化框架 ( Hook Activity 启动过程 | 静态代理 )
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 一 | Activity 进程相关源码 )
【Android 插件化】Hook 插件化框架 ( 从 Hook 应用角度分析 Activity 启动流程 二 | AMS 进程相关源码 | 主进程相关源码 )

【Android 插件化】Hook 插件化框架 ( hook 插件化原理 | 插件包管理 )
【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements )


文章目录

  • Android 插件化系列文章目录
  • 前言
  • 一、通过反射获取 "插件包" 中的 Element[] dexElements
    • 1、反射获取 BaseDexClassLoader.class
    • 2、反射获取 DexPathList pathList 字段
    • 3、反射获取 DexPathList pathList 对象
    • 4、获取 DexPathList pathList 对象
    • 5、反射获取 Element[] dexElements 字段
    • 6、反射获取 Element[] dexElements 对象
  • 二、完整代码示例
  • 三、博客资源

前言

在上一篇博客 【Android 插件化】Hook 插件化框架 ( hook 插件化原理 | 插件包管理 ) 中简要介绍了 hook 插件化原理 , 并开始开发插件化管理类 , 本博客中开始加载插件包中的 Element[] dexElements ;

Android 中的类加载器 DexClassLoader , PathClassLoader 的父类是 BaseDexClassLoader ,

BaseDexClassLoader 中有 private final DexPathList pathList 成员变量 ,

DexPathList 中有 private Element[] dexElements 成员变量 ,

Element[] dexElements 就是最终存放 Dex 字节码数据的内存变量 , 最终将 " 插件包 " 中读取的 dexElements 合并到 " 宿主 " 应用的 dexElements 中 ;


一、通过反射获取 “插件包” 中的 Element[] dexElements


反射 " 插件包 " 应用的 dexElement 执行步骤 :

① 反射获取 BaseDexClassLoader.class

② 反射获取 BaseDexClassLoader.calss 中的 private final DexPathList pathList 成员字段

③ 反射获取 plugin_dexClassLoader 类加载器中的 DexPathList pathList 成员对象

④ 获取 DexPathList.class

⑤ 反射获取 DexPathList.class 中的 private Element[] dexElements 成员变量的 Field 字段对象

⑥ 反射获取 DexPathList 对象中的 private Element[] dexElements 成员变量对象

1、反射获取 BaseDexClassLoader.class

反射获取 BaseDexClassLoader.class , 通过反射获取插件包中的 dexElements , 这种类加载是合并类加载 , 将所有的 Dex 文件 , 加入到应用的 dex 文件集合中 , 可参考 dex 加固 , 热修复 , 插装式插件化 的实现步骤 ;

反射出 BaseDexClassLoader 类 , PathClassLoader 和 DexClassLoader 都是 BaseDexClassLoader 的子类 ;

参考 : https://www.androidos.net.cn/android/9.0.0_r8/xref/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java

代码示例 :

// ① 反射获取 BaseDexClassLoader.class// 通过反射获取插件包中的 dexElements
// 这种类加载是合并类加载 , 将所有的 Dex 文件 , 加入到应用的 dex 文件集合中
//  可参考 dex 加固 , 热修复 , 插装式插件化 的实现步骤
// 反射出 BaseDexClassLoader 类 , PathClassLoader 和 DexClassLoader
//  都是 BaseDexClassLoader 的子类
// 参考 https://www.androidos.net.cn/android/9.0.0_r8/xref/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
Class<?> baseDexClassLoaderClass = null;
try {baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader");
} catch (ClassNotFoundException e) {e.printStackTrace();
}

2、反射获取 DexPathList pathList 字段

// ② 反射获取 BaseDexClassLoader.calss 中的 private final DexPathList pathList 成员字段
Field plugin_pathListField = null;
try {plugin_pathListField = baseDexClassLoaderClass.getDeclaredField("pathList");// 设置属性的可见性plugin_pathListField.setAccessible(true);
} catch (NoSuchFieldException e) {e.printStackTrace();
}

3、反射获取 DexPathList pathList 对象

根据 Field 字段获取 成员变量 , DexClassLoader 继承了 BaseDexClassLoader, 因此其内部肯定有 private final DexPathList pathList 成员变量 ;

// ③ 反射获取 plugin_dexClassLoader 类加载器中的 DexPathList pathList 成员对象
// 根据 Field 字段获取 成员变量
//  DexClassLoader 继承了 BaseDexClassLoader, 因此其内部肯定有
//  private final DexPathList pathList 成员变量
Object plugin_pathListObject = null;
try {plugin_pathListObject = plugin_pathListField.get(plugin_dexClassLoader);
} catch (IllegalAccessException e) {e.printStackTrace();
}

4、获取 DexPathList pathList 对象

获取 DexPathList.class , 之前已经通过反射获取了 DexPathList pathList 对象 , 这里直接通过调用该对象的 getClass 方法 , 获取该类对象 ;

参考 : https://www.androidos.net.cn/android/9.0.0_r8/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java

// ④ 获取 DexPathList.class
// DexPathList 类中有 private Element[] dexElements 成员变量
// 通过反射获取该成员变量
// 参考 https://www.androidos.net.cn/android/9.0.0_r8/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java
// 获取 DexPathList pathList 成员变量的字节码类型 ( 也可以通过反射获得 )
// 获取的是 DexPathList.class
Class<?> plugin_dexPathListClass = plugin_pathListObject.getClass();

5、反射获取 Element[] dexElements 字段

// ⑤ 反射获取 DexPathList.class 中的 private Element[] dexElements 成员变量的 Field 字段对象
Field plugin_dexElementsField = null;
try {plugin_dexElementsField = plugin_dexPathListClass.getDeclaredField("dexElements");// 设置属性的可见性plugin_dexElementsField.setAccessible(true);
} catch (NoSuchFieldException e) {e.printStackTrace();
}

6、反射获取 Element[] dexElements 对象

// ⑥ 反射获取 DexPathList 对象中的 private Element[] dexElements 成员变量对象
Object plugin_dexElementsObject = null;
try {plugin_dexElementsObject = plugin_dexElementsField.get(plugin_pathListObject);
} catch (IllegalAccessException e) {e.printStackTrace();
}

二、完整代码示例


package kim.hsl.plugin;import android.content.Context;import java.lang.reflect.Field;import dalvik.system.DexClassLoader;/*** 使用 Hook 实现的插件使用入口*  1. 加载插件包中的字节码*  2. 直接通过 hook 技术, 钩住系统的 Activity 启动流程实现*      ① Activity 对象创建之前 , 要做很多初始化操作 , 先在 ActivityRecord 中加载 Activity 信息*          如果修改了该信息 , 将要跳转的 Activity 信息修改为插件包中的 Activity*          原来的 Activity 只用于占位 , 用于欺骗 Android 系统*      ② 使用 hook 技术 , 加载插件包 apk 中的 Activity*      ③ 实现跳转的 Activity ( 插件包中的 )*  3. 解决 Resources 资源冲突问题*  ( 使用上述 hook 插件化 , 可以不用考虑 Activity 的声明周期问题 )**  插件包中的 Activity 是通过正规流程 , 由 AMS 进行创建并加载的*      但是该 Activity 并没有在 AndroidManifest.xml 清单文件中注册*      这里需要一个已经在清单文件注册的 Activity 欺骗系统**  插装式插件化 是通过代理 Activity , 将插件包加载的字节码 Class 作为一个普通的 Java 类*      该普通的 Java 类有所有的 Activity 的业务逻辑*      该 Activity 的声明周期 , 由代理 Activity 执行相关的生命周期方法*  hook 插件化 : hook 插件化直接钩住系统中 Activity 启动流程的某个点*      使用插件包中的 Activity 替换占位的 Activity*/
public class PluginManager {/*** 上下文*/private Context mBase;/*** 单例*/private static PluginManager instance;public static PluginManager getInstance(Context context) {if (instance == null) {instance = new PluginManager(context);}return instance;}private PluginManager(Context context) {this.mBase = context;}/*** Application 启动后 , 调用该方法初始化插件化环境*  加载插件包中的字节码*/private void init() {// 加载 apk 文件loadApk();}private void loadApk() {// 插件包的绝对路径 ,  /data/data/< package name >/files/String apkPath = mBase.getFilesDir().getAbsolutePath() + "plugin.apk";// 加载插件包后产生的缓存文件路径// /data/data/< package name >/app_plugin_cache/String cachePath =mBase.getDir("plugin_cache", Context.MODE_PRIVATE).getAbsolutePath();// 创建类加载器DexClassLoader plugin_dexClassLoader =new DexClassLoader(apkPath,                // 插件包路径cachePath,              // 插件包加载时产生的缓存路径null,   // 库的搜索路径, 可以设置为空mBase.getClassLoader()  // 父加载器, PathClassLoader);// 1. 反射 " 插件包 " 应用的 dexElement// 执行步骤 :// ① 反射获取 BaseDexClassLoader.class// ② 反射获取 BaseDexClassLoader.calss 中的 private final DexPathList pathList 成员字段// ③ 反射获取 plugin_dexClassLoader 类加载器中的 DexPathList pathList 成员对象// ④ 反射获取 DexPathList.class// ⑤ 反射获取 DexPathList.class 中的 private Element[] dexElements 成员变量的 Field 字段对象// ⑥ 反射获取 DexPathList 对象中的 private Element[] dexElements 成员变量对象// ① 反射获取 BaseDexClassLoader.class// 通过反射获取插件包中的 dexElements// 这种类加载是合并类加载 , 将所有的 Dex 文件 , 加入到应用的 dex 文件集合中//  可参考 dex 加固 , 热修复 , 插装式插件化 的实现步骤// 反射出 BaseDexClassLoader 类 , PathClassLoader 和 DexClassLoader//  都是 BaseDexClassLoader 的子类// 参考 https://www.androidos.net.cn/android/9.0.0_r8/xref/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.javaClass<?> baseDexClassLoaderClass = null;try {baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader");} catch (ClassNotFoundException e) {e.printStackTrace();}// ② 反射获取 BaseDexClassLoader.calss 中的 private final DexPathList pathList 成员字段Field plugin_pathListField = null;try {plugin_pathListField = baseDexClassLoaderClass.getDeclaredField("pathList");// 设置属性的可见性plugin_pathListField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// ③ 反射获取 plugin_dexClassLoader 类加载器中的 DexPathList pathList 成员对象// 根据 Field 字段获取 成员变量//  DexClassLoader 继承了 BaseDexClassLoader, 因此其内部肯定有//  private final DexPathList pathList 成员变量Object plugin_pathListObject = null;try {plugin_pathListObject = plugin_pathListField.get(plugin_dexClassLoader);} catch (IllegalAccessException e) {e.printStackTrace();}// ④ 获取 DexPathList.class// DexPathList 类中有 private Element[] dexElements 成员变量// 通过反射获取该成员变量// 参考 https://www.androidos.net.cn/android/9.0.0_r8/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java// 获取 DexPathList pathList 成员变量的字节码类型 ( 也可以通过反射获得 )// 获取的是 DexPathList.classClass<?> plugin_dexPathListClass = plugin_pathListObject.getClass();// ⑤ 反射获取 DexPathList.class 中的 private Element[] dexElements 成员变量的 Field 字段对象Field plugin_dexElementsField = null;try {plugin_dexElementsField = plugin_dexPathListClass.getDeclaredField("dexElements");// 设置属性的可见性plugin_dexElementsField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// ⑥ 反射获取 DexPathList 对象中的 private Element[] dexElements 成员变量对象Object plugin_dexElementsObject = null;try {plugin_dexElementsObject = plugin_dexElementsField.get(plugin_pathListObject);} catch (IllegalAccessException e) {e.printStackTrace();}}}

三、博客资源


博客资源 :

  • GitHub : https://github.com/han1202012/Plugin_Hook

【Android 插件化】Hook 插件化框架 ( 通过反射获取 “插件包“ 中的 Element[] dexElements )相关推荐

  1. 【Android 插件化】Hook 插件化框架 ( 通过反射获取 “宿主“ 应用中的 Element[] dexElements )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  2. 【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  3. 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 使用反射获取方法创建本应用的 dexElements | 各版本创建 dex 数组源码对比 )

    文章目录 一.不同 Android 系统创建 dex 数组源码对比 二.不同 Android 系统创建 dex 数组源码对比 三. Android 5.1 及以下系统反射方法并创建 Element[] ...

  4. 【EventBus】事件通信框架 ( 订阅方法注册 | 检查订阅方法缓存 | 反射获取订阅类中的订阅方法 )

    文章目录 一.检查订阅方法缓存 二.反射获取订阅类中的订阅方法 三.完整代码示例 一.检查订阅方法缓存 注册订阅者时 , 只传入一个订阅者类对象 , 其它信息都需要通过反射获取 ; 1. 获取订阅者类 ...

  5. 【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | 反射获取 IActivityManager 对象 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  6. 【EventBus】事件通信框架 ( 取消注册 | 获取事件参数类型 | 根据事件类型获取订阅者 | 移除相关订阅者 )

    文章目录 一.取消注册订阅者 二.完整代码示例 一.取消注册订阅者 取消注册操作 : 从 Map<Object, List<Class<?>>> typesBySu ...

  7. 【Android 热修复】热修复原理 ( 合并两个 Element[] dexElements | 自定义 Application 加载 Dex 设置 | 源码资源 )

    文章目录 一.合并两个 Element[] dexElements 二. 完整修复包加载工具类 三. 源码资源 一.合并两个 Element[] dexElements 在 [Android 热修复] ...

  8. 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 将系统的 dexElements 与 应用的 dexElements 合并 | 替换操作 )

    文章目录 一.将系统的 dexElements 与 应用的 dexElements 合并 二.Element[] dexElements 替换操作 三.完整 dex 加载源码 参考博客 : [Andr ...

  9. 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 反射获取系统的 Element[] dexElements )

    文章目录 一.dex 文件准备 二.加载 dex 文件流程 三.Element[] dexElements 分析 四.反射获取系统的 Element[] dexElements 参考博客 : [And ...

最新文章

  1. 深入理解JVM虚拟机(十一):线程安全与锁优化
  2. zabbix items 配置
  3. 【Acwing 219. 剪纸游戏】
  4. 【2018.5.19】模拟赛之一-ssl2432 面积最大【数学】
  5. python图片显示中文
  6. 蚂蚁金服开放计算架构:下一代金融级计算架构
  7. MongoDB Element Query Operators(元素判断操作符)
  8. Exchange 2013 创建新用户
  9. 如何回滚特定的迁移?
  10. 管理感悟:计算缺陷的权重
  11. VB代码颜色修改(修改注册表的方法)
  12. wp8.1 java,Windows Phone 粉的福音:如何给 WP8.1 解锁部署 xap 软件
  13. list转json字符串
  14. Scratch3.0(一)初识Scratch3.0
  15. OROCOS之KDL(1)—— Linux环境搭建篇
  16. 热点登陆打不开网页 服务器已关闭,手机登录路由器管理页面打不开怎么办?...
  17. 上海交通大学python期末考试样题加解析_上海交通大学python期末考试样题加解析...
  18. 在醒目的底子上踏实肯干
  19. JS设置select标签选中的值
  20. 选择工控,你后悔吗?

热门文章

  1. OPatch cannot find a valid oraInst.loc file to locate Central Inventory
  2. 关于release后retainCount还是1的问题
  3. SQLserver 中时间减,并把结果转换成varchar类型,拼接上字符串
  4. SuSE 10 Enterprise 下 Oracle 10g 关于找不到initorcl.ora文件和控制文件问题
  5. Cisco pix515配置实例
  6. 阅读器关闭时Read的尝试无效
  7. Java实现单例模式
  8. stm32无法进入串口接收中断
  9. css3滤镜Filter使用
  10. bnu 34986 Football on Table(数学+暴力)