美文网首页
Hook技术实现大型集中式登录框架

Hook技术实现大型集中式登录框架

作者: Laughing_G | 来源:发表于2019-08-25 16:31 被阅读0次

    前言:类似于京东、淘宝等大型app,不需要账号登录,也能浏览商品,但是等你需要加入购物车或者开始购买时候,就需要跳转到登录界面,实现这个需求,可以用AOP来实现,也可以用Hook技术实现,这篇文章讲的是通过Hook技术来实现登录架构。

    一、什么是Hook?

    Hook技术也称为钩子函数,钩子函数实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。在系统没有调用该函数之前,钩子程序就先捕获该消息,这样钩子函数先得到控制权,这时钩子函数既可以加工处理(改变)该函数的执行行为,还可以强制结束消息的传递。

    二、Hook技术(java层面)实现途径

    第一:找到Hook点;(这一点是最难的,是寻找方法的过程)
    第二:找到Hook方法,然后插入我们执行前的代码和执行后的代码;
    第三:将Hook方法放到系统之外执行。
    备注:实现Hook技术,可以分两个层面,一个是java层,就是通过反射,另一个是ndk层,比如andfix、xPos等,直接找到java对象来操作。

    三、Hook技术在java层有个前提条件

    找到的对象,一定要是静态的,原因是反射获取的实例对象一定要和内部方法有关联,假如不是静态的反射之后就不是同一个对象了

    四、Hook技术实现登录流程说明

    写在前面:登录架构需要劫持Android系统中的AMS.
    打开Activity的源码,找到startActivity的方法,发现它内部的核心方法是:
    ActivityServiceNative.getDefault().startActivity();
    此时要将这个核心方法拆分为两个部分:1.ActivityServiceNative.getDefault;2.startActivity


    image.png

    步骤一、找到了Hook点是ActivityServiceNative.getDefault,首先我们要还原getDefault的成员变量


    image.png

    这一步我们得到了IActivityManager,接下来要在塔调用的startActivity方法之前和之后插入我们自己的业务逻辑,那么这一点就是相当于把系统的startActivity拉到我们自己的代码来执行,那么此刻对于Java层有两种实现方法:1.动态代理;2.设置接口。
    考虑到IActivityManager本身就是一个接口,同时系统也没有提供额外的接口给我们,所以这里使用动态代理的方法。
    代理设计模式:可以粗俗的理解为创造一个假的孙悟空,来代替真的孙悟空,Proxy.newProxyInstance(),该方法三个参数,在下图中有注释说明:

    image.png
    image.png

    好了,做到这一步,然后再MainActivity中执行startActivity的代码,发现InvocationHandler中的invoke两行日志可以答应出来,证明我们已经对startActivity成功Hook。

    步骤二、接下来,新建一个ProxyActivity,我们可以先做这样一个测试,就是MainActivity执行startActivity方法跳转到SecondActivity,然后我们在invoke方法中,进行一次"瞒天过海"的骚操作,就是让它跳转到ProxyActivity!如图所示:

    image.png
    步骤三、完成了步骤一和步骤二,就完成了startActivity的hook,但是只是完成了一半,因为通过观察ActivityThread源码发现,拉起一个Activity的核心方法是在ActivityThread的内部类Handler,在收到消息为100之后,执行LaunchActivity方法。所以我们接下来还要进行第二个Hook点,就是找到Handler的handlerMessage方法,通过源码可知,ActivityThread的内部类H不是静态的,那我们就找ActivityThread的本身有没有静态的对象(这里衍生个问题,如果ActivityThread本身也没有静态的对象,我们该怎么办?那只有往上一步看看哪些上层的类持有ActivityThread的静态对象),幸运的是ActivityThread类由一个静态的成员对象:sCurrentActivityThread
    image.png

    上图中的注释我写的很清楚了,这里通过设置接口的方式,来将handlerMessage拉到我们自己的代码里来执行,如下图所示:

    image.png

    写到这里我们就完成了简单的集中式登录架构,此刻我突然回想起在2019年8月份在oppo面试的一道题目,当时面试官问到:如何加载一个未注册的Activity?它是怎么绕过系统AMS的检查?这里我再次做一个总结性的回答:
    1.Activity的跳转入口对于Android层面来说是startActivity方法,我们在执行startActivity方法时候,必须要传入Intent这个意图,这个Intent就包含有要跳转的页面信息,可以是显示的也可以是隐试的,对于集中式登录框架来讲,就必须要hook抓住系统的startActivity方法,然后通过动态代理的方式,重写InvocationHandler的invoke方法,将传递过来的Intent,转换为一个注册过的ProxyActivity,这里就是和阿里插件的插桩式类似,然后将真实的意图通过键值对的方式保存到新的Intent中,这里就然后了AMS的检查;
    2.因为拉起一个Activity,核心方法是在ActivityThread类中的Handler类,当接收到LAUNCH_ACTIVITY(100)这个消息后,执行LaunchActivity这个方法,所以我们还要Hook住Handler的HandlerMessage这个方法,因为Handler本身已经提供了Callback这个接口,所以我们可以通过设置接口的方式,将HandlerMessage这个方法拉到自己的业务代码中来,重新对Intent进行还原。
    所以回到到以上两点,应该就能把这个面试问题解释清楚。
    Demo地址:
    https://github.com/cWX411904/HookPlugin

    相关文章

      网友评论

          本文标题:Hook技术实现大型集中式登录框架

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