Zelix KlassMaster - Java Obfuscator

Zelix KlassMaster Java Obfuscator and Obfuscation FAQ

Version 5.1

  1. Why wont Zelix KlassMaster run?
  2. Does Zelix KlassMaster support generics, annotations and Java 6?
  3. What is the difference between the evaluation and licensed versions of Zelix KlassMaster?
  4. Will Zelix KlassMaster run in Windows, Mac OS X, UNIX or using the Microsoft SDK?
  5. Does Zelix KlassMaster support J2METM and J2EETM?
  6. Why don't all names change when I obfuscate?
  7. Wont string encryption slow down my code and make it bigger?
  8. When I change a method name in one class, why do some methods in other classes also get renamed?
  9. When changing a method name, why do I get the message "New name clashes with a method in Class name" when the class mentioned doesn't seem to be related to the class that defines the method?
  10. After being obfuscated why does my code get the runtime errors "ClassFormatError", "VerifyError", "NoClassDefFoundError" or "Can't find class Classname"?
  11. Are there classes that Zelix KlassMaster can't reliably process automatically?
  12. When I open some classes why do I get the "Class Open Warnings" screen?
  13. When I open some classes why do I get the "Class Open Errors" screen?
  14. What options should I use when obfuscating my classes?
  15. What can I do if I get an OutOfMemoryError or "Insufficient Memory to open classes" error?
  16. Why does Zelix KlassMaster run so slowly?
  17. How do I obfuscate classes with native methods?
  18. I used the Zelix KlassMaster ZKM Script Helper to create a ZKM Script file but when I run it I get warnings. Why?
  19. Can Zelix KlassMaster obfuscate JSPs?
  20. Wont flow obfuscation slow down my code and make it bigger?
  21. Can I tell Zelix KlassMaster not to flow obfuscate certain methods?
  22. Why aren't all my methods flow obfuscated?
  23. What is the difference between "normal", "aggressive" and "flow obfuscate" String encryption?
  24. After obfuscation, why don't my classes work properly?
  25. What does the message "WARNING: changeLogIn fileName: Method oldMethodName in class className1 is mapped to new name newMethodName1 but the corresponding method in class className2 is mapped to new name newMethodName2. Using mapping of newMethodName2 for both methods" mean?
  26. How does the Input Change Log functionality interact with the name exclusion functionality?
  27. If I exclude a class from being obfuscated will the class's methods still be obfuscated?
  28. Can I edit a change log and then use it as an input change log so that I can predetermine new class, field or method names?
  29. I have a number of applets in the default package that I obfuscate separately. How do I stop Zelix KlassMaster from giving them the same name (e.g."a.class")?
  30. What is the easiest way of excluding non-static, non-transient fields from being renamed in serializable classes?
  31. My application will consist of a client jar file and server jar file which share some common classes. How do I obfuscate it?
  32. Does Zelix KlassMaster support incremental obfuscation?
  33. Can Zelix KlassMaster be called from a build tool such as Apache Ant?
  34. Can I access environment variables from within a ZKM Script?
  35. Our application uses Java Serialization. How does this impact obfuscation?
  36. Does Zelix KlassMaster support ResourceBundles as used in Localization and Internationalization?
  37. Why do I get a ClassCastException when I try to obfuscate bytecode compiled with Java 5 (i.e. JDK 1.5)?

Answers

Q1. Why wont Zelix KlassMaster run?

There could be a number of problems.
  1. You cannot run Zelix KlassMaster using a JDK 1.1.x, 1.2.x or 1.3.x JVM. You need Java 1.4 (JDK 1.4 or better).
  2. Zelix KlassMaster may not run on your operating system. See the answer to Q4.
If you are not getting a useful error message, try running with the -verify and -verbose switches.

Q2. Does Zelix KlassMaster support generics, annotations and Java 6?

Yes. Although, Zelix KlassMaster only requires the JDK 1.5 to run, it can handle Java 6 (i.e. JDK 1.6) bytecode. However, Zelix KlassMaster does allow you to remove annotations and generics information if you choose so, if you are experiencing problems in this area, you should check your settings.

Of course Zelix KlassMaster will also open and process JDK 1.1.x, 1.2.x, 1.3.x and 1.4.x bytecode. All you need to do is set the Zelix KlassMaster classpath to point to the appropriate bootstrap class archive file (i.e. classes.zip or rt.jar).

