美文网首页
拦截Activity的启动流程绕过AndroidManifest

拦截Activity的启动流程绕过AndroidManifest

作者: Peakmain | 来源:发表于2019-02-27 12:56 被阅读0次

若对Activity的启动流程不熟悉的可以看我这篇文章App启动——Activity的启动流程

首先看一般的activity的启动流程

一般的activity的启动流程.png

我们要进行拦截activity,AMS中进行HOOK这个是不可能的因为它还管理其他APP呢,所以我们可以对第一步和最后一步进行Activity的拦截,如何拦截,看下面这个图


image.png

在第一步启动ActivityB的时候进行拦截

我们都知道Activity和AMS进行通信是通过AMN/AMP,我们在AMN中可以看到这行代码

   private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

IActivityManger中有这行代码

public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
            ProfilerInfo profilerInfo, Bundle options) throws RemoteException;

因此我们实际上可以对IActivityManger中的startActivity方法进行拦截,把第二个参数intent换成我们安全的intent,再用代理对象将原本的IActivityManager整体进行替换(代码有足够的解释,不再阐述)

private Context mContext;
    private Class<?> mProxyClass;
    //保留原始intent
    private final String EXTRA_ORIGIN_INTENT = "EXTRA_ORIGIN_INTENT";
    public HookStartActivityUtil(Context context, Class<?> proxyClass) {
        this.mContext = context.getApplicationContext();
        this.mProxyClass = proxyClass;
    }
    public void hookStartActivity() throws Exception {
        //1.首先获取到ActivityManagerNative中的gDefault属性
        Class<?> amnClazz = Class.forName("android.app.ActivityManagerNative");
        //获取属性
        Field gDefaultField = amnClazz.getDeclaredField("gDefault");
        //获取权限
        gDefaultField.setAccessible(true);
        //获取值
        Object gDefault = gDefaultField.get(null);
        //2.获取gDefault中的mInstance属性
        //因为gDefault实际是android.util.Singleton属性,而我们实际的目的是替换它里面的泛型也就是mInstance
        Class<?> singletonClazz = Class.forName("android.util.Singleton");
        //获取属性
        Field mInstanceField = singletonClazz.getDeclaredField("mInstance");
        //获取属性
        mInstanceField.setAccessible(true);
        //获取mInstance值
        Object mInstance = mInstanceField.get(gDefault);

        //获得里面的值之后就开始替换了,要替换的泛型mInstance实际上是IActivityManager,看gDefault的源码,用代理对象去替换
        //首先创建一个IActivityManager对象
        Class<?> iamClazz = Class.forName("android.app.IActivityManager");
       mInstance = Proxy.newProxyInstance(HookStartActivityUtil.class.getClassLoader(),
                new Class[]{iamClazz},
                new StartActivityInvocationHandler(mInstance));
        //3.重新指定
        mInstanceField.set(gDefault,mInstance);
    }

    private class StartActivityInvocationHandler implements InvocationHandler {
        // 方法执行者
        private Object mObject;

        public StartActivityInvocationHandler(Object object) {
            this.mObject = object;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Log.e("TAG",method.getName());

            if(method.getName().equals("startActivity")){
                //1.首先要获取原来的intent
                Intent originIntent  = (Intent) args[2];
                //2.创建一个安全的intern
                Intent safeIntent=new Intent(mContext,mProxyClass);
                //偷梁换柱
                args[2]=safeIntent;
                //保存原始的的originIntent,最后一步的时候需要设置回去
                safeIntent.putExtra(EXTRA_ORIGIN_INTENT, originIntent);
            }
            return method.invoke(mObject,args);
        }
    }

现在将最后一步代理的activity换成原本的

