日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

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

發布時間:2025/6/17 Android 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 ) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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 插件化】Hook 插件化框架 ( 通過反射獲取 “宿主“ 應用中的 Element[] dexElements )
【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 與 “宿主“ 中的 Element[] dexElements | 設置合并后的 Element[] 數組 )


文章目錄

  • Android 插件化系列文章目錄
  • 前言
  • 一、合并 “插件包“ 與 “宿主“ 中的 Element[] dexElements
    • 1、獲取 “插件包“ 與 “宿主“ 中的 Element[] dexElements 數組長度
    • 2、獲取數組元素類型 Element
    • 3、計算合并后的 Element[] dexElements 數組長度
    • 4、創建 Element[] 數組
    • 5、拷貝 Element[] 數組元素
    • 6、完整代碼
  • 二、設置 “宿主“ 中的 Element[] dexElements
  • 三、完整代碼示例
  • 四、博客資源


前言

在 【Android 插件化】Hook 插件化框架 ( 通過反射獲取 “插件包“ 中的 Element[] dexElements ) 博客中介紹了從 " 插件包 " APK 文件中獲取 Element[] dexElements 流程 ;

在上一篇博客 【Android 插件化】Hook 插件化框架 ( 通過反射獲取 “宿主“ 應用中的 Element[] dexElements ) 介紹了從 " 宿主 " 應用中獲取 Element[] dexElements 流程 ;

本篇博客中開始將 " 插件包 " APK 中的 Element[] dexElements 和 “宿主“ 應用中的 Element[] dexElements 合并 ;






一、合并 “插件包“ 與 “宿主“ 中的 Element[] dexElements



將兩個 Element[] dexElements 數組合并 , 合并完成后 , 設置到 PathClassLoader 中的 DexPathList pathList 成員的 Element[] dexElements 成員中 ;


1、獲取 “插件包“ 與 “宿主“ 中的 Element[] dexElements 數組長度


調用 Java 提供的 Array API 中的 getLength 方法 , 獲取數組長度 ;

// 獲取 “宿主“ 中的 Element[] dexElements 數組長度 int host_dexElementsLength = Array.getLength(host_dexElementsObject); // 獲取 “插件包“ 中的 Element[] dexElements 數組長度 int plugin_dexElementsLength = Array.getLength(plugin_dexElementsObject);

2、獲取數組元素類型 Element


獲取 Element[] dexElements 數組中的 , 數組元素的 Element 類型 , 獲取的是 Element.class ;

// 獲取 Element[] dexElements 數組中的 , 數組元素的 Element 類型 // 獲取的是 Element.class Class<?> elementClazz = host_dexElementsObject.getClass().getComponentType();

3、計算合并后的 Element[] dexElements 數組長度


// 合并后的 Element[] dexElements 數組長度 int new_dexElementsLength = plugin_dexElementsLength + host_dexElementsLength;

4、創建 Element[] 數組


創建 Element[] 數組 , elementClazz 是 Element.class 數組元素類型 ;

// 創建 Element[] 數組 , elementClazz 是 Element.class 數組元素類型 Object newElementsArray = Array.newInstance(elementClazz, new_dexElementsLength);

5、拷貝 Element[] 數組元素


為新的 Element[] newElementsArray 數組賦值 , 先將 “插件包“ 中的 Element[] dexElements 數組放入到新數組中 , 然后將 “宿主“ 中的 Element[] dexElements 數組放入到新數組中 ;

// 為新的 Element[] newElementsArray 數組賦值 // 先將 “插件包“ 中的 Element[] dexElements 數組放入到新數組中 // 然后將 “宿主“ 中的 Element[] dexElements 數組放入到新數組中 for (int i = 0; i < new_dexElementsLength; i++) {if (i < plugin_dexElementsLength) {// “插件包“ 中的 Element[] dexElements 數組放入到新數組中Array.set(newElementsArray, i, Array.get(plugin_dexElementsObject, i));} else {// “宿主“ 中的 Element[] dexElements 數組放入到新數組中Array.set(newElementsArray, i, Array.get(host_dexElementsObject, i - plugin_dexElementsLength));} }

6、完整代碼


完整代碼 :

