首页 > 编程语言 >从零开发基于ASM字节码的Java代码混淆插件XHood

从零开发基于ASM字节码的Java代码混淆插件XHood

时间:2023-11-02 09:15:51浏览次数:38  
标签:混淆 插件 需要 Java XHood 重写 注解 方法 asm

项目背景

因在公司负责基础框架的开发设计,所以针对框架源代码的保护工作比较重视,之前也加入了一系列保护措施

例如自定义classloader加密保护,授权license保护等,但都是防君子不防小人,安全等级还比较低

经过调研各类加密混淆措施后,决定自研混淆插件,自主可控,能够贴合实际情况进行定制化,达到框架升级后使用零感知,零影响。

快速开始

项目地址:https://gitee.com/code2roc/xhood

在线文档:https://code2roc.gitee.io/xhood/#/

  • 下载最新发行版到本地,执行maven install

  • 工程项目配置maven plugin ,详细配置见在线文档

<build>
   <plugins>
      <plugin>
        <groupId>com.code2roc</groupId>
        <artifactId>xhood</artifactId>
        <version>1.0.0</version>
        <executions>
        	<execution>
               <goals>
                  <goal>obscure</goal>
               </goals>
               <phase>compile</phase>
             </execution>
         </executions>
         <configuration>
             <!--配置项目根包名 -->
             <packageName>com.xxx.xxx</packageName>
             <!--配置忽略项目启动类 -->
              <obscureIgnoreClasss>com.xxx.xxx.Application</obscureIgnoreClasss>
         </configuration>
       </plugin>
   </plugins>
</build>

方案设计

我们首先要清除代码混淆要实现什么,就是将原代码名称结构和内容使用一系列的规则码替换

达到阅读困难,理解困难,恢复困难的作用

混淆的事项包括方法,成员变量,临时变量,方法参数,常量,类,包,枚举

这些事项的混淆还需要遵循固定的顺序,因为事项之间还存在相互引用的情况

在完成结构混淆(类文件,包名)后,需要删除对应的原class文件

混淆前后的效果如下图所示

方案实现

pom引用

  		<dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm</artifactId>
            <version>9.0</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-commons</artifactId>
            <version>9.0</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-util</artifactId>
            <version>9.0</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-tree</artifactId>
            <version>9.0</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-analysis</artifactId>
            <version>9.0</version>
        </dependency>

名称混淆

名称混淆指的是把类名,方法名,参数名,变量名等定义的名称进行规则码替换,以混淆方法名为例

  • 混淆方法定义

    自定义ClassVisitor重写visit方法

    过滤枚举类的方法

    过滤main方法,过滤lambda表达式方法,过滤构造函数方法

    过滤非混淆范围内接口的实现方法

    过滤非混淆范围内父类的重写方法

  • 混淆方法调用

    自定义MethodVisitor重写visitMethodInsn,visitInvokeDynamicInsn方法

    visitMethodInsn修混淆方法定义中的方法

    visitInvokeDynamicInsn修改接口的实现方法和父类的重写方法(混淆范围内且混淆方法定义中的方法)

结构混淆

结构混淆指的是修改类名,包名时对实体class文件和文件夹的重命名,以混淆类名为例

  • 混淆类定义

    自定义ClassVisitor重写visit方法

    过滤非混淆范围内的class

    重写visitSource,visitField,visitMethod,visitInnerClass,visitOuterClass等方法

  • 混淆类定义调用

    自定义MethodVisitor重写visitMethodInsn,visitFieldInsn,visitFrame,visitInvokeDynamicInsn等方法

  • 混淆类重命名

    定义ClassWriter获取class文件byte数组重新写入文件

注解混淆

注解的混淆比较特殊,需要继承AnnotationVisitor类来重写visit方法实现

针对注解中有枚举需要重写visitEnum方法

针对嵌套注解需要重写visitAnnotation方法

针对注解有参数有数组的,需要重写visitArray方法

visitAnnotation和visitArray方法需要返回AnnotationVisitor对象,调用super方法后返回自定义AnnotationVisitor对象递归处理即可

混淆规则

无论混淆哪一部分,我们总是要根据一个名称例如abc混淆后得到一个固定的规则码例如123

这时候我们会想到md5这种固定输入对应固定输出的信息摘要算法

md5内容太长,我们需要截取某几位进行简化

简化后的规则码在待混淆内容越多时越容易碰撞,需要需要动态调整,简单递归即可,最坏结果就是完整的md5表示

    public static String getTakeName(String name, int takeLimit, HashMap<String, String> typeMap) {
        String obscureName = getObscureName(name);
        if (takeLimit <= 16) {
            obscureName = obscureName.substring(8, 24);
        }
        String takeName = obscureName.substring(0, takeLimit);
        if (typeMap.containsValue(takeName)) {
            takeName = getTakeName(name, takeLimit + 1, typeMap);
        }
        return takeName;
    }

