Removing all log messages with ProGuard

ProGuard is an open source Java code obfuscator that is supplied with the Android SDK. For those unfamiliar with obfuscators, they remove any information from the code that is not needed for execution, for example, unused code and debugging information. Also, identifiers are renamed from an easy-to-read, descriptive, and maintainable code you've written into an optimized, shorter, and very difficult-to-read one. Before, an object/method call might look something like this: SecurityManager.encrypt(String text);, but after obfuscation, it could look like: a.b(String c);. As you can see, it gives no clue about its purpose.

ProGuard also reduces the amount of code by removing unused methods, fields, and attributes, and makes it execute quicker by using machine-optimized code. This is ideal for a mobile context, as this optimization can drastically reduce the size of the exported .apk file. This is especially useful when only using a subset of third-party libraries.

There are other Java obfuscators available, but due to the fact that ProGuard is part of the Android SDK, many third-party development libraries contain custom ProGuard configuration to ensure they function correctly.

Getting ready

First, we'll enable ProGuard on an Android application:

  1. If you're developing your application using Eclipse with the Android ADT plugin, you'll need to locate your workspace and navigate to the folder containing your application code. Once you've found it, you should see a text file called project.properties:
    Getting ready

    To enable ProGuard, you need to make sure the following line is uncommented:

    proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

    This assumes that you have the default folder structure for the Android SDK, since the previous configuration includes a static path, namely /tools/proguard/proguard-android.txt. If you don't have the correct folder structure or you're not using the Android Developer's Toolkit plugin for Eclipse, you can fetch the proguard-android.txt file and place it one folder above your application's working folder. In this case, you can configure this directory as follows:

    proguard.config=proguard-android.txt:proguard-project.txt
  2. Android Studio configuration requires the following lines in your buildType release to your Gradle build file:
    android {
    ...
        buildTypes {
            release {
                runProguard true
                proguardFile file('../proguard-project.txt)
                proguardFile getDefaultProguardFile('proguard-android.txt')
            }
        }
    }
  3. It's important to keep the reference to the proGuard-android.txt file, as it contains Android-specific exclusions and without them, the app will likely not run. Here's an extract from the proguard-android.txt file instructing ProGuard to keep methods in activities that could be used in the XML attribute onClick:
    -keepclassmembers class * extends android.app.Activity {
       public void *(android.view.View);
    }

How to do it...

Once ProGuard is enabled for your project, there are two simple steps to ensure all logging messages are removed.

  1. To enable ProGuard to successfully find all of the log statements, we must use a wrapper class to wrap the Android log:
    public class LogWrap {
    
      public static final String TAG = "MyAppTag";
    
      public static void e(final Object obj, final Throwable cause) {
          Log.e(TAG, String.valueOf(obj));
          Log.e(TAG, convertThrowableStackToString(cause));
        }
    
      public static void e(final Object obj) {
          Log.e(TAG, String.valueOf(obj));
        }
    
      public static void w(final Object obj, final Throwable cause) {
          Log.w(TAG, String.valueOf(obj));
          Log.w(TAG, convertThrowableStackToString(cause));
        }
    
      public static void w(final Object obj) {
          Log.w(TAG, String.valueOf(obj));
        }
    
      public static void i(final Object obj) {
          Log.i(TAG, String.valueOf(obj));
        }
    
      public static void d(final Object obj) {
          Log.d(TAG, String.valueOf(obj));
      }
    
      public static void v(final Object obj) {
          Log.v(TAG, String.valueOf(obj));
      }
    
      public static String convertThrowableStackToString(final Throwable thr) {
        StringWriter b = new StringWriter();
        thr.printStackTrace(new PrintWriter(b));
        return b.toString();
      }
    }
  2. In your application code, use LogWrap instead of the standard android.util.Log. For example:
    try{
      …
     } catch (IOException e) {
      LogWrap.e("Error opening file.", e);
    }
  3. Insert the following custom ProGuard configuration into the project's proguard-project.txt file:
    -assumenosideeffects class android.util.Log {
        public static boolean isLoggable(java.lang.String, int);
        public static int v(...);
        public static int i(...);
        public static int w(...);
        public static int d(...);
        public static int e(...);
    }
  4. Enable ProGuard Optimize by adding the optimize configuration file to the project:
    proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt
    
  5. Build your application in release mode to apply ProGuard:
    • Use the Android Tools export wizard in Eclipse
    • In a terminal window at the root of your project, type the following commands:

      For Ant: ant release

      For Gradle: gradle assembleRelease

How it works...

When you build an application in release mode, the build system will check the proguard.config property when it is uncommented and use ProGuard to process the application's bytecode before packaging it into the application (.apk).

When ProGuard is processing bytecode, the assumeNoeffects attribute allows it to completely remove these lines of code—in this case, all of the relevant methods from android.util.Log. Using the optimize configuration and log wrapper, we let ProGuard safely identify all of the calls to the various android.util.Log methods. An added benefit of enabling Optimize is that optimizing the code enhances the obfuscation factor, making it even harder to read.

There's more...

Let's take a closer look at some of the outputs from ProGuard and the limitations.

ProGuard output

These are the output files from applying ProGuard to Android .apk:

  • mapping.txt: As the name suggests, this contains the mappings between the obfuscated class, field names, and original names, and is essential to use the companion tool ReTrace to deobfuscate stack traces/bug reports produced by the obfuscated apps
  • Seeds.txt: This lists the classes and members that are not obfuscated
  • Usage.txt: This lists the code that was stripped from the .apk file
  • Dump.txt: This describes the internal structure of all of the class files in the .apk file

Tip

It's also worth noting that the output files for each build are overwritten with ProGuard. It's essential to save a copy of the mappings.txt file for every application release; otherwise, there is no way to convert stack traces.

Limitations

Obfuscating an application with ProGuard increases the time and skill level needed to reverse engineer, understand, and exploit an application. However, reversing is still possible; so, it certainly should not be the only piece of securing an application, but rather a part of the overall security approach.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.78.145