Java Tip 22: Protect your bytecodes from reverse engineering/decompilation

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 example

Before 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,, then compiling 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 */
class test
    public static void main(String astring[])
        System.out.println("Hi there");

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, 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.
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: (see Resources)

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
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*
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.

Learn more about this topic

  • Editor's NoteSince Mr. van Vliet's death (from cancer) the sites he set up for the distribution of Mocha and Crema have ceased to exist.
  • Eric Smith's Mocha distribution site
  • Crema on the CERN site