Android Reversing Bootcamp
by Andy G (@vxhex)
So, you've built your first Android application. Now what?
This is a brief introduction to Android application reversing. It assumes a basic knowledge of Java (packages, classes, etc.) and the Android SDK (activities, intents, and the manifest). If you're new to Android development, it'd be helpful to read through some of Vogella's excellent tutorials.1
Most of the tools we'll be using are available in the "Reverse Engineering" section on the latest BackTrack Linux.2
Reversing engineering can violate some EULAs. It can be used for malicious or legitimate purposes. Be careful what you hack (or who you talk to about it).
First Things First
Android apps are packaged into an APK (application package) file for distribution. APKs are based on Java's JAR format: they're zipped archives containing the app's manifest, resources, and code. Like JARs, you can unpackage them with any ZIP archive manager.
To get our hands on some APKs, we'll be using ASTRO File Manager, available in the Google Play store. Astro allows you to "back up" your apps by saving them to your device's memory as an APK. In Astro, navigate to the Application Manager, select an installed app, and click "Backup." The APK will be saved to backups/apps/. From there, you can upload it to your dropbox, email it to yourself, or USB it from your device.
Other methods exist for acquiring APKs (like scripts for the Play store and ADB pulls). If you're interested in trying these out, flex your Google-fu and let me know what worked best for you.
Now that we have some APKs, let's unpack them using Apktool. Apktool is a program for unpacking and repacking APKs. You can unpack an APK with:
$ apktool d application.apk
This will create a folder containing the unpacked APK's components.
AndroidManifest.xml is a good place to start.3 Here we can check permissions, services, and the app's main activity.
An app's starting activity will have an intent-filter listing an action of android.intent.action.MAIN. An app is permitted to have multiple entry points, but it is common to see just one. Make a note of the app's starting activity, as that will be the starting point for our code analysis.
The res/ folder contains the app's resources, like icons, menus, and strings. Android encourages storing strings and values in XML files instead of hardcoding them into your application, and these can be found in res/values/. Menus, also defined in XML, are found in res/layout/.
An assets folder may also be present, containing miscellaneous files used by the app.
Reading Some Code
It's fairly easy to reconstruct decent Java from an APK. The Java typically won't be perfect, but it's readable and lets you examine the app's logic.
First we'll convert our APK to a JAR using dex2jar:
$ d2j-dex2jar.sh application.apk
This will produce a JAR file, named application-dex2jar.jar, that can be reversed like any other Java application.
We'll use JD-GUI to look at what we've got.4 Although it doesn't come standard on BackTrack, JD-GUI will run out-of-the-box. Just extract the tarball and click the "JD-GUI" icon to run. From here, head to "File -> Open", and select the newly-created JAR. This will load the app into the decompiler and you should see the packages laid out in a nice tree to the left. You can start from the main activity's onCreate() method and work your way through the application's flow.
If you don't want to install any new software, you can use a Java decompiler called JAD. We can unzip the JAR file, explore the package structure, and run JAD on the .class files we're interested in. This will produce .JAD files that contain the class's Java code. From here, you're free to grep away.
$ unzip application-dex2jar.jar $ jad com/package/application/*.class $ grep onCreate *.jad
That Was Too Easy
Let's head back to Apktool's unpacked stuff and check out the smali folder. This folder contains the decompiled bytecode of the application. Its folder structure represents the various packages that make up the app, and the .smali files can be opened with any text editor.
Smali is an assembly-like translation of the Dalvik bytecode. This normally sits inside of the APK in a file called classes.dex. Because Smali is a direct translation of the app's code, once you understand how it works, you can edit these files to modify the app. This is commonly how APKs are cracked or repackaged with malware. Conversely, it can also be used to remove advertisements or malicious payloads. This ability to edit and repackage an APK makes Smali worth diving into a bit deeper.
This article won't make you fluent in Smali, but this should give you enough information to start hacking on things. Keep a reference guide open as you work.5.
Smali uses single characters to represent Java's primitive types:
Z - boolean I - int C - char V - void B - byte F - float D - double J - long S - short
Arrays are represented as a [ before a variable type. For example, [[I would be a two-dimensional array of ints.
Methods follow a format of: methodName (parameters) returnValue
For example, here's a method that takes a char array and int as parameters and returns a boolean:
Objects are represented with a capital L followed by the object's package and name. For example, an object of Java's String class looks like:
L designates the object, java/lang/ is the package name, and String is the class itself. Object attributes appear as Name:Type. An object's methods and attributes are accessed using the -> operator.
Comments can be added by starting a line with a # character.
Smali instructions are human-readable representations of Dalvik op-codes. A reference will usually be necessary to look up exact syntax and functionality of an instruction, but you can generally infer what's happening.6.
Like assembly, Smali instructions operate on registers. These are represented by a letter, indicating the type of register, and a number. Registers starting with a v, like v2, are local registers, while a p indicates a parameter register.
Now let's look at some examples and break down each one:
The if-xxx statements are conditionals.
if-nez stands for "if not equal zero." This will evaluate to true if our target, v0, is not equal to zero. :label_name is the label for the block of code we'll jump to if our condition is met.
This is a labeled block of code that moves a string constant into the v0 register. This block of code can be jumped to by referencing label_name. After this operation, we can use this string by referencing v0.
invoke-xxx statements are used to call methods.
In this code, Java's trim() method is called on the String object located in v9. The resulting String object is then moved into v9, overwriting our original. The v9 register is our reference to Java's "this," or the calling object. The method prototype follows the syntax previously described: the calling object type (String), the method (trim()), then the return object (also a String). move-result-object then moves the previous instruction's return value into the designated register: v9
Smali can be a bit overwhelming in large doses, so again grep is your friend when hunting for specific functionality. Otherwise, start in the main activity and look for the onCreate method:
After you make changes to an app, you can rebuild it using:$ apktool b UnpackedAPK
The resulting APK can then be signed7, via Keytool and Jarsigner, and distributed for installation.
Practice makes perfect. You'll learn quite a bit by building basic "hello world" type apps and hacking on them.
Other topics to explore include ProGuard, SQLite, OWASP's GoatDroid Project, binary reversing (for proprietary binary assets, like those used in Rovio's apps), and Apktool's debugging features.
Blog dedicated to Android cracking: androidcracking.blogspot.com
Forum for mobile developers: forum.xda-developers.com
Android reversing examples: www.exploit-db.com/papers/21325