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.
First, we'll enable ProGuard on an Android application:
project.properties
: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
buildType
release to your Gradle build file:android { ... buildTypes { release { runProguard true proguardFile file('../proguard-project.txt) proguardFile getDefaultProguardFile('proguard-android.txt') } } }
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); }
Once ProGuard is enabled for your project, there are two simple steps to ensure all logging messages are removed.
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(); } }
LogWrap
instead of the standard android.util.Log
. For example:try{ … } catch (IOException e) { LogWrap.e("Error opening file.", e); }
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(...); }
proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt
For Ant: ant release
For Gradle: gradle assembleRelease
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.
Let's take a closer look at some of the outputs from ProGuard and the limitations.
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 appsSeeds.txt
: This lists the classes and members that are not obfuscatedUsage.txt
: This lists the code that was stripped from the .apk
fileDump.txt
: This describes the internal structure of all of the class files in the .apk
fileObfuscating 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.
3.147.78.145