proguard混淆maven多模块实战(干货)

背景

一般来说,后端代码部署在服务器上,用户是无法接触到的,所以后端代码混淆做得比较少,但是公司的业务,有Saas业务,需要将后端整套代码都进行部署到用户的服务器上,由于Java极其容易进行反编译,所以用户很容易得到我们的源代码,进行破解,所以我们有必要对代码进行混淆,经常尝试,使用proguard进行混淆,但是现在的工程基本上是多模块应用,混淆的时候踩了很多坑

工程模块图示例

在这里插入图片描述
也就是app这个依赖于admin,business,common等其它工程,最终打包出来的app工程是聚合了其它模块的工程,那么我们的操作基本是在app的pom进行操作
但是按照正常打包的方式,生成的结构会是打包了app的代码,而admin等模块会被打包成jar,放入lib里面。我们需要进行整体混淆,那么就需要先把其它模块给拆分出来,然后聚合到app包里面去,所以我们先在最顶层用

  <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <!-- 打包生成的包不拼接xml里的id 为后缀 -->
                    <appendAssemblyId>false</appendAssemblyId>
                    <!--打包文件路径-->
                    <descriptors>
                        <descriptor>${project.basedir}/assembly.xml</descriptor>
                    </descriptors>
                </configuration>
                <executions>
                    <execution>
                        <id>assembly-package</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

上面插件基本不变,添加assmbly.xml文件
assmbly.xml

<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">

    <!--项目标识,设置的话,生成后的zip文件会加上此后缀-->
    <id>${project.version}</id>
    <!--打包格式-->
    <formats>
        <format>jar</format>
    </formats>
    <!--压缩包下是否生成和项目名相同的根目录-->
    <includeBaseDirectory>false</includeBaseDirectory>
    <fileSets>
        <fileSet>
            <directory>${project.build.directory}/classes</directory>
            <outputDirectory>/</outputDirectory>
        </fileSet>
    </fileSets>
    <dependencySets>
        <!-- 把依赖的项目其他模块代码放到jar包里,方便对其他模块代码 -->
        <dependencySet>
            <includes>
                <include>com.lmy.optical:*</include>
            </includes>
            <unpack>true</unpack>
        </dependencySet>
    </dependencySets>

</assembly>```
然后开始添加混淆配置

```java
  <!-- 代码混淆 -->
            <plugin>
                <groupId>com.github.wvengen</groupId>
                <artifactId>proguard-maven-plugin</artifactId>
                <version>2.3.1</version>
                <executions>
                    <execution>
                        <!-- 打包的时候开始混淆-->
                        <phase>package</phase>
                        <goals>
                            <goal>proguard</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <injar>${project.build.finalName}.jar</injar>
                    <!--输出的jar-->
                    <outjar>${project.build.finalName}.jar</outjar>
                    <!-- 是否混淆-->
                    <obfuscate>true</obfuscate>
                    <proguardInclude>${basedir}/proguard.cfg</proguardInclude>
                    <injarNotExistsSkip>true</injarNotExistsSkip>
                    <options>
                        <!--指定java版本号-->
                        <option>-target 1.8</option>
                        <!--不做收缩(删除注释、未被引用代码)-->
                        <option>-dontshrink</option>
                        <!--默认是开启的,这里关闭字节码级别的优化-->
                        <option>-dontoptimize</option>
                        <!--混淆类名之后,对使用Class.forName('className')之类的地方进行相应替代-->
                        <option>-adaptclassstrings</option>
                        <!--混淆时不生成大小写混合的类名,默认是可以大小写混合-->
                        <option>-dontusemixedcaseclassnames</option>
                        <!--                            指定将相同的混淆名称分配给具有相同名称的类成员,并将不同混淆名称分配给名称不同的类成员,(我猜)假设两个类有相同的类成员(如方法名),则混淆后名称一样-->
                        <!--                            <option>-useuniqueclassmembernames</option>-->
                        <!-- 忽略warn消息-->
                        <option>-ignorewarnings</option>
                        <!--对异常、注解信息在runtime予以保留,不然影响springboot启动-->
                        <option>-keepattributes
                            Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
                        </option>
                        <!--不混淆所有interface接口-->
                        <!--                        <option>-keepnames interface **</option>-->
                        <!--                            <option>-keep interface * extends * { *; }</option>-->
                        <!--保留枚举成员及方法-->
                        <option>-keepclassmembers enum * { *; }</option>
                        <!-- 不参与混淆的类参数也不混淆,controller如果参数也混淆会导致传参映射不上 -->
                        <option>-keepparameternames</option>

                        <!--不混淆带有main 方法的类 网上的配置我没用-->
                        <!--                            <option>-keepclasseswithmembers public class * {-->
                        <!--                                public static void main(java.lang.String[]);}-->
                        <!--                            </option>-->
                        <!--百度的配置,注释掉没出问题,忽略note消息,如果提示javax.annotation有问题,那麽就加入以下代码-->
                        <!--                            <option>-dontnote javax.annotation.**</option>-->
                        <!--                            <option>-dontnote sun.applet.**</option>-->
                        <!--                            <option>-dontnote sun.tools.jar.**</option>-->
                        <!--                            <option>-dontnote org.apache.commons.logging.**</option>-->
                        <!--                            <option>-dontnote javax.inject.**</option>-->
                        <!--                            <option>-dontnote org.aopalliance.intercept.**</option>-->
                        <!--                            <option>-dontnote org.aopalliance.aop.**</option>-->
                        <!--                            <option>-dontnote org.apache.logging.log4j.**</option>-->
                        <!--                            <option>-keep class org.apache.logging.log4j.util.* { *; }</option>-->
                        <!--                            <option>-dontwarn org.apache.logging.log4j.util.**</option>-->
                        <!--不混淆所有类,保存原始定义的注释,网上找到的配置,我注释掉没出现任何问题-->
                        <!--                            <option>-keepclassmembers class * {-->
                        <!--                                @org.springframework.beans.factory.annotation.Autowired *;-->
                        <!--                                @org.springframework.beans.factory.annotation.Value *;-->
                        <!--                                @org.springframework.web.bind.annotation.PostMapping *;-->
                        <!--                                @org.springframework.web.bind.annotation.DeleteMapping *;-->
                        <!--                                @org.springframework.stereotype.Repository *;-->
                        <!--                                @com.shark.example.configuration.log *;-->
                        <!--                                }-->
                        <!--                            </option>-->
                    </options>
                    <libs>
                        <!-- 添加依赖 java8-->
                        <lib>${java.home}/lib/rt.jar</lib>
                        <lib>${java.home}/lib/jce.jar</lib>
                    </libs>
                </configuration>
                <dependencies>
                    <!-- https://mvnrepository.com/artifact/net.sf.proguard/proguard-base -->
                    <dependency>
                        <groupId>com.guardsquare</groupId>
                        <artifactId>proguard-base</artifactId>
                        <version>7.0.0</version>
                    </dependency>
                </dependencies>
            </plugin>

