您的当前位置:首页正文

Spring Boot 代码混淆(proguard-maven-plugin的使用说明)

2024-11-26 来源:个人技术集锦

什么是代码混淆?

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

Proguard是什么?

本文目标

本文并不是介绍proguard如何使用(proguard有standalone模式,可以直接使用proguard.sh命令行进行混淆代码),而是使用wvengen的proguard-maven-plugin插件实现将一个spring boot项目进行混淆。

准备项目

我这里使用的是Spring Boot 2.7.x,JDK使用的是8.

混淆前

首先打包看下未混淆前打包,查看反编译后的文件,这里需要使用反编译工具,可以去 打包:使用mvn clean package -DskipTests 或者直接使用IDEA的Build工具都可以。

#非必须选项,因为我电脑上安装多个版本的JDK。而环境变量中配置的不是jdk1.8,所有需要执行如下命令。
➜  Spring-Boot-Proguard git:(main) ✗ export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_333.jdk/Contents/Home
#我这里使用的是./mvnw,用mvn也可(只要你的电脑配置了环境变量,如果没配置,就可以使用spring boot项目下的mvnw)
➜  Spring-Boot-Proguard git:(main) ✗ ./mvnw clean package -DskipTestclears
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------< com.itlab1024:Spring-Boot-Proguard >-----------------
[INFO] Building Spring-Boot-Proguard 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:3.2.0:clean (default-clean) @ Spring-Boot-Proguard ---
^C%                                                                                                                ➜  Spring-Boot-Proguard git:(main) ✗ 
➜  Spring-Boot-Proguard git:(main) ✗ ./mvnw clean package -DskipTests     
[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------< com.itlab1024:Spring-Boot-Proguard >-----------------
[INFO] Building Spring-Boot-Proguard 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:3.2.0:clean (default-clean) @ Spring-Boot-Proguard ---
[INFO] Deleting /Users/itlab/workspace/github/Spring-Boot-Proguard/target
[INFO] 
[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ Spring-Boot-Proguard ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] Copying 1 resource
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.10.1:compile (default-compile) @ Spring-Boot-Proguard ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/itlab/workspace/github/Spring-Boot-Proguard/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:3.2.0:testResources (default-testResources) @ Spring-Boot-Proguard ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'UTF-8' encoding to copy filtered properties files.
[INFO] skip non existing resourceDirectory /Users/itlab/workspace/github/Spring-Boot-Proguard/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.10.1:testCompile (default-testCompile) @ Spring-Boot-Proguard ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/itlab/workspace/github/Spring-Boot-Proguard/target/test-classes
[INFO] 
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ Spring-Boot-Proguard ---
[INFO] Tests are skipped.
[INFO] 
[INFO] --- maven-jar-plugin:3.2.2:jar (default-jar) @ Spring-Boot-Proguard ---
[INFO] Building jar: /Users/itlab/workspace/github/Spring-Boot-Proguard/target/Spring-Boot-Proguard-0.0.1-SNAPSHOT.jar
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.7.4:repackage (repackage) @ Spring-Boot-Proguard ---
[INFO] Replacing main artifact with repackaged archive
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.584 s
[INFO] Finished at: 2022-10-15T17:31:08+08:00
[INFO] ------------------------------------------------------------------------

完成后,我们target下就能看到打好的jar文件。使用jd-gui打开查看。

可以看到,代码没有被混淆。

代码混淆

接下来我使用proguard实现代码混淆。主要是在pom中使用插件来实现。

<?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.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itlab1024</groupId>
    <artifactId>Spring-Boot-Proguard</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Spring-Boot-Proguard</name>
    <description>Spring-Boot-Proguard</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.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <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>${project.basedir}/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>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                        <configuration>
                            <mainClass>com.itlab1024.proguard.SpringBootProguardApplication</mainClass>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

再新建个mvc的controller。

package com.itlab1024.proguard.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {
    /**
     * 主页Mapping
     * @return
     */
    @GetMapping
    public String index() {
        return "这是主页";
    }
}

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[]);
    }

混淆后反编译结果如下:

可以看到IndexController被混淆了,Spring Boot的启动类SpringBootProguardApplication未被混淆。

对混淆的jar进行启动

➜  target git:(main) ✗ java -jar Spring-Boot-Proguard-0.0.1-SNAPSHOT.jar 

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.4)

2022-10-16 16:44:23.132  INFO 12416 --- [           main] c.i.p.SpringBootProguardApplication      : Starting SpringBootProguardApplication v0.0.1-SNAPSHOT using Java 17.0.3.1 on 192.168.0.100 with PID 12416 (/Users/itlab/workspace/github/Spring-Boot-Proguard/target/Spring-Boot-Proguard-0.0.1-SNAPSHOT.jar started by itlab in /Users/itlab/workspace/github/Spring-Boot-Proguard/target)
2022-10-16 16:44:23.138  INFO 12416 --- [           main] c.i.p.SpringBootProguardApplication      : No active profile set, falling back to 1 default profile: "default"
2022-10-16 16:44:24.406  INFO 12416 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-10-16 16:44:24.420  INFO 12416 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-10-16 16:44:24.420  INFO 12416 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.65]
2022-10-16 16:44:24.528  INFO 12416 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-10-16 16:44:24.528  INFO 12416 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1266 ms
2022-10-16 16:44:24.996  INFO 12416 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-10-16 16:44:25.007  INFO 12416 --- [           main] c.i.p.SpringBootProguardApplication      : Started SpringBootProguardApplication in 2.538 seconds (JVM running for 3.108)

访问主页:

备注

显示全文