Task documentation
Preamble
Using the yGuard
Ant task, name obfuscation and code shrinking can be seamlessly integrated into your deployment process.
The yguard
task contains two nested elements that perform the name obfuscation and code shrinking separately:
- The rename element performs name-obfuscation, renaming all packages, classes, methods and fields according to a selectable name-mapping scheme. Elements can be excluded from the renaming process by annotating them with a certain annotation class in the source code or using a nested keep element.
- The shrink element removes all code elements that are not reachable from the entrypoints given in the nested keep element.
Table of contents
yguard
element- Controlling obfuscation exclusion with annotations
- Generating patch JARs
- Deobfuscating stacktraces
- DTD used for Ant
<yguard>
The yguard Element
The yguard
task is a container element for the rename
and shrink
task elements as well as configuration elements that are common to rename
and shrink
.
Being a container element only, the yguard
task does not perform any actions on its own, but needs a rename
and/or shrink
child element for name obfuscating and/or code shrinking.
Please see the troubleshooting section to learn about common pitfalls when using name obfuscation and shrinking software.
Attributes
The yguard
element has no attributes.
Child Elements
The inoutpair
Element
At least one inoutpair
element or one non-empty inoutpairs
element has to be specified in order to run the yguard
tasks. This element specifies the paths to the input and output jar files.
Note that only regular jar files are supported. Enterprise archives (ear) or web archives (war) are not supported. Moreover, jar files with non-standard directory structures (like e.g. Spring boot archives that store application classes in a BOOT_INF directory) are not supported either.
Attributes
Attribute | Description | Required |
---|---|---|
in |
Specifies an exisiting jar file, which contains the unshrinked and unobfuscated .class files. | Yes |
out |
Specifies a path to a jar file which will be created and used to put the results of the shrinking and obfuscation process. | Yes |
resources |
Will only be considered if the
yguard element
contains a nested
shrink element.
Determines how the shrinking engine handles all non-.class files. Currently the following three resource policies are supported:
|
No, defaults to copy .
|
Child Elements
The inoutpair
element has no child elements.
If multiple jar files need to be obfuscated at once the inoutpairs
element can be used instead.
The inoutpairs
Elements
Additionally or alternatively to inoutpair
elements this element can be specified in order to specify the paths to the input and output jar files.
Note that only regular jar files are supported. Enterprise archives (ear) or web archives (war) are not supported. Moreover, jar files with non-standard directory structures (like e.g. Spring boot archives that store application classes in a BOOT_INF directory) are not supported either.
Attributes
Attribute | Description | Required |
---|---|---|
resources |
Will only be considered if the
yguard element
contains a nested
shrink element.
Determines how the shrinking engine handles all non-.class files. Currently the following three resource policies are supported:
|
No, defaults to copy .
|
Child Elements
- patternset
- optionally a mapper that determines the name mapping between the unobfuscated and obfuscated versions of the jar files. Note that
identitymapper
andmergemapper
are not supported. All matched jar file names need to be mapped to exactly one jar file name that differs from the original jar file.
Examples
<!-- use all jars in the input-lib-dir directory and obfuscate them to *_obf.jar -->
<inoutpairs resources="auto">
<fileset dir="${input-lib-dir}">
<include name="myapp*.jar"/>
<exclude name="*_obf.jar"/>
</fileset>
<mapper type="glob" from="*.jar" to="*_obf.jar"/>
</inoutpairs>
<!-- the above mapper is the default one so the following snippet does the same -->
<inoutpairs resources="auto">
<fileset dir="${input-lib-dir}">
<include name="myapp*.jar"/>
<exclude name="*_obf.jar"/>
</fileset>
</inoutpairs>
The externalclasses
Element
If the jar to be processed by yGuard
depends on external classes or libraries, this element can be used to specify classpaths to these entities. These libraries will neither be shrinked nor obfuscated. Use the inoutpair
element for this purpose! See the external_library
example for an example of when to use this element.
In order to achieve a maximum shrinking effect by the shrink
task, all external dependencies should be declared in the externalclasses
element. Otherwise, all non-private methods of classes that inherit from unresolvable classes will not be shrinked.
The elements attributes and child elements can be seen on the Ant documentation page about using path elements.
The attribute Element
Using the attribute
element, you can specify which attributes present in the input classes should be kept in the obfuscated output classes.
See the linked_example
for an example of when to use this element.
Attributes
Attribute | Description | Required |
---|---|---|
name |
A comma-separated list of attribute names that are to be retained in the shrinked and/or obfuscated class files. | Yes |
Child Elements
Example
<attribute name="SourceFile, LineNumberTable, LocalVariableTable">
<patternset>
<include name="com.mycompany.mylibrary.**"/>
</patternset>
</attribute>
This will retain the attributes named "SourceFile", "LineNumberTable", and "LocalVariableTable" effectively enabling debugging information for all classes in the com.mycompany.mylibrary
package and subpackages.
The shrink
Element
The shrink
task removes all classes, fields and methods that are not reachable from a number of entrypoints given by a nested keep element.
See the examples explanation of some common use cases. If your code uses reflection, please read the troubleshooting section for information on this topic.
Attributes
Attribute | Description | Required |
---|---|---|
logfile |
Determines the name of the logfile that is generated
during the shrinking process. The logfile contains information about
the entrypoints the shrinking engine uses, the removed classes,
methods and fields as well as any warnings.
If the name ends with a ".gz", yGuard will automatically create a gzipped version of the file which potentially saves a lot of disc space. |
No, defaults toyshrinklog.xml
|
createStubs
|
Instead of removing methods completely, this attribute causes the
shrink task to insert a method
stub that throws a java.lang.InternalError if it is
called. This attribute is very useful if the shrinking process
causes your application to break and you are uncertain about which
additional code entities you have to include in the
keep element. Note that classes considered as completely obsolete by the shrinking engine are still removed completely - this attribute only affects obsolete methods of non-obsolete classes. |
No, defaults to false
|
Child Elements
The entrypointjar
Element
The entrypointjar
element can be used for convenience if your application uses libraries that are to be shrinked, but the jarfile using these libraries should be left untouched by the shrinking engine. Such a jarfile could be specified as an entrypointjar
.
Attributes
Attribute | Description | Required |
---|---|---|
name |
Path to to the jar file to use as entrypointjar. | Yes |
Child Elements
The entrypointjar
element has no child elements.
Example
<yguard>
<inoutpair in="lib-in.jar" out="lib-out.jar" />
<shrink>
<entrypointjar name="myApp.jar"/>
</shrink>
</yguard>
The rename
Element
The basic idea is, that all elements will be renamed by this task. There are different use cases, where you sometimes want to exclude or simply just have to exclude some elements from name obfuscation, i.e. not rename them but keep in the API as is. See the examples for explanation of some common use cases. If your code uses reflection, please read the troubleshooting section for information on this topic. Excluding elements can be achieved by using the keep element, the mainclass
attribute of the rename
element and by annotating elements in the source code with the annotation that is specified in the annotationClass
attribute of the rename
element. Using the nested keep
element, you have to specify all classes, methods, fields, and attributes that should be excluded from name obfuscation. Another way is to annotate the elements directly in the source code that should be obfuscated or excluded. You can use the yFiles obfuscation annotation com.yworks.util.annotation.Obfuscation
for that or specify your own annotation in the annotationClass
attribute of this element.
Child Elements
The property Element
property
elements can be used to give hints to the name obfuscation engine. Depending on the exact version of yGuard, the task may use these hints to control the process of obfuscation.
Attributes
Attribute | Description | Required |
---|---|---|
name |
Specifies a key which may be interpreted by the obfuscation task. | Yes |
value |
Specifies the corresponding value of the property. | Yes |
Supported properties
Name | Description | Default |
---|---|---|
error-checking |
Can be used to tell yGuard to bail out if it detects any problems.
Currently this property can be set to the following value:
|
false |
naming-scheme |
Can be used to tell the renaming engine to use a different naming
scheme during the obfuscation.
Currently this property can be set to one of the following values:
|
small |
language-conformity |
Can be used to advise the renaming engine to produce names, that
should be decompilable by most decompilers. On the other hand,
yGuard can produce class files that should be executable and
verifiable by all of todays virtual machines, but produces
absolutely nonsense names when decompiled (Ever tried to compile
'int class = false.this super(String$super.init if); '
?!)
Currently this property can be set to one of the following values:
|
legal |
overload-enabled |
Determines whether the renaming engine tries to use the same names
for methods with different signatures or whether it always generates
unique method names.
Setting this property to false eases the analysis of
stacktraces but reduces the obfuscation effect.
|
true |
obfuscation-prefix |
Can be used to instruct the renaming engine to prefix packages, that
are fully obfuscated with a given package prefix, e.g.
com.mycompany.obf .
|
- |
digests |
Can be used to tell yGuard which digest algorithms should be used
for the digest generation in the manifest file. Valid values are
either none , or a comma-separated
list of digest-algorithm identifiers, e.g.
SHA-1, MD5 (which is the default).
|
SHA-1, MD5 |
expose-attributes |
Can be used to give yGuard a list of attributes yGuard should expose
in addition to the standard attributes.
By default yGuard removes unneeded attributes like "Deprecated" from
methods. The value can be a comma separated list of attributes as
defined in
Section 4.7 of the VM Specification of the .class File Format.
E.g. in order to keep the "Deprecated" attribute one can add the
following property:
<property name="expose-attributes" value="Deprecated"/>
Note that this affects all classes which will be obfuscated. For a better control of which attributes should be exposed in what classes use the Attribute Element. |
- |
Child Elements
The property
element has no child elements.
The keep
Element
This element is a child of the rename or shrink element. It can be used to specify elements that are excluded from the parent rename
or shrink
task. The excluded classes, methods and fields are defined using nested package, class, method and field elements.
Attributes
The keep
element provides a number of boolean attributes that determine whether debug information and annotations present in the input class files are to be retained in the output files. The default behavior of the rename
and shrink
elements for the respective attributes is explained in the table below.
Note that a more fine-grained control over which attributes to keep for which class files is possible using the attribute element. Also, the attribute
element allows to define attributes to keep for both the rename and the shrink element in a common place.
Attribute | Description | Default (rename ) |
Default (shrink ) |
---|---|---|---|
sourcefile |
Determines whether the name of the original source code file should be included in the output class files. | remove |
remove |
linenumbertable |
Determines whether the line number table, that contains a mapping from each opcode in the class file to the line number in the original source code file should be included in the output class files. | remove |
remove |
localvariabletable |
Determines whether the local variable table, that contains a mapping from each local variable in the class file to the name that has been used in the original source code file should be included in the output class files. | remove |
remove |
localvariabletypetable |
Determines whether the local variable type table, that contains a mapping from each local variable in the class file to the name and its generic type signature that has been used in the original source code file should be included in the output class files. | remove |
remove |
runtimevisibleannotations |
Determines whether annotations with the retention policy
RetentionPolicy.RUNTIME should be included in the output
class files.
|
keep1 |
keep |
runtimevisibleparameterannotations |
Determines whether method paramater annotations with the retention
policy RetentionPolicy.RUNTIME should be included in
the output class files.
|
keep1 |
keep |
runtimevisibletypeannotations |
Determines whether type annotations with the retention
policy RetentionPolicy.RUNTIME should be included in
the output class files.
|
keep1 |
keep |
runtimeinvisibleannotations |
Determines whether annotations with the retention policy
RetentionPolicy.CLASS should be included in the output
class files.
|
keep1 |
remove |
runtimeinvisibleparameterannotations |
Determines whether method paramater annotations with the retention
policy RetentionPolicy.CLASS should be included in the
output class files.
|
keep1 |
remove |
runtimeinvisibletypeannotations |
Determines whether type annotations with the retention
policy RetentionPolicy.CLASS should be included in the
output class files.
|
keep1 |
remove |
1 rename
always keeps annotations irrespective of its
runtime*annotations
attribute values.
The class
Element
The class
element can be used for excluding certain classes and/or their fields and methods from the renaming or shrinking process.
If no name
, extends
or implements
attribute is given and the class
element contains no nested patternset
, a class
element matches all class names.
The classes
, methods
and fields
attributes tell the shrinking and renaming engines which classes, methods and fields to keep based on their visibility. The following table lists the possible values for all of these attributes and shows which elements will be excluded. A '*' denotes, that elements that have the given visibility will be excluded for the specified attribute value. A '-' denotes that the these elements will not be excluded from the process.
Value/Visibility | public |
protected |
friendly |
private |
none |
- | - | - | - |
public |
* | - | - | - |
protected |
* | * | - | - |
friendly |
* | * | * | - |
private |
* | * | * | * |
Attributes
Attribute | Description | Required |
---|---|---|
name |
The name of the class to be kept. | No |
classes |
The visibility of the classes to be kept. |
No, defaults to none |
methods |
The visibility of the methods to be kept. |
No, defaults to none |
fields |
The visibility of the fields to be kept. |
No, defaults to none |
extends |
If no name attribute is given, keeps
all classes that equal or extend the class defined by the given
fully qualified classname.
See serializable_example for an example usage of this attribute. |
No |
implements |
If no name attribute is given, keeps
all classes that equal or implement the class defined by the given
fully qualified classname.
See serializable_example for an example usage of this attribute. |
No |
Child elements
Explanation
There are three possible ways of specifying which classes will be excluded from the shrinking and obfuscation process:
1) One can specify a single java class using the fully qualified name in java syntax with the name attribute. For example:
<class name="mypackage.MyClass"/>
2) One can specify multiple java classes using a modified version of a patternset. The patternset's includes and excludes element should use java syntax, but the usual wildcards are allowed. Some examples:
<class>
<patternset>
<include name="com.mycompany.**.*Bean"/>
<exclude name="com.mycompany.secretpackage.*"/>
<exclude name="com.mycompany.myapp.SecretBean"/>
</patternset>
</class>
3) This will expose all classes which reside in the package subtree of com.mycompany
and whose name ends with Bean
except for those, that reside in the com.mycompany.secretpackage
package and the single SecretBean
in com.mycompany.myapp
.
<class>
<patternset>
<include name="com.mycompany.myapp.MainClass"/>
<include name="org.w3c.sax?."/>
<exclude name="org.w3c.sax?.**.*$$*"/>
</patternset>
</class>
This will expose the MainClass
class and all classes, which reside in packages like org.w3c.sax1
, org.w3c.sax2
, org.w3c.saxb
except for inner classes. '$'
is used as a separator between outer class names and inner class names. Since Ant uses '$'
as an escape character, you have to use two consecutive '$'s
('$$'
) if you want to pass one as an argument to the task.
4) Finally one can specify classes depending on their visibility, i.e. depending whether they have been declared public
, protected
, package-private
or private
(inner classes). This can be achieved by additionally specifying the classes attribute in the class element.
<class classes="protected">
<patternset>
<include name="com.mycompany.myapi."/>
</patternset>
</class>
This will keep all class names, that are either public
or protected
and which reside in one of the subpackages of com.mycompany.myapi
(note the abbreviation: the trailing dot behaves like the trailing '/'
in the usual patternset, i.e. it could be rewritten as com.mycompany.myapi.**.*
)
<class classes="protected"
methods="protected"
fields="protected">
<patternset>
<include name="**.*"/>
</patternset>
</class>
This example shows the very common use case of excluding a complete public API from the shrinking and obfuscation process. There is an abbreviation for this use case: you can omit the patternset
element, since in the case where the classes
attribute is specified and there is no patternset
child element used, the task will automatically apply this rule. In this example all classes will be exposed, that are either public
or protected
. Their methods and fields will be exposed as long as they are declared public
or protected
. If a class is package-private
or private
(inner classes), neither itself nor its methods or fields will be exposed.
The last example shows how to keep the public
methods of certain classes only, but neither field names nor the class names themselves.
<class classes="none" methods="public" fields="none">
<patternset>
<include name="com.mycompany.myapi."/>
</patternset>
</class>
The method
Element
Using the method
element you can specify methods by signature which should be excluded from shrinking or name obfuscation.
Attributes
Attribute | Description | Required |
---|---|---|
name |
Specifies the method to keep. Use the complete signature using fully qualified class names and the return type! | Yes |
class |
Specifies the class which contains the method. Use the normal java syntax, i.e. the fully qualified name. This attribute can be omitted, if the patternset element is used as a child element, in which case all classes matching the patternset will be searched and their corresponding methods will be kept. | No |
Child Elements
Examples
<method class="com.mycompany.myapp.MyClass"
name="void main(java.lang.String[])"/>
<method class="com.mycompany.myapp.MyClass"
name="int foo(double[][], java.lang.Object)"/>
<method name="void writeObject(java.io.ObjectOutputStream)">
<patternset>
<include name="com.mycompany.myapp.data.*"/>
</patternset>
</method>
<method name="void readObject(java.io.ObjectInputStream)">
<patternset>
<include name="com.mycompany.myapp.data.*"/>
</patternset>
</method>
This will keep the main method of the MyClass
class and the foo
method. Additionally all readObject
and writeObject
methods (used for serialization) will be kept in all classes of the com.mycompany.myapp.data
package. Note that you have to specify the return argument's type, even if it is void and that you have to use the fully qualified name for all classes, even those, that are in the java.lang package
.
The field
Element
Using the field
element you can specify fields by name which should be excluded from shrinking or name obfuscation.
Attributes
Attribute | Description | Required |
---|---|---|
name |
Specifies the field to keep. Use the name of the field only, do not include its type! | Yes |
class |
Specifies the class which contains the field.
Use the normal java syntax, i.e. the fully qualified name.
This attribute can be omitted, if the
patternset element is used as
a child element, in which case the all classes matching the
patternset will be searched and their corresponding fields will be
kept.
|
No |
Child Elements
Examples
<field class="com.mycompany.myapp.MyClass" name="field"/>
<field name="serialVersionUID">
<patternset>
<include name="com.mycompany.myapp.data.*"/>
</patternset>
</field>
This will keep the field named field
of the MyClass
class. Additionally all the serialVersionUID
fields (used for serialization) will be kept in all classes of the com.mycompany.myapp.data
package.
The package
Element
The package
element can be used for excluding certain package's names from the renaming process. It cannot be used for the shrinking process.
All packages that are matched be the nested patternset element will not be obfuscated. This has no influence on the class, method, or field names but will only result in the package's name not being obfuscated. Normally, it is not necessary to use this element, instead the class element is used to keep class names (and thus their package names) from being obfuscated.
Child Elements
Example
<package>
<patternset>
<include name="com.mycompany.myapp.*"/>
</patternset>
</package>
This will keep the names of all packages that are direct descendants of com.mycompany.myapp
. This will not influence the names of the classes contained in these packages.
The sourcefile
Element
The sourcefile
element allows for a special treatment of the sourceFile attribute by the rename element.
Using nested property elements, the mapping of sourceFile attributes in obfuscated class files can be adjusted.
Attributes
Name | Description |
---|---|
mapping |
The value of this property determines the name all
sourceFile attributes matched by the
sourcefile element are mapped to.
|
Child Elements
Example
<sourcefile>
<property name="mapping" value="y"/>
<patternset>
<include name="com.mycompany.myapp.**"/>
</patternset>
</sourcefile>
This will map all of the sourceFile
attributes in the packages below com.mycompany.myapp
to "y", which is small and generally a nice letter.
The linenumbertable
Element
The linenumbertable
element allows for a special treatment of the linenumbertable attribute by the rename element.
Using nested property
elements, the mapping of linenumbertable
attributes in obfuscated class files can be adjusted.
Attributes
Name | Description |
---|---|
mapping-scheme |
Can be used with the following two values:
|
scrambling-salt |
Can be used in conjunction with
mapping-scheme to provide an integer
value that will be used to "salt" the algorithm's random seed for
the scrambling.
|
Child Elements
Examples
<linenumbertable>
<patternset>
<include name="com.mycompany.myapp.**"/>
</patternset>
</linenumbertable>
This will keep the line numbers of all the classes in the com.mycompany.myapp
packages and subpackages. Note that in order to see the line numbers in stacktraces, the sourcefile attribute has to be retained for those files, too, since otherwise the JDK will display "Unknown source" for the stack elements.
<linenumbertable>
<property name="mapping-scheme" value="scramble"/>
<property name="scrambling-salt" value="1234"/>
<patternset id="CompanyPatternSet">
<include name="com.mycompany.myapp.**"/>
</patternset>
</linenumbertable>
<sourcefile>
<property name="mapping" value="y"/>
<patternset refid="CompanyPatternSet"/>
</sourcefile>
This will keep scrambled line numbers for all classes found in and below the com.mycompany.myapp
packages. The scrambling algorithm will use the given "salt" value to use a predefined scrambling scheme. In order to see the scrambled line numbers, a sourcefile element is used on the same patternset, which is referenced by its previously declared reference id, to rename the source files to "y".
The adjust
Element
Using the adjust
element one can specify resource files whose names and/or contents should be adjusted by the rename engine to reflect the obfuscated class names.
Note: This will only adjust files that are part of the inoutpair jars! I.e. the fileset's root directory is the combined root of all jars that are passed to yGuard via the inoutpair
elements. yGuard will not modify any of the files on disk, except for the out-jar!
Attributes
Attribute | Description | Required |
---|---|---|
replaceContentPolicy |
Specifies if and how the content of resource files should be adjusted. See replaceContentPolicy for supported values. | No, defaults to none
|
replaceContent |
Deprecated - use replaceContentPolicy instead.Specifies whether or not the contents of resource files should be adjusted. |
No, defaults to false
|
replaceContentSeparator |
Specifies which separator is used to replace text in content.
Supports . , / , and ./ .
|
No, defaults to /
|
replacePathPolicy |
Specifies if and how the file names of resource files should be adjusted. See replacePathPolicy for supported values. | No, defaults to path
|
replacePath |
Deprecated - use replacePathPolicy instead.Specifies whether or not the paths to the resource files should be adjusted. |
No, defaults to true |
replaceName |
Deprecated - use replacePathPolicy instead.Specifies whether or not the names of the specified resources should be adjusted. |
No, defaults to false
|
The replaceContentPolicy Attribute
Specifies if and how the content of resource files should be adjusted. Supported values are:
none
-
The content of resource files is not adjusted.
lenient
-
Text that is recognized as qualifed class or package name is replaced.
This policy matches the yGuard 3.x behavior for
replaceContent="true"
strict
-
Text that is recognized as qualifed class name is replaced.
This policy matches the yGuard 2.x behavior for
replaceContent="true"
The replacePathPolicy Attribute
Specifies if and how the file names of resource files should be adjusted. Supported values are:
none
-
The paths to and names of resource files are not adjusted.
The names of service provider configuration files are not adjusted.
This policy matches the yGuard 3.x behavior for
replaceName="false" replacePath="false"
path
-
The paths to resource files are adjusted, if they match the package name of a renamed package. The names of resource files are not adjusted.
The names of service provider configuration files are not adjusted.
This policy matches the yGuard 3.x behavior for
replaceName="false" replacePath="true"
name
-
The paths to resource files are not adjusted. The names of resource files are adjusted, if the path to and the name of the resource file match the qualified name of a renamed class.
The names of service provider configuration files are adjusted, if the name of the configuration file matches the qualified name of a renamed class.
This policy matches the yGuard 3.x behavior for
replaceName="true" replacePath="false"
file
-
The paths to and names of resource files are adjusted, if they match the qualified name of a renamed class.
The names of service provider configuration files are adjusted, if the name of the configuration file matches the qualified name of a renamed class.
This policy matches the yGuard 3.x behavior for
replaceName="true" replacePath="true"
fileorpath
-
Combines policies
file
andpath
.
I.e. if the path to and name of a resource file match the qualified name of a renamed class, both path and name are adjusted accordingly. If the path and name do not match the qualified name of a renamed class, but the path matches the package name of a renamed package, the path is adjusted accordingly. If the path does not match the package name of a renamed package, but path fragments match the package name of a renamed package, those path fragments are adjusted accordingly.
The names of service provider configuration files are adjusted, if the name of the configuration file matches the qualified name of a renamed class. lenient
-
Tries to adjust as much of the paths to and names of resource and service provider configuration files as possible.
For paths to and names of resource files, this policy is the same asfileorpath
.
The names of service provider configuration files are adjusted, if the name of the configuration file matches the qualified name of a renamed class. If the name does not match the qualified name of a renamed class, but name fragments match the package name of a renamed package, those name fragments are adjusted accordingly.
Explanation
Suppose yGuard's input set consists of the following files
com/mycompany/myproduct/MyClass.class
com/mycompany/myproduct/MyClass.properties
com/mycompany/myproduct/SomeResource.txt
com/mycompany/shared/SharedResource.txt
META-INF/services/com.mycompany.myproduct.MyClass
META-INF/services/com.mycompany.shared.SharedService
and rename
changes the name of class
com.mycompany.myproduct.MyClass
to
A.A.A.A
.
In this case, the individual replacePathPolicy
polices will result
in the following path and name adjustments:
path
-
A/A/A/MyClass.properties A/A/A/SomeResource.txt A/A/shared/SharedResource.txt META-INF/services/com.mycompany.myproduct.MyClass META-INF/services/com.mycompany.shared.SharedService
The path
com/mycompany/shared
does not match any package name, but its path fragmentscom/mycompany
match the package namecom.mycompany
and thus are changed.
The two service provider configuration files are not adjusted. name
-
com/mycompany/myproduct/A.properties com/mycompany/myproduct/SomeResource.txt com/mycompany/shared/SharedResource.txt META-INF/services/A.A.A.A META-INF/services/com.mycompany.shared.SharedService
The path to and name of the second and third resource files do not match any qualified class name in the code base and thus are not changed.
The namecom.mycompany.shared.SharedService
does not match any qualified class name and thus is not changed. file
-
A/A/A/A.properties com/mycompany/myproduct/SomeResource.txt com/mycompany/shared/SharedResource.txt META-INF/services/A.A.A.A META-INF/services/com.mycompany.shared.SharedService
The path to and name of the second and third resource files do not match any qualified class name in the code base and thus are not changed.
The namecom.mycompany.shared.SharedService
does not match any qualified class name and thus is not changed. fileorpath
-
A/A/A/A.properties A/A/A/SomeResource.txt A/A/shared/SharedResource.txt META-INF/services/A.A.A.A META-INF/services/com.mycompany.shared.SharedService
The path
com/mycompany/shared
does not match any package name, but its path fragmentscom/mycompany
match the package namecom.mycompany
and thus are changed.
The namecom.mycompany.shared.SharedService
does not match any qualified class name and thus is not changed. lenient
-
A/A/A/A.properties A/A/A/SomeResource.txt A/A/shared/SharedResource.txt META-INF/services/A.A.A.A META-INF/services/A.A.shared.SharedService
The path
com/mycompany/shared
does not match any package name, but its path fragmentscom/mycompany
match the package namecom.mycompany
and thus are changed.
The namecom.mycompany.shared.SharedService
does not match any qualified class name, but its name fragmentscom.mycompany
match the package namecom.mycompany
and thus are changed.
Child Elements
The adjust
element can be used just like the standard Ant ZipFileSet
element.
Examples
<!-- adjust the names of all java property files in the jars -->
<adjust replacePathPolicy="file">
<include name="**/*.properties"/>
</adjust>
<!-- adjust the classnames specified within a single XML file in the jar -->
<adjust file="plugins.xml" replaceContentPolicy="strict" replaceContentSeparator="."/>
<!-- suppress the adjustment of the resource path com/mycompany/myapp/resource in the jar. -->
<!-- the package com.mycompany.myapp still gets obfuscated. -->
<adjust replacePathPolicy="none">
<include name="com/mycompany/myapp/resource/*"/>
</adjust>
The map
Element
The map
element is an immediate optional child of the rename element. It can be used to specify the mapping for the renaming process directly. This is an advanced topic.
Child Elements
All of these elements use the name
attribute to specify the specific element. The method
and field
elements need the class
attribute in order to function properly. Neither wildcards nor nested patternset
elements are allowed. Use the map
attribute to specify the new name (subpackage, classname, methodname and fieldname respectively).
Examples
<map>
<package name="com" map="etc"/>
<package name="com.mycompany" map="nocompany"/>
<package name="com.mycompany.myapp" map="asdf"/>
<class name="com.mycompany.myapp.MainApp" map="foo"/>
<method class="com.mycompany.myapp.MainApp"
name="void main(java.lang.String[])" map="bar"/>
<field class="com.mycompany.myapp.MainApp" name="field" map="a"/>
</map>
In this example the package structure com.mycompany.myapp
will be obfuscated to etc.nocompany.asdf
. The MainApp
class will be called foo
and its main
method will be remapped to bar
(and can therefor not be executed from commandline anymore). The field called field
will be renamed to a
.
Controlling obfuscation exclusion with annotations
In order to exclude certain elements from obfuscation, it is possible to use annotations in the source code instead of listing those elements in the keep element.
Any annotation class can be used for this, but it must be specified in the annotationClass
attribute of the rename element and follow the convention as explained below to work. yGuard contains such an annotation in the distribution package ready for use. The annotation class is com.yworks.util.annotation.Obfuscation
and can be found in the yGuard distribution in ObfuscationAnnotation.jar
. Feel free add this attribute definition to your own codebase and possibly adjust the package name to your needs. Here is the source code for it:
Obfuscation.java
package com.yworks.util.annotation;
public @interface Obfuscation {
boolean exclude() default true;
boolean applyToMembers() default true;
}
This class is also the default annotation yGuard is looking for when obfuscating. By default the Obfuscation
annotation is inherited using the @Inherited
trait. If this behaviour is undesirable, consider creating a custom obfuscation annotation.
The convention for annotation classes that yGuard understands as obfuscation controlling annotations requires two attributes:
Attribute | Description | Default value |
---|---|---|
exclude |
Specifies whether the annotated element should be excluded from the obfuscation. Note, that when retaining a class, the hierarchy of that class, i.e. the chain of outer class names and the package name, is also retained. | true |
applyToMembers |
Specifies whether the child elements of the annotated element, if
not otherwise specified, should be excluded from the obfuscation.
For example, when annotating a class with
exclude = true and this attribute set to
true , inner classes, fields and methods of this
class will be excluded from obfuscation. Annotating a child element
of an element that has this attribute set to true will
override the parents annotation configuration.
|
true |
Generating Patch JARs
The true power of the map
element lies in its use together with the patch
element, which itself is a child element of the rename
top level element.
Attributes
The patch
element has no attributes.
Child Elements
Examples
Using the patch
element one can generate jars, that can be used to serve as patches for versions of an application that have already been deployed in obfuscated form. During the main obfuscation run, yGuard produces an xml-logfile, in which the mapping between the unobfuscated and obfuscated names is contained. The patch element is used to declare a set of classes, that need to be patched. During the obfuscation, yGuard will include those files in the obfuscated jars only, that are declared inside this element.
<patch>
<class name="com.mycompany.myapp.MainClass"/>
<class>
<patternset>
<include name="com.mycompany.myapp.bugs.*"/>
</patternset>
</class>
</patch>
<map logfile="yguardlog.xml"/>
This will only include the MainClass class and all classes that belong to the bugs package in a patch jar. In order to work with the previously delivered obfuscated version, it is important to use the map element to specify the mapping of the elements from the previous run. This can most conveniently be achieved by specifying the log file from the corresponding run in the map element's logfile attribute.
Deobfuscating stacktraces
yGuard provides a simple tool that makes it easy for the obfuscating party to deobfuscate stacktraces which have been obfuscated using yGuard. During the obfuscation yGuard produces an xml logfile which can automatically be gzipped for convenient storage. You should always keep those logfiles in order to be able to deobfuscate fully qualified classnames or methods or fields for debugging purposes e.g. In order to run the yGuard deobfuscation tool do the following:
Console> java -jar yguard.jar mylogfile.xml
A tiny GUI will popup that will enable you to easily deobfuscate stacktraces and fully qualified classnames as well as provide a convenient way to browse the mapping generated by yGuard. In the main window a tree view displays the package, class, and classmember hierarchy using the unobfuscated names. For each entry that has been obfuscated (classes, packages, methods, and fields that have not been obfuscated at all may not always be shown in the tree) the corresponding mapped/obfuscated name is displayed. The two buttons at the top of the window allow to change the sorting of the items in the tree structure, so that they are either sorted according to their names before or after the obfuscation. Items will always be sorted by type first: packages, classes, innerclasses, methods, and fields. Small icons provide a convenient way to quickly find the corresponding items.
The lower part of the window contains an editable text area that can be used to enter text or paste stacktraces in. Pressing the button at the bottom of the window labelled "Deobfuscate" will trigger the deobfuscation of the contents in the text area. The tool will try to identify fully qualified class names (separated by dots) and use the mapping information to reconstruct the original names. If the tool identifies a stack trace element, it will try to deobfuscate scrambled line numbers, too, if they have been scrambled during the obfuscation process.
DTD used for Ant <yguard>
The obfuscation and shrinking process can be completely configured inside your Ant script. The yguard task and nested elements should be used according to the following DTD. Note that this is for information purposes only, i.e. you do not have to include the following lines anywhere. This DTD should just provide a quick overview of the yGuard syntax. Due to restrictions of the DTD specification, the given DTD does not describe all available yGuard options. Please browse through the documentation above for complete documentation of the yGuard Ant task elements.
<!ELEMENT yguard (inoutpair+,externalclasses?,attribute*,(shrink|rename)+)>
<!ELEMENT inoutpair EMPTY>
<!ATTLIST inoutpair
in CDATA #REQUIRED
out CDATA #REQUIRED
resources CDATA #IMPLIED>
<!--
NOTE: the resources attribute only has an effect if a shrink element is present inside the yguard element.
-->
<!ELEMENT externalclasses ANY>
<!-- the externalclasses element is used just like Ant's classpath
element. See the Ant documentation for further details-->
<!ELEMENT attribute (patternset)*>
name CDATA #REQUIRED>
<!ELEMENT shrink (entrypointjar*,keep?)>
<!ATTLIST shrink
logfile CDATA #IMPLIED
createStubs CDATA #IMPLIED>
<!ELEMENT entrypointjar>
<!ATTLIST entrypointjar
name CDATA #REQUIRED>
<!ELEMENT rename (property*,patch?,adjust*,map?,keep?)>
<!ATTLIST rename
mainclass CDATA #IMPLIED
logfile CDATA #IMPLIED
conservemanifest CDATA #IMPLIED
replaceClassNameStrings CDATA #IMPLIED>
<!ELEMENT property EMPTY>
<!ATTLIST property
name CDATA #REQUIRED
value CDATA #REQUIRED>
<!ELEMENT patch (class)*>
<!ELEMENT adjust (#PCDATA)>
<!ATTLIST adjust
replaceName CDATA #REQUIRED
replaceContent CDATA #REQUIRED
replacePath CDATA #REQUIRED>
<!ELEMENT map (class|method|field|package)*>
<!ELEMENT package (patternset)*>
<!ATTLIST package
name CDATA #REQUIRED
map CDATA #REQUIRED>
<!--
NOTE: the map attribute is only supported
if the <package> element is nested inside a <map> element, whereas the patternset is
only supported inside the <keep>/<expose> sections.
-->
<!ELEMENT keep (package|class|method|field|sourcefile|linenumbertable)*>
<!--
NOTE: the nested <package>,<sourcefile>,<linenumbertable> and <attribute> sections are only
supported in the <rename> element.
-->
<!ATTLIST keep
linenumbertable CDATA #IMPLIED
localvariabletable CDATA #IMPLIED
localvariabletypetable CDATA #IMPLIED
runtimeinvisibleannotations CDATA #IMPLIED
runtimeinvisibletypeannotations CDATA #IMPLIED
runtimevisibleannotations CDATA #IMPLIED
runtimevisibletypeannotations CDATA #IMPLIED
sourcefile CDATA #IMPLIED>
<!ELEMENT class (patternset)*>
<!ATTLIST class
classes CDATA #IMPLIED
fields CDATA #IMPLIED
map CDATA #IMPLIED
methods CDATA #IMPLIED
name CDATA #IMPLIED>
<!--
NOTE: the map attribute is only supported
if the <class> element is nested inside an <rename> element.
-->
<!ELEMENT method (patternset)*>
<!ATTLIST method
class CDATA #IMPLIED
map CDATA #IMPLIED
name CDATA #IMPLIED>
<!--
NOTE: the map attribute is only supported
if the <method> element is nested inside an <rename> element.
-->
<!ELEMENT field (patternset)*>
<!ATTLIST field
class CDATA #IMPLIED
map CDATA #IMPLIED
name CDATA #IMPLIED>
<!--
NOTE: the field attribute is only supported
if the <method> element is nested inside an <rename> element.
-->
Attention users of IDEs that "support" the creation of Ant files (e.g. IDEA's IntelliJ): Your IDE may indicate some errors inside your ANT file when you use yGuard specific elements. This is because the IDE does not know about the DTD used by yGuard. However this is not a real problem, since the Ant file should nevertheless work as expected.