Learn how the Crema obfuscator can help protect your Java code from decompilers such as Mocha If you are writing Java classes and distributing them over the Internet, you should know that people can reverse-engineer, disassemble, or decompile your classes into Java source code. The most widely used decompiler (at least publicly) is Mocha. Mocha reads one or more files of bytecodes (classes) and converts them back to Java source code. Although the code generated by Mocha is not exactly the same as the original source code, it is close enough for someone to understand and modify. If you are interested in developing Java classes and distributing them over the Internet — and you would like to protect them from being decompiled — read on.Mocha: an exampleBefore introducing Crema, we will walk through an example using Mocha. The following simple program displays the string “Hi there” on the screen:class test { public static void main(String argv[]) { System.out.println("Hi there"); } } If the above four lines were saved in a file, test.java, then compiling test.java would generate a new file, test.class, that contains the Java bytecodes representing that Java source code. Now let’s run Mocha on the class file and see the Mocha output: % java mocha.Decompiler test.class // the % is my C shell prompt on UNIX. The above command generates a file called test.mocha, which contains the Java source code generated by Mocha:% more test.mocha /* Decompiled by Mocha from test.class */ /* Originally compiled from test.java */ import java.io.PrintStream; class test { public static void main(String astring[]) { System.out.println("Hi there"); } test() { } } As you can see from the example above, Mocha has given us Java source code that is easy to read and understand. If you copy this file to test.java, compile it again, and run it, it will compile and run just fine.Crema to the rescue!So how can you protect your classes from being decompiled? One answer is Crema. Crema scrambles the symbolic information in your .class files so that they will become less vulnerable to decompilation. The symbolic information that Crema scrambles includes the name of the class, its superclass, interfaces, variable names, methods, and so on. These symbolic names are needed by the Java virtual machine (JVM) to link your classes with library packages. Crema scrambles these symbolic names and makes references to them in the same way so that the JVM can still achieve the correct linking between classes and packages. So how does Crema work? Basically, before distributing your class files on the Internet, run Crema on them. Crema will scramble the symbolic information contained in them, and will place each new class in the file 1.crema. Your job then is to rename 1.crema to something like filename.class before distributing it on the Internet.Let’s run Crema on our test.class example shown above, and then try to decompile it with Mocha:% java Crema -v test.class // -v is an option to turn the verbose // mode on. There are many more options. CREMA - The Java Obfuscator - EVALUATION VERSION Copyright (c) 1996 Hanpeter van Vliet Loading test.class Obfuscating test Saving test as 1.crema NOTE: Classes processed with the evaluation version of Crema can only be used locally, as most browsers will refuse to load them. For the full version of Crema, point your browser to: http://www.inter.nl.net/users/H.P.van.Vliet/crema.html (see <a href="#RESOURCES">Resources</a>) The above command has generated a new file, 1.crema, which contains the bytecodes with scrambled symbolic information. Note that Crema has many command-line option parameters that you can use; for more information on Crema, see the Resources section. Now let’s move that file into test.class again and decompile it using Mocha:% mv 1.crema test.class % java mocha.Decompiler test.class java.lang.NullPointerException SIGSEGV 11* segmentation violation si_signo [11]: SIGSEGV 11* segmentation violation si_errno [0]: Error 0 si_code [1]: SEGV_ACCERR [addr: 0x0] stackbase=EFFFF35C, stackpointer=EFFFF040 Full thread dump: "Finalizer thread" (TID:0xee3003b0, sys_thread_t:0xef490de0) prio=1 "Async Garbage Collector" (TID:0xee300368, sys_thread_t:0xef4c0de0) prio=1 "Idle thread" (TID:0xee300320, sys_thread_t:0xef4f0de0) prio=0 "clock handler" (TID:0xee3001f8, sys_thread_t:0xef5b0de0) prio=11 "main" (TID:0xee3000a0, sys_thread_t:0x835a0) prio=5 *current thread* java.lang.Throwable.printStackTrace(Throwable.java) java.lang.ThreadGroup.uncaughtException(ThreadGroup.java) java.lang.ThreadGroup.uncaughtException(ThreadGroup.java) Monitor Cache Dump: Registered Monitor Dump: Finalize me queue lock: unowned Thread queue lock: unowned Class lock: unowned Java stack lock: unowned Code rewrite lock: unowned Heap lock: unowned Has finalization queue lock: unowned Monitor IO lock: unowned Child death monitor: unowned Event monitor: unowned I/O monitor: unowned Alarm monitor: unowned Waiting to be notified: "clock handler" Sbrk lock: unowned Monitor cache lock: unowned Monitor registry: monitor owner: "main" Thread Alarm Q: Abort (core dumped) As you can see in the code above, the first thing Mocha complains about is a NullPointerException because it was confused about the symbolic information. Hence, our goal of making it difficult to decompile our code is achieved.It should be noted that the author of Mocha, Hanpeter van Vliet, is also the author of Crema! Mocha is distributed without charge. An evaluation copy of Crema is available without charge, but the full version is a commercial product. When distributing Java classes over the Internet, you can protect your Java bytecode from the risk of being reverse-engineered. The code examples above show how Mocha is used to effect decompilation and how Crema can come to the rescue by preventing such activity.Qusay H. Mahmoud is a graduate student in computer science at The University of New Brunswick, Saint John campus, Canada. Java