最后进行打包

 <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.6.4</version>
                <configuration>
                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
                    <mainClass>com.lmy.AppApplication</mainClass>

                    <!--start:混淆配置 由于配置混淆插件,会把其他模块的依赖包混淆后直接放入 springboot最后生成的jar包,所以就不需要把其他模块的jar包放到lib里了-->
                    <excludeGroupIds>
                        com.lmy
                    </excludeGroupIds>
                    <!-- end:混淆配置 -->
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <!-- 配置编译时不混淆方法名,需要时在配置 -->
                     <compilerArgument>-parameters</compilerArgument>
                </configuration>
            </plugin>
        </plugins>

也可以在引入混淆配置proguard.cfg

#所有类(包括接口)的方法参数不混淆(包括没被keep的) 如果参数混淆了 mybatis mapper 参数绑定会出错(如#{id}-keepattributes MethodParameters

#入口程序类不能混淆,混淆会导致springboot启动不了
-keep class com.lmy.AppApplication {*;}

#由于spring会根据参数名称绑定参数,如果参数名称被混淆了,参数绑定是会报错,所以不混淆controller的所有的public方法(也可以不混淆类名)
#因为配置了'keepparameternames'所以不混淆方法时参数也不会混淆
-keepclassmembers class com.lmy.*.controller.* {public *** *(...);}
#但是因为swagger配置了根据包路径进行扫描,所以如果混淆了会导致swagger扫描不到混淆后的包,所以不混淆controller的包路径
-keeppackagenames com.lmy.*.controller

#实体类不混淆不然会导致mybatis xml 配置的实体类找不到
#如果是spring jpa 用到@Query 也会导致找不到相关类
-keep class com.lmy.common.module.** {*;}

-keepclassmembers  class com.lmy.**.dto.** {*;}

-keepclassmembers  class com.lmy.**.vo.** {*;}

-keep class com.lmy.common.base.** {*;}

#mybatis mapper不混淆 否则会导致xml 配置的mapper找不到
-keep class com.lmy.common.dao.** {
    *;
}

#-keep interface com.lmy.common.service.** {
#    *;
#}
#
#-keep class com.lmy.common.service.impl.** {
#   *;
#}

#不混淆spring jpa的 repository,否则就无法根据方法名查询了
-keep class com.dataexa.fzty.deduction.repository.** {
    *;
}

#保留service的所有公共方法名,由于使用AOP控制事务,根据拦截get,update等方法进行事务控制,所以需要不混淆service下的public方法名
-keepclassmembers class com.lmy.common.service.** {public *** *(...);}
#不混淆service包名,由于使用AOP(POINTCUT=serivce包名包名)控制事务,所以需要保留service的包名防止找不到service
-keeppackagenames com.lmy.common.service.**

#frannework下都是一些配置类比如datasource,aopconfig,swaggerconfig如果混淆会导致各种启动报错,
#比如用@Around(value = "apiLog()")指定apiLog方法对应的@Pointcut作为切入点,但是因为apiLog方法被混淆成a导致找不到对应@Pointcut
#所以全部不混淆 省心点
-keep class com.lmy.framework.config.** {
    *;
}
-keep @org.springframework.context.annotation.Configuration class * {
    *;
}
-keep @org.springframework.stereotype.Component class * {
    *;
}

#注解了Aspect的都不混淆,由于把framework下的所有类都不混淆,所以此配置就可有可无了
#-keep @org.aspectj.lang.annotation.Aspect class * {
#    *;
#}

#保留Serializable序列化的类不被混淆
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值