Intro

This past winter I got a chance to attend AnDevCon IV in San Francisco.  It was a great conference, especially for beginning Android developers like myself.  There were a number of sessions to help new developers get up to speed with tools and best practices for Android development.  During one of our breaks I overheard some other attendees talk about a particular session on Android application binary (APK) hacking.  I didn’t attend that session but what I heard from the other attendees blew me away.  Using off the shelf tools you can easily disassemble any Android application binary, inject your own code, repackage the binary and distribute it.  After hearing about this I decided to do a little bit of my own research to see how easy it was.  My goal was to take Intelliware’s AgileTourToronto app from the Google Play store and hack it to send private information to a server.  By the end of the exercise I succeeded in having the app send the GPS location of the device to a server.

The rest of the post will show you how to hack Android APKs and what you can do protect yourself against this kind of attack.

The Target

The first step is to get the APK that you want to hack.  The easiest way to do this is to use an Android backup tool.  APKs are not usually directly accessible but backup tools allow you to copy them to areas of your Android device where they are, like an SD card.  Once the APK has been backed up you can use the Android File Transfer tool to copy it to your local filesystem.

Breaking it Down

Once you’ve got the APK you need to download apktool.  On the apktool project page it states:

It is a tool for reverse engineering 3rd party, closed, binary Android apps. It can decode resources to nearly original form and rebuild them after making some modifications; it makes possible to debug smali code step by step. Also it makes working with app easier because of project-like files structure and automation of some repetitive tasks like building apk, etc.It is NOT intended for piracy and other non-legal uses. It could be used for localizing, adding some features or support for custom platforms and other GOOD purposes. Just try to be fair with authors of an app, that you use and probably like.

Using apktool we can decompile our APK and gain access to its resources, source code and other project metadata.

After decompiling the APK you’ll find a directory called “smali”.  This directory contains the source code for the APK in assembly for the Dalvik VM that runs on Android devices.  Because Android binaries are compiled into bytecode decompilers have a much easier time doing their job because of all the metadata embedded in bytecode.  Here’s a sample of what a public method in smali looks like:

.method public onCreateOptionsMenu(Landroid/view/Menu;)Z
    .locals 2
    .parameter "menu"

    .prologue
    .line 50
    invoke-virtual {p0}, Lca/intelliware/agiletourtoronto/MainActivity;->getMenuInflater()Landroid/view/MenuInflater;

    move-result-object v0

    const/high16 v1, 0x7f06

    invoke-virtual {v0, v1, p1}, Landroid/view/MenuInflater;->inflate(ILandroid/view/Menu;)V

    .line 51
    const/4 v0, 0x1

    return v0
.end method

The Hack

At first I tried to learn smali to inject my own behaviour but that proved to be time consuming for anything more than trivial tinkering.  I realized I could probably write my code in Java and export an APK which I could decompile using apktool.  I could then inject the smali version of my code into the original APK.  To reduce any side affects on the original code I could encapsulate all the behaviour I need in a single class and make it invokable through a static method.  I created a new Android project and wrote some code to query the GPS location of the device and make an HTTP request to send the data, all in a background thread.

After exporting my code to an APK and decompiling it I had to merge my code with the target APK.  The best place to bootstrap your code is in the onCreate() method of the MainActivity.  Every Android application has a MainActivity and onCreate() method.  This method is called when your Android application is launched.  Looking at the onCreate() method of the smali version of my project we can see the following lines:

    .line 15
    new-instance v0, Lca/intelliware/trojan/Trojan;

    invoke-direct {v0}, Lca/intelliware/trojan/Trojan;->()V

    invoke-virtual {v0, p0}, Lca/intelliware/trojan/Trojan;->hack(Landroid/content/Context;)V

apktool is helpful and tells us that my single line method invocation in Java code corresponds to 3 smali instructions.  All I need to do is copy those 3 lines of code into the onCreate() method of the AgileTourToronto app.  After copying that code I still need to make the Trojan class resolvable in the AgileTourToronto app.  Fortunately APKs are following the same structure as JAR files where package names are turned into directory structures.  Since my class is in the package ca.intelliware.trojan I simply copy the trojan folder from my project into the appropriate spot in the AgileTourToronto project structure.  Finally since my new version of the AgileTourToronto app needs some extra permissions I have to modify AndroidManifest.xml to include them.

Building it Up

After making the necessary modifications to the code we need to package the directory up back into an APK using apktool.

Once you have the APK you need to sign it using jarsigner.  To create the keystore used for signing you need to follow the instructions here.

jarsigner -verbose -keystore agiletour.keystore agiletourtoronto.apk ca.intelliware.agiletourtoronto

 Distribution

There are a number of ways the hacked APK can get on to a device:

  • Put the hacked APK up on a website.  As long as the user’s device is set to install apps from a non-trusted source they will be able to install the app.  For example, someone nefarious could download/hack a popular game from the Google Play store and put it up on a torrent site.
  • Submit to the Play Store (or any other Android app store).  Theoretically this is possible, but a different app ID is needed, so that it doesn’t conflict with the original existing app in the store.

Defence?

At the moment there are no known ways of protecting against this kind of attack.  Google’s Eclipse tools provide developers with the ability to obfuscate their code using ProGuard.  This will protect your code from hackers who want to reverse engineer your algorithms or processes.  However, you can’t obfuscate the system calls to your application so you will always be able to find the entry point to any Android application and inject your code appropriately.