Android高级进阶之-Hook技术实现页面跳转权限验证,绕过manifest需要注册Activity

java中的Hook技术简单来说就是利用反射,去替换某些对象的某些属性,我们可以对属性进行修改,增加我们想要执行的业务逻辑。举个栗子:ActivityThread内部持有一个Handler sMainThreadHandler ,Android的事件驱动都会回调到sMainThreadHandler.handleMessage()方法内进行处理,加入我们需要在what=100 也就是LAUNCH_ACTIVITY 这个事件被sMainThreadHandler处理之前进行拦截,修改一下intent,那么是不是可行呢?

了解Handler机制的都知道,Handler可以自身持有一个mCallback,并且所有的Message都是优先交给mCallback处理的。那么好了,我们就可以利用反射机制,给ActivityThread.sMainThreadHandler设置一个mCallback,然后再把msssage交给sMainThreadHandler处理,不就达到了我们想要的目的了。

是的,上述就是Hook技术的目的,只是手段仅是其一,后面我们会讲另外一种情景。下面上代码看看动态设置接口Hook是怎么实现的:

            Class forName = Class.forName("android.app.ActivityThread");
            Field sMainThreadHandlerField = forName.getDeclaredField("sMainThreadHandler");
            sMainThreadHandlerField.setAccessible(true);
            //hook点找到了
            final Handler sMainThreadHandler= (Handler) sMainThreadHandlerField.get(null);

            Field mCallbackField = Handler.class.getDeclaredField("mCallback");
            mCallbackField.setAccessible(true);
            mCallbackField.set(sMainThreadHandler, new Handler.Callback() {
                @Override
                public boolean handleMessage(Message msg) {
                    if (msg.what == 100) {
                        //这个事件为LAUNCH_ACTIVITY ,你可以参考系统源码改造这里的intent
                    }
                    sMainThreadHandler.handleMessage(msg);//最后交付该系统原有逻辑处理
                    return true;
                }

上述是反射补充接口的形式进行Hook,当然很多情况下没有预留接口给我们补充,这样的话就需要通过动态代理复制一份和原属性一模一样的对象,然后用新的替换旧的,新替换上的对象内部的方法被调用都会回调起Object invoke(Object proxy, Method method, Object[] args)方法,我们在invoke()中可以对参数动手脚,然后再交给原属性对象处理,这样也达到了Hook的目的。下面上代码:

            Class ActivityManagerClass;
            Field gDefaultField;
            if (Build.VERSION.SDK_INT >= 26) {
                ActivityManagerClass = Class.forName("android.app.ActivityManager");
                gDefaultField = ActivityManagerClass.getDeclaredField("IActivityManagerSingleton");
            } else {
                ActivityManagerClass = Class.forName("android.app.ActivityManagerNative");
                gDefaultField = ActivityManagerClass.getDeclaredField("gDefault");
            }
            gDefaultField.setAccessible(true);
            final Object IActivityManagerSingletonObject = gDefaultField.get(null);

            Class SingletonClass = Class.forName("android.util.Singleton");
            final Field mInstanceField = SingletonClass.getDeclaredField("mInstance");
            mInstanceField.setAccessible(true);
            final Object IActivityManagerObject = mInstanceField.get(IActivityManagerSingletonObject);//需要替换的原属性对象

            Class IActivityManagerIntercept = Class.forName("android.app.IActivityManager");

            //利用动态代理,准备新的属性对象
            final Object proxyInstance = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                    new Class[]{IActivityManagerIntercept}, new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            Log.i(TAG, "invoke: " + method.getName());
                            if (method.getName().equals("startActivity")) {
                                int index = 0;
                                for (int i = 0; i < args.length; i++) {
                                    Object arg = args[i];
                                    if (arg instanceof Intent) {
                                        index = i;
                                        break;
                                    }
                                }
                                Intent oldIntent = (Intent) args[index];
                                Intent newIntent = new Intent();
                                newIntent.putExtra("oldIntent", oldIntent);
                                newIntent.setComponent(new ComponentName(context, ProxyActivity.class));
                                args[index] = newIntent;
                            }
                            return method.invoke(IActivityManagerObject, args);//动态代理后再交付给原对象处理
                        }
                    });
            mInstanceField.set(IActivityManagerSingletonObject, proxyInstance);//反射,属性对象替换

讲到这里,Hook的两种方式都出来了:设置接口、动态代理。

Hook技术实现讲完了,下面进入两个示例,就是Activity页面跳转时需要登录态验证,以往的做法是startActivity之前执行判断逻辑,如果验证通过进入目标Activity,如果不通过把目标Activity保存在intent中,进入登录页面,登陆成功后取出原来的目标Activity,然后在进行跳转。

上面我们讲了Hook技术,那我们就可以把登录态验证的这一套逻辑直接通过Hook来实现了。比如我们看到系统startActivity是最终调用了IActivityManager.startActivity,OK,到了这里相信你知道怎么做了。

还有一个Activity绕过manifest注册验证的示例,我们可以在动态代理IActivityManager.startActivity时对Intent的目标Activity修改为manifest中已注册过的一个空Activity,把原目标Activity作为extra参数存入intent,然后在ActivityThread的Handler.mCallback时进行intent还原,就可以绕过系统manifest验证了,不过上述的目标Activity不支持基类为AppCompatActivity。

附上源码:
链接:https://share.weiyun.com/5u7ZwIC

你可能感兴趣的:(Android高级进阶之-Hook技术实现页面跳转权限验证,绕过manifest需要注册Activity)