Maven 环境下使用 proguard-maven-plugin 插件混淆你的源码

摘要  a、ProGuard(http://proguard.sourceforge.net/) 是比较出色的 Java 代码混淆工具,可以有效的保护与优化你的代码。当然这里说的保护是防止恶意抄袭,通过混淆造成反编译阅读困难。但逻辑与内容并不会加密,仔细分析还是可以获得一些信息。 b、proguard-maven-plugin 是 Maven 中的 ProGuard 插件,可以非常方便的在你做 Maven 打包时进行代码混淆。 c、本文重点介绍 Maven 环境下插件的配置(重点参数),与类路径加载资源问题。

一、场景介绍

两个工程 Project1,Project2(将被混淆的工程)。Project1 将通过 Maven 依赖配置的方式引用混淆后的 Project2。后面我会详细介绍 pom.xml 的配置。

二、Maven 配置

1、Project1 的 pom.xml

该 pom.xml 比较简单主要通过 classifier 来判断是否使用混淆的 Jar(Project2)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<? 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 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
     < modelVersion >4.0.0</ modelVersion >
 
     < groupId >org.noahx.proguard.example</ groupId >
     < artifactId >project1</ artifactId >
     < version >1.0-SNAPSHOT</ version >
 
     < dependencies >
         < dependency >
             < groupId >org.noahx.proguard.example</ groupId >
             < artifactId >project2</ artifactId >
             < classifier >pg</ classifier > <!--如果不想依赖混淆的包,请注释掉该行-->
             < version >1.0-SNAPSHOT</ version >
         </ dependency >
     </ dependencies >
 
</ project >


2、Project2 的 pom.xml

pom.xml 中配置的 proguard-maven-plugin 来做混淆,详细说明见注释。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<? 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 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
     < modelVersion >4.0.0</ modelVersion >
 
     < groupId >org.noahx.proguard.example</ groupId >
     < artifactId >project2</ artifactId >
     < version >1.0-SNAPSHOT</ version >
 
 
     < build >
         < plugins >
 
             < plugin >
                 < groupId >com.github.wvengen</ groupId >
                 < artifactId >proguard-maven-plugin</ artifactId >
                 < version >2.0.7</ version >
                 < executions >
                     < execution >
                         < phase >package</ phase >
                         < goals >
                             < goal >proguard</ goal >
                         </ goals >
                     </ execution >
                 </ executions >
                 < configuration >
                     < attach >true</ attach >
                     < attachArtifactClassifier >pg</ attachArtifactClassifier >
                     <!-- attach 的作用是在 install 与 deploy 时将生成的 pg 文件也安装与部署 -->
                     < options > <!-- 详细配置方式参考 ProGuard 官方文档 -->
                         <!--<option>-dontobfuscate</option>-->
                         < option >-ignorewarnings</ option > <!--忽略所有告警-->
                         < option >-dontshrink</ option >   <!--不做 shrink -->
                         < option >-dontoptimize</ option > <!--不做 optimize -->
                         < option >-dontskipnonpubliclibraryclasses</ option >
                         < option >-dontskipnonpubliclibraryclassmembers</ option >
 
                         < option >-repackageclasses org.noahx.proguard.example.project2.pg</ option >
                         <!--平行包结构(重构包层次),所有混淆的类放在 pg 包下-->
 
                         <!-- 以下为 Keep,哪些内容保持不变,因为有一些内容混淆后(a,b,c)导致反射或按类名字符串相关的操作失效 -->
 
                         < option >-keep class **.package-info</ option >
                         <!--保持包注解类-->
 
                         < option >-keepattributes Signature</ option >
                         <!--JAXB NEED,具体原因不明,不加会导致 JAXB 出异常,如果不使用 JAXB 根据需要修改-->
                         <!-- Jaxb requires generics to be available to perform xml parsing and without this option ProGuard was not retaining that information after obfuscation. That was causing the exception above. -->
 
                         < option >-keepattributes SourceFile,LineNumberTable,*Annotation*</ option >
                         <!--保持源码名与行号(异常时有明确的栈信息),注解(默认会过滤掉所有注解,会影响框架的注解)-->
 
                         < option >-keepclassmembers enum org.noahx.proguard.example.project2.** { *;}</ option >
                         <!--保持枚举中的名子,确保枚举 valueOf 可以使用-->
 
                         < option >-keep class org.noahx.proguard.example.project2.bean.** { *;}</ option >
                         <!--保持 Bean 类,(由于很多框架会对 Bean 中的内容做反射处理,请根据自己的业务调整) -->
 
                         < option >-keep class org.noahx.proguard.example.project2.Project2 { public void init(); public void
                             destroy(); }
                         </ option >
                         <!-- 保持对外的接口性质类对外的类名与方法名不变 -->
 
                     </ options >
                     < outjar >${project.build.finalName}-pg</ outjar >
                     < libs >
                         < lib >${java.home}/lib/rt.jar</ lib >
                     </ libs >
 
                 </ configuration >
             </ plugin >
 
          </ plugins >
     </ build >
 
</ project >


三、Java 混淆前后内容比较

这里只比较 Project2 类的不同。其它类的比较,请大家使用 jd-gui 等反编译工具进行比较。

1、混淆前的 Project2 类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package org.noahx.proguard.example.project2;
 
import org.noahx.proguard.example.project2.dao.TestDao;
import org.noahx.proguard.example.project2.impl.User;
 
/**
  * Created by noah on 8/20/14.
  */
public class Project2 {
 
     public void init() {
         test1();
         test2();
     }
 
     private void test1() {
         Status on = Status.valueOf( "On" );
         switch (on) {
             case On: {
 
             }
             break ;
             case Off: {
 
             }
             break ;
         }
     }
 
     private void test2() {
         TestDao testDao= new TestDao();
         User user= new User();
         user.setUserid( "abc" );
         user.setPassword( "pwd" );
         user.setDescription( "des" );
         testDao.save(user);
 
     }
 
     private void test3() {
     }
 
     private void test4() {
     }
 
     private void throwException() {
         throw new RuntimeException( "hello" );
     }
 
     public void destroy() {
         test3();
         test4();
         throwException();
     }
}


2、混淆后的 Project2 类

所有没有指定 keep 的内容都变为了 a,b,c...,增大了阅读难度。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package org.noahx.proguard.example.project2;
 
import org.noahx.proguard.example.project2.pg.a;
 
public class Project2
{
   public void init()
   {
     b();
     c();
   }
 
   private void b() {
     b localb = b.valueOf( "On" );
     switch (a.a[localb.ordinal()])
     {
     case 1 :
       break ;
     case 2 :
     }
   }
 
   private void c()
   {
     a locala = new a();
     org.noahx.proguard.example.project2.pg.b localb = new org.noahx.proguard.example.project2.pg.b();
     localb.a( "abc" );
     localb.b( "pwd" );
     localb.c( "des" );
     locala.a(localb);
   }
 
   private void d()
   {
   }
 
   private void e() {
   }
 
   public void a() {
     throw new RuntimeException( "hello" );
   }
 
   public void destroy() {
     d();
     e();
     a();
   }
}


四、类路径中资源加载问题

使用 ProGuard 产生的 Jar 包,会发生无法定位 Jar 中资源的问题。原因不详,我没有太深入研究。

使用 [类名].class.getResource(),Thread.currentThread().getContextClassLoader().getResource(),不论是否以“/”开头都返回 null。没有混淆的 Jar 是没有这个问题的。

我使用了一种直接读取 Jar 中内容的方式来解决。

?
1
2
3
4
5
6
7
8
9
10
11
12
final File jarFile = new File([类名]. class .getProtectionDomain().getCodeSource().getLocation().getPath()); //定位类所在的 Jar 文件
             if (jarFile.isFile()) {
                 final JarFile jar = new JarFile(jarFile);
                 Enumeration<JarEntry> entries = jar.entries();
                 while (entries.hasMoreElements()) {
                     JarEntry entry = entries.nextElement();
                     if (entry.getName().startsWith( "org/noahx" )) {
                         InputStream entryInputStream = jarFile.getInputStream(entry);  //遍历包中的内容来获得资源
                     }
                 }
                 jar.close();
             }

五、总结

使用 proguard-maven-plugin 插件,既保持了 Maven 的依赖模式,又满足了我的混淆需求。其它详细的参数配置,大家可以参考官方文档。

ProGuard 满足了我的需求。至于是好是坏,希望大家不要围绕这点做没有必要的争论,谢谢。

样例程序下载:http://pan.baidu.com/s/1dDGNoDr

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页