代码混淆:SpringMVC配置proguard

代码混淆:

背景

	开发了个智能外呼系统,就是用来拨打经常接到的电话比如:
问你要不要买房,买保险或者说是你的游戏助手等,用来发掘潜在客户或为其它功能提供支持的项目。
因为业务需要将这个项目部署到第三方平台,但是需要对一些核心功能进行限制,例如线程数。
所以需要对核心代码进行混淆,同时再提供一个授权服务,项目只有在授权后才能获得登录和其它相关功能的权限。

根据背景需要完成的功能示意图如下:

在这里插入图片描述

下面进入正题,通过proguard进行简单的代码混淆:

proguard缺点:
	无法对dao层的代码进行混淆,由于proguard无法混淆mapper.xml中的内容,所以与xml文件对应的mapper也不能进行混淆。

一、代码混淆的操作流程

注:如不想试错,请直达下面配置详情

<plugin>
    <groupId>com.github.wvengen</groupId>
    <artifactId>proguard-maven-plugin</artifactId>
    <version>2.0.13</version>
    <executions>
        <execution>
            <!-- 混淆时刻,这里是打包的时候混淆-->
            <phase>package</phase>
            <goals>
                <!-- 使用插件的什么功能,当然是混淆-->
                <goal>proguard</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <!-- 是否将生成的PG文件安装部署-->
        <attach>true</attach>
        <!-- 是否混淆-->
        <obfuscate>true</obfuscate>
        <!-- 指定生成文件分类 -->
        <attachArtifactClassifier>pg</attachArtifactClassifier>
        <options>
            <!-- JDK目标版本1.8-->
            <option>-target 1.8</option>
            <!-- 不做收缩(删除注释、未被引用代码)-->
            <option>-dontshrink</option>
            <!-- 不做优化(变更代码实现逻辑)-->
            <option>-dontoptimize</option>
            <!-- 不路过非公用类文件及成员-->
            <option>-dontskipnonpubliclibraryclasses</option>
            <option>-dontskipnonpubliclibraryclassmembers</option>
            <!--不用大小写混合类名机制-->
            <option>-dontusemixedcaseclassnames</option>


            <!-- 优化时允许访问并修改有修饰符的类和类的成员 -->
            <option>-allowaccessmodification</option>
            <!-- 确定统一的混淆类的成员名称来增加混淆-->
            <option>-useuniqueclassmembernames</option>
            <!-- 不混淆所有包名-->
            <!--<option>-keeppackagenames</option>-->


            <!-- 需要保持的属性:异常,注解等-->
            <option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod</option>
            <!-- 不混淆所有的set/get方法 -->
            <!-- <option>-keepclassmembers public class * {void set*(***);*** get*();}</option>-->


            <!-- 不混淆包下的所有类名,且类中的方法也不混淆-->
            <option>-keep class net.oschina.j2cache.** { *; }</option>
            <option>-keep class org.** { *; }</option>
            <option>-keep class com.jeeplus.core.** { *; }</option>
            <!--<option>-keep class com.xxx.xxx.xxx.controller.** { <methods>; }</option>-->
            <!--<option>-keep class com.xxx.xxx.xxx.dao.** { <methods>; }</option>-->
            <!--<option>-keep class com.xxx.xxx.xxx.exception { <methods>; }</option>-->
            <!--<option>-keep class com.xxx.xxx.xxx.model.** { <methods>; }</option>-->


        </options>
        <!--class 混淆后输出的jar包-->
        <outjar>classes-autotest.jar</outjar>
        <!-- 添加依赖,这里你可以按你的需要修改,这里测试只需要一个JRE的Runtime包就行了 -->
        <!--<libs>-->
            <!--<lib>${java.home}/lib/rt.jar</lib>-->
        <!--</libs>-->
        <!-- 对什么东西进行加载,这里仅有classes成功,毕竟你也不可能对配置文件及JSP混淆吧-->
        <injar>classes</injar>
        <!-- 输出目录-->
        <outputDirectory>${project.build.directory}</outputDirectory>
    </configuration>
</plugin>

1、报错:
Failed to execute goal com.github.wvengen:proguard-maven-plugin:2.0.13:proguard (default) on project jeeplus: Obfuscation failed (result=1) -> [Help 1]
网上搜索到的都是:

将<injar>${project.build.finalName}/WEB-INF/classes/</injar>
改为<injar>${project.build.finalName}.jar</injar>

对我来说没有用

仔细查看完整报错

