8

I was trying to learn how to use ProGuard, and it is no way as easy as I thought. At first I found a simple Java code to try it, a simple two class Swing calculator.

The code can be found by following that link, but I found it too verbose to post the it here. Anyway, it is a plain application with entry point on Calc.main(), there are no packages.

Then I compiled both sources with:

$ javac *.java

and created the .jar file (because it seems ProGuard only work with jars):

$ jar cvef Calc calc.jar *.class
added manifest
adding: Calc.class(in = 3869) (out= 2126)(deflated 45%)
adding: Calc$ClearListener.class(in = 468) (out= 327)(deflated 30%)
adding: CalcLogic.class(in = 1004) (out= 515)(deflated 48%)
adding: Calc$NumListener.class(in = 1005) (out= 598)(deflated 40%)
adding: Calc$OpListener.class(in = 1788) (out= 1005)(deflated 43%)

Wrote the ProGuard file named obfuscate.pro:

-injars       calc.jar
-outjars      calc_obf.jar
-libraryjars  <java.home>/lib/rt.jar

-keep public class Calc extends javax.swing.JFrame {
public static void main(java.lang.String[]);
}

And finally run ProGuard:

$ ~/progs/proguard/proguard4.8/bin/proguard.sh @obfuscate.pro
ProGuard, version 4.8
Reading program jar [/home/lucas/tmp/calc.jar]
Reading library jar [/usr/lib/jvm/java-7-openjdk-i386/jre/lib/rt.jar]
Error: The output jar is empty. Did you specify the proper '-keep' options?

Well, obviously didn't work. I got tired of messing with ProGruard parameters, specially with that -keep options, with no success. All I found in the docs related to my problem could not help me. Then I am resorting to you... What is wrong? How to do it right?

lvella
  • 12,754
  • 11
  • 54
  • 106
  • Your `main` method is capitalized, which it almost certainly shouldn't be. – Louis Wasserman Aug 24 '12 at 17:51
  • @LouisWasserman Right, fixed. Still have the same problem. – lvella Aug 24 '12 at 17:53
  • This looks fine to me. Can you upload your jar and your ProGuard configuration somewhere, so we can test solutions instead of just guessing what might be wrong on your computer? – Louis Wasserman Aug 24 '12 at 18:04
  • I have no ProGuard configuration, just unpacked and used right away, from the `bin` directory (see my invocation). I gave all the steps to build the jar, but here it is: http://www.4shared.com/file/xekHfRyx/calc.html?refurl=d1url – lvella Aug 24 '12 at 18:26
  • Here is one example with gradle
    https://stackoverflow.com/questions/64355998/proguard-example-for-gradle-java-application/64375319#64375319
    – jfk Oct 15 '20 at 15:59

3 Answers3

6

I got it to work using the following configuration file:

-injars       calc.jar
-outjars      calc_obf.jar
-libraryjars  <java.home>/lib/rt.jar
-keep class Calc {
  public static void main(java.lang.String[]);
}

Most notably, I ditched the public in front of class Calc.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
1

I've had similar problems, solved by taking out Java modifiers.

Java modifiers such as visibility modifiers are optional in the ProGuard configuration file -keep option (and in related options -keepclassmembers etc.)

From manual: -keep [,modifier,...] class_specification

So unless there is a specific reason otherwise, you can leave them out.

0

Here is solution with gradle

  1. Create a runnable jar with all dependent libraries copied to a directory "dependencies" and add the classpath in the manifest.

    task createJar(type: Jar) {
       println("Cleaning...")
       clean
       manifest {
       attributes('Main-Class': 'com.abc.gradle.hello.App',
         'Class-Path': configurations.default.collect { 'dependencies/' + 
          it.getName() }.join(' ')
          )
       }
       from {
          configurations.compile.collect { it.isDirectory() ? it : zipTree(it) 
          }
       } with jar
       println "${outputJar} created"
       }
    
  2. Copy the dependencies

    task copyDepends(type: Copy) {
      from configurations.default
      into "${dependsDir}"
    }
    
  3. Obfuscate the library with Proguard

    task proguard(type: proguard.gradle.ProGuardTask) {
       println("Performing obfuscation..")
       configuration 'proguard.conf'
       injars "${outputJar}"
       outjars "${buildDir}/libs/${rootProject.name}_proguard.jar"
       libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
       libraryjars "${dependsDir}"
     }
    

Here is the complete build.gradle

buildscript {
 repositories {
    mavenCentral()
 }
 dependencies {
    classpath 'net.sf.proguard:proguard-gradle:6.0.3'
    classpath 'net.sf.proguard:proguard-base:6.0.3'
 }
}

plugins {
 id 'java'
 id 'application'
}

repositories {
  mavenCentral()
}

dependencies {
   implementation 'org.slf4j:slf4j-api:1.7.30'
   implementation 'ch.qos.logback:logback-classic:1.2.3'
   implementation 'ch.qos.logback:logback-core:1.2.3'
   testImplementation 'junit:junit:4.13'
}

def outputJar = "${buildDir}/libs/${rootProject.name}.jar"
def dependsDir = "${buildDir}/libs/dependencies/"
def runnableJar = "${rootProject.name}_fat.jar";

task copyDepends(type: Copy) {
 from configurations.default
 into "${dependsDir}"
}

task createJar(type: Jar) {
 println("Cleaning...")
 clean
 manifest {
    attributes('Main-Class': 'com.abc.gradle.hello.App',
            'Class-Path': configurations.default.collect { 'dependencies/' + 
   it.getName() }.join(' ')
    )
  }
  from {
    configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
   } with jar
   println "${outputJar} created"
  }

task proguard(type: proguard.gradle.ProGuardTask) {
   println("Performing obfuscation..")
   configuration 'proguard.conf'
   injars "${outputJar}"
   outjars "${buildDir}/libs/${rootProject.name}_proguard.jar"

   libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
   libraryjars "${dependsDir}"

  }

Proguard.conf

-keep public class * {
   public * ;
 }

Gradle commands to obfuscate

gradle createJar
gradle copyDepends
gradle proguard
jfk
  • 4,335
  • 34
  • 27