Q3. What is the difference between the evaluation and licensed versions of Zelix KlassMaster?

The major differences between the evaluation version and the commercial version are as follows:
  • The evaluation version will flow obfuscate only one or two methods in each class.
  • The evaluation version is time limited to thirty days.

Q4. Will Zelix KlassMaster run in Windows, Mac OS X, UNIX or using the Microsoft SDK?

Zelix KlassMaster is written entirely in Java 5 and technically should run on any platform that supports a 1.5 Virtual Machine. However, differences in the file systems and GUIs can cause problems. Also, Zelix KlassMaster's flow obfuscation technology can expose bugs in some Just In Time compilers. It has been tested on
  • Windows Vista™ using
    • Sun JDK 1.6.0_03 (build 1.6.0_03-b05) Java HotSpot™ Client VM and Server VM
    • Sun JDK 1.5.0_14 (build 1.5.0_14-b03) Java HotSpot™ Client VM and Server VM
    • BEA WebLogic JRockit(R) 1.6.0_02 (build 1.6.0_02_b06)
    • BEA WebLogic JRockit(R) 1.5.0_12 (build 1.5.0_12_04)
  • Solaris 10 on SPARC using
    • Sun JDK 1.6.0_03 (build 1.6.0_03-b05) Java HotSpot™ Client VM and 64-Bit Server VM
    • Sun JDK 1.5.0_09 (build 1.5.0_14-b03) Java HotSpot™ Client VM and 64-Bit Server VM
  • Linux (SuSe 10.1) using
    • Sun JDK 1.6.0_03 (build 1.6.0_03-b05) Java HotSpot™ Client VM and Server VM
    • Sun JDK 1.5.0_09 (build 1.5.0_14-b03) Java HotSpot™ Client VM and Server VM
    • IBM JDK 1.5.0 Classic VM (build pxi32devifx-20071025) (SR6b)
    • BEA WebLogic JRockit(R) 1.6.0_02 (build 1.6.0_02_b06)
    • BEA WebLogic JRockit(R) 1.5.0_12 (build 1.5.0_12_04)
  • Mac OS X 10.4 using
    • build 1.5.0_07-164 with HotSpot™ Client VM
Also note that Zelix KlassMaster:
  • will not run on the Microsoft VM because it does not support Java 1.5

Q5. Does Zelix KlassMaster support J2METM and J2EETM?

Yes. Zelix KlassMaster supports J2ME. There is a plugin for the Sun J2ME Wireless Toolkit 2.0. If you are not using the Sun J2ME Wireless Toolkit 2.0 then see the J2ME obfuscation tutorial for more detail on the steps invloved.

Yes. Zelix KlassMaster supports J2EE. Its default exclusions and its SmartSaveTM technology provide automatic support for servlets, the EJB 1 specification and the EJB 3 specification to the extent that you have used annotations rather than XML. If your application is an EJB 2 application that uses advanced features such as container managed persistence then we recommend that, for all classes directly related to the EJBs, you exclude
  • public class names and their containing package names,
  • public field names,
  • public method names.
If your EJB related classes are in specific packages then it should be quite easy to specify these exclusions in ZKM Script. Flow obfuscation and String encryption should cause no J2EE problems.

Q6. Why don't all names change when I obfuscate?

There are a number of reasons why all class, field or method names don't change when you obfuscate.
  • The name is public or protected and your obfuscate options say that public or protected names shouldn't be changed.
  • The name of a package scoped method is overridden to be protected or public in a subclass. If your obfuscate options say that protected or public method names shouldn't be changed then the overridden method name can't be changed without breaking the polymorphic link.
  • The name of a method overrides a method in a superclass or implements a method in an interface but the superclass or interface hasn't been opened inside Zelix KlassMaster. In such cases the method name cannot be changed without breaking the polymorphic link.

Q7. Wont string encryption slow down my code and make it bigger?

Encrypted strings are decrypted at runtime using code that has been added to the class. This means that the class will run slightly slower and will be bigger. How much slower and bigger depends on how many String literals there are in your bytecode. Typically the performance impact is insignificant. The bytecode size increase typically is in the range of 5% to 10%. It is recommended that you measure the impact on your classes.

