java代码混淆方式

3,655 阅读2分钟

什么是代码混淆?

就是将代码的通过工具,使其可读性变差(越差越好 )

为什么需要混淆

因为java代码可以反编译,当自己的代码不想被人看到时或者有时候要保护自己的知识产权就可以利用混淆

混淆的方式

1、将class文件加密,这个是最安全的,但也费事儿,因为要重写classloader来解密class文件;

2、使用花指令,使得class文件不能反编译(利用反编译工具漏洞);安全性一般,还是有花指令破解器;

3、代码混淆,提高代码阅读成本;简单易操作,一般采用这种或者与其它方式结合;

混淆工具

  1. 混淆工具ProGuard

    该工具主要是为了实现Java以及Android App的代码混淆工作

Proguard是什么

ProGuard是一个纯java编写的混淆工具,有客户端跟jar包两种使用方式。可以将程序打包为jar,然后用工具进
行混淆,也可以在maven中导入ProGuard的插件,对代码进行混淆。
官方推荐了两个maven插件:
https://github.com/wvengen/proguard-maven-plugin

https://github.com/dingxin/proguard-maven-plugin

准备项目

我这里使用的是Spring Boot 2.7.X,JDK使用的是1.8

  • 新建一个springboot项目
  • 在pom中添加proguard插件来实现代码混淆
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>proguard-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-proguard</name>
    <description>代码混淆</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
​
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
​
        <dependency>
            <groupId>org.eclipse.paho</groupId>
            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
            <version>1.2.2</version>
        </dependency>
    </dependencies>
​
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.github.wvengen</groupId>
                <artifactId>proguard-maven-plugin</artifactId>
                <version>2.6.0</version>
                <executions>
                    <!-- 以下配置说明执行mvn的package命令时候,会执行proguard-->
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>proguard</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!-- 就是输入Jar的名称,我们要知道,代码混淆其实是将一个原始的jar,生成一个混淆后的jar,那么就会有输入输出。 -->
                    <injar>${project.build.finalName}.jar</injar>
                    <!-- 输出jar名称,输入输出jar同名的时候就是覆盖,也是比较常用的配置。 -->
                    <outjar>${project.build.finalName}.jar</outjar>
                    <!-- 是否混淆 默认是true -->
                    <obfuscate>true</obfuscate>
                    <!-- 配置一个文件,通常叫做proguard.cfg,该文件主要是配置options选项,也就是说使用proguard.cfg那么options下的所有内容都可以移到proguard.cfg中 -->
                    <proguardInclude>proguard.cfg</proguardInclude>
                    <!-- 额外的jar包,通常是项目编译所需要的jar -->
                    <libs>
                        <lib>${java.home}/lib/rt.jar</lib>
                        <lib>${java.home}/lib/jce.jar</lib>
                        <lib>${java.home}/lib/jsse.jar</lib>
                    </libs>
                    <!-- 对输入jar进行过滤比如,如下配置就是对META-INFO文件不处理。 -->
                    <inLibsFilter>!META-INF/**,!META-INF/versions/9/**.class</inLibsFilter>
                    <!-- 这是输出路径配置,但是要注意这个路径必须要包括injar标签填写的jar -->
                    <outputDirectory>${project.basedir}/target</outputDirectory>
                    <!--这里特别重要,此处主要是配置混淆的一些细节选项,比如哪些类不需要混淆,哪些需要混淆-->
                    <options>
                        <!-- 可以在此处写option标签配置,不过我上面使用了proguardInclude,故而我更喜欢在proguard.cfg中配置 -->
                    </options>
                </configuration>
            </plugin>
        </plugins>
    </build></project>
  • 在项目根目录下创建proguard.cfg配置文件

    #指定Java的版本
    -target 1.8
    #proguard会对代码进行优化压缩,他会删除从未使用的类或者类成员变量等
    -dontshrink
    #是否关闭字节码级别的优化,如果不开启则设置如下配置
    -dontoptimize
    #混淆时不生成大小写混合的类名,默认是可以大小写混合
    -dontusemixedcaseclassnames
    # 对于类成员的命名的混淆采取唯一策略
    -useuniqueclassmembernames
    #混淆时不生成大小写混合的类名,默认是可以大小写混合
    -dontusemixedcaseclassnames
    #混淆类名之后,对使用Class.forName('className')之类的地方进行相应替代
    -adaptclassstrings
    ​
    #对异常、注解信息予以保留
    -keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
    # 此选项将保存接口中的所有原始名称(不混淆)-->
    -keepnames interface ** { *; }
    # 此选项将保存所有软件包中的所有原始接口文件(不进行混淆)
    #-keep interface * extends * { *; }
    #保留参数名,因为控制器,或者Mybatis等接口的参数如果混淆会导致无法接受参数,xml文件找不到参数
    -keepparameternames
    # 保留枚举成员及方法
    -keepclassmembers enum * { *; }
    # 不混淆所有类,保存原始定义的注释-
    -keepclassmembers class * {
                            @org.springframework.context.annotation.Bean *;
                            @org.springframework.beans.factory.annotation.Autowired *;
                            @org.springframework.beans.factory.annotation.Value *;
                            @org.springframework.stereotype.Service *;
                            @org.springframework.stereotype.Component *;
                            }
    ​
    #忽略warn消息
    -ignorewarnings
    #忽略note消息
    -dontnote
    #打印配置信息
    -printconfiguration
    -keep public class com.itlab1024.proguard.SpringBootProguardApplication {
            public static void main(java.lang.String[]);
        }
    

image.png

  • 执行maven打包操作

image.png

  • 利用jd-gui工具打开jar,混淆后反编译结果如下:

image.png

未混淆的jar包代码

image.png