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 替换掉 ;
代码语言:javascript复制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 成员 ;
代码语言:javascript复制public class ActivityManager {
/**
* @hide
*/
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected 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 类是单例的实现 , 注意该类只能由系统使用 , 应用开发者不能调用 ;
代码语言:javascript复制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 参数 ;
代码语言:javascript复制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
*/
@Override
public 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];
// 方法参数类型是 Intent
if(arg instanceof Intent){
// 将原来的传入的 Intent 参数 , 改成自己的 Intent , 启动自己的类
intent = (Intent) arg;
// 新的 Intent , 用于替换原有的 Intent
Intent 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 接口 ;
代码语言:javascript复制// IActivityManager 是接口
// 这是一个 AIDL 文件生成的 , 由 IActivityManager.aidl 生成
Class<?> IActivityManagerInterface = null;
try {
IActivityManagerInterface = Class.forName("android.app.IActivityManager");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
2、动态代理
创建 InvocationHandler 对象 ;
然后创建动态代理对象 ;
代码语言:javascript复制// 动态代理的实际代理类
AmsInvocationHandler amsInvocationHandler =
new AmsInvocationHandler(context, mInstanceObject);
// 动态代理过程
Object proxy = Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(), // 类加载器
new Class[]{IActivityManagerInterface}, // 接口
amsInvocationHandler); // 代理的对象
3、替换 mInstance 成员
使用动态代理类 , 替换原来的 ActivityManager 中的 IActivityManagerSingleton 成员 的 Singleton 类中的 mInstance 成员 ;
代码语言:javascript复制// 使用动态代理类 , 替换原来的 ActivityManager 中的 IActivityManagerSingleton 成员
// 的 Singleton 类中的 mInstance 成员
try {
mInstanceField.set(iActivityManagerSingletonObject, proxy);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
4、代码示例
完整代码示例 :
代码语言:javascript复制// 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();
}
五、完整代码
代码语言:javascript复制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> IActivityManagerSingleton
Object 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