Q8. When I change a method name in one class, why do some methods in other classes also get renamed?

When you change a method name, Zelix KlassMaster automatically changes all method names that are polymorphically linked to that method. So overridden methods in superclasses and overriding methods in subclasses must also be renamed. If the method is an implementation of an interface method then the method in the interface and the corresponding methods in all classes that implement that interface must also be renamed. So the change can ripple across to different branches of the class hierarchy.

Q9. When changing a method name, why do I get the message "New name clashes with a method in Class name" when the class mentioned doesn't seem to be related to the class that defines the method?

The answer to Q8 explains how a method name change can ripple across to different branches of the class hierarchy. So Zelix KlassMaster must check that the new name wont clash with existing names in these other classes. A name clash occurs if the proposed new signature
  • already exists in a class
  • already exists in a superclass or subclass so that a new polymorphic relationship would be created.

Q10. After being obfuscated why does my code get the runtime errors "ClassFormatError", "VerifyError", "NoClassDefFoundError" or "Can't find class Classname"?

This will happen if you obfuscate your bytecode using Java illegal identifiers or adding heavy corruption, and you have run you code with verification switched on. Verification is on:
  • in JDK 1.1.7 or less, for applications run with the -verify switch
  • in Java 2 by default unless you use the -Xverify:none switch
  • is always switched on for Applets.
You cannot use illegal identifiers or add heavy corruption if your classes must run after being verified. The JDK 1.2 (Java 2) or better will not even accept light corruption.

Alternatively, you will get such messages even when not runing with verification if you have renamed your highest level package qualifiers so that class names are Java illegal when fully qualified. For example a class named com.1.0 will cause no problems when running without verification but a class named 1.1.0 will cause problems.

Q11. Are there classes that Zelix KlassMaster can't reliably process automatically?

Some classes cannot be automatically and reliably obfuscated or have names changed without needing some explicit exclusions. Examples are classes that use the Java Reflection API by hardcoding package, class, field or method names in a string and then
  • at runtime, test a class, field or method's name against that string,
  • create Class, Field, Method or Constructor instances at runtime using that string.
Zelix KlassMaster can automatically handle many simple Reflection API calls. However, if Zelix KlassMaster opens a class that it might not be able to process reliably then it reports the fact using the "Class Open Warnings" screen. See the answer to Q12 for more detail on the "Class Open Warnings" screen and the methods that trigger it.

Zelix KlassMaster may still be able to automatically process classes that appear in the Class Warnings list. For example, calls to Class.getName() are often made purely for debugging purposes. Also, in certain situations, Zelix KlassMaster can change the contents of a string containing a class name to match the new class name. Zelix KlassMaster can do this only if:
  • the string is stored as an unencrypted string constant within an opened class file (as opposed, for example, to being read from a file) and
  • the fully qualified old class name:
    • is at least three characters long
    • contains at least one alpha character
    • contains the package separator character "."
In any case, the user must look at the way the call is used to determine if the class can be reliably processed automatically. If necessary, the package, class, field or method names that are accessed by name must be explicitly excluded from being renamed.

Q12. When I open some classes why do I get the "Class Open Warnings" screen?

When Zelix KlassMaster opens a class that it might not be able to trim or obfuscate reliably it reports the fact using the "Class Open Warnings" screen. You may get the "Class Open Warnings" screen when an opened class contains a Reflection API call to a method like one of the following:
  • Class.forName(String)
  • Class.getName()
  • Class.getField(String)
  • Class.getMethod(String)
  • Class.getDeclaredField(String)
  • Class.getDeclaredMethod(String)
  • Field.getName()
  • Method.getName()
  • Constructor.getName()
  • ClassLoader.loadClass(String,boolean)
  • ClassLoader.defineClass()
  • ClassLoader.findSystemClass(String)
  • ClassLoader.findLoadedClass(String)
  • RMIClassLoader.loadClass(String)
  • RMIClassLoader.loadClass(URL, String)
  • LoaderHandler.loadClass(String)
  • LoaderHandler.loadClass(URL, String)
  • EventSetDescriptor(Class, String, Class, String)
  • EventSetDescriptor(Class, String, Class, String[], String, String)
  • EventSetDescriptor(Class, String, Class, String[], String, String, String)
