Zelix KlassMaster - Documentation
 

Obfuscate Options

Zelix KlassMaster - Name Obfuscate Options

Overview

Zelix KlassMaster™ provides the following obfuscation options. Note that there is no name obfuscation option. Generally speaking, all package, class, field and method names not excluded using the Obfuscate Name Exclusions dialog will be obfuscated.

Use input change log file

If you select "use input change log file" Zelix KlassMaster™ will read the name change details from the existing change log file that you named in the input field to the right of the option. This ensures consistent renaming across releases which can be vital in certain situations (e.g. RMI and serialization).

Produce a change log file

If you select "produce a change log file" Zelix KlassMaster™ will write the name change details to a change log file. The change log file will be given the name that you entered in the input field to the right of the option.

It is recommended that you always select this option. With a change log, you can use the Stack Trace Translate tool to translate obfuscated stack traces. Without a change log, debugging the stack traces caused by uncaught exceptions is extremely difficult if not impossible. Also, you can use the change log as an input change log when you obfuscate your next release so that the same obfuscated names will be used.

Note that only the latest changes will appear in the file. If you obfuscate twice with the same change log file name then only the second set of name changes will be retained. Also, if the change log out file name is the same as the input change log file name then, after it has been read, the original file will be overwritten with the new change details.

Obfuscate Control Flow

If you select light, normal, aggressive or extraAggressive in the "Obfuscate Control Flow" list, Zelix KlassMaster™ will obfuscate most selection (eg. if...else) and loop (eg. while or for) constructs so that they cannot be directly decompiled back to the Java language. Selecting aggressive results in more flow obfuscation than would be done if you selected normal. Selecting normal results in more flow obfuscation than would be done if you selected light.

To switch off flow obfuscation, you should select none in the "Obfuscate Control Flow" list.

The disadvantages of flow obfuscation are that your bytecode will run slower and will be slightly larger. 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 in a compressed JAR file 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 2%
normal 3%
aggressive 7%
extraAggressive 10%

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(TM) 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 5%
normal 7%
aggressive 10%
extraAggressive 15%
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.

Also, flow obfuscation can expose bugs in some JVMs and particularly in some JITs. This is more likely to happen if you use the aggressive or extraAggressive options and it is much less likely to occur if you use the light option. Be sure to test your code in every environment in which it must run.

Exception obfuscation

If you select light or heavy in the "Exception obfuscation" list, Zelix KlassMaster™ will perform a kind of flow obfuscation which involves exceptions. If you select heavy then the obfuscation will be more aggressive.

Note that Exception Obfuscation interacts with both Flow Obfuscation and String Encryption. If you use Flow Obfuscation and/or String Encryption then the intensity of any Exception Obfuscation will be increased. Similarly, the more aggressive the Flow Obfuscation and/or String Encryption you select then the more intense the Exception Obfuscation that will be possible.

The disadvantage of Exception obfuscation is that your bytecode may run slower and it will be larger. The more intense the Exception Obfuscation then the greater the bytecode size increase will be. It is a trade off between the degree of protection against decompilation and bytecode size and speed.

Exception Obfuscation is not normally affected by the ZKM Script obfuscateFlowExclude statement. Its effect is normally all or nothing. However, you can use the special ZKM_TREAT_EXCEPTION_OBFUSCATION_AS_FLOW_OBFUSCATION configuration option to ask Zelix KlassMaster™ to make Exception Obfuscation subject to the obfuscateFlowExclude statement.

Encrypt String literals

When the "Encrypt String literals" option is set to normal, Zelix KlassMaster™ will replace your string literals with encrypted strings and add instructions to your bytecode that will decrypt the strings at runtime. The aggressive setting goes further by removing any static final String constants that can be left unencrypted when the normal setting is used. The compatibility of the aggressive setting depends upon the compiler that generated the bytecode. It works fine with the Oracle and IBM compilers that we have tested. If you use another compiler and experience problems with your aggressive string encrypted bytecode then use the normal setting instead.

The flow obfuscate setting is the same as the aggressive setting except that it flow obfuscates the decryption methods automatically inserted into your bytecode. This makes the decryption methods harder to decompile but, as with all flow obfuscation, it can expose bugs in some VMs and JITs. Note that the String Encryption flow obfuscate setting is quite independent of the

The enhanced setting is the same as the flow obfuscate setting except that it provides enhanced encryption which is more difficult to reverse. It is the recommended setting if you do not need to compile against any obfuscated classes and if an greater increase in bytecode size is tolerable.

To switch off String encryption, you should set the "Encrypt String literals" option to none.

The advantage of string encryption is that the Java source produced by a decompiler is much less comprehensible if the string literals are gibberish. The disadvantages are that your code will slightly slower and will be a little larger. Typically, the performance cost is insignificant. The bytecode size increase is typically in the range of about 5% to 10% but it ulimately depends on the number of String literals in your application. It is recommended that you measure the impact on your classes.

