METHOD FOR PROTECTING BYTECODE
Field of the Invention
The present invention relates to a method for protecting compiled software application code, and a code protection system.
Background of Invention
There are many programming languages available that compile to platform independent bytecode, such as Elisp and Java, the latter being described in references A and B recited below. One of the greatest criticisms of such programming languages is that the bytecode, being defined at a high level, can easily be reverse- engineered into the source language. The problem is compounded with the wide availability of bytecode decompilers on the Internet, as described in reference C. It means that any novice computer user can produce readable source code from compiled bytecode. While the output of bytecode decompilers may not be the same as the original source code, it is nevertheless sufficiently close to allow any programmer to understand and make unauthorised use of the output.
The current most commonly used protection against bytecode decompilers is a bytecode obfuscator, as described in reference D. A bytecode obfuscator is a tool that goes through an application and renames all the symbolic information inside, such as the class names, method names and field names. Bytecode obfuscation does not protect the bytecode from being decompiled, but it makes the decompiled code a lot more difficult to understand.
Some bytecode obfuscators protect further by adding corrupted information into the application files to confuse the bytecode decompilers. This technique is frequently applied at the expense of violating the standard bytecode file format specification, which may render the resulting bytecode incompatible with certain implementations
of the run-time system. This technique is also limited, due to the availability of free tools on the Internet that can remove the corrupted information, as described in reference E.
Certain other techniques for protecting bytecode have been discussed in reference F. These other techniques, however, fall short in that they either require the main application logic to reside on a separate machine, or they require the developer not to use bytecode for sensitive application logic.
Summary of the Invention
In accordance with the present invention there is provided a method of protecting bytecode, including: encrypting bytecode for an application; providing the encrypted bytecode to a user; executing a code loader to load the encrypted bytecode, access a decryption key, decrypt the encrypted bytecode, and pass the decrypted bytecode to a run-time system; and executing said decrypted bytecode with said run-time system.
The present invention also provides a software tool stored on a computer readable storage medium, including: means for accessing bytecode; means for determining if the bytecode is encrypted; means for accessing a decryption key; means for decrypting encrypted bytecode using the decryption key; and means for passing bytecode to a run-time system.
The present invention further provides a software protection system, including: means for accessing bytecode; means for determining if the bytecode is encrypted;
means for accessing a decryption key; means for decrypting encrypted bytecode using the decryption key; and means for passing bytecode to a run-time system.
The present invention also provides a method for execution by a computer system, including: accessing bytecode; determining if the bytecode is encrypted; accessing a decryption key; decrypting encrypted bytecode using the decryption key; and passing bytecode to a run-time system.
Brief Description of the Drawing
A preferred embodiment of the present invention is hereinafter described, by way of example only, with reference to the accompanying drawing, wherein:
Figure 1 is a flow diagram of a process executed by a code loader of the preferred embodiment.
Detailed Description of the Preferred Embodiment
A software protection system of the preferred embodiment uses a software tool, hereinafter referred to as deCaf™, which includes an encryption module, a code loader and a driver program. The system comprises at least one computer having electronic memory used for storing, reading and executing the software tool, and a run-time system for executing bytecode of a software application. The system normally comprises a server computer and a user computer, where the tool is stored on the server with application bytecode, and the bytecode when encrypted is transmitted to the user's computer with the code loader and the driver program for storage and execution on the user's computer. The code loader and the drive program can be transmitted separately and also can be prestored on a user's computer. The
encryption module is used to encrypt bytecode, which can then only be decrypted by the code loader. The driver program installs the code loader for a run-time system of a user's machine, instructs the code loader to decrypt the encrypted bytecode, and then causes the decrypted code to be executed on the user's machine. By applying encryption to bytecode, deCaf ™ is able to prevent bytecode decompilers from reading the bytecode. The decompilers are unable to decompile the encrypted bytecode without first decrypting it. To understand the encrypted bytecode format, normally this will require modification of a run-time system, but deCaf™ does not require any such modification, as it is able to rely on the code loader which can be applied in any run- time system that supports the installation of a code loader by the software application to be executed. In particular, deCaf™ is able to encrypt Java software applications and then execute them on an unmodified Java run-time system, being the Java Virtual Machine.
The encryption module when executed, normally by a transmitting server, acts on the compiled bytecode of a software application and applies an encryption algorithm to produce decrypted bytecode. Any secured encryption algorithm can be used, although one which enhances the execution speed of the encryption module is preferred.
In any encryption algorithm, there is an encryption key as well as a decryption key. In an asymmetric encryption algorithm, the encryption and decryption keys are different. While in a symmetric encryption algorithm, both keys are the same. Regardless of which is used, the decryption key is distributed to the application user so the encrypted bytecode can be decrypted later and executed.
This key distribution is done in one of the following ways:
1. Using a trusted public-private key authentication infrastructure. In the presence of a trusted public-private key authentication infrastructure, the user's public key is used to encrypt the application bytecode. Then, the private key can decrypt the bytecode on receipt. As such, no one else other than a legitimate
user can run the software. No actual key distribution is required since the user uses his own private key for decryption of the software.
2. Embedding the decryption key in the encrypted bytecode. In the event that an infrastructure to support key distribution is not available, the decryption key can be hidden within the encrypted bytecode. The code loader will know this hidden location, so that the key can be extracted at run-time to decrypt the bytecode. To avoid disclosing the secret location of the key within the encrypted bytecode, the location can be made random by having it dependent on a relatively random data pattern, such as the message digest of the application code. The customised code loader will normally be provided together with the encrypted bytecode. As such, this method of distributing the decryption key is not completely secure, since a hacker could go through the code of the code loader to try and determine the location of the decryption key. Nevertheless, the task of doing so is labourious enough to deter most hackers. Thus this key distribution method is still useful when protecting less sensitive application bytecode.
3. Distributing the decryption key separately. Instead of embedding the decryption key within the encrypted application, the decryption key is passed separately to the user. The encrypted application bytecode is distributed to the user who is then required to register his particulars before the decryption key is passed. This key distribution method has the same weakness as the former, in that a hacker could go through the labourious task of attempting to understand the code loader, and determine how it applies the decryption key. As such, its usefulness is also confined to protecting less sensitive application bytecode. However, this method helps keep track of legitimate users, much like the serial number required to install most commercial software. If an illegal copy of encrypted software is received, it can be traced back to its original legitimate user.
In some run-time environments, such as Java's, application software running in the environment is given the ability to install its own code loader. A code loader (known as the ClassLoader in Java) is a small piece of software that is responsible for loading the application code from a disk, a network or any other storage medium. DeCaf™ exploits this feature by providing it's own code loader to perform code decryption at run-time, hence omitting the need to modify the run-time system.
The code loader's role is to find and load the correct application bytecode, and then pass it to the run-time system. To provide a code loader that can understand the encrypted bytecode, appropriate decryption routines are inserted and executed between the loading of the application code and handing it over to the run-time system. This ensures that the run-time system always receives bytecode it can execute.
The code loader of deCaf™, as shown in Figure 1 , first receives a request to load a bytecode file, at step 2. When the run-time system needs to load a bytecode file, it passes the request to the code loader for execution. The code loader then looks for the bytecode file, at step 4. The bytecode file can reside anywhere in the local disk, or even in a network. In most run-time systems, the list of places to look for the bytecode is given by a predefined variable which the user can change. In Java, this is given by the CLASS PATH environment variable. Once the application bytecode file is loaded, the custom code loader determines whether it is in encrypted form, at step 6. In deCaf™ a predefined constant of OxDECAFO is assigned to all encrypted bytecode. The loader determines the existence of this constant in order to decide whether the bytecode is encrypted or not. If the loader determines that the bytecode is encrypted, operation proceeds to step 8, whereas otherwise operation proceeds to step 12. At step 8, the code loader loads the decryption key. Loading the decryption key will depend on how the decryption key is distributed. In a current implementation of deCaf™, the decryption key is encoded in the encrypted bytecode. The loader accesses this information, and loads the decryption key accordingly. Once the decryption key is loaded, the custom code loader executes the required decryption
algorithm on the encrypted code, at step 10. As mentioned earlier, any secure encryption algorithm can be chosen. One particular encryption algorithm can be chosen, or the type of encryption algorithm used can be encoded in the encrypted bytecode. In the latter case, the code loader looks up the type of encryption algorithm used, and applies the corresponding decryption algorithm. Once the bytecode has been decrypted, or if it is not encrypted in the first place, it is passed directly to the run-time system, at step 12 by the code loader.
The driver program of deCaf ™ is used to tie the components of the tool together and run the encrypted application. The driver program executes the following steps:
1. Install the code loader in the run-time system;
2. Instruct the code loader to load the encrypted application bytecode; and
3. Run the decrypted application.
All the above tasks are dependent on the run-time system to be used. To install the code loader in Java, a code loader object of deCaf™ is initiated. This is followed by extracting out the encrypted application bytecode, and passing it to the loadClass procedure of the code loader. Finally, the Java reflection API is used to invoke the main procedure of the decrypted application.
Many modifications will be apparent to those skilled in the art without departing from the scope of the present invention as herein described with reference to the accompanying drawing.
References
A. James Gosling, Bill Joy, Guy Steele, The Java Language Specification, ISBN: 0-201- 63451-1 , Addison Wesley.
B. Tim Lindholm, Frank Yellin, The Java Virtual Machine Specification, ISBN: 0-201-63452- X, Addison Wesley.
C. Decompilers available on the Internet: - Mocha, http://www.brouhahn.com/~eric/computers/mocha.html
WingDis, http://www.winqsoft.com/windis.shtml
Jasmine, http://www.members.tripod.com/~SourceTec/
DejaVu, http://ww.isq.de/OEW/Java
Jad, http://web.unicom.com.cv/~kpd/iad.html
D. Qusay H. Mahmoud, Protect your bytecodes from reverse engineering/decompilation. In Java World, http://www.iavaworld.com/iavatips/iw~iavatip221.html.
E. Unobfuscator example: Zelix KlassMaster, http://www.zelix.com/klassmaster/index.html.
F. Scott Oaks. Protecting your bytecode. In Java Report, pgs. 86-88, November 1997.