[proguard] Reading library jar [C:\Users\Lenovo\.m2\repository\net\dongliu\commons\6.10.8\commons-6.10.8.jar]
[proguard] Error: Can't read [C:\Users\Lenovo\.m2\repository\net\dongliu\commons\6.10.8\commons-6.10.8.jar] (Can't process class [META-INF/versions/9/module-info.class] (Unsupported class version number [53.0] (maximum 52.0, Java 1.8)))
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 57.119 s
[INFO] Finished at: 2019-08-12T15:06:12+08:00
[INFO] Final Memory: 47M/440M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal com.github.wvengen:proguard-maven-plugin:2.0.13:proguard (default) on project jeeplus: Obfuscation failed (result=1) -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

发现是proguard版本不支持jdk1.8选择最新的版本
从maven库中找到最新版本的proguard
地址:https://mvnrepository.com/artifact/com.github.wvengen/proguard-maven-plugin
2、接下来的报错是:Note: there were 2199 duplicate class definitions.

[proguard] Reading library jar [C:\Users\Lenovo\.m2\repository\net\sf\json-lib\json-lib\2.4\json-lib-2.4-jdk15.jar]
[proguard] Note: there were 2199 duplicate class definitions.
[proguard]       (http://proguard.sourceforge.net/manual/troubleshooting.html#duplicateclass)
[proguard] Warning: there were 1 classes in incorrectly named files.
[proguard]          You should make sure all file names correspond to their class names.
[proguard]          The directory hierarchies must correspond to the package hierarchies.
[proguard]          (http://proguard.sourceforge.net/manual/troubleshooting.html#unexpectedclass)
[proguard]          If you don't mind the mentioned classes not being written out,
[proguard]          you could try your luck using the '-ignorewarnings' option.
[proguard] Error: Please correct the above warnings first.
[proguard] Reading library jar [C:\Users\Lenovo\.m2\repository\commons-lang\commons-lang\2.5\commons-lang-2.5.jar]

在这里,他说你可以试下自己的运气,将这个报错忽略掉(但是尽量还是将能解决的报错解决掉)

<option>-ignorewarnings</option>  

后续流程:

1:
    mvn clean package 后生成classes-pg.jar和xxx.war(这个是平时的war包)文件,classes-pg.jar是根据之前的配置文件生成的
2:
    随便在某个地方新建个A文件夹和B文件夹,将classes-pg.jar文件放到A文件夹中,通过 jar -xvf classes-pg.jar命令进行解压
    将xxx.war文件放到B文件夹中,通过 jar -xvf xxx.war命令进行解压
    通过Beyond Compare 4进行对比:D:\B\WEB-INF\classes 和D:\A (只是为了可以比较直观的看到效果)
    将A替换B的WEB-INF\classes文件
    将B的名字修改为root后放到tomcat的webapps目录下,启动tomcat进行测试,如果测试成功则通过
    jar -cvfM0 xxx.war 将B文件加打成war包

3、接下来又出现了报错:Annotation-specified bean name ‘a’ for bean class [com.jeeplus.modules.a.e.a.a] conflicts with existing, non-compatible bean definition of same name and class [com.jeeplus.modules.a.d.a]

上面的问题是:Spring的默认bean命名策略不允许bean的名称重复,平时的话我们只需要修改下bean的名称就可以了,但是现在做不到
原因是:
1、proguard使用了默认的字典,默认字典的命名方式是a-z,然后proguard在每一层级按a-z开始重命名。暂时没有找到能够让proguard生成的类名唯一的方法
解决办法:
修改Spring的bean命名策略为包名加类名,因为proguard生成的名称太规律了,为避免重复,bean的命名策略修改为 "com_a包_b包_c包_D"bean的命名使用了全部的包名,
但是光是这样的话还会导致某些使用了默认bean名称的架构无法获得到bean(比如NoSuchBeanDefinitionException: No bean named 'systemAuthorizingRealm' available)
所以还需要修改proguard的命名策略,让proguard按我们的自定义规则dictionary_rules.txt来进行命名,这样就可以选择性的为使用了混淆的bean添加包名加类名的名称
  1. 修改proguard命名策略
添加
<!--指定外部模糊字典-->
<option>-obfuscationdictionary dictionary_rules.txt</option>
<!--指定class模糊字典-->
<option>-classobfuscationdictionary dictionary_rules.txt</option>
<!--指定package模糊字典-->
<option>-packageobfuscationdictionary dictionary_rules.txt</option>
添加dictionary_rules.txt,存放位置为和项目的pom.xml同级
  1. dictionary_rules.txt文件(用中文名。。怎么恶心怎么来)
九q
九w
九e
九r
九t
九y
九u
九i
九o
九p
九a
九s
九d
九f
九g
九h
九j
九k
九l
九z
九x
九c
九v
九b
九n
九m

3.修改Spring的bean的命名策略

第一步
public class SdpAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {
    /**
     * 为了配合proguard使用,需要自定义bean的命名策略为结合包名的,
     * @param definition
     * @return
     */
    protected String buildDefaultBeanName(BeanDefinition definition) {
        String className =definition.getBeanClassName();
        if(className.contains("九")){
            //proguard混淆
            className=className.replaceAll("\\.","_");
        }else{
            //普通代码
            className=className.substring(className.lastIndexOf(".")+1);
            if(className.toLowerCase().endsWith("impl")){
                className=className.substring(0, className.length()-4);
            }
            if((className.toLowerCase().endsWith("service")||className.toLowerCase().endsWith("dao"))==false){
                return super.buildDefaultBeanName(definition);
            }
        }
        return className;
    }
}
第二步
1、在所有context:component-scan中添加:
    name-generator="com.jeeplus.common.beanname.SdpAnnotationBeanNameGenerator"

光是这样还不够,还是会报Annotation-specified bean name 'xx'错误,比如mybatis就不是使用Spring的配置文件,而是自己扫描到Mapper的(MapperScannerConfigurer),由于下面的原因放弃mybatis层的混淆。
2、我的mybatis的xml所处的层级是在各个
放弃mybatis层混淆的原因:
进行修改mybatis的扫描配置
我的mybatis扫描配置之前为:
<!-- 扫描basePackage下所有以@MyBatisMapper注解的接口 -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    <property name="basePackage" value="com.jeeplus"/>
    <property name="annotationClass" value="com.jeeplus.core.persistence.annotation.MyBatisMapper"/>
</bean>
修改为
<!-- 扫描basePackage下所有以@MyBatisMapper注解的接口 -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
       <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
       <property name="basePackage" value="com.jeeplus"/>
       <property name="annotationClass" value="com.jeeplus.core.persistence.annotation.MyBatisMapper"/>
       <property name="nameGenerator" ref="SdpAnnotationBeanNameGenerator"/>
</bean>
<!--自定义扫描-->
<bean id="SdpAnnotationBeanNameGenerator" class="com.jeeplus.common.beanname.SdpAnnotationBeanNameGenerator">
</bean>
接下来在mybatis中又出现了错误,can not find class CallQuality无法找到类。
因为CallQualityMapper.xml这个文件没有进行对应的混淆
<mapper namespace="com.jeeplus.modules.callquality.mapper.CallQualityMapper">
   <select id="findList" resultType="CallQuality" >
如果能够在proguard进行混淆的时候对对应xxmappe.xml的namespace和resultType进行修改的话倒还好,问题是这一处地方实在无从下手,所以放弃mybatis层的混淆

4.spring的自动注入无法使用,配置中添加

<option>-keepdirectories</option>

配置详情:

1、pom.xml

<!-- ProGuard混淆插件-->
<plugin>
    <groupId>com.github.wvengen</groupId>
    <artifactId>proguard-maven-plugin</artifactId>
    <version>2.1.1</version>
    <executions>
        <execution>
            <!-- 混淆时刻,这里是打包的时候混淆-->
            <phase>package</phase>
            <goals>
                <!-- 使用插件的什么功能,当然是混淆-->
                <goal>proguard</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <!-- 是否将生成的PG文件安装部署-->
        <attach>true</attach>
        <!-- 是否混淆-->
        <obfuscate>true</obfuscate>
        <!-- 指定生成文件分类 -->
        <attachArtifactClassifier>pg</attachArtifactClassifier>
        <options>
            <!-- JDK目标版本1.8-->
            <option>-target 1.8</option>
            <!-- 不做收缩(删除注释、未被引用代码)-->
            <option>-dontshrink</option>
            <!-- 不做优化(变更代码实现逻辑)-->
            <option>-dontoptimize</option>
            <!-- 不路过非公用类文件及成员-->
            <option>-dontskipnonpubliclibraryclasses</option>
            <option>-dontskipnonpubliclibraryclassmembers</option>
            <!--不用大小写混合类名机制-->
            <option>-dontusemixedcaseclassnames</option>


            <!-- 优化时允许访问并修改有修饰符的类和类的成员 -->
            <option>-allowaccessmodification</option>
            <!-- 确定统一的混淆类的成员名称来增加混淆-->
            <option>-useuniqueclassmembernames</option>
            <!-- 不混淆所有包名-->
            <!--<option>-keeppackagenames</option>-->


            <!-- 忽略重复文件提示-->
            <option>-ignorewarnings</option>
            <!--解决混淆后无法Srping无法自动注入的问题-->
            <option>-keepdirectories</option>


            <!-- 需要保持的属性:异常,注解等-->
            <option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod</option>
            <!-- 不混淆所有的set/get方法 -->
            <!-- <option>-keepclassmembers public class * {void set*(***);*** get*();}</option>-->


            <!-- 不混淆包下的所有类名,且类中的方法也不混淆-->
            <option>-keep class net.oschina.j2cache.** { *; }</option>
            <option>-keep class org.** { *; }</option>
            <option>-keep class com.jeeplus.core.** { *; }</option>
            <option>-keep class com.jeeplus.common.** { *; }</option>
            <option>-keep class com.jeeplus.modules.sys.** { *; }</option>
            <option>-keep class com.jeeplus.modules.monitor.task.** { *; }</option>
            <option>-keep class com.jeeplus.modules.**.mapper.** { *; }</option>
            <option>-keep class com.jeeplus.modules.**.entity.** { *; }</option>
            <!--此文件下存在xml的bean的使用-->
            <option>-keep class com.jeeplus.modules.act.** { *; }</option>
            <!--<option>-keep class com.jeeplus.modules.**.web.** { *; }</option>-->
            <!--<option>-keep class com.jeeplus.modules.**.service.** { *; }</option>-->
            <!--<option>-keep class com.xxx.xxx.xxx.controller.** { <methods>; }</option>-->
            <!--<option>-keep class com.xxx.xxx.xxx.dao.** { <methods>; }</option>-->
            <!--<option>-keep class com.xxx.xxx.xxx.exception { <methods>; }</option>-->
            <!--<option>-keep class com.xxx.xxx.xxx.model.** { <methods>; }</option>-->
            <!--指定外部模糊字典-->
            <!--<option>-obfuscationdictionary dictionary_rules.txt</option>-->
            <!--指定class模糊字典-->
            <option>-classobfuscationdictionary dictionary_rules.txt</option>
            <!--指定package模糊字典-->
            <!--<option>-packageobfuscationdictionary dictionary_rules.txt</option>-->


        </options>
        <!--class 混淆后输出的jar包-->
        <outjar>classes-autotest.jar</outjar>
        <!-- 添加依赖,这里你可以按你的需要修改,这里测试只需要一个JRE的Runtime包就行了 -->
        <libs>
            <lib>${java.home}/lib/rt.jar</lib>
        </libs>
        <!-- 对什么东西进行加载,这里仅有classes成功,毕竟你也不可能对配置文件及JSP混淆吧-->
        <injar>classes</injar>
        <!-- 输出目录-->
        <outputDirectory>${project.build.directory}</outputDirectory>
    </configuration>
</plugin>

2、dictionary_rules.txt

九q
九w
九e
九r
九t
九y
九u
九i
九o
九p
九a
九s
九d
九f
九g
九h
九j
九k
九l
九z
九x
九c
九v
九b
九n
九m

3、自定义bean的命名策略类

public class SdpAnnotationBeanNameGenerator extends AnnotationBeanNameGenerator {
    /**
     * 为了配合proguard使用,需要自定义bean的命名策略为结合包名的,
     * @param definition
     * @return
     */
    protected String buildDefaultBeanName(BeanDefinition definition) {
        String className =definition.getBeanClassName();
        if(className.contains("九")){
            //proguard混淆
            className=className.replaceAll("\\.","_");
            System.out.println("---------------------------------------------");
            System.out.println("---------------------------------------------");
            System.out.println("---------------------------------------------");
            System.out.println(className);
            System.out.println("---------------------------------------------");
            System.out.println("---------------------------------------------");
            System.out.println("---------------------------------------------");
        }else{
            //普通代码
            className=className.substring(className.lastIndexOf(".")+1);
            if(className.toLowerCase().endsWith("impl")){
                className=className.substring(0, className.length()-4);
            }
            if((className.toLowerCase().endsWith("service")||className.toLowerCase().endsWith("dao"))==false){
                return super.buildDefaultBeanName(definition);
            }
        }
        return className;
    }
}

4、为扫描配置自定义的命名类

<context:component-scan base-package="xxx" name-generator="com.jeeplus.common.beanname.SdpAnnotationBeanNameGenerator">
   ....
</context:component-scan>

二、混淆后的代码处理流程

1、pom.xml文件调整proguard

在这里插入图片描述

2、第一步打包

在这里插入图片描述

3、找到生成的混淆的jar包

在这里插入图片描述

4、将classes-pg.jar复制到D:\temp目录下通过“jar -xvf classes-pg.jar”解压jar包,其他方式可能有乱码

在这里插入图片描述

5、找到需要单独打成jar包的文件夹

在这里插入图片描述

6、放到D:\package\com\jeeplus目录下

在这里插入图片描述

7、将MANIFEST.MF文件放在packag目录下

在这里插入图片描述

8、打开cmd按截图执行命令

d:
cd package
jar -cfm robot.jar MANIFEST.MF com

在这里插入图片描述

9、将生成的jar包放在WEB-INF/lib目录下

在这里插入图片描述

在这里插入图片描述

10、删除dialoguesession文件夹

在这里插入图片描述

11、pom.xml配置maven本地jar包

在这里插入图片描述

12、添加robot.jar到依赖

在这里插入图片描述

13、调整由于类重命名导致的import失效即可

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值