// 3. 合并 “插件包“ 與 “宿主“ 中的 Element[] dexElements// 將兩個 Element[] dexElements 數組合并 ,// 合并完成后 , 設置到 PathClassLoader 中的// DexPathList pathList 成員的 Element[] dexElements 成員中// 獲取 “宿主“ 中的 Element[] dexElements 數組長度int host_dexElementsLength = Array.getLength(host_dexElementsObject);// 獲取 “插件包“ 中的 Element[] dexElements 數組長度int plugin_dexElementsLength = Array.getLength(plugin_dexElementsObject);// 獲取 Element[] dexElements 數組中的 , 數組元素的 Element 類型// 獲取的是 Element.classClass<?> elementClazz = host_dexElementsObject.getClass().getComponentType();// 合并后的 Element[] dexElements 數組長度int new_dexElementsLength = plugin_dexElementsLength + host_dexElementsLength;// 創建 Element[] 數組 , elementClazz 是 Element.class 數組元素類型Object newElementsArray = Array.newInstance(elementClazz, new_dexElementsLength);// 為新的 Element[] newElementsArray 數組賦值// 先將 “插件包“ 中的 Element[] dexElements 數組放入到新數組中// 然后將 “宿主“ 中的 Element[] dexElements 數組放入到新數組中for (int i = 0; i < new_dexElementsLength; i++) {if (i < plugin_dexElementsLength) {// “插件包“ 中的 Element[] dexElements 數組放入到新數組中Array.set(newElementsArray, i, Array.get(plugin_dexElementsObject, i));} else {// “宿主“ 中的 Element[] dexElements 數組放入到新數組中Array.set(newElementsArray, i, Array.get(host_dexElementsObject, i - plugin_dexElementsLength));}}



二、設置 “宿主“ 中的 Element[] dexElements



將之前 合并 “插件包“ 與 “宿主“ 中的 Element[] dexElements 數組 , 設置到 宿主 PathClassLoader 中的 DexPathList pathList 成員的 Element[] dexElements 屬性值中 ;

先獲取 Element[] dexElements 字段 Field 對象 ;

Field elementsFiled = null; try {elementsFiled = host_pathListObject.getClass().getDeclaredField("dexElements"); } catch (NoSuchFieldException e) {e.printStackTrace(); } elementsFiled.setAccessible(true);

然后調用 Field 的 set 方法 , 設置該屬性值 , 其中 host_pathListObject 是原來的屬性值 , newElementsArray 是新的合并后的 Element[] dexElements 數組 ;

elementsFiled.set(host_pathListObject, newElementsArray);

完整代碼 :

// 4. 重新設置 PathClassLoader 中的 DexPathList pathList 成員的 Element[] dexElements 屬性值 Field elementsFiled = null; try {elementsFiled = host_pathListObject.getClass().getDeclaredField("dexElements"); } catch (NoSuchFieldException e) {e.printStackTrace(); } elementsFiled.setAccessible(true);// 設置 DexPathList pathList 的 Element[] dexElements 屬性值 // host_pathListObject 是原來的屬性值 // newElementsArray 是新的合并后的 Element[] dexElements 數組 // 注意 : 這里也可以使用 host_dexElementsField 字段進行設置 try {elementsFiled.set(host_pathListObject, newElementsArray); } catch (IllegalAccessException e) {e.printStackTrace(); }



三、完整代碼示例



