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.
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).
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.
If you select light, normal or aggressive 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% |
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% |
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 option 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.
NB: The previously supported extraAggressive option is now deprecated because of the presence JVM bugs.
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.
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 Obfuscate Control Flow option.
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.
Generally speaking, any in this section to an integer constant should be taken to mean a reference to a byte, char, short or int constant.
Reference types like Byte, Character, Short an Integer are not treated as integer constants.
When the "Encrypt Integer Constants" option is set to normal, Zelix KlassMaster will replace your integer constants
with encrypted equivalents and add instructions to your bytecode that will decrypt the integers at runtime.
Any integer fields which are directly initialized with a value other than -1, 0 or 1 will have their initialization values encrypted.
Also, if there is a reference in a method to an integer constant that is less than Short.MIN_VALUE and greater than Short.MAX_VALUE, then that integer value will be encrypted.
With the aggressive setting (as with the normal setting) any integer, byte, char or short fields which are directly initialized with a value other than -1, 0 or 1 will have their initialization values encrypted.
However, unlike the normal setting, if there is a reference in a method to an integer constant that is less than -1 and greater than 5, then that integer value will be encrypted.
To switch off Integer encryption, you should set the "Encrypt Integer Constants" option to none.
The advantage of integer constant encryption is that the Java source produced by a decompiler is much less comprehensible if the
integer constants are disguised. 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 integer constants in your application. It is recommended that you measure the impact on your classes.
Note that the integer constant encryption used by Zelix KlassMaster is not irreversible. Don't rely on it to protect highly sensitive data.
When the "Encrypt Long Constants" option is set to normal, Zelix KlassMaster will replace your long constants
with encrypted equivalents and add instructions to your bytecode that will decrypt the integers at runtime.
Any integer fields which are directly initialized with a value other than 0 or 1 will have their initialization values encrypted.
Also, if there is a reference in a method to an integer constant other than 0 or 1 then that long value will be encrypted.
To switch off Long Encryption, you should set the "Encrypt Long Constants" option to none.
The advantage of long constant encryption is that the Java source produced by a decompiler is much less comprehensible if the
long constants are disguised. 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 heavily on the number of long constants in your application. It is recommended that you measure the impact on your classes.
Note that the long constant encryption used by Zelix KlassMaster is not irreversible. Don't rely on it to protect highly sensitive data.
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.
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).
The specified 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
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 |
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.
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.
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".
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.
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 six 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
- the name of the method is not obfuscated and
- the names of the containing class and package are not obfuscated.
When you select "keepMethodParametersIfNotObfuscated" the method parameter variable names of all methods, regardless of their access modifiers, are retained only if
- the name of the method is not obfuscated and
- the names of the containing class and package are not obfuscated.
These last three 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.
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.
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 Reference Obfuscation Tutorial for more detail.
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.
If you select normal or random from this list then Zelix KlassMaster will add special additional parameters to some of your methods.
The random setting will make the type and position of the additional parameters more random with a possible, slight cost to runtime performance.
This is explained in the Method Parameter Changes Tutorial.
As is explained in the tutorial, this option is only relevant if you are also using
If you allow Zelix KlassMaster to add additional method parameters then it can make its "enhanced" String Encryption,
Integer Constant Encryption and Reference Obfuscation much more difficult to reverse.
The flowObfuscate setting is the same as the random setting but a special kind of Flow Obfuscation may be applied at a possible cost to runtime performance.
The disadvantage is that it interlinks your classes such that the obfuscated application must be released as a whole and will not be suitable for "patching" with changed subsets of the classes.
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.
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.
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(*) .
|