使用动态代理拦截Android Activity的启动

xiaoxiao2021-02-27  134

使用动态代理拦截Android Activity的启动

1.动态代理拦截的要求

要代理的类要实现接口要能获取目标类的对象

2.对startActivity进行拦截

activity的启动过程通过分析源码知道了实际内部调用了ActivityManagerNative.getDefault() .startActivity这个方法,而getDefault这个方法内部是

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替换掉了。

转载请注明原文地址: https://www.6miu.com/read-16980.html

最新回复(0)