Input & Output
input defines the path where the target artifact can be found, while
output declares where the obfuscated output will be emitted.
These paths are either relative to the location of the configuration file or absolute, depending on if the class starts with an absolute base path (e.g.
/ on sane operating systems, or a drive letter Ã la
C:/ on Windows).
input: path/to/application.jar output: obfuscated-application.jar
There are two ways to define libraries with Paramorphism:
libraries is a simple list of JAR files (or directories of JAR files), whereas
maven_libraries is a specification of maven-like structures to use. The most common use of
maven_libraries is the .m2 directory in the user's home.
libraries, simply list the JAR files and/or directories that you wish to include. Just like
output, these paths are relative to the location of the configuration file.
libraries: - my_library-1.0.jar - libs/google/guava.jar - libs/eclipse/ # All JAR files inside the libs/eclipse/ directory
maven_libraries, you need to declare a base directories mapped to a list of artifact specifiers. Base directories are also relative to the configuration file.
HTTPS support is planned for maven base directories in future.
maven_libraries: /home/myself/.m2/: - "com.google.code.gson:gson:2.8.5" - "io.netty:netty-all:4.1.0.Final" path/to/another/maven: - "com.example:proprietary-library:1.0.0"
In order for the remapper to function correctly, all libraries upon which the application depends need to be declared in the configuration file.
An element mask defines which elements are to be included and excluded in an obfuscation pass. The global mask is defined by the
mask entry in the configuration file, and controls which classes any obfuscation strategy can touch.
Element masking has two concepts, including and excluding. By default, all elements are included. If any elements are defined in the mask's
include list, then only matching elements are included. Then, any elements matching the
exclude list are also excluded.
An example of a use of exclusion masks is when there are classes which are subject to heavy reflection, for instance, field name introspection when using Java serializables or something like Gson.
mask: include: - com/example/myproject/ - org/business/proprietarylibrary/ exclude: - com/example/myproject/beans/serializable/ - com/example/myproject/config/ConfigurationJSONBean
exclude are lists of matching rules. This is a simple concept:
- If the rule ends with
/, it will match anything starting with the rule. For instance, the rule
path/rule/two, but not
- If the rule ends with
*, it will act as a wildcard. For instance, the rule
wildcard/ruletwothreefour/five, but not
- Otherwise, the rule matches anything identical to itself.
Flags are simple boolean toggles to change obfuscation behaviour.
Currently, Paramorphism has the following flags implemented:
The 'corruption' flag instructs the obfuscator to emit a JAR file that is technically invalid, but executes anyway due to Java's lenient JAR parsing.
With this flag, most analysis tools are rendered non-functional, with the exception of those custom-made for Paramorphism obfuscation.
The 'anti_decompression' flag tries to ensure that individual classes cannot be pulled out of the JAR file for analysis.
The 'kotlin' flag instructs the obfuscator to enable specific obfuscation strategies for the Kotlin programming language. For example, a Kotlin-specific strategy might strip out debugging information that is unique to the Kotlin compiler.
Presently, use of the
kotlin flag can corrupt behaviour in programs that make use of the
kotlin-reflect library. (Please note that regular Java reflection is unaffected by the flag.)
Individual strategies can be configured in Paramorphism.
All strategies have at least two configurable properties:
enabled determines whether the obfuscation strategy will be used in the obfuscation of the target program, and is a boolean. The default value of
enabled is true for all obfuscation strategies, but some obfuscation strategies are gated by configuration flags.
mask is a local specific mask that defines which classes the obfuscation strategy will be applied to. Please note that exclusions from the global mask cannot be overridden by an inclusion from a local mask.
Using the strategy 'Field Access Indirection' as an example, we set 'enabled' to true, and disable the strategy for a performance-critical class:
field_access_indirection: enabled: true # Here for demonstration purposes; but true is the default mask: exclude: - com/example/project/ASuperPerformanceCriticalClass
The following are the currently-existing strategies in Paramorphism:
As more strategies are implemented, it is likely that some will develop their own specific configurable parameters.
The name generator is used throughout the obfuscator, but its most obvious use is in the remapper. The name generator operates on four types of elements: Packages, classes, fields, and methods.
There are three different name generation facets: Dictionaries, prefixes, and suffixes.
A facet can be configured to act upon any of the element types like so:
name_generation: [facet]: all: ... packages: ... classes: ... # fields: ... # Since fields is omitted, its value defaults to the value of 'all' methods: ...
There are currently four different dictionaries in Paramorphism:
name_generation: dictionaries: all: alphabet classes: enterprise
Prefixes are a constant string applied to the start of every generated name:
name_generation: prefixes: classes: MyProjectClass
Suffixes are a constant string applied to the end of every generated name:
name_generation: suffixes: fields: ""
In addition, the name generator can take an 'inflation' parameter. This generates a number of random extra name segments depending on the inflation value. For instance, the name 'a' with inflation 0 could be generated as 'fdgjia' with inflation 5.