Note that the "Class Open Warnings" screen lists
  • the class in which the method call appears
  • the signature of the method in which the method call appears
  • the signature of the method being called.
It does not name the class, field or method that is being accessed by name. Please see the answer to Q11 for detail on what to do if you get "Class Open Warnings".

Q13. When I open some classes why do I get the "Class Open Errors" screen?

Some obfuscators add corrupt information to bytecode files in the hope of confusing or crashing decompilers. Zelix KlassMaster detects this corrupt information and reports the fact using the "Class Open Errors" screen. Corrupt Local Variable Table and Inner Class information is automatically removed.

Zelix KlassMaster will also report the existence of duplicate classes if the classes
  • appear in the same archive or
  • are not absolutely identical.

Q14. What options should I use when obfuscating my classes?

Generally, don't select the "keep inner class information" option. This will reduce the size of your bytecode. Typically, JVMs make no use of inner class information at runtime. However, compilers do make use of this information at compile time. So, if your classes form a library which third party classes will be compiled against and if some of your inner classes are exposed to the user then you will need to select the "keep inner class information" setting.

If the size of your bytecode is critical then select the "delete" line numbers option. However, if you are obfuscating for a beta release or if the size of your code isn't critical then you can select the "scramble" line numbers option. The code will be larger but you will find crashes much easier to track down.

The "encrypt string literals" option is generally safe. However, use of the "aggressive" or "flowObfuscate" settings can, in certain unusual circumstances, result in the contents of public static final String fields of some interfaces not being accessible to classes outside of the set that you have obfuscated. If this happens, you will get a warning message in the Zelix Klassmaster log. Also, note that String encryption does make your bytecode larger and slightly slower (see the answer to Q7).

If you are obfuscating an applet note that there are known bugs in the JITs of the early browsers that can be exposed by flow obfuscation. If you flow obfuscate using the "light" option then the risk of JIT problems will be greatly reduced. Nonetheless, if you flow obfuscate your applet then test it thoroughly.

If your classes make up a self-contained application then it should be safe to change all package, class, field and method names other than those of the public static main(String[]) method and the class that contains it. You can achieve this by selecting the "Self contained application or applet" application type and by selecting your entry paint class in the "Don't change main class name" list.

If you are obfuscating a set of classes that will be used by third parties as a non-extensible class library then you should
  • not obfuscate public class names
  • not obfuscate public field or method names
You can achieve this is the GUI by selecting the "Non-extensible class library" application type.

If you are obfuscating a set of classes that will be used by third parties as an extensible framework then you should
  • not obfuscate public class names
  • not obfuscate public or protected field or method names
You can achieve this is the GUI by selecting the "Extensible framework" application type.

In either case you should
  • limit String encryption by either
    • using the "normal" setting or
    • using the "aggressive" or "flowObfuscate" settings but excluding all interfaces from String encryption using the ZKM Script stringEncryptionExclude statement. (e.g. "stringEncryptionExclude interface *.*;")
  • consider choosing the line numbers "scramble" option

If your classes form a complex EJB 2 application or (an EJB 3 application where you have used XML rather than annotations) then the easiest solution is to exclude all public classes, fields and methods that are directly related to the EJBs. Otherwise it should be safe to use light flow obfuscation and String encryption.

It is highly recommended that you always use the "legal identifiers" option and never make use of the "add corruption" option. Both of these options are now available only in ZKM Script and only for the purposes of backwards compatibility. If you are obfuscating an application that doesn't have to run with verification switched on then you can get extra protection with these options but, as decompilers mature, these "tricks" will become less effective and they will cause problems with modern JVMs.

Please note that whatever options you choose it remains your responsibility to fully test or retest your classes after they have been processed by Zelix KlassMaster.

Q15. What can I do if I get an OutOfMemoryError or "Insufficient Memory to open classes" error?

