当前位置 : 主页 > 手机开发 > android >

从零开始使用gradle配置即可执行的Hook库详解

来源:互联网 收集:自由互联 发布时间:2023-02-01
目录 背景 本文须知 当前技术背景 底层选择 目标流程图 Transform ASM 封装开始 目标 实现 gradle 定义extension Transform阶段收集信息: 自定义的classvisitor 自定义method visitor 自定义hook操作 总
目录
  • 背景
    • 本文须知
    • 当前技术背景
    • 底层选择
    • 目标流程图
  • Transform
    • ASM
      • 封装开始
        • 目标
        • 实现
          • gradle 定义extension
          • Transform阶段收集信息:
          • 自定义的classvisitor
          • 自定义method visitor
          • 自定义hook操作
      • 总结

        背景

        有一天,老板突然找到小B说,隐私合规需要我们获取权限前,需要明确授权来意,这个你来跟一下吧!小B此时就可愁了,因为项目权限那么多,每个自己手动加上授权来意提示的话,可能会漏掉很多,工作量也大,这可咋办呀!老B看到小B这么愁眉苦脸,连忙说:“可以用ASM进行插桩呀!hook想要的方法”,小B听了,兴奋的去百度了一下,但是发现asm学习成本又高,短期又不可能搞完,这可咋办呀!明明我只想搞hook一个方法交差来着!!老B:”没事,所以本文就来了!”

        本文须知

        这里只是提供一个设计思路,不会涉及到太多细节,需要读者了解相关的知识,如果不清楚只想使用的话,也是有的 github.com/TestPlanB/S… 欢迎点星星或者pr噢!

        当前技术背景

        目前可以利用字节码进行hook的框架有很多,比如ASM,AspectJ,javassit等等,都是可以在编译时插入相关的字节码,进行方法的插桩,从而达到一个hook的目的,但是这些工具好归好,但是都有一个小问题,就是需要上手,部分hook框架上手门槛高,也有自己独特的用法,短时间内可能很难使得开发人员上手。所以对hook库进行一个二次封装,也是很多公司在做的一个事情。方法有很多种,作者基于自己的理解,认为配置式的hook才是最简单的,毕竟,Android就有gradle进行各种的项目工程配置,那么我们为什么就不能通过gradle进行配置的Hook呢?基于上面的猜想,就有了本文!友情提示:阅读本文最好对asm跟transform机制有所了解

        底层选择

        为了更加通用和高效,本次采用asm作为底层,进行二次封装,毕竟android官方的link还有比较出色的aspectj都是基于asm进行底层修改的,那我们这次也同样使用,好了就开干!

        目标流程图

        Transform

        为了让不太了解的ASM的也能够阅读本文,所以也会介绍部分ASM相关的信息,详细了解还需要大家去官网阅读噢!这里先介绍Transform机制。 Transform是android 进行编译时,在class 文件生成 dex文件时,给我们开发者预留的一个小口,可以理解在这个阶段,我们可以修改已生成的class等文件,编织入自己额外的字节码,从而达到无需修改项目本身的源代码就可以行为修改的机制!如果大家有留意的话,这个机制就是gradle 在build阶段中,会存在一个transformClassesWithXXForXX的task,举例子:

        transformClassesWithSpiderPluginForDebug,就是在这里进行的transform修改。 当然,一个项目会存在多个transform,如图所示

        就像流水线一样,我们的transform处理完就会交给下一个transform,共同修改生成的字节码的行为。大家可以先简单理解为这是一个任务,提供了接口给外部修改生成字节码的机会,具体我们可以google相关的资料,也可以看下最后例子项目的处理

        ASM

        ASM是一个字节码修改框架,他就在我们上文提到的Transform里面做了文章。关于ASM的介绍我们简单来几下,有个大概的认知就好,就像我们访问一个方法/属性一样,jvm肯定是先加载类,然后在执行方法或者属性的方法,ASM的运行机制就如图一样

        封装开始

        目标

        我们的目标是建立一个基于gradle配置即可运行的hook库,先从使用角度考虑,如果我想hook一个类是LogUtils,中的test方法的话,需要哪些参数呢?快动一下你聪明的小脑袋,emmm,比如类的名称需要吧!方法名称!还有捏!只靠这两个明显还不够,因为我们还存在着各种重载不是嘛,那怎么表示一个特定方法呢!没错,还有函数签名对吧!毕竟编译器底层就是靠着函数签名去识别某个方法的呀,还有嘛?找到这个方法后,我们是在方法前/方法本身/方法后 进行自定义修改呢?所以就还需要一个类似于模式一样的东西吧!这里就称为hook模式好了,还有嘛?找到这个方法,我们还需要自己自定义的操作吧!就定义为hook操作吧。 总结起来,我们需要hook模式,类的名称,方法名称,函数签名,hook操作就可以完成一次hook某个方法的需求了对吧,就比如以下代码所示

        比如hook LogUtils类的test方法,签名是()V,
        替换为调用LogTest类的一个静态方法test
        hookMethod hookMode.Default(hook模式), 
        "com/example/spider/LogUtils"(类的名称), 
        "test"(方法名称), "()V"(函数签名), { MethodVisitor mv ->
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, 
            "com/example/spider/LogTest", "test", "()V", false)
        }(hook操作)
         

        实现

        为了使只要通过上面的代码就能实现hook操作,我们需要定义: asm相关的:自定义的classvisitor,methodvisitor gradle:extension参数,比如上面的“hookMethod”,用来标记我们需要哪部分进行hook操作 transform:标准transform写法。

        gradle 定义extension

        我们按照上面思路,是不是需要定义一个类,包含hook模式,类的名称,方法名称,函数签名,hook操作,才能将参数传给transform,从而执行自己的ASM操作。 所以就需要定义extension参数: 我们可以在定义plugin的时候,在apply阶段通过project.extensions.create,创建一个自己的配置格式参数,比如Hook.class里面就有我们的参数

        project.extensions.create("hook"(标识名称), Hook.class)
        

        使用的话就可以在任意gradle文件使用

        hook{
          参数1 对象值
          参数2 对象值
        }

        这样的话,我们只需要在Transform阶段收集到配置信息传给ASM即可!。

        Transform阶段收集信息:

        gradle声明的信息我们都可以通过project.xx(标识名称)获取

        比如

        hook.methodHooker = project.hook,就拿到了一个属于Hook类的hook对象
        后续通过hook.hook模式就可以拿到属性是hook模式的参数了

        自定义的classvisitor

        我们transform阶段会遍历所有的类,但是我们只需要对特定的类进行修改对不对,所以在这里,我们需要针对只需对gradle配置的类,比如例子中的LogUtils进行处理即可,而不需要动刀其他的类! transform进行时,调用classvisitor就会调用其visit方法,我们在这里识别出我们需要hook的类即可对不对,加入我们需要hook的东西都在 hook.hookMethodList里面,我们只需要遍历一遍,找到需要的类,然后打上一个标记

        @Override
        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
            super.visit(version, access, name, signature, superName, interfaces);
           for(遍历hookMethodList里面){
            if 如果配置的类 == name{
                标记就为true
            }
            }
        }
        

        调用visit方法后,就代表了这个类被访问过了,就会调用其visitmethod方法,如果标记有效,我们就采用自定义的method visitor进行方法的修改,否则就还是原本的method visitor

        @Override
        public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
            MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
            if (标记不为true) {
                return mv;
            }
            进行我们自定义的method visitor操作
            }
            return mv;
        }
        

        自定义method visitor

        如果class是我们需要hook的class,就会走到了自定义的method visitor,这里是ASM的定义

        @Override
        public void visitCode() {
            if hook模式是方法前{
             hook 行为执行
             }
            super.visitCode();
        }
        @Override
        public void visitMethodInsn(int opcode, String owner, String methodName, String descriptor, boolean isInterface) {
        if hook模式是方法本身{
             hook 行为执行
             }
            super.visitMethodInsn(opcode, owner, methodName, descriptor, isInterface);
        }
        @Override
        public void visitInsn(int opcode) {
            if (opcode == Opcodes.ATHROW || (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)) {
             if hook模式是方法后{
             hook 行为执行
             }
            }
            super.visitInsn(opcode);
        }
        

        自定义hook操作

        在配置阶段,一个hook操作就可以抽象为Closure,如果用groovy语法就是Closure,如果是Kotlin就是一个函数,代表要进行的操作。 在Transform阶段我们就可以织入自定义的closure,等满足条件就触发。幸运的是,ASM本身就提供了一个为AndroidStudio,准备的插件,叫“ASM Bytecode viewer”,通过这个插件,我们可以直接生成想要的插入代码所对应的ASM编码,如图:

        通过closure所传递的methodvisitor,我们就可以执行配置的hook操作了。值得注意一点是,Spider不重新定义hook规则,而是在ASM基础上,封装比较容易编译错误的点,比如Transform编写,visitor类的编写等等,便于实现我们自己的hook规格,而脱离框架本身,这点是需要运用Spider的开发者需要注意的点!

        总结

        因为ASM体系有很多细节,文章是没办法列举出所有细节,所以只能表露一个设计思路,具体的用法大家可以移步github.com/TestPlanB/S… 上面也是Spider的设计思路,具体用法也可以看Readme噢!

        以上就是从零开始使用gradle配置即可执行的Hook库详解的详细内容,更多关于gradle配置可执行Hook库的资料请关注自由互联其它相关文章!

        网友评论