使用动态代理拦截Android Activity的启动
1.动态代理拦截的要求
- 要代理的类要实现接口
- 要能获取目标类的对象
2.对startActivity进行拦截
activity的启动过程通过分析源码知道了实际内部调用了ActivityManagerNative.getDefault()
这个方法,而getDefault这个方法内部是
.startActivity
static public IActivityManager getDefault() {
return gDefault.get();
}
这个gDefault是一个静态常量Singleton。
所以关键就是通过反射获取到gDefault然后拦截它的startactivity方法。
ActivityManagerNative是一个继承了Binder的类,还实现了IActivityManager这个接口.相当于AIDL中系统生成的Stub类。然后ActivityManagerNative是一个抽象类,它的实现类是ActivityManagerService。
ActivityManagerNative内部还有一个类,ActivityManagerProxy,这个类就是这个Binder的远端代理类。我们要拦截的就是这个ActivityManagerProxy对象的startActivity方法。
public static void hookAms() {
try {
Class<?> activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
gDefaultField.setAccessible(true);
Object gDefault = gDefaultField.get(null);
Class<?> singleton = Class.forName("android.util.Singleton");
Field mInstanceField = singleton.getDeclaredField("mInstance");
mInstanceField.setAccessible(true);
Object rawIActivityManager = mInstanceField.get(gDefault);
Class<?> iActivityManager = Class.forName("android.app.IActivityManager");
Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{iActivityManager}
,new AmsHookBinderInvocationHanlder(rawIActivityManager));
mInstanceField.set(gDefault,proxy);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
然后在我们的InvocationHandler中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("startActivity".equals(method.getName())){
Intent raw;
int index = 0;
for(int i=0;i< args.length;i++){
if(args[i] instanceof Intent){
index = i;
break;
}
}
raw = (Intent) args[index];
Intent newIntent = new Intent();
String targetPackage = "com.github";
ComponentName componentName = new ComponentName(targetPackage, FileInterSendActivity.class.getName());
newIntent.setComponent(componentName);
newIntent.putExtra("_tartget_intent",raw);
Log.d("hook",Thread.currentThread().getName());
Log.d("hook","拦截activity的启动成功"+"\n" +
"component:"+((Intent)args[2]).getComponent().getPackageName()+","+((Intent)args[2]).getComponent().getClassName());
args[index] = newIntent;
Log.d("hook","change activity component successful"+"\n" +
"component:"+((Intent)args[2]).getComponent().getPackageName()+","+((Intent)args[2]).getComponent().getClassName());
return method.invoke(obj,args);
}
return method.invoke(obj, args);
}
运行项目,会发现我们成功的将想要启动的activity替换掉了。