Note that the string encryption used by Zelix KlassMaster™
  • is cumulative. That is, if you obfuscate more than once with the "Encrypt String literals" option set to normal, aggressive or flow obfuscate then your string literals will be encrypted more than once. Any performance and size penalty will be compounded.
  • is not irreversible. Don't rely on it to protect highly sensitive data.

Mixed case class names

The Java™ environment is case sensitive. However, the file systems of some operating systems (e.g. Windows™) are not. So if classes are going to be stored directly in the file system of a non-case sensitive operating system then the obfuscated names of those classes should be different other than just in case.

On the otherhand, if your obfuscated classes will always be stored within an archive (e.g. JAR file) then you can reduce the size of your application by using mixed case obfuscated class names.

The "Mixed case class names" drop down list allows you to specify how Zelix KlassMaster™ generated new, obfuscated class names. If you select true then obfuscated class names will aways be generated using mixed case. If you select false then obfuscated class names will be generated using only lower case. If you select if only in archive then obfuscated class names will be generated using mixed case only for those classes which appear only inside of archive files.

Collapse packages

When the "collapse packages" box is selected, Zelix KlassMaster™ will recursively collapse subpackages into their superpackages. Effectively, classes in subpackages will be moved into their superpackages. By reducing the overall length of the package names, this option reduces the length of fully qualified class names and therefore reduces the size of the bytecode.

Packages whose names have been excluded from being changed are never collapsed. So packages with excluded superpackages will be collapsed into the nearest excluded superpackage. If a package has no excluded superpackage then it will be collapsed into the package specified in the "Default name" field that appears to the immediate right of the "Collapse packages" box. If the "Default name" field is empty then packages with no excluded superpackage will be collapsed into the Java default package "" (which is no package at all). If a default package name is specified then it must be a top level package. For example "foo" is OK but "foo.bar" is not. The specified top level package need not already exist.

Remember that one of the purposes served by package names is to ensure that fully qualified class names are unique. If you collapse your packages into the Java default package (ie. no package) then Zelix KlassMaster™ will ensure that your class names are unique within your application. However, you must be sure that there will be no runtime name clashes with other default package classes in the runtime classpath.

Take as an example the following set of packages.
com
com.mycompany
com.mycompany.package1
com.mycompany.package2
com.yourcompany
com.yourcompany.package1

If you
1. select the "Collapse packages" box
2. exclude the com.mycompany package name from being excluded
3. enter foo into the "Default name" field

then the packages will be collapsed as follows
com=>com
com.mycompany=>com.mycompany
com.mycompany.package1=>com.mycompany
com.mycompany.package2=>com.mycompany
com.yourcompany=>foo
com.yourcompany.package1=>foo

giving the result
com
com.mycompany
foo

Typically you would only collapse the package structure if your obfuscated classes were self contained. The following settings are typical for the different application types.
Application type Ok to collapse packages?
Non-extensible library No
Extensible framework No
Java ME MIDlet Yes
Self contained application or applet Yes

Aggressive method renaming

If you select this option, Zelix KlassMaster™ will rename your methods more aggressively. The resulting bytecode will run without problem but you may have difficulties compiling Java source against your obfuscated bytecode.

Select this option only if your application is stand-alone and self-contained. Do not select this option if your classes make up an extensible framework or a class library.

Randomize

When selected, this option tells Zelix KlassMaster™ to generate new obfuscated names in a random fashion. By default, if the opened classes are unchanged, Zelix KlassMaster™ will generate the same obfuscated names.

Keep inner class information

The JDK 1.1 introduced inner classes. At the level of the bytecode, inner classes are distinguished by the structure of their names and by the presence of a few attributes. This inner class information is not critical to the running of your bytecode. It is provided for the use of compilers and debuggers and similar utilities.

If you select "true" in the "keep inner class information" list then Zelix KlassMaster™ will retain this inner class information in all inner classes. If you select "false" then Zelix KlassMaster™ will delete this inner class information from all inner classes. Finally, if you select "ifNameNotObfuscated" then Zelix KlassMaster™ will retain this information in all inner classes that do not have their names obfuscated and it will delete it in all others. The rationale of the "ifNameNotObfuscated" setting is that you are unlikely to have changed the name of an inner class that needs to be accessed by a compiler or utility.

Because inner class information is not used at runtime, it is generally suggested that you select "false". However, if you or your customers must compile classes against your obfuscated inner classes then you must select "true" or at least "ifNameNotObfuscated".

Keep generics information

The JDK 1.5 introduced generics. At the level of the bytecode, generics information is stored in special attributes. As in the case of inner class information, generics information is not critical to the running of your bytecode but is provided for the use of compilers and debuggers and similar utilities.

If you select "true" in the "keep generics information" list then Zelix KlassMaster™ will retain this information in all classes. If you select "false" then Zelix KlassMaster™ will delete this information from all classes.

Because generics information is not used at runtime, it is generally suggested that you select "false". However, if you or your customers must compile classes against your obfuscated classes that make use of the genericity of those classes then you must select "true". Some JEE environments may also require that generics information be retained.

