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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 中,可以使用 ActivityManager 监听 Activity启动情况,并在需要的时候拦截某个 Activity启动。具体步骤如下: 1. 在 AndroidManifest.xml 中注册一个监听器服务。 ```xml <service android:name=".MyService"> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> </service> ``` 2. 创建一个 Service 类,并在其中实现一个继承自 Binder 的内部类 MyBinder。 ```java public class MyService extends Service { private MyBinder binder = new MyBinder(); public class MyBinder extends Binder { public void intercept(String packageName, String activityName) { // 在这里实现拦截逻辑 } } @Nullable @Override public IBinder onBind(Intent intent) { return binder; } } ``` 3. 在 MyBinder 的 intercept 方法中,通过 ActivityManager 监听 Activity启动情况,并在需要的时候拦截某个 Activity启动。 ```java public void intercept(String packageName, String activityName) { final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); activityManager.addOnBackStackChangedListener(new ActivityManager.OnBackStackChangedListener() { @Override public void onBackStackChanged() { String currentPackageName = ""; String currentActivityName = ""; if (activityManager.getRunningTasks(1).size() > 0) { ComponentName componentName = activityManager.getRunningTasks(1).get(0).topActivity; currentPackageName = componentName.getPackageName(); currentActivityName = componentName.getClassName(); } if (currentPackageName.equals(packageName) && currentActivityName.equals(activityName)) { // 拦截逻辑 } } }); } ``` 注意,为了保证拦截的准确性,需要在拦截逻辑中判断当前启动Activity 是否是需要拦截Activity。在上面的代码中,通过比较包名和类名的方式来判断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值