package kim.hsl.plugin;import android.content.Context;import java.lang.reflect.Array; import java.lang.reflect.Field;import dalvik.system.DexClassLoader; import dalvik.system.PathClassLoader;/*** 使用 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 成員字段// ③ 反射獲取 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();}// 2. 反射 " 宿主 " 應用的 dexElement// 執行步驟 :// ① 反射獲取 BaseDexClassLoader.class// ② 反射獲取 BaseDexClassLoader.calss 中的 private final DexPathList pathList 成員字段// ③ 反射獲取 PathClassLoader 類加載器中的 DexPathList pathList 成員對象// ④ 反射獲取 DexPathList.class// ⑤ 反射獲取 DexPathList.class 中的 private Element[] dexElements 成員變量的 Field 字段對象// ⑥ 反射獲取 DexPathList 對象中的 private Element[] dexElements 成員變量對象// ① 反射獲取 BaseDexClassLoader.classClass<?> host_baseDexClassLoaderClass = null;try {host_baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader");} catch (ClassNotFoundException e) {e.printStackTrace();}// ② 反射獲取 BaseDexClassLoader.calss 中的 private final DexPathList pathList 成員字段Field host_pathListField = null;try {host_pathListField = host_baseDexClassLoaderClass.getDeclaredField("pathList");// 設置屬性的可見性host_pathListField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// ③ 反射獲取 DexClassLoader 類加載器中的 DexPathList pathList 成員對象// 根據 Field 字段獲取 成員變量// DexClassLoader 繼承了 BaseDexClassLoader, 因此其內部肯定有// private final DexPathList pathList 成員變量PathClassLoader host_pathClassLoader = (PathClassLoader) mBase.getClassLoader();Object host_pathListObject = null;try {host_pathListObject = host_pathListField.get(host_pathClassLoader);} 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<?> host_dexPathListClass = host_pathListObject.getClass();// ⑤ 反射獲取 DexPathList.class 中的 private Element[] dexElements 成員變量的 Field 字段對象Field host_dexElementsField = null;try {host_dexElementsField = host_dexPathListClass.getDeclaredField("dexElements");// 設置屬性的可見性host_dexElementsField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// ⑥ 反射獲取 DexPathList 對象中的 private Element[] dexElements 成員變量對象Object host_dexElementsObject = null;try {host_dexElementsObject = host_dexElementsField.get(host_pathListObject);} catch (IllegalAccessException e) {e.printStackTrace();}// 3. 合并 “插件包“ 與 “宿主“ 中的 Element[] dexElements// 將兩個 Element[] dexElements 數組合并 ,// 合并完成后 , 設置到 PathClassLoader 中的// DexPathList pathList 成員的 Element[] dexElements 成員中// 獲取 “宿主“ 中的 Element[] dexElements 數組長度int host_dexElementsLength = Array.getLength(host_dexElementsObject);// 獲取 “插件包“ 中的 Element[] dexElements 數組長度int plugin_dexElementsLength = Array.getLength(plugin_dexElementsObject);// 獲取 Element[] dexElements 數組中的 , 數組元素的 Element 類型// 獲取的是 Element.classClass<?> elementClazz = host_dexElementsObject.getClass().getComponentType();// 合并后的 Element[] dexElements 數組長度int new_dexElementsLength = plugin_dexElementsLength + host_dexElementsLength;// 創建 Element[] 數組 , elementClazz 是 Element.class 數組元素類型Object newElementsArray = Array.newInstance(elementClazz, new_dexElementsLength);// 為新的 Element[] newElementsArray 數組賦值// 先將 “插件包“ 中的 Element[] dexElements 數組放入到新數組中// 然后將 “宿主“ 中的 Element[] dexElements 數組放入到新數組中for (int i = 0; i < new_dexElementsLength; i++) {if (i < plugin_dexElementsLength) {// “插件包“ 中的 Element[] dexElements 數組放入到新數組中Array.set(newElementsArray, i, Array.get(plugin_dexElementsObject, i));} else {// “宿主“ 中的 Element[] dexElements 數組放入到新數組中Array.set(newElementsArray, i, Array.get(host_dexElementsObject, i - plugin_dexElementsLength));}}// 4. 重新設置 PathClassLoader 中的 DexPathList pathList 成員的 Element[] dexElements 屬性值Field elementsFiled = null;try {elementsFiled = host_pathListObject.getClass().getDeclaredField("dexElements");} catch (NoSuchFieldException e) {e.printStackTrace();}elementsFiled.setAccessible(true);// 設置 DexPathList pathList 的 Element[] dexElements 屬性值// host_pathListObject 是原來的屬性值// newElementsArray 是新的合并后的 Element[] dexElements 數組// 注意 : 這里也可以使用 host_dexElementsField 字段進行設置try {elementsFiled.set(host_pathListObject, newElementsArray);} catch (IllegalAccessException e) {e.printStackTrace();}}}



四、博客資源



博客資源 :

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

總結

以上是生活随笔為你收集整理的【Android 插件化】Hook 插件化框架 ( 合并 “插件包“ 与 “宿主“ 中的 Element[] dexElements | 设置合并后的 Element[] 数组 )的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。