注意事项

开发事项

在混淆过程中,需要针对不同的情况进行细节处理,举例如下

  • 混淆名称中有相同部分的优先排序替换长度最长的部分

例如方法名HandleMethod和Handle两部分,Handle对应的规则码为123,我先替换Handle部分变成了123Method和123,那么123Method这个方法混淆后就会定义错误

  • 临时变量和方法变量都会调用MethodVisitor的visitLocalVariable方法,需要区分

先定义ParamterAdapter继承MethodVisitor重写visitParameter记录方法变量

使用事项

在springboot项目中,我们需要进行一些配置避免导致项目无法运行或运行错误**

  • 所有需要通过接口返回的实体类需要忽略,例如数据库实体DO

  • 通过ConfigurationProperties映射的yml文件配置项类需要忽略

  • 通过类名/字段名反射调用的类需要忽略

  • 针对@Aspect注解切面进行了兼容,参照如下写法则混淆无影响

    PointCut注解/类需要指定全名,Around注解指定方法名

    @Aspect
    @Component
    public class RepeatSubmitAspect {
        /**
         * 切面点 指定注解
         */
        @Pointcut("@annotation(com.code2roc.fastboot.framework.submitlock.SubmitLock) " +
                "|| @within(com.code2roc.fastboot.framework.submitlock.SubmitLock)")
        public void repeatSubmitAspect() {
    
        }
    
        /**
         * 拦截方法指定为 repeatSubmitAspect
         */
        @Around("repeatSubmitAspect()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            return point.proceed();
        }
    }
    

标签:混淆,插件,需要,Java,XHood,重写,注解,方法,asm
From: https://www.cnblogs.com/yanpeng19940119/p/17804623.html

相关文章

  • 每日总结Java设计模式之原型模式
    今天完成了设计模式的原型模式实验用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节简单说就是先创建一个原型类实例,然后通过克隆的方法来复制一个一样的新对象,这个对象和原来......
  • 每日总结Java设计模式之单例模式
    今天做了单例模式的实验代码在有些系统中,为了节省内存资源、保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式。单例模式有3个特点:单例类只有一个实例对象;该单例对象必须由单例类自行创建;单例类对外提供一个访问该单例的全局访问点;1.单例模式的......
  • Java while 和do while 循环
    循环是程序中的重要流程结构之一。循环语句能够使程序代码重复执行,适用于需要重复一段代码直到满足特定条件为止的情况。所有流行的编程语言中都有循环语句。Java中采用的循环语句与C语言中的循环语句相似,主要有while、do-while和for。另外Java5之后推出了for-each循环语......
  • gin框架curd 和java springboot crud 的比较及性能
    Gin框架与SpringBoot框架的CURD比较Ginvs.SpringBoot:简介Gin(Go语言):Gin是用于构建Web应用程序和API的轻量级、高性能框架,使用Go编程语言。它以简洁和高性能而闻名。SpringBoot(Java):SpringBoot是一个用于构建基于Java的Web应用程序的开源Java框架。它简化了使......
  • Java while 和do while 循环
    循环是程序中的重要流程结构之一。循环语句能够使程序代码重复执行,适用于需要重复一段代码直到满足特定条件为止的情况。所有流行的编程语言中都有循环语句。Java中采用的循环语句与C语言中的循环语句相似,主要有while、do-while和for。另外Java5之后推出了for-each循环......
  • Java笔记—Java修饰符
    Java语言提供了很多修饰符,主要分为以下两类:访问修饰符非访问修饰符1、访问控制修饰符Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java支持4种不同的访问权限。default (即默认,什么也不写):在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方......
  • Java笔记—Java修饰符
    Java语言提供了很多修饰符,主要分为以下两类:访问修饰符非访问修饰符1、访问控制修饰符Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java支持4种不同的访问权限。default (即默认,什么也不写):在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方......
  • overflow溢出属性 前端基础之JavaScript
    今日内容详细overflow溢出属性visible 默认值。内容不会被修剪,会呈现在元素框之外。hidden 内容会被修剪,并且其余内容是不可见的。scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。auto 如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。●over......
  • Java工程师必备-一些资料的整理
    [Java工程师必备+学习+知识点+面试]:包含计算机网络知识、JavaSE、JVM、Spring、Springboot、SpringCloud、Mybatis、多线程并发、netty、MySQL、MongoDB、Elasticsearch、Redis、HBASE、RabbitMQ、RocketMQ、Pulsar、Kafka、Zookeeper、Linux、设计模式、智力题、项目架构、分布式......
  • 六、Java常用类:Object,Scanner
    一、Object类Object:ClassObject是类Object结构的根。每个Class都有Object作为超类。所有对象(包括数组)都实现了这个类的方法。成员方法:publicinthashCode()用来生成对象的唯一哈希码(hashcode),它是用来快速比较两个对象是否相等的publicfinalClassgetClass()......