Skip to content

Latest commit

 

History

History
213 lines (180 loc) · 12.8 KB

README.md

File metadata and controls

213 lines (180 loc) · 12.8 KB

Build Status Download Gitter

HiBeaver

Java字节码修改神器HiBeaver:黑掉你的SDK

cute animals always busy in building their river dam

简介

HiBeaver是一个用于进行Java字节码插桩的Gradle插件,可以用来:

1.修改Jar文件内部的代码实现,注入逻辑(同时还支持对Android的aar文件进行修改)。

2.实现Java轻量级AOP设计,支持Android Gradle Plugin。

结合强大的Java ASM字节码修改工具和Gradle Transform API,HiBeaver可以实现在Android应用编译阶段,依据使用者的配置,对工程内所包含的Java字节码进行修改,从而支持使用者仅通过Gradle配置对字节码进行代码注入和AOP设计,或对项目依赖的Jar包内的代码增加Hook节点。

从1.2.7版本开始,HiBeaver不再依赖于Android编译插件,可以在Gradle环境下独立运行,随心所欲地修改Jar/Aar文件内的代码逻辑。

Beaver,即河狸,是一种日日忙碌于在自己栖息河流上修建和装修大坝的可爱小动物。河狸的堤坝虽说不上像三峡那样“高峡出平湖”,却也为自然和生态做出了暖男般的贡献。

快速上手

该插件已经上传到Jcenter,可直接引用最新版本如下:

classpath 'com.bryansharp:hibeaver:1.2.7'

在1.2.7及以上的版本中,hibeaverModifyFiles任务不再依赖Android的gradle插件,也就是说只要你有gradle和Java运行环境,建一个build.gradle就可以指定Jar/Aar文件进行修改了。详见testJarModify目录下的示例。

Link to Jcenter

然后在工程的build.gradle里加入如下片段(或通过其他.gradle引入):

    apply plugin: 'hiBeaver'
    import com.bryansharp.gradle.hibeaver.utils.MethodLogAdapter
    import org.objectweb.asm.ClassVisitor
    import org.objectweb.asm.MethodVisitor
    import org.objectweb.asm.Opcodes
    //or you can import like bellow:
    //import org.objectweb.asm.*
    hiBeaver {
        //下面这个参数仅仅影响log输出,为本次修改命名,无实际意义,不配置也可以
        hiBeaverModifyName = 'myHibeaverTest'
        //设置为true可以显示帮助内容,默认为true
        showHelp = true
        //keepQuiet默认为false,为true时不会有字节码修改的log输出,建议为false
        keepQuiet = false
        //下面的参数设置为true时会输出工程编译耗时信息
        watchTimeConsume = false
        
        //重头戏是配置下面的参数:modifyMatchMaps
        //基础配置结构形如: ['class':[[:],[:]],'class':[[:],[:]]], 类型是 Map<String, List<Map<String, Object>>>
        modifyMatchMaps = [
                //此处可以进行模糊匹配,!表示排除,!android*即表示排除掉android开头的全类名。
                //|符号不完全表示或,而仅仅是匹配的分隔符。*表示任意长度(>0)的任意字符
                '*Activity|*Receiver|!android*'             : [
                        //methodDesc设置为空代表对methodDesc不进行限制
                        //方法名也可以用模糊匹配 用javap -s 命令来查看类中方法的description
                        ['methodName': 'on**', 'methodDesc': null, 'adapter': {
                            ClassVisitor cv, int access, String name, String desc, String signature, String[] exceptions ->
                                MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, signature, exceptions);
                                MethodVisitor adapter = new MethodLogAdapter(methodVisitor) {
                                    @Override
                                    void visitCode() {
                                        super.visitCode();
                                        methodVisitor.visitLdcInsn(desc);
                                        methodVisitor.visitLdcInsn(name);
                                      //下面这行代码 为要调用的方法,请酌情修改
                                        methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, 
                                            "bruce/com/testhibeaver/MainActivity", 
                                                "hookXM", "(Ljava/lang/Object;Ljava/lang/Object;)V");
                                    }
                                }
                                return adapter;
                        }]
                ]
                ,
                //此处以r:开头,代表正则表达式匹配模式
                'r:.*D[a-zA-Z]*Client'              : [
                        ['methodName': 'on**', 'methodDesc': null, 'adapter': {
                            ClassVisitor cv, int access, String name, String desc, String signature, String[] exceptions ->
                                MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, signature, exceptions);
                                MethodVisitor adapter = new MethodLogAdapter(methodVisitor) {
                                    @Override
                                    void visitCode() {
                                        super.visitCode();
                                    }
                                }
                                return adapter;
                        }]
                ]
        ]
        //下面为对Jar或Aar进行单独修改的配置,执行hibeaverModifyFiles的Gradle任务来对路径所指向的文件进行修改,
        //产出物在build/HiBeaver目录下
        modifyTasks = ["${rootDir.absolutePath}/submodule/app/libs/MiPush_SDK_Client_3_2_2.jar": modifyMatchMaps]
    }

