Code obfuscation in Java

  1. What is Obfuscation?
  2. Code Obfuscation Techniques
  3. Code Obfuscation Tools for Java
  4. Obfuscation in Java
  5. Summary

This tutorial introduces code obfuscation in Java and also lists some example codes to understand the topic.

Obfuscation is a programming technique used to make our code difficult to understand. It is done to protect our source code from malicious users. In this tutorial, we will learn more about obfuscation.

What is Obfuscation?

  • Obfuscation is the process of making a piece of code less readable, difficult to understand, and time-consuming.
  • Obfuscation does not affect the execution of the code, and the code will continue to do what it was meant to.
  • Code obfuscation is used to protect our code from hackers and attackers. These malicious users may try to reverse-engineer our code and take advantage of some shortcomings of our code. Preventing reverse-engineering of our code is one of the major use cases of obfuscation.
  • Hackers and attackers also use obfuscation to prevent antivirus tools from detecting their hostile code.

Code Obfuscation Techniques

A lot of code obfuscation tools exist, and they use a variety of techniques to prevent attacks. In a nutshell, obfuscation uses redundant logic and adds unwanted code to astray the reader or a reverse-engineering tool(like a decompiler).

Let’s discuss a few of the most common code obfuscation techniques.

  • Renaming Variables and Method Names: renaming variables and methods into some difficult-to-read names or using unprintable or invisible characters is a commonly used obfuscation technique.
  • Changing the Control Flow: obfuscation tools will often change the control flow of the code. This will make the code perform the same task but becomes difficult to follow.
  • Using Dummy Code: some tools will often include fake code which has nothing to do with the original logic. This will make the code difficult to reverse-engineer.
  • Regularly altering the obfuscated code: if we regularly update the obfuscated code, then all the progress of the hacker on the previous code will be lost. The attacker will have to begin from scratch on the new code.
  • Encryption: Encryption of data(like strings) prevents the hacker from understanding the true meaning of the code. Decryption can be performed when the code needs to be executed.

Code Obfuscation Tools for Java

Java, just like any other programming language, is prone to reverse-engineering attacks. Decompilers are available for Java which can easily reverse-engineer the compiled Java byte-code. The following are some of the most popular Java obfuscator tools.

  • ProGuard
  • JODE
  • JavaGuard
  • RetroGuard
  • jarg
  • yGuard

Obfuscation in Java

Let’s obfuscate the simple code shown below using an obfuscation tool.

public class StringAddition
{
	public static void main(String args[])
	{
		String s1 = "a";
		String s2 = "b";
		String s3 = s1 + s2;
	}
}

The code is obfuscated into the following code. Unwanted dummy variables and logic is placed in the obfuscated code. The original code logic is difficult to understand.

