在构建“maven-plugin”包时如何使用 Proguard 混淆?

Posted

技术标签:

【中文标题】在构建“maven-plugin”包时如何使用 Proguard 混淆?【英文标题】:How do I use Proguard obfuscation while building a "maven-plugin" package? 【发布时间】:2016-04-14 20:56:24 【问题描述】:

“maven-plugin”项目(使用maven-plugin-plugin)生成的输出JAR 被Proguard 工具执行的混淆破坏。尝试将混淆的 JAR 用作 Maven 插件会生成异常,例如 MojoExecutionException,它会因错误而终止构建。允许生成包含自动生成的插件描述符的工作“maven-plugin”JAR 的正确 Proguard 配置选项是什么?

【问题讨论】:

如果我们有更多这样的答案(和问答)就好了。 感谢您的赞美 :) 我希望这对其他人有所帮助 - 在导致集成测试失败后,我花了将近 4 个小时来追踪问题的确切原因。由于我无法找到另一个可以解决我的确切问题的网络资源,所以我提出了这个 Q/A,希望没有其他人需要在这个错误上浪费这么多时间。 【参考方案1】:

Maven 插件和 Proguard 工具的基础知识

为了生成一个 Maven 插件(maven 包装类型"maven-plugin",它会生成一个包含插件特定配置资源的 JAR),我们必须在我们的 Mojos 的位置和名称上指示 maven-plugin-plugin。假设正确配置了 maven-plugin-plugin 执行,using annotations 或其他配置选项,生成的 JAR 将在 JAR 根目录的 META-INF 目录中包含一个 plugin.xml 文件。这个 plugin.xml 文件使用对 Java 类和包名称的静态引用来描述插件的目标和可配置参数(您可以在此文件here 上找到更多信息)。

在构建“maven-plugin”JAR 时必须特别注意混淆;在这里,我们解释了使用Proguard obfuscation library 所采取的步骤。使用 default Proguard configuration for library obfuscation 时,生成的 JAR 将不再正常工作,因为 Proguard 重命名、缩小、重定位和混淆了 Maven 插件的重要文件。尝试使用您的插件可能会导致异常终止构建,并出现与 Maven 运行时无法定位和处理插件的配置和类文件相关的错误。

然而,通过一些重新配置,我们可以指示 Proguard 正确维护生成的插件文件和“maven-plugin”JAR 的目录结构。 Proguard 选项的必要更改如下(请参阅有关以下链接的注释):


自定义 Proguard 配置

目录结构

-keepdirectories

-keepdirectories

这指示 Proguard 维护输入 JAR 目录结构,而不是将所有文件移动到根目录。 Maven 期望 plugin.xml 文件位于 /META-INF/maven/ 目录中,该目录通过此选项与所有其他目录一起保留。您可以通过指定目录过滤器更具体地过滤保留的目录,但是我选择不加选择地维护所有输入目录结构。

静态包参考

-keeppackagenames

-keeppackagenames org.apache.maven.plugin.my.MyMojo

您应该将占位符包替换为包含您的 Mojo 定义的包。如果您的 Mojo 定义不共享一个公共包,您应该根据需要使用多个选项指定每个唯一的包。如果您不确定需要保留哪些包,请在文本编辑器中打开生成的 plugin.xml 文件并检查每个“mojo”定义中的“实施”元素。 “implementation”元素通过完全限定名称指定一个类。这些完全限定类名的每个包组件都是您应该指定的包。例如,我的 basedir-plugin 包含一个 Mojo 实现元素值“com.github.emabrey.maven.plugins.basedir.RootDirectoryGoal”,所以我将选项写为-keeppackagenames com.github.emabrey.maven.plugins.basedir

静态类引用

-keepnames

-keepnames class * implements org.apache.maven.plugin.AbstractMojo

此选项可防止 Proguard 重命名包含 Maven 插件 Mojo 实现的类。如果这些类被重命名,上述“实现”元素将不再正确识别包含 Mojo 实现的类。

私有类字段和方法

-keepclassmembers

-keepclassmembers class * implements org.apache.maven.plugin.AbstractMojo 
    private <fields>;
    private <methods>;

此选项可防止 Proguard 重命名插件 Mojo 实现中的类级别方法和字段。 Maven 使用这些类字段/方法的名称来生成插件的配置元素。如果 Proguard 重命名字段,Maven 执行环境将无法使用用户配置正确填充 Mojo 实现。


