使用 ProGuard 混淆 clojure uberjars

Posted

技术标签:

【中文标题】使用 ProGuard 混淆 clojure uberjars【英文标题】:Obfuscating clojure uberjars with ProGuard 【发布时间】:2012-08-30 04:02:49 【问题描述】:

我想知道是否有人有任何使用 proguard 混淆他们的 leiningen 编译的 uberjar 的经验。我已尽力在 Google 上寻找解决方案,但无法真正找到答案。我想知道这是否可能。

我一直试图混淆一个默认的 lein 项目。这是 core.clj 文件:

(ns proguard.core
(:gen-class))

(defn -main
  "I don't do a whole lot."
  [& args]
  (println "Hello, World!"))

项目文件:

(defproject proguard "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license :name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"
  :dependencies [[org.clojure/clojure "1.4.0"]]
  :aot :all
  :main proguard.core)

还有我的 proguard 配置文件:

-injars clojure/proguard/target/proguard-0.1.0-SNAPSHOT-standalone.jar
-outjars clojure/test-project

-libraryjars /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/rt.jar

-dontshrink
-dontoptimize
-dontusemixedcaseclassnames
-dontpreverify
-dontnote
-printseeds

-keepclasseswithmembers public class * 
    public static void main(java.lang.String[]);


-keep class clojure.core__init  public static void load(); 
-keep class clojure.core_proxy__init  public static void load(); 
-keep class clojure.core_print__init  public static void load(); 
-keep class clojure.genclass__init  public static void load(); 
-keep class clojure.core_deftype__init  public static void load(); 
-keep class clojure.core.protocols__init  public static void load(); 
-keep class clojure.gvec__init  public static void load(); 
-keep class clojure.java.io__init  public static void load(); 
-keep class clojure.lang__init  public static void load(); 

-keep class proguard.core__init 
    public static void load();

-keep class proguard.core 
    public *** super*(...);

每当我尝试运行经过混淆的 jar 时,我都会收到以下错误:

Exception in thread "main" java.lang.ExceptionInInitializerError
    at clojure.lang.ve.<init>(Unknown Source)
    at clojure.lang.ve.c(Unknown Source)
    at clojure.lang.yf.a(Unknown Source)
    at proguard.core.<clinit>(Unknown Source)
Caused by: java.lang.ClassNotFoundException: clojure.lang.PersistentList, compiling:(clojure/core.clj:20)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.at.b(Unknown Source)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.bj.a(Unknown Source)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.at.b(Unknown Source)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.at.a(Unknown Source)
    at clojure.lang.xh.a(Unknown Source)
    at clojure.lang.xh.a(Unknown Source)
    at clojure.lang.xh.b(Unknown Source)
    at clojure.lang.xh.d(Unknown Source)
    at clojure.lang.xh.c(Unknown Source)
    at clojure.lang.xh.<clinit>(Unknown Source)
    ... 4 more
Caused by: java.lang.ClassNotFoundException: clojure.lang.PersistentList
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
    at clojure.lang.ec.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
    at clojure.lang.xh.h(Unknown Source)
    at clojure.lang.bp.b(Unknown Source)
    at clojure.lang.bp.a(Unknown Source)
    at clojure.lang.bq.a(Unknown Source)
    ... 19 more

我不太确定我在这里做错了什么...我尝试遵循针对 clojure 的 proguard 教程 obfuscating with proguard,但是它是 android 和 ant 特定的,所以我想知道这个过程是否是对于使用 lein 的桌面应用程序来说完全不同。

提前致谢。

【问题讨论】:

我没有使用 proguard 的经验,但从堆栈跟踪看来,这个混淆器已经从 uberjar 中排除了 clojure 运行时。您必须保留 clojure.jar 中的 all 类才能使您的程序正常工作,而不仅仅是从您的配置中看到的几个 __init 类。我猜测一下,说你必须将 clojure.jar 添加到 -libraryjars 的列表中。 嘿,感谢您为我指明了正确的方向!整个 clojure.jar 确实需要保留。我很快就会回答我自己的问题。 [编辑:嗯,我想我不能那样做,因为这个问题还太年轻......] 您应该正确回答自己的问题,因为它已经足够老了。就目前而言,问题之前的答案令人困惑。 我现在已经做到了。请参阅下面的答案。 【参考方案1】:

从上面复制:

混淆 uberjars

1.准备你的 project.clj 文件

这是我的一份副本(简单,默认的 lein 项目,带有 cmets):

(defproject proguard "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license :name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"
  :dependencies [[org.clojure/clojure "1.4.0"]]
  :main proguard.core
  ;;; Make sure everything is aot compiled
  :aot :all
  ;;; Remove source .clj files from the resulting jar
  :omit-source true
  )

这里没有更多内容...还要确保 (:gen-class) 包含在您的命名空间声明中。

使用lein uberjar 构建 uberjar,然后我们将进入下一步。

2。准备你的 ProGuard 配置文件

我的文件的副本再次带有注释

# Our uberjar
-injars clojure/proguard/target/proguard-0.1.0-SNAPSHOT-standalone.jar
# Our output direcotry
-outjars clojure/obfuscated

# Link to rt.jar. I'm on a Mac so your path may differ
-libraryjars /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/rt.jar

# ProGuard options. Detailed explanation here http://proguard.sourceforge.net/index.html#manual/usage.html
-dontskipnonpubliclibraryclassmembers
-dontnote
-printseeds

# What we will be doing is obfuscating, shrinking and optimizing the jar. 
# If you experience any problems start out with obfuscation and add the 
# -dontoptimize  and the -dontshrink flags and see if it works.

# Tell proguard to leave the clojure runtime alone
# You would need to add any other classes that you wish to preserve here.
-keep class clojure.**  *; 

# Keep our core__init class
-keep class proguard.core__init 
    public static void load();


# Keep classes that contain a main method (otherwise we won't be able to run the jar)
-keepclasseswithmembers public class * 
    public static void main(java.lang.String[]);

就是这样。现在用你的新配置文件java -jar proguard.jar @myconfig.pro 运行proguard。由于-printseeds 标志,您应该会看到一堆输出(如果您不想看到 proguard 将保留哪些类,您当然可以将其删除)。

【讨论】:

以上是关于使用 ProGuard 混淆 clojure uberjars的主要内容,如果未能解决你的问题,请参考以下文章

使用 ProGuard 进行文件混淆

防止 Proguard 使用注释混淆子类

使用 ProGuard 混淆私有字段

Spring boot使用ProGuard实现代码混淆

使用 proguard 的 Android 混淆应用程序会不断混淆库 jar - 是吗?

为啥 proguard 不混淆方法体?