As a security professional, I'm called on to evaluate the security of Android applications on a regular basis. This evaluation process usually takes on one of two forms:
- Evaluate app security from an end-user perspective
- Evaluate app security from a publisher perspective
While there is a lot of overlap between the two processes, the difference effectively boils down to this: whose risk perspective does my customer care about the most?
When an app publisher wants me to evaluate the security of their Android app, I need to determine if the app employs sufficient controls to protect the required app functionality and publisher brand. Often, this requires me to identify critical app components (critical for my customer, such as how they make revenue from the app, or the integrity of the data transmitted by the app), and determine if I can manipulate them in interesting ways.
As a guide, I developed an Application Report Card system to steer an analyst through the application evaluation process. One of these tasks is to manipulate the Android application by modifying the low-level Smali bytecode, removing the intended publisher functionality.
In my SEC575: Mobile Device Security and Ethical Hacking course, we use a custom application, IsItDown as our evaluation target. In the exercise, participants have to install and run the application to identify the app functionality and constraints, then decompile, modify, reassemble, and re-sign the application so the app can be used without restrictions.
In this 2-part article, we'll take a peek at the SEC575 hands-on lab exercise for modifying Android apps. In the first part, we'll take a look at how we can leverage the Apktool utility to decompile an Android app, followed by a quick primer on reading Smali code. In the second part, we'll generate custom keys to sign the modified application so that it can be used on a virtual or physical Android device, and look at defense techniques.
Feel free to download the IsItDown application and follow along. You'll also need the following tools for your system:
- IsItDown - http://www.willhackforsushi.com/sec575/IsItDown.apk
- Apktool - http://ibotpeaches.github.io/Apktool/install/
- Java Development Kit - http://www.oracle.com/technetwork/java/javase/downloads
- The Android SDK for a virtual Android device - http://developer.android.com/sdk (or you can use a real Android device with Android Debug Bridge access turned on)
Evaluate the App
After starting a virtual Android device (or connecting your physical Android device over USB), use the adb utility to install the IsItDown.apk application as shown above. Next, run the app and experiment.
IsItDown is a basic IsItDownForJustMeOrForEveryoneElseToo app... except it's only testing from your mobile device. Frankly, it's not that useful, but it serves our needs fine.
If you are working from a virtual device, you'll quickly be disappointed. Not only does IsItDown have an obnoxious banner ad on the bottom of the page, it only teases you with the promise of functionality before it tells you to go away.
Our goal here is modify the Android application to allow us to run in the Android Emulator, and to remove that annoying banner ad.
Decompile the App
First, we'll use Apktool written by Ryszard Wisniewski and Connor Tumbleson to convert the IsItDown.apk file into Smali code. Smali code is a representation of the app code using the Android Dalvik opcodes - essentially an intermediate representation of the code between the original Java source and the processor-specific assembly instructions. Apktool allows us to take the Android APK file, convert it into a Smali source representation that can be modified, and then recompile it back into a new APK file.
Note: The pedantic reader will no doubt be questioning my use of "decompile" as a verb here. Converting an Android APK file to Smali code is not quite decompilation, but it's not quite disassembly either. It's somewhere in the middle. I'll keep using decompilation, since you are getting a high-level representation of the app code in the Smali file, but if you are more comfortable with the decompilation verb, feel free to search+replace this article.
Apktool isn't so much a hacking tool as it is a mechanism to evaluate Android applications. Sure, people with ill intent can manipulate an application for evil purposes, but it can also be used for Android application troubleshooting, and for the localization (adding local language support) for applications as well. Don't use it to do evil things, OK? (Ed.: I second that.)
Make sure you have apktool.jar (renamed from apktool-2.0.0.jar), apktool.bat and IsItDown.apk all in the same directory (or put apktool.jar and apktool.bat in your system PATH somewhere). Next, use apktool.bat to decompile the APK file, as shown here:
Apktool will generate a new directory IsItDown that holds the application resources, AndroidManifest.xml declarations, the original signature information from the developer, and the Smali code itself.
Modify the App
Browsing to the smali directory, we'll see a directory structure created for the application package names (e.g. com/willhackforushi/isitdown/). For our simple application, only a handful of Smali files are generated, as shown here:
Most of these Smali files include auto-generated code, so we don't have to look through all of them. First, let's search for a reference to the string "No emulator use permitted." using the Windows findstr.exe utility:
Here we see the string is in the MainActivity.smali file. This is unusual; typically, string values will be defined in the res/values/strings.xml file, making it easier to localize the application. Here, the developer just got lazy, and embedded the string directly in the Java source. This makes it a little easier for us to evaluate the Smali code though: simply open the MainActivity.smali file with your favorite editor and skip to the line where the string is defined.
At this point, if you're not a developer, or have never seen Smali code before, you might be like "WTW? I'm supposed to read this?". Have no fear! You just need to know a few things about Smali:
- Smali uses declared registers as placeholders for objects, variables. v0 is a local register, p0 is a parameter register (e.g. something passed to the function/method)
- Syntax in Smali is always destination, then source
- Object types are specified with a capital letter at the end of the object or method:
- V - Void
- Z - Boolean
- B - Byte
- S - Short
- C - Char
- I - Int
- J - Long (64-bits)
- F - Float
- D - Double (64-bits)
- L - Object
A cheat sheet is a useful thing to have as well, that explains common Smali opcodes and their functionality. Here's one from my SEC575 course!
Finally, the reference maintained by Gabor Paller at http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html is awesome, and frankly, is how I learned to read Smali code. You should bookmark that link!
Looking at that Smali code, there is a lot of stuff we don't care about. We know that the application shows us an error "Go away" and refuses to run. Logically, before that message is displayed, we should see some code that determines whether or not to display that error. Sure enough, check out line 350:
Line 350 invokes a method calls "isEmulator( )" which returns a Boolean value (see the big "Z" at the end?). The Boolean result is moved to the "v13" register, and then the "if-egz' opcode determines if the value is 0 (or "False"). If v13 is equal to 0, then the code jumps to the "code_0" block. Otherwise, we get the nasty "No emulator use permitted." message.
Not so hard, right? Knowing this, we can make a simple change to this code. Consider this small "fix":
See what I did on line 354? I changed "if-egz" to "if-nez", effectively inverting the test. Now, even though "isEmulator( )" still returns True on emulated devices, the code behaves as if it the device were not an emulator, jumping to the "cond_0" block.
This is not completely desirable, since this change would invert the test, and break the functionality for legitimate devices that install the modified IsItDown.apk file. You could modify the "isEmulator( )" method to always return False as another option, but this is what I ended up doing:
On line 354 is the original "if-egz" test, and then I added the inverted test immediately afterward. This way, regardless of what the "isEmulator( )" method returns, the code always skips the "No emulator use permitted" message. It's a little hackish, but it gets the job done. (Ed.: Did Tom Liston teach you that, Josh?)
Next up: removing that banner ad. Banner ads are usually displayed in a WebView object, which is effectively a little tiny web browser in the app. Searching for the string "http:" reveals two references that look like the source of our advertising:
Searching for that same string in the MainActivity.smali and MainActivity$1.smali files reveals code like this:
In this example, line 268 loads the reference to the WebView in the v2 parameter, while line 270 loads the ad URL in the v3 parameter. Line 272 loads the URL content into the WebView. Easy enough to change that behavior:
Simply commenting-out the "invoke-virtual" opcode that fills the WebView is enough to cause the banner ad to stop loading. Repeat this step for both MainActivity.smali, and MainActivity$1.smali and you're done!
Concluding Part One
In this first part of our article, we saw how Apktool can be used to decompile an Android application, and looked at the Smali code with a focus on changing the code to overcome Android emulator restrictions and to disable an annoying banner ad. In Part Two we'll pick up where we left off and re-build the application and sign it with the Java Development Kit utilities so we can run the modified app on an emulated or real Android device. Finally, we'll address defensive techniques that you can use in your next Android pen test report with suggestions to pass on to Android developers, and briefly discuss how Android testing can also be useful when evaluating iOS targets.
Until next time