Zelix KlassMaster holds a lot of information in memory for each class that it opens. So, the more classes you open and the more complicated those classes are the more memory you need. If Zelix KlassMaster tells you that there was insufficient memory to open your classes or if it crashes with an OutOfMemoryError then you can do one of the following:
  1. Give Java more memory to work with by using the -Xmx??m option where ?? represents the number of megabytes. (For example, the option -Xmx256m gives Java 256MB of heap space.)
  2. When you are running Zelix KlassMaster via Ant then you need to give more memory to Ant itself. An easy way of doing this is by setting the "ANT_OPTS" environment variable.
    e.g. set ANT_OPTS=-Xmx256m
  3. Use the "Tools/Garbage Collect" menu option or the gc ZKM Script statement after opening your classes and before obfuscating.
  4. Install more physical memory.
It is not recommended that you make use of virtual memory (by giving Java more memory to work with than is physically installed.) Performance will be unreasonably degraded as memory is swapped to and from the disk.

Q16. Why does Zelix KlassMaster run so slowly?

There are a number of reasons Zelix KlassMaster may run slowly.
  1. Your computer may have insufficient real memory installed. If your computer has to use virtual memory performance will be very poor. You will notice that the hard disk is being very heavily utilized.
  2. You are obfuscating while viewing a very large class or method. This results in reduced performance due to the overhead of updating the class or method details in the View Panel.

Q17. How do I obfuscate classes with native methods?

Zelix KlassMaster's default exclusions will automatically handle any native methods by ensuring that
  1. the names of the native methods themselves and
  2. the fully qualified names of the classes that contain them
will not be changed.

However, Zelix KlassMaster has no way of knowing if your native code accesses your Java fields or methods. If your native code does access any of your Java fields or methods then you will need to explicitly exclude the accessed member names and the fully qualified names of the classes that contain them from obfuscation.

Q18. I used the Zelix KlassMaster ZKM Script Helper to create a ZKM Script file but when I run it I get warnings. Why?

The current version of the ZKM Script Helper does not validate all of your choices to ensure they are not contradictory. For example, it will allow you to exclude final abstract methods even though such methods cannot exist. The parser will give you a warning in this case.

Q19. Can Zelix KlassMaster obfuscate JSPs?

Zelix KlassMaster cannot obfuscate JSP (Java Server Page) source but it can obfuscate the servlet that is generated from a JSP. However, problems can arise if a JSP servlet is automatically regenerated at runtime replacing the class produced by Zelix KlassMaster. If this can happen in your environment then you should specify your JSP servlet classes as "fixed" by using the ZKM Script fixedClasses statement. For example you could say:

fixedClasses *.* implements javax.servlet.jsp.JspPage;

Q20. Wont flow obfuscation slow down my code and make it bigger?

Generally, Zelix KlassMaster's flow obfuscation will slightly increase the size of your bytecode and it will reduce its performance. It is a trade off between the degree of protection against decompilation and bytecode size and speed. The table below shows the approximate bytecode size increase that could be expected for typical applications. Note that the size increase will vary from application to application and you should measure the impact on your bytecode.
flow obfuscation
option used
approximate
size increase
"light" < 1%
"normal" 1%
"aggressive" 3%

The performance impact of flow obfuscation varies depending upon
  • the bytecode that is being obfuscated,
  • the JVM used to execute the bytecode,
  • the flow obfuscation option used.
When the HotSpot™ 1.4.0 JVM is used, the approximate performance impact for general purpose applications is shown in the table below.
flow obfuscation
option used
approximate
performance decrease
"light" 1%
"normal" 25%
"aggressive" 25%
Again, it is recommended that you measure the impact on your classes. If you experience an unacceptable performance impact then you should
  • use "light" flow obfuscation,
  • use the ZKM Script obfuscateFlowExclude statement to exclude performance critical methods from flow obfuscation.

Q21. Can I tell Zelix KlassMaster not to flow obfuscate certain methods?

You can use the ZKM Script "obfuscateFlowExclude" statement to specify methods that you don't want flow obfuscated. This functionality is not yet available in the GUI interface. (Note that the name exclusion functionality has no impact at all on flow obfuscation.)

Q22. Why aren't all my methods flow obfuscated?

Zelix KlassMaster only attempts to obfuscate the flow of methods that already have some control flow complexity. So methods without if, switch, while or for constructs will not be flow obfuscated. Also there are small percentage of methods with some control flow complexity that Zelix KlassMaster cannot yet flow obfuscate. Finally, note that the evaluation version will only flow obfuscate one or two methods in each opened class.