已完成 Proguard 配置

为方便起见,此处提供了 2.0.13 版的完整配置(more versions here;请参阅有关插件版本的说明),包括默认库配置以及上述修改(请记住指定 $tool.proguard.version属性为latest version of the proguard-base artifact,并将占位符包“org.apache.maven.plugin.my.MyMojo”替换为适当的值):

<!-- Configures Proguard obfuscation tool to generate an
     obfuscated version of the JAR file that replaces the
     default unobfuscated JAR.
-->
<plugin>
    <groupId>com.github.wvengen</groupId>
    <artifactId>proguard-maven-plugin</artifactId>
    <version>2.0.13</version>
    <executions>
        <execution>
            <id>obfuscation-packaging</id>
            <phase>package</phase>
            <goals>
                <goal>proguard</goal>
            </goals>
            <configuration>
                <proguardVersion>$tool.proguard.version</proguardVersion>
                <obfuscate>true</obfuscate>
                <attach>true</attach>
                <appendClassifier>false</appendClassifier>
                <addMavenDescriptor>true</addMavenDescriptor>
                <injar>$project.build.finalName.jar</injar>
                <injarNotExistsSkip>true</injarNotExistsSkip>
                <libs>
                    <lib>$java.home/lib/rt.jar</lib>
                </libs>

                <options>
                    <option>-keepdirectories</option>
                    <option>-keeppackagenames org.apache.maven.plugin.my.MyMojo</option>
                    <option>-keepnames class * implements org.apache.maven.plugin.AbstractMojo</option>
                    <option>-keepclassmembers class * implements org.apache.maven.plugin.AbstractMojo 
                        private <![CDATA[<fields>]]>;
                        private <![CDATA[<methods>]]>;
                    
                    </option>
                    <option>-keepparameternames</option>
                    <option>-renamesourcefileattribute SourceFile</option>
                    <option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
                        SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
                    </option>
                    <option>-target 1.8</option>
                    <option>-keep public class * 
                        public protected *;
                        
                    </option>
                    <option>-keepclassmembernames class * 
                        java.lang.Class class$(java.lang.String);
                        java.lang.Class class$(java.lang.String, boolean);
                        
                    </option>
                    <option>-keepclasseswithmembernames,includedescriptorclasses class * 
                        native <![CDATA[<methods>]]>;
                        
                    </option>
                    <option>-keepclassmembers,allowoptimization enum * 
                        public static **[] values();
                        public static ** valueOf(java.lang.String);
                        
                    </option>
                    <option>-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();
                        
                    </option>
                </options>
            </configuration>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>net.sf.proguard</groupId>
            <artifactId>proguard-base</artifactId>
            <version>$tool.proguard.version</version>
        </dependency>
    </dependencies>
</plugin>  

备注

链接问题 (9-04-2019)

Proguard 网站存在某种问题,这意味着我指向程序选项的链接并不总是像包含锚点的链接那样指向锚点的位置。如果您在他们的网页上最初没有看到您点击的选项,只需稍微向上滚动即可。

proguard-maven-plugin 的版本问题 (9-04-2019)

截至 2017 年 3 月,com.github.wvengen:proguard-maven-plugin 的当前版本为 2.0.14,直到进行此编辑。我将使用版本号2.0.13 保持原始配置不变,因为版本2.0.14 包含潜在的重大更改。它现在包含种子和映射文件,作为最终 Proguard 混淆工件的输出工件的一部分。大多数用例实际上不太可能在使用工件中的其他文件时遇到任何问题,但我不是忍者编辑配置以指向2.0.14,而是留下此注释并让您评估哪个版本适合您的项目.也就是说,只需将版本更改为 &lt;version&gt;2.0.14&lt;/version&gt; 应该没问题,因为版本 2.0.14 的提交历史记录中没有注意到插件配置更改。

【讨论】:

感谢您的信息。我能够使用您的答案和***.com/a/34838377/819866 在项目中实施proguard。

以上是关于在构建“maven-plugin”包时如何使用 Proguard 混淆?的主要内容,如果未能解决你的问题,请参考以下文章

版本-maven-plugin - 不使用更新的属性构建。

我们如何在构建 R 包时设置常量变量?

构建 R 包时如何链接静态库

Springboot项目打成jar包时,执行jar包出现中XXX.jar没有主清单属性

使用 sbt-native-packager 构建 docker 包时重复映射

添加nuget包时不会自动安装依赖项