Local variable tables

Java compilers can optionally include local variable tables in your bytecode that store the local variable names that you used in your source code. The names that you give your method parameters are also local variables. This local variable information can be useful when you are debugging your code but it can also make the job of a decomplier that much easier.

Zelix KlassMaster™ gives you five ways of dealing with local variable tables. These options appear in the "Local variable tables"drop down list. When you select "delete" (the default) all local variable information is deleted. You should use this setting in almost all cases.

When you select "keepVisibleMethodParameters" the method parameter variable names of public or protected methods are retained. When you select "keepVisibleMethodParametersIfNotObfuscated" the method parameter variable names of public or protected methods are retained only if
  1. the name of the method is not obfuscated and
  2. the names of the containing class and package are not obfuscated.
These two options can be of use when obfuscating a library that will be used within an IDE. Many IDE's will preview a method's signature including its parameter names.

The "obfuscate" setting tells Zelix KlassMaster™ to obfuscate the local variable names. Obfuscated local variable names will typically take up less space than meaningful variable names but they will take up more space than would be the case if the "delete" setting was used. The final "keep" setting is not recommended and is provided only for those rare cases where it may temporarily make debugging easier.

However, you should note that method parameter names may also be stored in the methodParameters attribute. These can be independently managed using the obfuscate statement.

Line number tables

Java compilers can optionally include line number tables in your bytecode that map bytecode instructions to source code line numbers. If your code contains line number information and it experiences an uncaught exception at runtime then the corresponding source code line number is displayed by the Virtual Machine. However, line number tables can also provide clues to decompliers.

Zelix KlassMaster™ gives you three ways of dealing with line number tables. These options appear in the drop down list. If you select delete, Zelix KlassMaster™ will remove all line number debugging information. This reduces the size of your bytecode but it can make it difficult to analyze the stack traces produced by uncaught exceptions. This is especially the case in obfuscated code where many methods share the same name.

If you select scramble, Zelix KlassMaster™ will mix-up the line number table entries and write the mapping of the new to original line numbers to the nominated change log file. This gives decompilers little extra information while allowing you to determine the source code line numbers in stack traces. The Stack Trace Translate tool makes the translation of scrambled to original line number easy. However, scrambled line numbers will make your bytecode larger.

The third choice is to select keep. Zelix KlassMaster™ will leave the existing line number tables as they are. Any stack traces will give the original source line numbers and your bytecode will be slightly smaller than if you had scrambled the line numbers. However, unscrambled line number tables can give decompilers valuable information about the structure of your original code.

In all cases, if there is no line number information in the bytecode, this option will have no effect.

Note also that most JVMs will not display line numbers in a stack trace unless a Source File attribute is present in that class. So if you want to keep or scramble your line numbers and you are also using Zelix KlassMaster™'s Trim option then you should not specify the deletion of Source File attributes.

Obfuscate references

If you select this option, Zelix KlassMaster™ will obfuscate the field or method references that you specify in the next window. A field or method reference is a field access or a method call. Zelix KlassMaster™ obfuscates references by replacing them with Reflection API calls.

The ZKM Script interface provides additional reference obfuscation functionality in the form of the obfuscate, obfuscateReferencesInclude and obfuscateReferencesExclude statements.

See the Obfuscate References Tutorial for more detail.

Auto reflection handling

If you select this option, Zelix KlassMaster™ will automatically handle Java Reflection API calls which access classes, fields or methods. Only those Reflection API calls which Zelix KlassMaster™ has not been able to fully resolve will need to be handled. Reflection API calls which have not been fully resolved will be listed in the Class Open Warnings window.

The ZKM Script interface provides additional AutoReflection™ functionality in the form of the obfuscate, accessedByReflection and accessedByReflectionExclude statements.

See the AutoReflection™ Tutorial for more detail on the AutoReflection™ function.

Keep balanced locks

If you select "keep balanced locks" then Zelix KlassMaster™ will maintain "structured locking". You should select this box if your classes will be used to generate bytecode for the Android ART verifier.

Preverify

If you select "preverify" then Zelix KlassMaster™ will fully preverify your classes. This is essential if your classes were compiled by a Java 6 or better compiler and if you will be running your bytecode on a JVM. So you should always select this check box except for special situations where your bytecode will be further processed (e.g. into Android dex bytecode) in a way that does not require preverification.

Default exclusions

Zelix KlassMaster™ excludes some class, method and field names by default ( see "Default Name Exclusions"). For example it supports RMI, JavaBeans™ and EJBs™ by:
  • not changing the "_Stub", "_Skel", "BeanInfo" or "Customizer" class name suffixes and by maintaining the necessary class name correspondence.
  • not changing the names of your RMI remote methods.
  • automatically adjusting the values of your BeanInfo
    • Class beanClass
    • Class customizerClass
    static fields to reflect the new class names.
  • not changing the static long serialVersionUID field name.
  • not changing the names of critical EJB methods such as create(*) and ejbCreate(*).
 
Tools | Obfuscate