Securing the Java Code
The threat of reverse engineering is a well-known security problem for Java applications. By default, the byte code generated by the Java compiler contains much symbolic information, including the actual Java source of the executable and debugging information. Using reverse engineering mechanisms, it is possible to disassemble and decompile the executable Java bytecode into actual Java source code. This fact highlights the vulnerabilities of Java applications and makes clear the risks of someone having the ability to do the following:
- Modify code and data
- Determine the flow of program execution
- Determine algorithms
- Construct a fraudulent application
- Steal intellectual property
- Apply code-level security breaches
Reverse Engineering: Disassembling and Decompiling
The process of reverse engineering the Java program is done by disassembling the executable classes to an intermediate assembly code and then decompiling the assembly code to obtain the higher-level abstractions of the byte code. This higher-level abstraction contains significant source code, including variables, methods, and so forth. When compared with the actual source code, the noticeable difference is the absence of comments. It is also noted that the reverse engineering process does not provide source code with accuracy. There are many commercial and freeware tools available that provide disassembling and decompiling capabilities.
From a security standpoint, it is very important to realize the threats posed by the use of disassembling and decompiling techniques to reverse engineer the Java executable. With these techniques, a hacker can reconstruct an application with modified code and disrupt the original application by attacking its underlying resources. To counter these issues, there are several tools and techniques that allow protecting the source code from prying eyes by making it difficult to apply any reverse engineering mechanisms.
The possible ways to prevent reverse engineering of Java executables and to protect the source code are as follows:
- Code authentication: This approach adopts evaluation and verification of executable code for trusted sources, runtime checks, predictable behavior, and output. This ensures that code is not executed from an unauthorized host, not modified to produce any unpredicted output, and not duplicated to act as an original application.
- Encryption and decryption: Using encryption and decryption of executable code in transmission ensures that the code is not accessible or tampered with during its transit. This approach limits portability of the application but works well in scenarios where applications are made available via server-side invocations.
- Code obfuscation: This approach uses a transformation mechanism that changes the program and generates Java code with obscure references. The obfuscated code is understood by compilers but difficult to read by humans. This is the most popular way to prevent the success of reverse engineering capabilities on executable code.
Code obfuscation is the process of transforming the executable in a manner that affects reverse engineering mechanisms by making the generated code more complex and harder to understand. It decouples the relationship between the executable code and its original source, which ultimately makes the decompiled code ineffective. With all those changes, the obfuscated program still works in a functionally identical way compared to the original executable. There are several transformation mechanisms that allow obfuscation of Java code, and the most common techniques [Obfuscation] are as follows:
- Structural or layout transformation: This transforms the lexical structure of the code by scrambling and renaming the identifiers of methods and variables.
- Data transformation: This transformation affects the data structures represented in the program. For example, it changes the data represented in the memory from a local to a global variable, converting a two-dimensional array into a one-dimensional array and vice-versa, changing the order of data in a list, and so forth.
- Control transformation: This transformation affects the flow control represented in the program. For example, it changes the grouping of statements as inline procedures, order of execution, and so forth.
- Tamper-proofing and preventive transformation: This transformation makes the decompiler fail to extract the actual program, and the generated code is unusable. Refer to [PrevTransform] for more detailed information.
- String encryption: This mechanism encrypts all string literals within the executable code, and during runtime invocation it decrypts them for use.
- Watermarking: This mechanism embeds a secret message in the executable that identifies the copy of the executable and allows you to trace the hacker who exploited the generated code.
With little performance overhead, the code obfuscation process restricts the abuse of decompilation mechanisms and offers portability without affecting the deployment platforms. Adopting code obfuscators is a good choice to make in the attempt to reduce the risks of reverse engineering. They prevent loss of intellectual property and offer protection of Java code from malicious attacks. The Java code obfuscators are publicly available in the form of freeware, shareware, and commercial applications.