Q23. What is the difference between "normal", "aggressive" and "flow obfuscate" String encryption?

"Normal" String encryption encrypts all String literals that are accessed by methods in the defining class. This can mean that the values of some final String fields were not obfuscated. For example, String constants in interfaces would typically not be encrypted.

"Aggressive" String encryption uses a more sophisticated approach that can normally encrypt Strings even in interfaces.

The "flow obfuscate" option is the same as the "aggressive" option but causes the runtime decryption instructions, that is inserted into your bytecode, to be flow obfuscated. This makes the decrypt instructions harder to decompile but it could cause problems with some JITs. Note that the limitations mentioned above for the "aggressive" option also apply for the "flow obfuscate" option. Note also that the String Encryption "flow obfuscate" option is quite independent of the general Flow Obfuscation functionality. You can choose to have one without the other.

Q24. After obfuscation, why don't my classes work properly?

If you get any of the runtime errors "ClassFormatError", "VerifyError", "NoClassDefFoundError" or "Can't find class Classname" see the answer to Q10.

Another reasons for errors such as "NoClassDefFoundError", "Can't find class Classname" or "NoSuchMethodError" are:
  • You didn't open all your classes inside Zelix KlassMaster before obfuscating
  • You application
    • uses the Reflection API and
    • Zelix KlassMaster has reported that there are some Reflection API calls in your bytecode that it may not be able to automatically handle and
    • you didn't exclude the names of the classes, fields or methods that are accessed by those Reflection API calls.
    Please see the answer to Q12 for more detail.

Finally, if you used Flow Obfuscation and your classes are causing the VM to crash (typically with a memory access error) or if you are getting an unexpected NullPointerException, you may be running foul of a bug in the JIT. To test this, run your application with the JIT switched off. If the problems occur only when the JIT is being used you should:
  • Upgrade to a more recent JIT. Of course it isn't always practical to ask your users to upgrade their JITs. JITs that are known to cause bugs with flow obfuscated bytecode are:
    • Microsoft VMs earlier than 5.00.3167
    • Symantec JITs earlier than 3.00.072b.
    • some of the IBM 1.3 JVMs
  • If you obfuscated with "aggressive" flow obfuscation, try the "normal" setting.
  • If you obfuscated with "normal" flow obfuscation, try the "light" setting. The "light" setting should eliminate most problems.
  • If you can identify the flow obfuscated method that is triggering the JIT bug then you can use the ZKM Script obfuscateFlowExclude statement to exclude that method from flow obfuscation.
  • As a last resort you can switch off flow obfuscation altogether by using the "none" option.

Q25. What does the message "WARNING: changeLogIn fileName: Method oldMethodName in class className1 is mapped to new name newMethodName1 but the corresponding method in class className2 is mapped to new name newMethodName2. Using mapping of newMethodName2 for both methods" mean?

The warning message indicates that the method name mappings in the Input Change Log are inconsistent for the opened classes. This can happen if
  • you have directly edited the change log file and make some mistakes or
  • your application has changed so that there are now polymorphic relationships between two or more methods that where previously unrelated.
In either case, Zelix KlassMaster handles the situation automatically to ensure the obfuscated bytecode is OK.

Q26. How does the Input Change Log functionality interact with the name exclusion functionality?

If you are using the GUI or if you specified an input change log using the changeLogFileIn parameter of the ZKM Script obfuscate statement then Zelix KlassMaster will always try to rename packages, classes, fields and methods to the names specified by the input change log. All the other statements such as the exclude and obfuscate statements remain fully active but generally they will only have impact on the names of packages, classes, fields and methods that do not already appear in the input change log.

