Zelix KlassMaster™<title> <center> <h1>Zelix KlassMaster™</h1> <br> <h3>Reviewed by: Matthew Ghigliotti</h3> </center> <h2>Abstract</h2> <em>Zelix KlassMaster is a tool known for being an excellent commercial Java bytecode obfuscator. In truth, Zelix KlassMaster has a number of additional tools to help Java programmers in preparing a program to be released as a finished product. Alongside the Java bytecode obfuscator which has made KlassMaster famous are other tools, useful in minimizing the size of a completed project, and also in making use of error reports that users submit on a program which has been obfuscated. Although the focus will largely be on the obfuscating engine of Zelix Klassmaster, it is useful to point out that it contains these additional features which gives a programmer further control over his own program. It is with properties such as these which allow Zelix KlassMaster to be a successful commercial product.</em> <h2>Introduction</h2> <em>Zelix KlassMaster is a commercially available Java bytecode obfuscator, with additional features to help programmers maintain their original source code programs. Developed by Zelix Proprietary Ltd. and initially released in October 1997, this product is still actively maintained, with version 5.1 release 5 being made available in August 2008.<p> Although KlassMaster is best known for its obfuscation capabilities, there are several extra features in the currently available version of KlassMaster, which are intended to help a Java programmer be able to better maintain both the original and obfuscated versions of the program. Possibly one of the most prominent functions beyond obfuscation which Zelix utilizes as a marketing point, is a trimming function to help remove unused functions, fields, and classes from a given project. Such a tool is useful in order to minimize the size of a given project. Further features include a disassembler in which the Java bytecode can be examined, both before and after a trim or obfuscation procedure; and a stack trace translator, which translates the error reports submitted by users into ones that can be used by programmers. To make the trimming and obfuscating processes both easier on the programmer and repeatable, KlassMaster includes a ZKM Script Helper, which is used to automate the obfuscating and trimming procedures on a project.</em> <h2>Installation</h2> <em>Obtaining a version of Zelix KlassMaster, either demonstration or a proper licensed copy, requires several steps. For the 30-day demo version, a prospective user first needs to go to the <a href=http://www.zelix.com/klassmaster/download1.html>evaluation download page</a> and complete the online form. The critical part of this form is to submit a valid e-mail address that does not come from a free online service; this e-mail address is used to send an e-mail containing the download links for the Zelix KlassMaster software.<p> A similar procedure is used to obtain a licensed version of Zelix KlassMaster. The only notable differences are that the e-mail may contain additional information, including the license key and the invoice. The restrictions on the usage of free e-mail services appears to be slightly relaxed as well, since such e-mail addresses are allowed only for non-credit card purchases.<p> In order to be able to run the program, Java 5 is required on the host machine. Actual installation of the demonstration version is as simple as decompressing the downloaded ZIP or TAR.GZ archive and placing the contents into their own directory. Normal execution of the program can be accomplished by the command 'java -Xmx256m -jar ZKM.jar'. If a user chooses to add ZKM.jar to the classpath, KlassMaster may instead be executed by the command 'java -Xmx256m com.zelix.ZKM'.</em> <h2>Usage</h2> <em>There are two primary means in which a user can invoke Zelix KlassMaster to transform their Java bytecode programs. The first and most intuitive means, not to mention the easiest means for new users, is by using the graphical interface of the program. Once started, a user can load in their project, transform it using the Trim or Obfuscate options in the Tools menu, complete the Trim or Obfuscate dialogs that occur, and resave the project. In this way, a project can easily be modified into an obfuscated and trimmed form, without the user needing to learn much more about KlassMaster itself.<p> For the more advanced KlassMaster user, there is a more advanced means of calling upon the Trim or Obfuscate functions, without making use of the graphical interface. This is accomplished through the ZKM scripting language, whose primary benefit is to be able to provide uniformity of operations from one project to the next, without needing to reset all of the program settings each time. The scripts are plain text files, containing various settings to be used for the obfuscating or trimming processes. Such a script can be generated by hand, or there is a wizard to produce such a script, from within the graphical interface. Once such a script is saved, it can be executed on a particular project by executing the command 'java -jar ZKM.jar <scriptFileName>'.<p> Regardless of whether KlassMaster's features are invoked through the GUI or through the scripting language, there are a number of settings in each which users can set, in order to control the extent to which each operates. For the purposes of trimming a program, the first setting is for the Trim Exclusions. This list of items specifies to KlassMaster the items which should not be pruned during the Trim operation. One general example that is almost always included in this list is the 'main' method entry point in the program. Once the exclusions are set, KlassMaster then asks for the types of information to be trimmed from the bytecode, such as information about the source file, or regarding deprecated functions. Once these two settings are completed, KlassMaster is able to invoke the Trim operation on the specified program.<p> A similar procedure is used for the Obfuscating process. Again, the first information that is needed by KlassMaster is a list of exclusions of functions, classes, or other such artifacts in the program which should not be obfuscated. Once this is completed, the next setting controls how the Obfuscate function operates. These settings include whether to produce a change log, the degree of control flow obfuscation, and the degree to which methods are renamed. Once this procedure is completed, the user need only save the final version of the project to a new location in order to make the Trimmed or Obfuscated version of the program a tangible product on the computer.</em> <h2>Internals</h2> <em>As a commercial product, it would be little surprise that a program such as KlassMaster has internal secrets within the program, in order to make it a marketable Java bytecode obfuscator. Most of the details of these secrets are not well-documented, in large part due to the license agreement restrictions which prevent reverse engineering or disassembly. Further compound this problem by the fact that Zelix KlassMaster is a Java bytecode obfuscator written in Java, and it is not difficult to assume that whatever algorithms were included in the program have already been applied to the executable itself. However, some aspects of the program's internal capabilities can be gathered from the promotional information, as well as creating test programs and comparing the results of the obfuscation against the original source code.<p> KlassMaster has several ways in which code can be obfuscated. Possibly the most trivial is by name obfuscation, in which descriptive names of methods or classes are replaced with less meaningful ones. Although the name obfuscation mechanism is not described to any extent among the documentation, it can most likely be likened to the Refactoring operation in various development environments. One additional note here, though, is that name obfuscation allows for what the documentation describes as "incremental obfuscating;" that is, as the program is modified, the new parts of the program may be obfuscated to match the naming of the preexisting parts. Such information is likely written into the changelog file, to ensure such consistency across many obfuscation operations. <p> There are two additional functions which, like the name obfuscator, have limited details beyond the information given in the documentation: the control flow obfuscator, and the trimming engine. However, despite this, one can still make some educated guesses as to how these might work. In the features listing, the control flow obfuscator is described as taking various control constructs in a program, and adjusting their bytecode in such a way as that they do not have direct counterparts in the Java sourcode. One means that this can be accomplished is to have a predetermined pattern in which to obfuscate 'if', 'while', 'for', and other constructs. One point which is visible in the obfuscated code, however, is a surprising increase in the number of labels in the program. It is likely the use of these labels and the required organization to utilize so many at once, that confuses most Java decompilers.<p> Additionally, the mechanism used for trimming the unused methods, fields, or classes within a Java program can also be theorized about. In order for a program to distinguish unused program data from used data, KlassMaster would likely need to develop a graph of program structures. The entries or vertices in this graph are classes, methods, or fields which exist in the program, and edges in the graph indicate that a method, class, or field was used. Once such a graph is constructed, the vertices which are not connected in any way to the main portion of the graph could be disposed of. This certainly allows for the trimming of a Java program, though it is unclear if this, like the other algorithms mentioned for name obfuscation or control flow obfuscation, is similar to the algorithm used within KlassMaster itself. <p> Along the same lines of simplistic obfuscation operations is the string obfuscation mechanism. This operation takes any literal string within the program and obfuscates its contents so that a decompiler could not read the string as cleartext. One important point with string obfuscating which distinguishes it from the previous functions, however, is that in order to maintain the same functionality as the original program, the strings eventually need to be deciphered. This allows for a unique look at how KlassMaster performs this operation, by examining the string decoding function placed within an output program. The first major operation performed by KlassMaster is to identify the string literals within the program, and associate an internal variable with each. In this way, there can be a separation between the string which is specified in the bytecode of the program (which is located in the 'constant pool') with one that the program modifies or decodes at runtime. Once this is done, the string can be obfuscated, and the obfuscated version is placed within the 'constant pool' of the Java bytecode. Each character in the string undergoes an XOR operation with any one of a finite set of constants. In this way, the strings within the program are converted from cleartext into what otherwise appears as unremarkable sequences of bytes. All that is required, then, is to place a decoding operation in the output program, which both undoes the string obfuscation, and occurs before any actual executed program instruction. An example of the code segment which is placed into a program to decrypt a string is given <a href=stringexample.txt>here</a>.</em> <h2>Evaluation</h2> <em>Zelix KlassMaster is a very powerful tool for a Java programmer who wants to perform a final set of modifications to their program prior to releasing the program to the general public. However, there are numerous ways in which KlassMaster can generate incorrect code or otherwise change working programs into nonfunctional ones. Possibly one of the easiest ways that this can be accomplished by the beginning KlassMaster user is to fail to explicitly add an exclusion for the 'main' method. By not explicitly adding this exclusion, the Obfuscator will rename the function to some alternative, for example 'a'. As such, when a prospective user attempts to run this program, it will quicly generate a NoSuchMethodError exception. Although this appears to be a pitfall moreso than an actual failure by the program, it seems like a greater oversight by not including the particular exclusion by default.<p> Building upon this previous example are more complex problems, stemming from the exclusions list for the obfuscate operation. There are even cases given in the Frequently Asked Questions, in which programs using the Java Reflections API fail to process properly under the default settings. In a situation like this, further entries would need to be added to the exclusion list explicitly in order to be processed properly. So in this sense, although the default settings for obfuscation are sufficient in many cases, by no means is it fully comprehensive. If a problem develops, it likely means that some setting must be adjusted, and it is the programmer's, not KlassMaster's, responsibility to correct this.<p> A further interesting point can be made in regard to the string obfuscation function, and the fact that the algorithm used to decode strings is placed in the obfuscated output programs. Since the strings are deciphered within the program, and specifically within the 'static' block, this does leave programs using the string obfuscation open to attack; in particular, such programs are susceptible to live code analysis. For example, by running an obfuscated Java program through a debugger such as 'jdb', one can read out the contents of any strings easily. <p> Since the central focus of KlassMaster is to obfuscate Java bytecode such that it is not easily decompiled by a decompiler, this aspect of KlassMaster was indeed tested. From these decompilation tests, one could see that some aspects of the program were still plainly visible even after using strong settings for the obfuscation. This is to be expected, since not all aspects of a program could necessarily be hidden. Fortunately, however, the obfuscator did accomplish its task in producing confusion from the decompiled bytecode. The decompiler used in this test appears to only interpret certain sequences of instructions; sequences outside of its normal pattern cause bizarre problems to develop. Such problems include disassembled Java instructions among the decompiled code, entire portions of the code missing, and in one case, the decompiler crashed altogether. Although this was only one Java decompiler being used as a representative in this test, it can demonstrate that KlassMaster can indeed produce bytecode which requires much more care and time to understand what operations are occurring. <p> Although a lot can be learned about Zelix KlassMaster through the evaluation version, there were several limitations which prevented a complete and thorough analysis of its performance on real-world projects. The one with the most repercussions indicates that the evaluation version only obfuscates two methods per class. Although this might be sufficient to see how well a methid might be obfuscated in theory, it does not allow an actual program, which can easily consist of more than two methods, to be tested. Further, because of this restriction, it is nearly impossible to tell with any accuracy whether an obfuscated program suffers from considerable performance issues in comparison to the non-obfuscated version. <p> Overall, Zelix KlassMaster is a very powerful Java program manipulator. Although the breadth of KlassMaster's functions only extends to trimming functions and obfuscation, these goals are accomplished. In particular, obfuscated code is notably more difficult to understand and decipher, as compared to the non-obfuscated original. Despite these upsides, there are several pitfalls to the program which can easily confuse beginning users of KlassMaster or otherwise leave them trying to figure out how to correct a problem; this is particularly true in trying to figure out and grasp the exclusion mechanism used in both the Trim and Obfuscate functions. </em> <h2>Screenshots</h2> <em> <table class="image"> <tr><td><img src=GUIscreen.gif></td></tr> <tr><td class="caption">The main GUI interface</td></tr> </table> <p> <table class="image"> <tr><td><img src=ObfusExcl.gif></td></tr> <tr><td class="caption">The dialog that indicates what exclusions apply to a program.</td></tr> </table> <p> <table class="image"> <tr><td><img src=ObfusPanel.gif></td></tr> <tr><td class="caption">This dialog controls what kinds of obfuscation occur, plus<br>controls for several other settings.</td></tr> </table> </em> <h2>References</h2> <ul> <li> <em> <a href=http://www.zelix.com/>Zelix KlassMaster Homepage</a> </em> <li> <em> <a href=http://www.zelix.com/klassmaster/download1.html>Download a 30-day Trial</a> </em> <li> <em> <a href=http://www.zelix.com/klassmaster/features.html>Zelix KlassMaster Features</a> </em> <li> <em> <a href=http://www.zelix.com/klassmaster/FAQ.html>KlassMaster FAQ</a> </em> </ul> </body> </html>