Sat
Apr 7

Hacking Android apps, part 1: the basics

Welcome to a short series of posts about modifying Android applications. The application to be used as a guinea pig in this case is Viber, a VOIP application for Android.

Assumed knowledge: some programming experience, access to a UNIX environment (such as Linux or OS X), and a rooted Android phone.

A short visual lesson in why the Android permissions system fails for complex apps

Android permissions provide a fine-grained way for applications to request elevated privilges. They are great when apps only request one or two permissions -- for example, you might be okay with your music player connecting to the Internet but you might not be okay with it reading your contacts list. However, for sufficiently-large applications, the system breaks down.

On the left is Viber's permission list, which is, I hope you will agree, somewhat ridiculous. If you can't be bothered reading that, and I don't blame you, the summary is that Viber is essentially asking for complete control of my phone. It can access my contacts, send SMSes, make calls, access the Internet -- basically do whatever it likes.

Avoiding the whole question of whether these permissions are justified, the question then becomes: do I trust this app to use its many powers for good? I'm sure the Viber people are excellent and don't want to do anything nasty with my phone, but even the best-intentioned software has bugs.

If I don't trust the app, the only choice Google Play gives me is not to install the app. Trust the app and let it do everything, or don't use it at all? These aren't great choices. Fortunately, if you have a rooted device and are willing to write some code, these aren't your only options.

Over the course of this series we'll look at modifying Viber so that it doesn't need a bunch of these permissions. In this introduction, you'll set up the tools you need to modify Android apps, and make a very small change to Viber, to prevent it from adding a shortcut to your home screen.

Setting up your environment

JDK

You'll need a Java development environment installed.

ADB

You'll need ADB, which lets you do various useful things to your phone from your computer. ADB comes with the Android SDK, which I encourage you to install. This page on the CyanogenMod Wiki contains more information on installing the Android SDK and getting ADB set up.

Make sure ADB works and verify that you have a rooted device by running adb shell

You should get a root prompt on your phone.

Viber

Install Viber on your device.

On your computer, create a working directory. I created ~/tmp/viber.

You'll now want to get the Viber APK onto your computer. Unfortunately, depending on your device, it could be in various places. Try:

adb shell ls /data/app |grep -i viber

If you see something like com.viber.voip-1.apk, then you're set. Change to your new working directory and use ADB to download the APK from your device.

~$ cd tmp/viber
~/tmp/viber$ adb pull /data/app/com.viber.voip-1.apk com.viber.voip-orig.apk

If, however, you don't see Viber installed in /data/app, it could be installed on the SD card. On my phone, SD card apps are available from /mnt/asec. Try:

adb pull /mnt/asec/com.viber.voip-1/pkg.apk com.viber.voip-orig.apk

apktool

Apktool is a nice program which saves a lot of time when working with APKs. Download it from here.

Opening the APK

An APK is a zip file containing everything required by the app. So in theory you could just unzip it, but instead we will use apktool. As well as unzipping the APK, apktool will run Baksmali (a disassembler) over the code, and will also convert the Manifest file to a text format (it's stored in the APK in compiled form).

~/tmp/viber$ apktool d com.viber.voip-orig.apk apk

This produces a bunch of files in the apk directory. The decompiled source code is in the smali directory. Have a look around and familiarise yourself a little with the assembly language being used. For this, the best resource is the Smali wiki, but there is not a huge amount of information there. Smali is based on Jasmin, so it may be worth reading up on the Jasmin instruction set also.

Application signing

You have to sign your modified app using your own key. If you've done Android development before, you will have a debug key in ~/.android/debug.keystore and you can use this. If not, you should create a key using keytool:

~/tmp/viber$ keytool -genkey -v -keystore key.keystore -alias key -keyalg RSA -keysize 2048 -validity 10000

Keytool asks you for a password, and then asks a whole lot of questions which it will use to fill in the key. It doesn't really matter how you answer these questions. If you're only planning on using this keystore for your Viber modifications (recommended) then you can leave them blank, and you can also choose a very simple password.

Sanity check -- does it work?

To check that everything is working up to this point, we'll now re-build the app, without any changes.

Run apktool to rebuild the APK.

~/tmp/viber$ apktool b apk com.viber.voip.apk

Then, sign the APK with your new key. If you're using the debug key, do this:

~/tmp/viber$ jarsigner -keystore ~/.android/debug.keystore -storepass android com.viber.voip.apk androiddebugkey

... if you're using a key you generated above, do this instead:

~/tmp/viber$ jarsigner -keystore key.keystore -storepass password com.viber.voip.apk key

Install the app:

~/tmp/viber$ adb install com.viber.voip.apk

Now run it on your device (you may want to turn on airplane mode first).

Modifying the APK: removing the shortcut-adding code

When you first run Viber, it adds a shortcut to your home screen. Let's stop it from doing that.

A quick search for "android shortcut api" reveals A stackoverflow.com post with code to create a shortcut on the launcher desktop. The key part of that code is this Intent:

com.android.launcher.action.INSTALL_SHORTCUT

That looks like an obvious thing to search for in the code, so let's do that:

~/tmp/viber$ grep -r INSTALL_SHORTCUT apk/smali/*
apk/smali/com/viber/voip/IdleActivity.smali:    const-string v5, "com.android.launcher.action.UNINSTALL_SHORTCUT"
apk/smali/com/viber/voip/IdleActivity.smali:    const-string v5, "com.android.launcher.action.INSTALL_SHORTCUT"

Great! The shortcut code seems to reside in a single file. Open that file in your favourite text editor.

~/tmp/viber$ vim apk/smali/com/viber/voip/IdleActivity.smali

You'll see that the INSTALL_SHORTCUT code is called from a method named "setupShortcut":

.method public setupShortcut(Z)V

The method parameters are encoded in the Java JNI format, as described on the Smali wiki. Referencing that, you can see that setupShortcut takes a single Boolean as parameter (the Z) and returns void (the V).

Let's delete the entire method body. Delete the entire method, from the line beginning with .method public setupShortcut to the line beginning with .end method. Replace it with this:

.method public setupShortcut(Z)V
.locals 0
.parameter "sendBroadcast"

return-void
.end method

This is basically the minimum we need. The locals line tells the assembler that the method doesn't use any local variables. The parameter line identifies the method argument, and the return-void line does what it suggests -- unlike Java, Smali methods must always return something explicitly, even if it is void.

Now rebuild the APK as before, and reinstall it:

~/tmp/viber$ adb uninstall com.viber.voip
~/tmp/viber$ apktool b apk com.viber.voip.apk
~/tmp/viber$ jarsigner -keystore key.keystore -storepass password com.viber.voip.apk key
~/tmp/viber$ adb install com.viber.voip.apk

Relaunch the app on your phone, and you will see that it does not create a shortcut on your desktop any more. To be doubly sure, you can also remove the appropriate permission lines from apk/AndroidManifest.xml -- they're the ones that have SHORTCUT in the name -- and reinstall. Now the application can't possibly create shortcuts, even if we missed something.

In the next entry, we'll get a little more complicated, by preventing Viber from accessing your contact list.