【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | AMS 启动前使用动态代理替换掉插件 Activity 类 )
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 插件化】Hook 插件化框架 ( 創建插件應用 | 拷貝插件 APK | 初始化插件包 | 測試插件 DEX 字節碼 )
【Android 插件化】Hook 插件化框架 ( Hook Activity 啟動流程 | Hook 點分析 )
【Android 插件化】Hook 插件化框架 ( Hook Activity 啟動流程 | 反射獲取 IActivityManager 對象 )
【Android 插件化】Hook 插件化框架 ( Hook Activity 啟動流程 | AMS 啟動前使用動態代理替換掉插件 Activity 類 )
文章目錄
- Android 插件化系列文章目錄
- 一、插件包 Activity 啟動原理
- 二、需要反射的相關類
- 1、Instrumentation
- 2、IActivityManager
- 3、ActivityManager
- 4、Singleton
- 三、動態代理類
- 四、使用動態代理替換 IActivityManagerSingleton 的 mInstance 成員
- 1、通過反射獲取 IActivityManagerInterface 接口
- 2、動態代理
- 3、替換 mInstance 成員
- 4、代碼示例
- 五、完整代碼
- 六、博客資源
一、插件包 Activity 啟動原理
使用動態代理 , 替換 android.app.ActivityManager 中的 private static final Singleton IActivityManagerSingleton 成員的 mInstance 成員 ;
注意 : 該操作一定要在 AMS 啟動之前將原來的 Intent 替換掉 , 使用占坑的 Activity 替換插件包中的 Activity , 之后 AMS 執行完畢 , 執行到主線程 實例化 Activity 對象之前 , 還要替換回去 ;
插件包組件啟動方式 : 使用 Intent 啟動插件包時 , 一般都使用隱式啟動 ; 調用 Intent 的 setComponent , 通過包名和類名創建 Component , 這樣操作 , 即使沒有獲得 Activity 引用 , 也不會報錯
該插件包中的 Activity 沒有在 “宿主” 應用中注冊 , 因此啟動報錯 ;
AMS 會干掉沒有注冊過的 Activity , 這里先 在啟動 AMS 之前 , 設置一個已經 注冊過的 占坑 Activity ( StubActivity ) 執行啟動流程 , 在主線程生成 Activity 實例對象時 , 還需要恢復插件包中的 Activity
二、需要反射的相關類
1、Instrumentation
在 Instrumentation 中的 execStartActivity 方法 , 最終調用 ActivityManager.getService() 的 startActivity 方法 , 其中傳入的參數就有 Intent , 這里我們需要將該 Intent 替換掉 ;
public class Instrumentation {public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {try {int result = ActivityManager.getService().startActivity(whoThread, who.getBasePackageName(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);} catch (RemoteException e) {}return null;} }2、IActivityManager
IActivityManager 是接口 , 由 IActivityManager.aidl 生成 ;
源碼路徑 : /frameworks/base/core/java/android/app/IActivityManager.aidl
3、ActivityManager
要替換的是 ActivityManager 中的 Singleton<IActivityManager> IActivityManagerSingleton 成員的 mInstance 成員 ;
public class ActivityManager {/*** @hide*/public static IActivityManager getService() {return IActivityManagerSingleton.get();}private static final Singleton<IActivityManager> IActivityManagerSingleton =new Singleton<IActivityManager>() {@Overrideprotected IActivityManager create() {final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);final IActivityManager am = IActivityManager.Stub.asInterface(b);return am;}}; }源碼路徑 : /frameworks/base/core/java/android/app/ActivityManager.java
4、Singleton
Singleton 類是單例的實現 , 注意該類只能由系統使用 , 應用開發者不能調用 ;
package android.util;/*** Singleton helper class for lazily initialization.** Modeled after frameworks/base/include/utils/Singleton.h** @hide*/ public abstract class Singleton<T> {private T mInstance;protected abstract T create();public final T get() {synchronized (this) {if (mInstance == null) {mInstance = create();}return mInstance;}} }源碼路徑 : /frameworks/base/core/java/android/util/Singleton.java
三、動態代理類
該類持有 mIActivityManager 接口對象 , 當檢測到調用 startActivity 方法時 , 攔截該方法 , 在該 startActivity 方法中替換方法中的 Intent 參數 ;
package kim.hsl.plugin;import android.content.Context; import android.content.Intent; import android.util.Log;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;/*** 動態代理的代理類*/ public class AmsInvocationHandler implements InvocationHandler {/*** 上下文對象*/private final Context mContext;/*** 持有被代理的原對象*/private final Object mIActivityManager;public AmsInvocationHandler(Context context, Object iActivityManager) {this.mContext = context;this.mIActivityManager = iActivityManager;}/*** 代理 IActivityManager 的 startActivity 方法* 替換要啟動的 Activity 的 Intent** @param proxy* @param method* @param args* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 檢測到方法名稱是 startActivity// 要使用自己的方法 , 替換被代理的方法// 主要進行替換要啟動的 Activity 的 Intent 操作if("startActivity".equals(method.getName())){Intent intent = null;// Intent 會通過參數傳入// 遍歷方法的參數即可for (int i= 0; i < args.length; i++){// 獲取參數對象Object arg = args[i];// 方法參數類型是 Intentif(arg instanceof Intent){// 將原來的傳入的 Intent 參數 , 改成自己的 Intent , 啟動自己的類intent = (Intent) arg;// 新的 Intent , 用于替換原有的 IntentIntent exchangeIntent = new Intent(mContext, StubActivity.class);// 原來的 Intent 不能丟 , 里面包含了很多信息 , 如實際的跳轉信息// 最終還要替換回去exchangeIntent.putExtra("actionIntent", intent);// 替換原來的 Intent 參數值args[i] = exchangeIntent;break;}}}// 繼續向后執行 , 這里要避免截斷方法return method.invoke(mIActivityManager, args);}}四、使用動態代理替換 IActivityManagerSingleton 的 mInstance 成員
1、通過反射獲取 IActivityManagerInterface 接口
IActivityManager 是接口 , 這是一個 AIDL 文件生成的 , 由 IActivityManager.aidl 生成 ;
通過反射獲取 android.app.IActivityManager 接口 ;
// IActivityManager 是接口 // 這是一個 AIDL 文件生成的 , 由 IActivityManager.aidl 生成 Class<?> IActivityManagerInterface = null; try {IActivityManagerInterface = Class.forName("android.app.IActivityManager"); } catch (ClassNotFoundException e) {e.printStackTrace(); }2、動態代理
創建 InvocationHandler 對象 ;
然后創建動態代理對象 ;
// 動態代理的實際代理類 AmsInvocationHandler amsInvocationHandler =new AmsInvocationHandler(context, mInstanceObject);// 動態代理過程 Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), // 類加載器new Class[]{IActivityManagerInterface}, // 接口amsInvocationHandler); // 代理的對象3、替換 mInstance 成員
使用動態代理類 , 替換原來的 ActivityManager 中的 IActivityManagerSingleton 成員 的 Singleton 類中的 mInstance 成員 ;
// 使用動態代理類 , 替換原來的 ActivityManager 中的 IActivityManagerSingleton 成員 // 的 Singleton 類中的 mInstance 成員 try {mInstanceField.set(iActivityManagerSingletonObject, proxy); } catch (IllegalAccessException e) {e.printStackTrace(); }4、代碼示例
完整代碼示例 :
// IActivityManager 是接口 // 這是一個 AIDL 文件生成的 , 由 IActivityManager.aidl 生成 Class<?> IActivityManagerInterface = null; try {IActivityManagerInterface = Class.forName("android.app.IActivityManager"); } catch (ClassNotFoundException e) {e.printStackTrace(); }// 動態代理的實際代理類 AmsInvocationHandler amsInvocationHandler =new AmsInvocationHandler(context, mInstanceObject);// 動態代理過程 Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), // 類加載器new Class[]{IActivityManagerInterface}, // 接口amsInvocationHandler); // 代理的對象// 使用動態代理類 , 替換原來的 ActivityManager 中的 IActivityManagerSingleton 成員 // 的 Singleton 類中的 mInstance 成員 try {mInstanceField.set(iActivityManagerSingletonObject, proxy); } catch (IllegalAccessException e) {e.printStackTrace(); }五、完整代碼
package kim.hsl.plugin;import android.content.Context;import java.lang.reflect.Field; import java.lang.reflect.Proxy;/*** 主要職責 : Hook Activity 的啟動過程* 本工具類只針對 API Level 28 實現 , 如果是完整插件化框架 , 需要實現所有版本的 Hook 過程* 不同的版本 , Activity 的啟動過程是不同的 , 需要逐個根據 Activity 啟動源碼進行 Hook 適配*/ public class HookUtils {/*** 最終目的是劫持 ActivityManagerService 的 startActivity 方法 ,* 修改 Intent 中藥啟動的 Activity 類*/public static void hookAms(Context context){// 獲取 android.app.ActivityManager 類Class<?> activityManagerClass = null;try {activityManagerClass = Class.forName("android.app.ActivityManager");} catch (ClassNotFoundException e) {e.printStackTrace();}// 獲取 android.app.ActivityManager 類 中的 IActivityManagerSingleton 屬性// private static final Singleton<IActivityManager> IActivityManagerSingleton 成員變量Field iActivityManagerSingletonField = null;try {iActivityManagerSingletonField =activityManagerClass.getDeclaredField("IActivityManagerSingleton");// 設置成員字段的可訪問性iActivityManagerSingletonField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 獲取 android.app.ActivityManager 類的靜態成員變量// private static final Singleton<IActivityManager> IActivityManagerSingleton// 直接調用 Field 字段 iActivityManagerSingletonField 的 get 方法 , 傳入 null 即可獲取Object iActivityManagerSingletonObject = null;try {iActivityManagerSingletonObject = iActivityManagerSingletonField.get(null);} catch (IllegalAccessException e) {e.printStackTrace();}// 獲取 Singleton 類// ActivityManager 中的 IActivityManagerSingleton 成員是 Singleton<IActivityManager> 類型的Class<?> singletonClass = null;try {singletonClass = Class.forName("android.util.Singleton");} catch (ClassNotFoundException e) {e.printStackTrace();}// 反射獲取 Singleton 類中的 mInstance 字段Field mInstanceField = null;try {mInstanceField = singletonClass.getDeclaredField("mInstance");// 設置字段的可訪問性mInstanceField.setAccessible(true);} catch (NoSuchFieldException e) {e.printStackTrace();}// 反射獲取 Singleton 類中的 mInstance 成員對象// 該 mInstanceObject 成員對象就是 IActivityManager// private static final Singleton<IActivityManager> IActivityManagerSingletonObject mInstanceObject = null;try {mInstanceObject = mInstanceField.get(iActivityManagerSingletonObject);} catch (IllegalAccessException e) {e.printStackTrace();}// 使用動態代理 , 替換 android.app.ActivityManager 中的// private static final Singleton<IActivityManager> IActivityManagerSingleton 成員的// mInstance 成員// 注意 : 該操作一定要在 AMS 啟動之前將原來的 Intent 替換掉// 之后還要替換回去// 使用 Intent 啟動插件包時 , 一般都使用隱式啟動// 調用 Intent 的 setComponent , 通過包名和類名創建 Component ,// 這樣操作 , 即使沒有獲得 Activity 引用 , 也不會報錯// 該插件包中的 Activity 沒有在 "宿主" 應用中注冊 , 因此啟動報錯// AMS 會干掉沒有注冊過的 Activity// 這里先在啟動 AMS 之前 , 設置一個已經 注冊過的 占坑 Activity ( StubActivity ) 執行啟動流程// 在主線程生成 Activity 實例對象時 , 還需要恢復插件包中的 Activity// IActivityManager 是接口// 這是一個 AIDL 文件生成的 , 由 IActivityManager.aidl 生成Class<?> IActivityManagerInterface = null;try {IActivityManagerInterface = Class.forName("android.app.IActivityManager");} catch (ClassNotFoundException e) {e.printStackTrace();}// 動態代理的實際代理類AmsInvocationHandler amsInvocationHandler =new AmsInvocationHandler(context, mInstanceObject);// 動態代理過程Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), // 類加載器new Class[]{IActivityManagerInterface}, // 接口amsInvocationHandler); // 代理的對象// 使用動態代理類 , 替換原來的 ActivityManager 中的 IActivityManagerSingleton 成員// 的 Singleton 類中的 mInstance 成員try {mInstanceField.set(iActivityManagerSingletonObject, proxy);} catch (IllegalAccessException e) {e.printStackTrace();}}}
六、博客資源
博客資源 :
- GitHub : https://github.com/han1202012/Plugin_Hook
總結
以上是生活随笔為你收集整理的【Android 插件化】Hook 插件化框架 ( Hook Activity 启动流程 | AMS 启动前使用动态代理替换掉插件 Activity 类 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 插件化】Hook 插件
- 下一篇: 【Android 插件化】Hook 插件