Obfuscating for Android with ProGuard

Obfu-what? Right, Obfuscation, in general, describes a practice that is used to intentionally make something more difficult to understand.
The nature of Java (the programming language for Android apps) is that the code is not compiled down to machine code; it is compiled to an intermediate format that is ready to be run on a variety of hardware platforms. While this allows great portability, it also leaves the code for Android apps, as present in the APK (Application PacKage file), available for extraction.
I’m going to describe a way for you to obfuscate your Android code to make it harder for others to reverse engineer. And also why not shrink the size of your Android applications and optimize them to make them run faster at the same time.

Without a doubt, the simplest method to protect an app is to enable the obfuscation in ProGuard. This freely available tool is already built into the Android toolkit.

Obfuscation

By default, compiled bytecode still contains a lot of debugging information: source file names, line numbers, field names, method names, argument names, variable names, etc. This information makes it straightforward to decompile the bytecode and reverse-engineer entire apps. Sometimes, this is not desirable. Obfuscators, such as ProGuard, can remove the debugging information and replace all names by meaningless character sequences, making it much harder to reverse-engineer the code. It further compacts the code as a bonus. The app remains functionally equivalent, except for the class names, method names, and line numbers given in exception stack traces.

Shrinking

Java source code (.java files) is typically compiled to bytecode (.class files). Bytecode is more compact than Java source code, but it may still contain a lot of unused code, especially if it includes program libraries. Shrinking programs such as ProGuard can analyze bytecode and remove unused classes, fields, and methods. The app remains functionally equivalent, including the information given in exception stack traces.

For a realistic example, take the following code:

if(Config.LOGD))
{
 Log.d(TAG, "Some text");
}

The code as shown above is a typical scenario during development. You create code like this to help debug and test your code. Before releasing the final product, though, you set Config.LOGD to false, so it doesn’t execute. The problem is, this code is still in your application. It makes it bigger, and may cause potential security issues by including code which should never be seen by a snooping hacker.

Shrinking the code solves this problem beautifully. The code is completely removed from the final product, leaving the final package safer and smaller.

Optimizing

Apart from removing unused classes, fields, and methods in the shrinking step, ProGuard can also perform optimizations at the bytecode level, inside and across methods.

Proguard

So let’s have a look at the proguard.cfg file. I recommend you open up the sample code, as I will be highlighting the key parts on this page.

Basic template

-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic
-keepattributes *Annotation*

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider

-keep public class * extends android.view.View {
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
    public void set*(...);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers class * implements android.os.Parcelable {
    static android.os.Parcelable$Creator CREATOR;
}

-keepclassmembers class **.R$* {
    public static <fields>;
}

Fragments

-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.app.Fragment

Serializables

-keepnames class * implements java.io.Serializable

-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    !static !transient <fields>;
    !private <fields>;
    !private <methods>;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

Removing Logging

-assumenosideeffects class android.util.Log {
    public static *** e(...);
    public static *** w(...);
    public static *** wtf(...);
    public static *** d(...);
    public static *** v(...);
}

Methods

-keepclasseswithmembernames class * {
    native <methods>;
}
-keepclassmembers class * {
    public void *ButtonClicked(android.view.View);
}

Now that we have added all our Proguard settings, we need to run Proguard during the build fase. I will use Maven to illustrate this.

Within your pom.xml the android-maven-plugin should be defined. To this definition add the proguard setting like:

      <plugin>
        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
        <artifactId>android-maven-plugin</artifactId>
        <version>3.0.0</version>
        <extensions>true</extensions>
        <configuration>
            <sdk>
            <platform>15</platform>
          </sdk>
          <dex>
            <jvmArguments>
              <argument>-Xms256m</argument>
              <argument>-Xmx512m</argument>
            </jvmArguments>
          </dex>
          <run>
              <debug>true</debug>
          </run>
          <proguard>
            <skip>false</skip>
            <config>proguard.cfg</config>
          </proguard>
        </configuration>
      </plugin>

All that is left is to run Maven with

mvn clean install

To check if the app has been obfuscated, install the apk on you Android device and when you run it, you shouldn’t see any logging in logcat.

  1. MUSTAFAGUVEN
    Hi, thank you for sharing. I tried to run proguard as you mentioned but it gives an error which I tried to explain in here http://stackoverflow.com/questions/22067018/proguard-maven-android-error-method-must-be-overridden-in-proguard-optimiz . what can be overlooked do you think?

Leave a Reply

*

captcha *

This site uses Akismet to reduce spam. Learn how your comment data is processed.