So, for example, if the input change log clashes with the exclusions that have been set (or haven't been set) then warnings will be generated but the input change log will be given priority. The only exceptions are where:
  • the input change log contains inconsistent or conflicting information. For example if it
    • contains duplicate new package, class, field or method names
    • contains fully qualified new class names that conflict with the corresponding new package name
  • the input change log contains information that cannot be validly applied to the opened classes. For example if it
    • would incorrectly make or break a polymorphic relationship between methods.
However, if you specified an input change log using the looseChangeLogFileIn parameter of the ZKM Script obfuscate statement then your exclusions will take precedence over the change log mappings. However, this could mean that the newly obfuscated classes will not be fully consistent with your previous release.

Q27. If I exclude a class from being obfuscated will the class's methods still be obfuscated?

Yes. If you specify a class in the exclude statement or using the GUI's Obfuscate Advanced Name Exclusion Options Dialog, you are excluding only the class name from obfuscation. Excluding a class name from obfuscation has no effect
  1. on the obfuscation of that class's field and method names or
  2. on the flow obfuscation or String encryption of any of its methods. To exclude methods from flow obfuscation you must use the ZKM Script obfuscateFlowExclude statement. To exclude String literals from encryption you must use the ZKM Script stringEncryptionExclude statement.

Q28. Can I edit a change log and then use it as an input change log so that I can predetermine new class, field or method names?

Yes but be careful. If you are using a change log that was generated when you obfuscated a release of your application or applet then make sure you edit a copy. You may still need the original to interpret stack dumps from the released bytecode.

Also, be careful when you choose you predetermined names. It's a complicated business - especially if you are predetermining method names. Zelix KlassMaster will perform a large number of cross checks on your input change log and on your opened classes but it may not check for every possible conflict. If Zelix KlassMaster gives you warnings then read them carefully.

Note that Zelix KlassMaster's ZKM Script language allows you to specify more than one input change log. So you could specify an small, edited input change log that specifies only your changes followed by the full, original input change log. This can be a safer approach.

Q29. I have a number of applets in the default package that I obfuscate separately. How do I stop Zelix KlassMaster from giving them the same name (e.g."a.class")?

It causes problems when different applets (or different classes used by different applets) are given the same name. Browsers and proxy servers can get confused. The recommended solution is to put your applets in different packages that are unique to your organisation and to exclude those package names from obfuscation. If you then obfuscate the package as a whole, then each class will be given a unique name within the name space of the package.

However, it is recognized that, for various reasons, not everyone wants to do this. The best alternative way of handling this situation is to use Zelix KlassMaster's Input Change Log functionality. Perform a preliminary obfuscation with all of your applet classes opened inside Zelix KlassMaster. Don't bother saving the obfuscated classes. All you want is the "cross applet" change log with each class being given a unique name. Now obfuscate each of the individual applets using the "cross applet" change log as an input change log so that each class again gets its unique name. Retain the "cross applet" change log for use as an input change log in any subsequent releases of your applets. You only need save the individual applet change logs if you have used line number scrambling.

Q30. What is the easiest way of excluding non-static, non-transient fields from being renamed in serializable classes?

Using the ZKM Script interface you can accomplish this easily with a statement like:

exclude *.* implements java.io.Serializable !static !transient *;

Using the GUI interface's Advanced Exclusion Options dialog, you can select "!static" and "!transient" from the drop down lists.

Q31. My application will consist of a client jar file and server jar file which share some common classes. How do I obfuscate it?

Obfuscate your application as a whole in one pass. Zelix KlassMaster version 3 or better automatically handles issues relating to obfuscating multiple JAR files.

If you will sometimes need to release just a changed client or server jar file then you should use Zelix KlassMaster's Input Change Log functionality to ensure consistent renaming across your releases. The steps are
  1. Initially obfuscate your client and server jar files together in one pass generating an overall change log.
  2. If you make changes to only one of the jar files then obfuscate both your client and server jar files together in one pass once more using the change log generated in the step above as an input change log. Release just the changed jar.
  3. Use the change log generated in the second step as the new overall change log.

Q32. Does Zelix KlassMaster support incremental obfuscation?

Yes. Zelix KlassMaster's Input Change Log functionality ensures
  1. consistent package, class, field and method renaming and
  2. consistent flow obfuscation
across releases. It is generally recommended that you always open ALL the classes of the application inside Zelix KlassMaster. This gives Zelix KlassMaster the opportunity to ensure that all references are consistent. This is the case even if you are planning to distribute just the changed class subset in the form of some kind of patch.

Zelix KlassMaster does provide some limited ability to obfuscate a subset of your application provided the mappings for the full application appears in an input change log. To do this you should set the allClassesOpened parameter of the obfuscate statement to false and set the classpath so that the unobfuscated versions of all the unopened classes of the application can been located.

However, if you are using the Trim function then you must still open your application as a whole.

Q33. Can Zelix KlassMaster be called from a build tool such as Apache Ant?

Yes. Zelix KlassMaster exposes a simple, generic Java API for use by build tools. It also provides an Ant task called ZKMTask. See the online documentation for a full description of the API and for extra detail on the Ant task definition.

Q34. Can I access environment variables from within a ZKM Script?

To access an enviroment variable such as PATH from within your ZKM script you should firstly add the environment variable to the System properties when you start Zelix KlassMaster. Use this syntax for Windows:

java -D"PATH=%PATH%" -jar ZKM.jar

and this syntax for Unix

java -DPATH=$PATH -jar ZKM.jar

If you running Zelix KlassMaster through Apache Ant then you can either add the environment variable to the Ant project properties or use the Zelix KlassMaster Ant task (ZKMTask) to add the environment variable to the System propeties. (See the online documentation for more detail.)

Then access the variable in your ZKM Script by using the %...% delimiters. For example %PATH%. The Zelix KlassMaster preprocessor will perform the substitution.

Q35. Our application uses Java Serialization. How does this impact obfuscation?

If you never have to deserialize a non-obfuscated class with a obfuscated class then Serialization presents no problems. Zelix KlassMaster will automatically handle the necessary exclusions using its defaults and its Input Change Log functionality can be used to ensure consistent renaming across releases. However, if you need to deserialize already existing (ie. unobfuscated) serialized instances using your obfuscated classes then your obfuscated classes need to be compatible for Serialization purposes with your unobfuscated classes.

To achieve this compatibility you need to use the ZKM Script existingSerializedClasses statement to specify the classes that have existing serialized instances. For each class matched by the statement, Zelix KlassMaster will
  • add name exclusions for
    • the fully qualified name of the class
    • the name of every field contained or inherited by the class
    • the fully qualified class name of the type of each non-primitive field contained or inherited by the class
  • add a serialVersionUID field to the class (if it doesn't already exist) set to a value based upon the non-obfuscated class definition.

Q36. Does Zelix KlassMaster support ResourceBundles as used in Localization and Internationalization?

The issue here is whether Zelix KlassMaster's obfuscation of class names will effect ResourceBundle.getBundle(String, Locale) calls. In the case of PropertyResourceBundles, because they are backed by properties files and don't involve Java class files, they are unaffected by obfuscation.

On the other hand, ListResourceBundles are backed by class files. If you create your ListResourceBundles by specifying the fully qualified base class name in a String literal and if the base class is within a package then Zelix KlassMaster will automatically change the value of the String literal to match the new obfuscated base class name. So the following code would be automatically handled (as far as the base class is concerned).

ResourceBundle myBundle = ResourceBundle.getBundle("package1.Class1", myLocale);

However, some additional work would still have to be done to handle the subsidiary ListResourceBundle classes such as
  • package1.Class1_de,
  • package1.Class1_de_DE,
  • package1.Class1_fr and
  • package1.Class1_fr_CH
Basically, a class suffix exclusion statement must be used for each language code, country code and locale variant combination to ensure that the subsidiary classes are renamed in synchronization with the base class with the suffixes being retained. An example ZKM Script exclusion statement would be:

exclude *.<link>_de and
        *.<link>_de_DE and
        *.<link>_fr and
        *.<link>_fr_CH;
If your organization uses a standard set of localizations, you could consider adding such an exclusion to your defaultExclude.txt file so that it is automatically applied.

Otherwise, if your ListResourceBundle class names are not stored as fully qualified names in String literals or if the classes are not within packages then you would have to explicitly exclude the base class and subsidiary class names from being obfuscated.

Q37. Why do I get a ClassCastException when I try to obfuscate bytecode compiled with Java 5 (i.e. JDK 1.5)?

A ClassCastException can occur if you obfuscate bytecode compiled with the JDK 1.5 or better with Zelix KlassMaster 4.2 or earlier. It is due to the fact that the JDK 1.5 changed the JVM specification for the loading of constants in a fundamental way.

Zelix KlassMaster (version 4.3 and better) has been enhanced to support bytecode created with the JDK 1.5. However, if you compile with the JDK 1.5 using the "-source 1.4 -target 1.4" parameters then you may still be able to use earlier versions of Zelix KlassMaster without further difficulties.