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 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(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 |
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.
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.
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 Sun, IBM, Symantec, Microsoft and Jikes 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" setting. You can use one without the other.
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.
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
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 |
| J2ME 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.
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 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.
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(*).
|
|