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

使用动态代理拦截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替换掉了。

猜你喜欢

转载自blog.csdn.net/u013648164/article/details/74909404