通过了解activity启动流程,我们知道当调用startActivity后,会通过ipc和ActivityManagerService服务
进行通信,然后做任务栈管理,包的解析等等工作,最终调用ActivityThread中的scheduleLaunchActivity方法
来启动新的activity。
了解这一基本知识后,我来练习一个小demo: 拦截ActivityManagerService 和 系统Handler ,加载一个没有注册的activity.
为什么拦截ActivityManagerService呢?
因为在自己的app进程中只能拦截我们自己的 ActivityManagerService 对象。(aidl对象),无法跨进程拦截
别的服务的对象。
hook 流程:
一、先hook 我们进程中的IActivityManager 对象。(aidl对象),用动态代理模式来代理出这个对象。
二、由于activity没有注册 是不能通过包管理器服务 检验的,所以 我们要找一个合格的activity来替换。
因此 需要拦截startActivity方法,并修改意图。改为一个合格的activity意图。(ProxyIntent)
三、 在ProxyIntent 中 携带我们真正要启动的activity 意图。(无法通过包管理器检验的意图)
四、通过管理器检验后将代理意图(ProxyIntent)替换回来 我们需要的意图。
这一步需要拦截系统Handler,在系统handler启动activity之前替换意图。
代码如下:
先拦截ActivityManagerService
/**
* 通过源码 得知当调用startActivity后 最终调用到AMS的startActivity.
* 我们这里来拦截AMS 对象。(并修改intent)
*/
public void hookActivityManagerService() {
//instumentation --execStartActivity
//ActivityManagerNative.getDefault().startActivity
//getDefault() :
// private static final Singleton<IActivityManager> gDefault
// = new Singleton<IActivityManager>()
//第一步 :通过反射拿到AMS对象
try {
Class amNativeClazz = Class.forName("android.app.ActivityManagerNative");
//拿到单例对象
Field field = amNativeClazz.getDeclaredField("gDefault");
field.setAccessible(true);
Object singletonObj = field.get(null);
//通过单例对象 拿到AMS对象
//ams 对象是个普通成员,所以必须通过单例对象来获得。
Class singletonClazz = Class.forName("android.util.Singleton");
Method getMethod = singletonClazz.getDeclaredMethod("get");
//最后获得 ams 对象
Object amsObj = getMethod.invoke(singletonObj);
// 第二部:拦截 ams对象,(用代理对象替换原来对象)这里用动态代理来实现。
// 使用一个代理对象来包装ams对象。
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//真实对象实现的接口 的 Class
Class interfaceClass = Class.forName("android.app.IActivityManager");
// 生成我们的代理对象
//
MyInvoketionHandler myHandler = new MyInvoketionHandler(amsObj);
Object proxyObj = Proxy.newProxyInstance(classLoader, new Class[]{interfaceClass}, myHandler);
//用代理对象替换原来对象
Field fInstance = singletonClazz.getDeclaredField("mInstance");
fInstance.setAccessible(true);
//替换singleton的instance对象
fInstance.set(singletonObj, proxyObj);
} catch (Exception e) {
e.printStackTrace();
}
}
class MyInvoketionHandler implements InvocationHandler {
//真正的ams对象
Object realAmsObj;
public MyInvoketionHandler(Object realAmsObj) {
this.realAmsObj = realAmsObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 拦截我们要拦截的方法
String methodName = method.getName();
//拦截startActivity方法 替换一个假的 意图,用来通过包管理器 检查。
if (methodName.contains("startActivity")) {
int len = args.length;
// 查找startActivity 的参数
for (int i = 0; i < len; i++) {
Object argsi = args[i];
if (argsi instanceof Intent) {
// 原来的意图 : 不合法的,因为没有注册此activity
Intent intent = (Intent) argsi;
ComponentName name = intent.getComponent();
// 创建新的假的意图
Intent newIntent = new Intent();
ComponentName newComponentName = new ComponentName(context, proxyActivityClazz);
// setClass 也可以
newIntent.setComponent(newComponentName);
// 用假的意图装载原来真的意图
newIntent.putExtra(TAG, intent);
// 替换真实意图
args[i] = newIntent;
return method.invoke(realAmsObj, args);
}
}
}
return method.invoke(realAmsObj, args);
}
}
然后拦截系统Handler
/**
* 包管理服务 验证完后 通过Activity中的handler 来发送启动新 activity 的消息。
* 那么就在这里 把原来代理意图 再次替换回来 ,就完成了 不用清单注册 的功能。
*/
public void hookSysHandler() {
// 从源码可以得知 ActivityThread 是单例的
//private static volatile ActivityThread sCurrentActivityThread;
// 系统的handler :负责启动activity,service 等等。
//final H mH = new H();
try {
Class activityThreadClass = Class.forName("android.app.ActivityThread");
//系统handler 对象
Field handlerField = activityThreadClass.getDeclaredField("mH");
//ActivityThread 对象
Field activityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
activityThreadField.setAccessible(true);
handlerField.setAccessible(true);
Object activityThreadInstance = activityThreadField.get(null);
Handler sysHandlerInstance = (Handler) handlerField.get(activityThreadInstance);
// 通过了解handler 消息的回调机制,我们让handler先回调我们的callback
// 然后再 回调handler 的 handMessage 方法。
Field callBackField = Handler.class.getDeclaredField("mCallback");
callBackField.setAccessible(true);
// 通过了解handler源码 ,知道handler的回调机制后,我们这里来拦截 handler的回调
// 回调完成后 再 回调原来的handMessage
// 替换系统的Handler (相当于hook 系统handler)
callBackField.set(sysHandlerInstance, new MyCallBack(sysHandlerInstance));//拦截 handler的回调
} catch (Exception e) {
e.printStackTrace();
}
}
// 定义我们自己的handler回调
class MyCallBack implements Handler.Callback {
// 系统的handler
private Handler realHandler;
public MyCallBack(Handler realHandler) {
this.realHandler = realHandler;
}
@Override
public boolean handleMessage(Message msg) {
int what = msg.what;
// 在这里将意图 替换回来。
if (what == LAUNCH_ACTIVITY) {
//msg.obj 就是ActivityClientRecord
// 而就是ActivityClientRecord中就包含intent,
try {
Field intentField = msg.obj.getClass().getDeclaredField("intent");
intentField.setAccessible(true);
Object activityClientRecord = msg.obj;
Intent proxyIntent = (Intent) intentField.get(activityClientRecord);
Intent realIntent = proxyIntent.getParcelableExtra(TAG);
if (realIntent != null) {
proxyIntent.setComponent(realIntent.getComponent());
}
//intentField.set(activityClientRecord,);
} catch (Exception e) {
e.printStackTrace();
}
}
realHandler.handleMessage(msg);
return true;
}
}
app启动后,在Application 中拦截。
MyApplication extends Application
oncreate:
HookUtil hookUtil = new HookUtil(this, ProxyActivity.class);
hookUtil.hookActivityManagerService();
hookUtil.hookSysHandler();