本repo项目中还包含一个submodule,里面有本插件的demo,可以使用git submodule来进行初始化,然后在项目根目录加入settings.gradle并编辑(include ':submodule:app')来包含这个子项目(是一个app demo)。

玩的愉快!有任何问题和bug请提issue,欢迎参与到本项目的完善中!

English Version

By applying the regular expression and wildcard features, HiBeaver now has been upgraded to a Java lightweight AOP design tool.

Beaver means 河狸 in Chinese, cute animals always busy in building their cute river dam.

Basically, HiBeaver is a Gradle plugin for modifying your java byte code.

This plugin has been uploaded to jcenter. You can use this by adding the following code to your buildScripts:

    classpath 'com.bryansharp:HiBeaver:1.2.7'

Link to Jcenter

and then add this to you app build scripts:

    import com.bryansharp.gradle.hibeaver.utils.MethodLogAdapter
    import org.objectweb.asm.ClassVisitor
    import org.objectweb.asm.MethodVisitor
    import org.objectweb.asm.Opcodes
    //or you can import like bellow:
    //import org.objectweb.asm.*
    hiBeaver {
        //this will determine the name of this hibeaver transform, no practical use.
        hiBeaverModifyName = 'myHibeaverTest'
        //turn this on to make it print help content, default value is true
        showHelp = true
        //this flag will decide whether the log of the modifying process be printed or not, default value is false
        keepQuiet = false
        //this is a kit feature of the plugin, set it true to see the time consume of this build
        watchTimeConsume = false

        //this is the most important part
        //basic structure is like ['class':[[:],[:]],'class':[[:],[:]]], type is Map<String, List<Map<String, Object>>>
        //advanced structure is like: ['classMatchPattern':['classMatchType':'wildcard','modifyMethods':[[:],[:]]],'classMatchPattern':['classMatchType':'regEx','modifyMethods':[[:],[:]]]]
        modifyMatchMaps = [
                //this is the basic version
                'classname of which to be modified': [
                        // you can use javap -s command to get the description of one method
                        // the adapter is a closure
                        ['methodName': 'the name of the method', 'methodDesc': 'javap -s to get the description', 'adapter': {
                            //the below args cannot be changed, to copy them entirely with nothing changed is recommended
                            ClassVisitor cv, int access, String name, String desc, String signature, String[] exceptions ->
                                //return null to modify nothing
                                return null;
                        }]
                        ,
                        ['methodName': 'the name of the method2', 'methodDesc': 'javap -s to get the description', 'adapter': {
                            ClassVisitor cv, int access, String name, String desc, String signature, String[] exceptions ->
                                return null;
                        }]
                ]
                ,
                //the latter ones are advanced cases
                '*Activity'                       : [
                        //the value of classMatchType can either be one of the three: all,regEx,wildcard
                        //default value is all
                        'classMatchType': 'wildcard',
                        'modifyMethods' : [
                                //methodMatchType会同时对methodName和methodDesc的匹配生效
                                //methodDesc设置为空代表对methodDesc不进行限制
                                ['methodName': 'on**', 'methodMatchType': 'wildcard', 'methodDesc': null, 'adapter': {
                                    ClassVisitor cv, int access, String name, String desc, String signature, String[] exceptions ->
                                        MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, signature, exceptions);
                                        MethodVisitor adapter = new MethodLogAdapter(methodVisitor) {
                                            @Override
                                            void visitCode() {
                                                super.visitCode();
                                                methodVisitor.visitLdcInsn(desc);
                                                methodVisitor.visitLdcInsn(name);
                                                methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "bruce/com/testhibeaver/MainActivity", "hookXM", "(Ljava/lang/Object;Ljava/lang/Object;)V");
                                            }
                                        }
                                        return adapter;
                                }]
                        ]
                ]
                ,
                '.*D[a-zA-Z]*Receiver'                       : [
                        'classMatchType': 'regEx',
                        'modifyMethods' : [
                                ['methodName': 'on**', 'methodMatchType': 'wildcard', 'methodDesc': null, 'adapter': {
                                    ClassVisitor cv, int access, String name, String desc, String signature, String[] exceptions ->
                                        MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, signature, exceptions);
                                        MethodVisitor adapter = new MethodLogAdapter(methodVisitor) {
                                            @Override
                                            void visitCode() {
                                                super.visitCode();
                                                methodVisitor.visitLdcInsn(desc);
                                                methodVisitor.visitLdcInsn(name);
                                                methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "bruce/com/testhibeaver/MainActivity", "hookXM", "(Ljava/lang/Object;Ljava/lang/Object;)V");
                                            }
                                        }
                                        return adapter;
                                }]
                        ]
                ]
        ]
    }

You can also see the content above in the build log outputs.

There is also a demo showing how to use it. You can either get it through git submodule and add a settings.gradle file to include the module, or get it by checking out hiBeaverDemo.

Hope you can enjoy it! Any comment and suggestion is welcomed.