我们都知道最后实际是mH发送一个LAUNCH_ACTIVITY(值为100)消息,并将含有intent的记录ActivityClientRecord发送过去,思路就是在发送消息之前也就是mCallback重写msg.what=100的消息将值intent重新赋值过去

 public void hookLaunchActivity() throws Exception {
        //1 获取ActivityThread实例
        Class<?> atClass = Class.forName("android.app.ActivityThread");
        Field scatField = atClass.getDeclaredField("sCurrentActivityThread");
        scatField.setAccessible(true);
        //获取值
        Object sCurrentActivityThread = scatField.get(null);
        //2.获取ActivityThread中的mH
        Field mhField  = atClass.getDeclaredField("mH");
        mhField.setAccessible(true);
        Handler mHandler = (Handler) mhField.get(sCurrentActivityThread);
        // 设置Callback
    /*    Field callBackField = Handler.class.getDeclaredField("mCallback");
        callBackField.setAccessible(true);*/
        Class<?> handlerClass = Class.forName("android.os.Handler");
        Field mCallbackField = handlerClass.getDeclaredField("mCallback");
        mCallbackField.setAccessible(true);
        mCallbackField.set(mHandler,new ActivityThreadHandlerCallBack());
    }

    private class ActivityThreadHandlerCallBack implements Handler.Callback{
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what==100){
                handleLaunchActivity(msg);
            }
            return false;
        }
    }

    private void handleLaunchActivity(Message msg) {
        try {
            Object obj = msg.obj;
            Field intentField = obj.getClass().getDeclaredField("intent");
            intentField.setAccessible(true);
            Intent proxyIntent = (Intent) intentField.get(obj);
            //获得原始的intent
            Intent originIntent = proxyIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT);
            //设置回去
            if(originIntent!=null){
                intentField.set(obj,originIntent);
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

兼容AppCompatActivity

上面代码在activity中是完美运行的,但是在AppCompatActivity中老是报错。修改handleLaunchActivity代码

   private void handleLaunchActivity(Message msg) {
            try {
                Object record = msg.obj;
                // 1.从record 获取过安检的Intent
                Field intentField = record.getClass().getDeclaredField("intent");
                intentField.setAccessible(true);
                Intent safeIntent = (Intent) intentField.get(record);
                // 2.从safeIntent中获取原来的originIntent
                Intent originIntent = safeIntent.getParcelableExtra(EXTRA_ORIGIN_INTENT);
                // 3.重新设置回去
                if (originIntent != null) {
                    intentField.set(record, originIntent);
                }
                // 兼容AppCompatActivity报错问题
                Class<?> forName = Class.forName("android.app.ActivityThread");
                Field field = forName.getDeclaredField("sCurrentActivityThread");
                field.setAccessible(true);
                Object activityThread = field.get(null);
                // 我自己执行一次那么就会创建PackageManager,系统再获取的时候就是下面的iPackageManager
                Method getPackageManager = activityThread.getClass().getDeclaredMethod("getPackageManager");
                Object iPackageManager = getPackageManager.invoke(activityThread);
                PackageManagerHandler handler = new PackageManagerHandler(iPackageManager);

                Class<?> iPackageManagerIntercept = Class.forName("android.content.pm.IPackageManager");
                Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                        new Class<?>[]{iPackageManagerIntercept}, handler);

                // 获取 sPackageManager 属性
                Field iPackageManagerField = activityThread.getClass().getDeclaredField("sPackageManager");
                iPackageManagerField.setAccessible(true);
                iPackageManagerField.set(activityThread, proxy);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    class PackageManagerHandler implements InvocationHandler {

        private Object mActivityManagerObject;

        public PackageManagerHandler(Object iActivityManagerObject) {
            this.mActivityManagerObject = iActivityManagerObject;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().startsWith("getActivityInfo")) {
                ComponentName componentName = new ComponentName(mContext, mProxyClass);
                args[0] = componentName;
            }
            return method.invoke(mActivityManagerObject, args);
        }
    }

相关文章

网友评论

      本文标题:拦截Activity的启动流程绕过AndroidManifest

      本文链接:https://www.haomeiwen.com/subject/ijqxuqtx.html