I'm very new to obfuscation and don't have a lot of experience with ant. Come someone provide me a way to obfuscate a regular Java application with ProGuard (or any other open source obfuscator). Currently I'm using NetBeans 6.5.1, and only see the obfuscation ability if I create a JAVA ME, and not a Java Application like I have. I've looked at http://wiki.netbeans.org/DevFaqModuleObfuscation, but don't understand what they're saying.
Thanks for any input.
The FAQ you point to is for obfuscating NetBeans modules. This is quite a complicated use case, so I will assume that it is not the regular application you are interested in.
Very briefly: the obfuscation process changes the names of classes, methods and fields to make it more difficult to reverse engineer your application.
This causes some issues:
the JVM requires your application to have a public static void main( String args[] ) in a public class, so you must tell proguard not to change this name
if you are using any sort of introspection, you have to protect the relevant names from being changed
other cases, as explained in the manual
Additionally, proguard strips out unused code. If you have any classes that are used but not referenced directly, you have to -keep them as well.
The proguard documentation includes an example of how to obfuscate a simple application. Here is the example explained (with some less confusing names):
-injars application.jar # obfuscate all the classes in the named jars
-outjars obfuscated.jar # save all the obfuscated classes to the named jar
-libraryjars <java.home>/lib/rt.jar # these are all the libraries that the application uses
-printmapping obfuscation.map # save a file linking the original names to the obfuscated ones
# this helps understanding stack traces from the obfuscated application
# we need to keep our main class and the application entry point
-keep public class com.mycompany.Application {
public static void main(java.lang.String[]);
}
Unless you specify -dontshrink, proguard will remove any code not kept or not referenced from any kept code. So in the above configuration, any code not referenced (indirectly) by the main method will be removed.
Proguard includes an Ant task that can be used to integrate with the NetBeans workflow. I would suggest experimenting manually first though, without Ant, as that takes one of the complicating factors out of the process. Build your application jar with NetBeans and then try to obfuscate with the above configuration (fleshed out if necessary). Make sure to test the obfuscated application, as innumerable things can go awry. Once you have a working proguard configuration, try adding an Ant task to your build file to automate the obfuscation process within NetBeans.
Another solution than -dontskipnonpubliclibraryclasses is to use the same JDK for running proguard as you used for compiling the code in the JAR file.
For example, instead of
java -jar ../proguard3.8/lib/proguard.jar
use
/usr/local/jdk1.5.0/bin/java -jar ../proguard3.8/lib/proguard.jar
Jacob
Related
For my master thesis I'm studying and improving the security of an application. The code is obfuscated and my goal now is to see how easily I can exploit the application. However, I'm having some problems; I think I may have found a piece of code that, when removed, will allow me to override some fundamental step of the application logic. As such, I want to recompile the single class that contains that piece of code and replace the one on the application with this new version. I used dex2jar to obtain a jar with all the classes and have already obtained the .java file with the class I want to alter. My exact problem is how I can recompile the file. I already downloaded the Android API jars and I'm using javac with the classpath pointing to the jar having the remaining classes of the application and to the Android API, but I still can't compile as javac complains about some Android literals being ambiguous. Can you please help? Thanks!
MATLAB is configured to search its static java class path before searching the user-modifiable dynamic path. Unfortunately, the static path contains quite a number of very old public libraries, so if you are trying to use a new version you may end up loading the wrong implementation and get errors.
For instance, the static path contains an old copy of the google-collections.jar, which has long been supplanted by Google's guava library and which has some of the same class names (e.g. com.google.common.base.Objects). As a result, if you invoke a Guava method that uses a newer method of one of such a class, you will end up getting surprising NoSuchMethodErrors because the google-collections jar is found first.
As of R2012b, MATLAB lets you specify additional jars to add to the static path by putting a javaclasspath.txt file in your preferences folder, but that adds jars to the end of the path, and doesn't let you override jars that are built into MATLAB.
So what is the best way around this?
I got an official response from Mathworks:
As of MATLAB R2013a (also in R2012b), classes can be added to the front of the static Java class path by including the following line in javaclasspath.txt:
<before>
Any directory that is after this line in javaclasspath.txt will be added to the front of the static Java class path. This is an undocumented use of javaclasspath.txt as of R2013a.
But overall in MATLAB, the ability to add classes to the front of the static Java classpath is not available through javaclasspath.txt in MATLAB 8.0 (R2012b).
MATLAB searches for classpath.txt in the following order:
In the startup directory. As of MATLAB 8.0 (R2012b) a warning will be shown if the file is found there and it will be ignored.
In the first directory on the MATLABPATH environment variable. (This environment variable is used in the bin/matlab shell script on Linux and in general is not used by the end-user).
In the toolbox/local directory.
Although the MATLABPATH environment variable of point 2 is normally not used by end-users we can use it in a workaround to allow reading a custom classpath.txt outside of the toolbox/local directory.
On Windows:
You will need to create the MATLABPATH environment variable. The first directory on it should be your directory with the custom classpath.txt AND you will also need to add the toolbox\local directory as second option. So from a cmd prompt you could do:
set MATLABPATH=c:\Users\user\Documents\myMATLABClasspath;c:\Program Files\MATLAB\R2012b
\toolbox\local
matlab.exe
One hack that appears to work is to add the jar to the top of the classpath.txt file that can be found in your MATLAB installations toolbox/local folder. Unfortunately, this is automatically generated and may get rewritten at some unspecified time, such as when you install new toolboxes, so this approach would require you to have some way to notice when this happens and reapply the hack.
If you're distributing a jar that's intended to be used with matlab, it may be better to use proguard as described at http://code.google.com/p/guava-libraries/wiki/UsingProGuardWithGuava.
If you specify that all of your classes and their (public) fields and methods are to be preserved and include guava as a program jar (not a library), then it will rename all of guava's methods and update your compiled bytecode to reference the new names.
It seems a bit hackish, but depending on the audience, it may be significantly easier than teaching your users about static vs. dynamic classpath, and it won't break any matlab code that depends on the old behavior.
Instead of obfuscating the package as suggested by #user2443532, I have found it easier to "shade" the conflicting package instead of obfuscating it - unless you actually need obfuscation. One easy way to do this is to build your package using Maven and use the maven-shade-plugin. Internal calls are modified automatically, so you don't need to modify any of the Java code.
Direct calls from Matlab will need to be modified - for example, calls to com.opensource.Class become shaded.com.opensource.Class.
For more info on shading, see What is the maven-shade-plugin used for, and why would you want to relocate Java packages?
To speed up the startup time of the JVM, the Sun developers decided it is a good idea to precompile the standard runtime classes for a platform during installation of the JVM. These precompiled classes can be found e.g. at:
$JAVA_HOME\jre\bin\client\classes.jsa
My company currently develops a Java standalone application which brings its own JRE, so it would be a fantastic option to speed up our application start time by adding our own application classes to this jsa file, too.
I don't believe the JSA file was created by magic, so: How is it created? And how can I trick the JVM into incorporating my own classes?
EDIT: I already found out the following:
The classes.jsa is created by the command
java -Xshare:dump
The list of classes to incorporate in the dump can be found in $JAVA_HOME/jre/lib/classlist.
I even managed to add my own classes here (and to add them into the rt.jar for java to find them), and to generate my own checksum below the classlist file.
The final problem is: Only classes in the packages java, com.sun, and org.w3c seem to be recognized, if I leave the same classes in their original packages, they won't be loaded. I searched the whole OpenJDK source for pointer about this, but it seems to have something to do with protection domains. If someone is interested enough in this topic and knowledgeable enough, please add some pointers for me to investigaete further.
As of Java 8u40 (and Embedded Java 8u51), Java now supports Application Class Data Sharing (AppCDS) (ie your own classes in the shared archive). On our embedded java, we've found a startup improvement of >40%! Pretty awesome for almost no work on our part...
https://blogs.oracle.com/thejavatutorials/entry/jdk_8u40_released
You were almost there, you only need a couple steps to make it work. To add your own classes to the clients.js you need the following steps:
The qualified name your classes (you have it)
The classpath of these classes (you have it)
Know how to recalculate the checksum (you have it)
Dump the new file, providing the classpath of the classes you are now precompiling with the Java classes.
Run the program, providing the same classpath that you used to dump the new classes.jsa
To provide the classpath where are the classes you are adding to the classlist, use the -Xbootclasspath/a command. It will append the directories/JARs when JVM is searching the places where the boot classes are. The default space for the classes.jsa is quite small, if you need to improve it you can use the -XX:SharedReadWriteSize and -XX:SharedReadOnlySize commands. Your dump command you look similar to this:
java -Xshare:dump -Xbootclasspath/a:C:/myfiles/directoryA/;C:/myfiles/directoryB/;C:/myJars/myJar.jar;
The last step is just run the java application normally, rememebering of turn on the share mode. You also need to add the Xbootclasspath excatly as you added on the dump. It will look similar to this:
java myapp.java -Xshare:on -Xbootclasspath/a:C:/myfiles/directoryA/;C:/myfiles/directoryB/;C:/myJars/myJar.jar;
Now every class that you put on the classlist is being shared with other instances running in the same JVM.
Interesting idea. As I read it though, it's used for sharing data across VMs and for speeding up classloading, not compiling. I'm not sure how much of a boost you would get, but it might be worth a try if you have a big lag at startup already (though the VM already tries to mitigate that).
As for trying it yourself, it appears this file is normally created when the Sun VM is installed, but you can also control it. Some details are in this older Sun Java 5 Class Data Sharing document (which you may have already seen?). Some Sun Java 6 docs also mention it a few times, but don't add much to the documentation. It seems it was originally an IBM VM feature. And, to continue the link dump, it's explained a bit in this article.
I don't personally know much about it, so I don't know how you might control it. You can regenerate it, but I don't think it's intended for you to put custom stuff into. Also, even if you can "trick" it, that would probably violate a Sun/Oracle license of some sort (you can't mess with rt.jar and redistribute, for instance). And, all that said, I doubt you would see a serious improvement in startup time unless you have thousands or tens of thousands of classes in your app?
(And this isn't really an answer, I know, but it was too big to fit in a comment, and I found the question interesting so I investigated a bit and put links here in case anyone finds the same info useful.)
It took a little figuring out but I have 4 Java8 VMs (version 1.8.0_162) running using shared classes. The following script was used to set up and test sharing and with a little modification could be used elsewhere:
#!/bin/bash
# Libraries to load
LIBS1="./lib/protobuf-java-2.6.1.jar:\
./lib/jetty-server-9.2.18.v20160721.jar:./lib/jetty-util-9.2.18.v20160721.jar:./lib/servlet-api-3.1.jar:./lib/jetty-http-9.2.18.v20160721.jar:./lib/jetty-io-9.2.18.v20160721.jar:\
./lib/derby.jar:\
./lib/json-simple-1.1.1.jar:"
LIBS2=":./lib/GTFS.jar"
# Uncomment these lines for the first phase where you are determining the classes to archive. During this phase aim to get as many classes loaded as possible
# which means loading a schedule and retrieving the stop list and next vehicle information
#
#APPCDS="-Xshare:off -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -XX:DumpLoadedClassList=../GtfsAppCds.lst"
#java -Xmx512m $APPCDS -Dderby.system.home=database -classpath $LIBS1$LIBS2 com.transitrtd.GtfsOperatorManager
# Uncomment these lines when the class list is created and run to create the shared archive. Classes marked as unverifiable will need to be removed from the
# archived class list in GtfsAppCds.lst and the lines below run again. LIBS2 above contains jars which are left out of the archive. These are jars which change
# frequently and would therefore cause the archive to be frequently rebuilt.
#
#APPCDS="-Xshare:dump -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -XX:SharedClassListFile=../GtfsAppCds.lst -XX:SharedArchiveFile=../GtfsAppCds.jsa"
#java -Xmx512m $APPCDS -classpath $LIBS1
# Uncomment these lines when wishing to verify the application is using the shared archive.
#
#APPCDS="-Xshare:on -XX:+UnlockCommercialFeatures -XX:+UseAppCDS -XX:SharedArchiveFile=../GtfsAppCds.jsa -verbose:class"
#java -Xmx512m $APPCDS -Dderby.system.home=database -classpath $LIBS1$LIBS2 com.transitrtd.GtfsOperatorManager
Note that the shared archive file (i.e.the jsa file) is architecture dependent and will need to be built on each target platform type.
Also if a jar uses sealed packages a security exception is thrown, see
https://docs.oracle.com/javase/tutorial/deployment/jar/sealman.html
for information on sealed packages. This was the case above with derby.jar but the problem could be solved by unpacking the jar file, replacing Sealed:true with Sealed:false in the manifest and repacking it.
jars built with older versions of java cannot be used in a shared archive, in the case above the derby version needed to be upgraded from 10.10 to 10.14 to benefit.
I want to decompile a java program and recompile the derived (obfuscated) source. I unpacked the .jar archive and got a directory structure like that:
com/
com/foo/A/
com/foo/A/A.class
com/foo/A/B.Class
com/foo/B/A.class
...
com/foo/A.class
com/foo/B.class
org/foo/Bar.class
...
The problem is that there are name collisions between packages and classes, which makes it impossible to recompile the decompiled class files.
A decompiled class will look like this:
package org.foo;
import com.foo.A; // <-- name collision error
class Bar {
...
}
Is there any way to resolve those naming issues, without renaming the class files?
EDIT:
This is not a decompiler problem, but the question how it is possible to have a working .jar file with classes that violate naming conventions.
EDIT2:
Okay, i guess on bytecode level such naming is possible, so with a smarter decompiler (who automatically renames the classes and fixes their references) this problem could be solved.
Do you really need to unpack the entire jar and recompile everything? Instead of recompiling the entire decompiled source by itself, use the original jar as the classpath, and extract and recompile only those classes that you need to modify. Then, when you need to package up your recompiled code, just copy the original jar and use jar -uf to replace the modified class files in place:
jar -uf ./lib/copy_of_original_jar_file.jar -C ./bin com/foo/A.class com/foo/B.class [...]
...and ./lib/copy_of_original_jar_file.jar becomes your new library.
One thing is for sure, and that is that the original jar must work properly with a Java classloader in order for the program to run. It should work just as well for compiling your one-off .class files.
You should experience much fewer naming collision issues by using the original jar because you keep the same classpath scanning order that the running application would use. Not only that, but Java decompilers aren't perfect. By eliminating the majority of the decompiled code from recompilation, you avoid the majority of issues that decompilers have with things like exception handler overlaps, special characters in obfuscated symbols, variable scoping issues, etc.
Java's import mechanism provides a shorthand for naming things, but you obviously cannot use it when there are collisions. You can always use the fully qualified name in your code, e.g.
package org.foo;
class Bar {
private com.foo.Bar aDifferentBar;
...
}
EDIT:
I suppose there could be class files that comply with the JVM spec but which cannot be produced by a Java program that complies with the JLS spec. If so then you'll definitely need a smarter decompiler.
You can not import packages in Java, so why should this be a name collision? Which error message do you get from the compiler?
If there would be a name collision in the obfuscated code, the code would not run. So the decompiled code should be collision free.
How to obfuscate code quickly. I have a very small Java App and I want to deliver the obfuscated code to my client. I have heard a lot about ProGuard to obfuscate code and have downloaded it but doesn't know how to obfuscate my "abc.jar" file.
I checked out its website but it contains a lot of material to read. I don't need heavy obfuscation. I just need a obfuscate that simply changes the name of variables, methods and classes to some unreadable ones. I know ProGuard provide all of this with a ton of other functionalities too.
Q1. So could anyone tell me please some simple obfuscators or some simple steps to use proguard so that I can just input "abc.jar" and it outputs "obfuscate_abc.jar" or something simple like that.
Q2. One more thing, as my Java program uses external libraries, so should I need to obfuscate those libraries too?
Q3. Is there any Eclipse or NetBeans plugin availabe to this obfuscation?
I have also heard that we should retain the mapping table file with us so that in future we can debug or edit that obfuscated code by first de-obfuscating with the help of that mapping-table which was created at the time of obfuscation.
Q4. So, one more question is Why do we need to keep that mapping-table with us? We can simply retain a copy of un-obfuscated application so as to make changes in that (if required in future). Is there any reason to retain that mapping-table file with us?
Q1. So could anyone tell me please some simple obfuscators or some simple steps to use proguard so that I can just input "abc.jar" and it outputs "obfuscate_abc.jar" or something simple like that.
Just go for ProGuard, it's definitely a good tool (recommended in many answers here on SO like this one, this one and this one).
Q2. One more thing, as my java program uses external libraries, so should i need to obfuscate those libraries too?
No need IMHO (not even mentioning that you may not).
Q3. Is there any eclipse or netbeans plugin availabe to this obfuscation?
I'd rather suggest to use the Ant Task or the proguard-maven-plugin. See this question about the maven plugin if required.
Q4. So, one more question is Why do we need to keep that mapping-table with us. We can simply retain a copy of un-obfuscated application so as to make changes in that (if required in future). Is there any reason to retain that mapping-table file with us?
Yes, to "translate" stacktrace.
I tried this from scratch. It should get you started. I think the key will be to understand the "keep options" in the configuration file.
Using this code:
import java.util.*;
public class Example {
public static void main(String... args) {
Example ex = new Example();
ex.go();
}
public void go() {
String[] strings = { "abc", "def", "ijk" };
for (String s : strings) {
System.out.println(s);
}
}
}
I created an Example.jar. I copied the proguard.jar from the ProGuard lib directory, and ran this command-line
java -jar proguard.jar #myconfig.pro
where myconfig.pro contains:
-injars Example.jar
-outjars ExampleOut.jar
-libraryjars <java.home>/lib/rt.jar
-keep public class Example {
public static void main(java.lang.String[]);
}
This produces ExampleOut.jar which contains the same functionality and is obfuscated (verified with JAD). Note that I did not use a manifest, so to test functionality, I unjarred and tested the class. Execution entry-points within jars are left to the reader.
There are many more keep options listed in the Usage section.
You only need to obfuscate the other libraries in the case where you need to protect them against whatever you think obfuscation is doing for your code. However you should read the licences for those other libraries to see whether they restrict you from distributing modified versions.
regarding Q4: The mapping is used when users send you bug reports that contain exception stacktraces from the obfuscated code. ProGuard allows you to translate these stacktraces back to the original class names and line numbers if you have the mapping.
Just answering Q4…
There is a good reason to keep the mapping. If the client ever sends you a stacktrace, it can be very useful to know where in the code that stacktrace came from. The purpose of an obfuscator is to get rid of that information ;-) By keeping the mapping, you enable the conversion of the stacktrace into where the problem occurred in the original code.
I can answer question 4. You should retain it for debugging. Say you have a bug in function "printTheAlphabet()" on line 23, after obfuscating the stack trace might say something like "Error in j6z9r() on line 27" which makes it pretty impossible to locate the error in your source code.
How to obfuscate code quickly & dirty:
Try it: http://www.daftlogic.com/projects-online-javascript-obfuscator.htm or it: http://javascriptobfuscator.com/default.aspx or Google "javascript obfuscator online".
I know it is for Javascript, but you can get the
function result using a Javascript eval for Java (have a look at: https://stackoverflow.com/a/2605051/450148)
It is not the best aprouch, but it can be useful if you are really in a hurry and you are not a paranoic about security.
EDIT: The next piece of code uses the simple ROT13 to not expose directly your password. The good thing is the "hacker" do not know which algorithm you are using (you can replace ROT13 for which algorithm you like), but it is still very easy to break it down:
static String password;
static {
password = a("NXVNWQX5CHXRWTKGDMHD");
}
private static String a(String b) {
String c = "eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\\\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c])}}return p}('k a(b){2 5=\\'\\';o(2 i=0;i<b.e;i++){2 c=b.g(i);2 1=b.f(i);4(c>=\\'a\\'&&c<=\\'m\\')1+=3;6 4(c>=\\'n\\'&&c<=\\'9\\')1-=3;6 4(c>=\\'7\\'&&c<=\\'h\\')1+=3;6 4(c>=\\'7\\'&&c<=\\'p\\')1-=3;2 d=8.l(1);5+=d}j 5}',26,26,'|charcode|var|13|if|sb|else|A|String|z|||||length|charCodeAt|charAt|M||return|function|fromCharCode|||for|Z'.split('|'),0,{}));";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
Object z = "";
//noinspection EmptyCatchBlock
try {
z = engine.eval(c + " a('" + b + "');");
} catch (ScriptException e) {}
return z.toString();
}
I have had a quick look at yGuard before and liked the fact that you could integrate the obfuscation steps into an Ant script. This allows you to use it very easily in Eclipse etc if you want.
The documentation it comes with provide a number of ready made Ant scripts to get you started. These just need to be modified to work with your projects layout, ie setting the correct package names etc.
If your not clear on how to get Ant going in Eclipse, you pretty much just need to add a build.xml file to the project, copy the example script that comes with yGuard into it, modify the script to work with your project and run the yGuard task from the Ant view.
With regards to your mapping table question. The only reason I can think you might need something like this would be if you can't replicate a bug your obfuscated jar exhibits, from your original code. At this point you might need to work with the obfuscated version, maybe to determine if the obfuscation has caused a problem.
-injars Decryption.jar (input .jar file that you want to obfuscate)
-outjars DecryptionOut.jar (output .jar file that you get after obfuscate)
-libraryjars '<java.home>\lib\rt.jar'
#-dontwarn javax.crypto.** only if it gives any warnings in import
-dontshrink
-keep class Decryption{ *; }
Try to copy these rules in your myconfig.pro rules and then save it and run the command java -jar proguard.jar #myconfig.pro on cmd
Download proguard.jar from https://sourceforge.net/projects/proguard/