Obfuscation rules

Prev Next

Obfuscation for DEX bytecode

In a Shielding Tool rules file, every obfuscation option has an opposite option to disable obfuscation for the given class or member. These include the following:

Inclusive Option

Exclusive Option

Description

obfuscate

preserve

Select classes or members to obfuscate or exclude from obfuscation.

scrambleStrings

keepStrings

Select classes or members in which to scramble constant string values.

removeAnnotation

keepAnnotation

Select classes or members from which to remove annotations.

removeDebug

keepDebug

Select classes or members from which to remove debug information.

removeLines

keepLines

Select classes or members from which to remove line numbers.

removeSourceFile

keepSourceFile

Select classes from which to remove the source file name.

String scrambling

Using the keepStrings operation will ensure that a matching class, method, or field will not be affected by the string scrambling operation. Optionally, the scrambleStrings operation asks the Shielding Tool to scramble string values. If both bind and scrambleStrings are enabled for a class or method, some constants are used for push and pull binding, and the remaining constants are used for string scambling.

Examples

The following example removes debug information from all classes and members but then preserves debug information for the MyClass.debugMethod() method (with any parameters):

removeDebug *;
match com.example.MyClass {
    keepDebug debugMethod(...);
}

The following example obfuscates MyClass.myMethod(), does not obfuscate mySecondMethod(), but locally scrambles strings in mySecondMethod():

match com.example.MyClass {
    obfuscate myMethod();
    preserve mySecondMethod();
    scrambleStrings mySecondMethod();
}

The following example demonstrates three different ways that you can obfuscate a class name but none of the members:

# Obfuscate MyClass but do nothing to its members (i.e., empty body)
obfuscate com.example.MyClass { }

# Or obfuscate MyClass but explicitly preserve its members
obfuscate com.example.MyClass {
    preserve <members>;
}

# Or obfuscate everything but then preserve the members in MyClass
obfuscate *;
match com.example.MyClass {
    preserve <members>;
}

The following example demonstrates two different ways to preserve the class name and all members:

# Obfuscate everything
obfuscate *;

# But preserve the class name (and members)
preserve class com.example.MyClass;

preserve class com.example.MyClass {
    preserve <members>;
}

Excluding Framework JARs

Framework JAR files must be excluded from the obfuscation process. This can be done using a frameworkjar directive in the Shielding Tool rules file. The most important framework JAR to exclude is the Android SDK itself. Generally, pointing to the same version used in targetSdk is the recommended option. For example:

frameworkjar "/home/android/platforms/android-23/android.jar";

If no frameworkjar directives are provided, the Shielding Tool falls back to an internal framework file covering the current android.jar interface.

Built-in rules

The Shielding Tool comes with a few built-in rules files. These are enabled by using the include option with the builtin keyword. For example:

include "builtin:obfuscate-on.cfg";

The built-in obfuscate-on.cfg rules enable class name obfuscation for all classes, then loads another built-in rules file called default-unobfuscate.cfg that disables obfuscation for some well-known exceptions.

obfuscate-on.cfg essentially looks like the following rules file example:

# Obfuscate and remove debug info from all classes
obfuscate removeDebug removeLines removeSourceFile *;

# Then apply well-known exceptions
include "builtin:default-unobfuscate.cfg";

For reference, default-unobfuscate.cfg contains the following rules:

# The static Enum#values() method is generated on all Enums and accessed through reflection
# These methods should not be obfuscated
match enum * {
    preserve public static values();
    preserve public static valueOf(...);
}

# android.os.Parcelable
preserve class * implements android.os.Parcelable {
    public static field * CREATOR;
}

# No obfuscation on annotations
preserve interface * implements java.lang.annotation.Annotation;

# Kotlin
match class *$WhenMappings {
    preserve <fields>;
}

# android.arch lifecycle
match enum android.arch.lifecycle.Lifecycle$Event {
    preserve <fields>;
}

preserve class * implements android.arch.lifecycle.LifecycleObserver;
preserve class * implements android.arch.lifecycle.GeneratedAdapter;

match class * {
    preserve @android.arch.lifecycle.OnLifecycleEvent <members>;
}

# Preserve classes and method names when there are native methods
preserve class * {
    native *(...);
}

# Preserve annotated JavaScript interface methods
match class * {
    preserve @android.webkit.JavascriptInterface <methods>;
}

# Firebase
match com.google.firebase.iid.FirebaseInstanceId {
    Shieldpreserve com.google.firebase.iid.FirebaseInstanceId getInstance(...);
}

# Understand the @Keep support annotation
preserve interface android.support.annotation.Keep;
preserve interface androidx.annotation.Keep;

preserve @android.support.annotation.Keep class *;
preserve @androidx.annotation.Keep class *;

match class * {
    preserve @android.support.annotation.Keep <members>;
    preserve @androidx.annotation.Keep <members>;
}

# View onClick handlers
match class * {
    preserve public *(android.view.View);
}

# Temporary exclusion until processing of resources.asrc (strings.xml) is added
preserve android.support.design.widget.AppBarLayout$ScrollingViewBehavior {}
preserve com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior {}

preserve android.support.design.widget.BottomSheetBehavior {}
preserve com.google.android.material.bottomsheet.BottomSheetBehavior {}

preserve android.support.design.transformation.FabTransformationScrimBehavior {}
preserve com.google.android.material.transformation.FabTransformationScrimBehavior {}

preserve android.support.design.transformation.FabTransformationSheetBehavior {}
preserve com.google.android.material.transformation.FabTransformationSheetBehavior {}

preserve android.support.design.behavior.HideBottomViewOnScrollBehavior {}
preserve com.google.android.material.behavior.HideBottomViewOnScrollBehavior {}

# Dynamite (Google gms)
# enforceInterface() which specifically checks if classNames was changed
preserve com.google.android.gms.dynamite.* {}

match com.google.android.gms.dynamite.DynamiteModule$DynamiteLoaderClassLoader {
    preserve field sClassLoader;
}

# Google Maps plugin for Cordova
match plugin.google.maps.PluginEnvironment {
    preserve isAvailable(org.json.JSONArray, org.apache.cordova.CallbackContext);
}

# Cordova webview reflection
match org.apache.cordova.CordovaWebViewImpl {
    preserve getView();
}

# Preserve any Cordova pluginManager
match org.apache.cordova.* {
    preserve org.apache.cordova.PluginManager pluginManager;
}

# The annotations used for these classes use Google's gson to parse a JSON file
# All the methods and fields in that class need to be excluded for correct parsing
preserve * {
   @com.google.gson.* <members>;
   preserve <members>;
}