import b.n;
public class StringAddition
{
    private static final String[] d;
    public static void main(final String[] array) {
        Label_0054: {
            break Label_0054;
        Label_0003:
            while (true) {
                final String str = StringAddition.d[Integer.parseInt("1", 22) << 10017];
                try {
                    new StringBuilder().append(str).append(StringAddition.d[24 << Integer.parseInt("9k1", 30)]).toString();
                    return;
                    final String x = StringAddition.d[8388608 >>> 4183];
                    System.out.println(x);
                }
                // iftrue(Label_0003:, x.hashCode() == 1033634479)
                // monitorenter(array)
                // monitorenter(array)
                catch (EnumConstantNotPresentException i) {
                    throw n.i = i;
                }
            }
        }
    }
    static {
        final char[] charArray = "\u0e47\u0e59\u0093\u0cc1¥£®£®\u00d1®®®®½£®A\u00da\u00dc®£®®\u00d1®®®\u00c2\u00dc®A\u00da£\u00d1£®®®\u00d1®®\u00c2£\u00d1A\u00da£®\u00dc®®®®\u00d1®\u00c2£®>\u00da£®£\u00d1®®®®\u00d1\u00c2£®A¥£®£®®®®®®½\u00f6\u00d1b\u00f9\u009e\u00d1\u0080\u008d\u008d\u0083\u00d1\u008d\u008d\u00e1\u009d\u00d1b\u00f9\u0080\u009f\u00dc\u008d\u008d\u008d\u0092\u00d1\u008d\u00e1\u0080\u0099>\u00f9\u0080\u008d\u0090\u00d1\u008d\u008d\u008d\u009e\u00d1\u00e1\u0080\u008d}¥\u0080\u008d\u0080\u009a\u00d1\u008d\u008d\u008d\u00df½\u0080\u008db\u00eb\u00dc\u008d\u0080\u008d\u0094\u00d1\u008d\u008d\u008d\u00e9\u00dc\u008db\u00f9\u00dc\u00d1\u00dc\u00d1\u00d1\u00d1\u00d1\u008d\u008d\u0097\u00dc\u008db\u00da£\u008d\u0080\u008d®®\u008d\u008d\u008d\u00c2£\u008db\u00f9£®\u0080\u008d\u008d®®\u008d\u008d\u00e1£®b\u00f9\u0080®£\u008d\u008d\u008d®®\u008d\u00e1\u0080®A\u00f9\u0080\u008d£®\u008d\u008d\u008d®®\u00e1\u0080\u008dA\u00da\u0080\u008d\u0080®®\u008d\u008d\u008d®\u00c2\u0080\u008db\u00da£®£®®®\u008d\u008d\u00fb½\u0080\u00deA\u00da \u008d\u00d3®®\u00ad\u008d\u00de®\u00c2 \u008d1\u00da£\u00ad\u0080\u00de®®\u00ad\u008d\u00de\u00c2£\u00adbª£® \u008d\u00de®®\u00ad\u008d²£®B\u00f9\u00d3®£\u00ad\u008d\u00de®®\u00ad\u00e1\u00d3®A\u00d9\u0080\u00de£®\u00ad\u008d\u00de®®\u00c1\u0080\u00deA\u00da£®£®®\u00ad\u008d\u00fb\u00d1½£®A\u00da\u00dc®£®®\u00d1®®®\u00c2\u00dc®A\u00da£\u00d1£®®®\u00d1®®\u00c2£\u00d1A\u00da£®\u00dc®®®®\u00d1®\u00c2£®>\u00da£®£\u00d1®®®®\u00d1\u00c2£®A¥£®£®\u00d1®®®®½£®A\u00da\u00dc®£®®\u00d1\u00fb\u00d1\u008d\u00e1\u0093\u00d1b\u00f9\u0080\u0093\u00dc\u008d\u008d\u008d\u0097\u00d1\u008d\u00e1\u0080\u0084>\u00f9\u0080\u008d\u008f\u00d1\u008d\u008d\u008d\u0092\u00d1\u00e1\u0080\u008d\u007f¥\u0080\u008d\u0080\u0085\u00d1\u008d\u008d\u008d\u009e½\u0080\u008db\u00f7\u00dc\u008d\u0080\u008d\u00dc\u00d1\u008d\u008d\u008d\u00e9\u00dc\u008db\u00f9\u008e\u00d1\u0080\u008d\u008d\u0098\u00d1\u008d\u008d\u00e1\u009d\u00d1b\u00f9\u0080\u009d\u00dc\u008d\u008d\u00fb\u00d1\u008d\u008d\u00c2£\u008db\u00f9£®\u0080\u008d\u008d®®\u008d\u008d\u00e1£®b\u00f9\u0080®£\u008d\u008d\u008d®®\u008d\u00e1\u0080®A\u00f9\u0080\u008d£®\u008d\u008d\u008d®®\u00e1\u0080\u008dA\u00da\u0080\u008d\u0080®®\u008d\u008d\u008d®\u00c2\u0080\u008db\u00da£\u008d\u0080\u008d®®\u008d\u008d\u008d\u00c2£\u008db\u00f9£®\u0080\u008d\u00fb\u00d1\u008d\u00de®\u00c2 \u008d1\u00da£\u00ad\u0080\u00de®®\u00ad\u008d\u00de\u00c2£\u00adbª£® \u008d\u00de®®\u00ad\u008d²£®B\u00f9\u00d3®£\u00ad\u008d\u00de®®\u00ad\u00e1\u00d3®A\u00d9\u0080\u00de£®\u00ad\u008d\u00de®®\u00c1\u0080\u00deA\u00da \u008d\u00d3®®\u00ad\u008d\u00de®\u00c2 \u008d1\u00da£\u00ad\u0080\u00fb\u00d1\u00fb\u0e59\u0090".toCharArray();
        int n = 64 << 5658;
        final StackTraceElement stackTraceElement;
        final int n2 = (stackTraceElement = new Throwable().getStackTrace()[107 >>> 11463]).getMethodName().hashCode() & Integer.parseInt("171h3c0", 22) - 149806781;
        final char[] charArray2 = stackTraceElement.getClassName().toCharArray();
        final char[] array = charArray;
        final int n3 = 101 >>> 10951;
        ++n;
        d = new String[array[n3] ^ Integer.parseInt("1g1nna6", 28) - 758393825 ^ n2];
        int n4 = 26 >>> Integer.parseInt("gk9", 31);
    Label_0101:
        while (true) {
            int n5;
            final char[] value = new char[n5 = (charArray[n++] ^ Integer.parseInt("ifjj061", 22) - 2122795820 ^ n2)];
            int n6 = 72 << 11485;
        Label_0334_Outer:
            while (true) {
                Label_0272: {
                    if (n5 <= 0) {
                        break Label_0272;
                    }
                    int n7 = charArray[n];
                Label_0334:
                    while (true) {
                        Label_0388: {
                            switch (charArray2[n % charArray2.length] ^ (0xC999A060 ^ 0xC999A0AE)) {
                                case 160: {
                                    break Label_0334;
                                }
                                case 162: {
                                    break Label_0334;
                                }
                                case 131: {
                                    break Label_0334;
                                }
                                case 163: {
                                    break Label_0334;
                                }
                                case 167: {
                                    break Label_0334;
                                }
                                case 136: {
                                    break Label_0388;
                                }
                                case 170: {
                                    break Label_0388;
                                }
                                case 186: {
                                    break Label_0388;
                                }
                                case 139: {
                                    break Label_0388;
                                }
                                case 171: {
                                    break Label_0388;
                                }
                            }
                            while (true) {
                                value[n6] = (char)n7;
                                try {
                                    ++n6;
                                    ++n;
                                    --n5;
                                    // monitorexit(charArray)
                                    n7 ^= -400944133 + 400944374;
                                    continue Label_0334_Outer;
                                    n7 ^= Integer.parseInt("83bdf8k", 22) - 925222572;
                                    continue Label_0334_Outer;
                                    continue Label_0334;
                                    StringAddition.d[n4++] = new String(value).intern();
                                    // iftrue(Label_0101:, n < charArray.length)
                                    return;
                                    n7 ^= Integer.parseInt("6j", 23) << 3840;
                                    continue Label_0334_Outer;
                                    n7 ^= 61440 >>> 11787;
                                    continue Label_0334_Outer;
                                    n7 ^= 364965749 - 364965616;
                                }
                                catch (Throwable t) {
                                    break;
                                }
                            }
                        }
                        break;
                    }
                }
            }
        }
    }
}

Note that the above code may not run directly in an IDE because an obfuscator also produces additional files and dependencies that need to be resolved before executing the program.

Summary

Code obfuscation is done to prevent attacks due to reverse engineering. Attackers and hackers also use obfuscation to fool antivirus software and other protection tools. Note that reverse-engineering a code is not made impossible by code obfuscator tools. They make it a lot difficult and time-consuming.

Contribute
DelftStack is a collective effort contributed by software geeks like you. If you like the article and would like to contribute to DelftStack by writing paid articles, you can check the write for us page.