In the last installment of this article, we looked at the IsItDown application, and how it is designed not to run in the Android Emulator, and to include a super-annoying banner ad. We showed how the Apktool utility can be used to decompile an Android APK file, and how we can evaluate and modify the produced Smali code to manipulate the application's functionality.
In this final installment, we'll re-build the IsItDown application with our Smali file changes, then we'll generate the necessary keys and sign the application so that it can be used in the modified form on a virtual or a physical Android device. We'll also look at techniques that can be applied to defend against this hack, with advice that you can pass on to Android developers.
Rebuild the App
With the completed changes to the Smali files saved, we can re-build the app. We return to the IsItDown directory created by Apktool when we decompiled the app, and rebuild:
As long as there are no syntax errors in your modified Smali code, Apktool will build a new Android APK file in the "dist" directory:
Sign the App
We can't install and run this new version yet though, because the Android platform requires signed application packages. Never fear though — the signature isn't anything that is checked (by anyone, ever), and can be self-signed.
First, use the JDK tools to run the keytool utility and create your own signing key as shown here:
Note that the path to the keytool.exe utility might be different for you depending on your version of the JDK. You can feel free to enter any values you find entertaining here, just make the alias "IsItDown" as shown. Next, use the "jarsigner.exe" utility to leverage the key and generate a signed application package:
With the jarsigner utility, specify the location of your keystore file, the APK filename, and the keystore alias "IsItDown". Enter the password you supplied when you generated the keystore and ignore the warning. Viola! Signed Android package!
Run the App
Finally, we get to reap the benefits of our work. Uninstall the old version of IsItDown, and install the modified version.
Next up, run the app and see your changes in action. AWESOME!
Defend the App
Now that we've seen the steps to manipulate the app, we should take a look at what developers can do about this. As a pen tester, it's important to always leave your customer with more than "this is broken": we need to address the audience and give them advice on what to do about the issues you've identified.
Here... it's hard. The bottom line is that anyone can modify and manipulate an Android app or any software (on any device not using end-to-end trusted execution policies). The developer can do things that make it harder for an attacker, but ultimately there is no reasonable way to stop a determined attacker from manipulating the application.
One easy opportunity for Android developers is to check the integrity of the application signature. When we generate a new APK file with Apktool, we have to also generate a self-signed key and sign the APK file before we can install it. Since we don't have the original developer's signing key, we can never reproduce the original signature information.
A developer can periodically check the certificate information for the application at runtime. I saw this technique first in Android Security Cookbook by Keith Makan and Scott Alexander-Bown, Scott (2013, Packt Publishing, page 179). Their code doesn't work on newer Android API levels, but I've modified it with a complete example available at https://github.com/joswr1ght/ValidateSigningCertificate.
Essentially, the developer generates the signing certificate, and calculates a SHA1 hash of the certificate, embedding it in the application source:
Periodically during the application execution, the developer calls "getPackageInfo( )" with the "PacketManager.GET_SIGNATURES" argument to retrieve the app signing certificate information, comparing the embedded SHA1 certificate hash with the hash of the current certificate:
This is... OK. An attacker who can modify the Smali code can also modify the embedded SHA1 of the developer's certificate to match their own signing certificate, or just disable the certificate checks altogether. The only "superior" defense is to move sensitive or critical code into a natively-compiled library with the Android Native Development Kit (NDK). Here, the developer would re-write their Java code in C/C++ to make it harder to manipulate the app's functionality (harder, but still not impossible, since many attackers can manipulate native libraries too).
In this article we've looked at the techniques for manipulating Android apps. Our IsItDown target app was a straightforward target, but you can use the same techniques on many other Android apps with just a little added patience.
Remember to use these techniques for good, and not evil. That game you like to play was written by someone who needs to make money too, and turning off their banner ads or manipulating the "coin" value x100 is fun for you, but it makes them think twice about implementing their next project too. Use these techniques ethically.
As a parting note: my friends who write iOS apps sputter about how iOS apps are natively compiled and can't be reverse-engineered this same way. Whenever I do iOS reverse-engineering, I take a look for the Android version of the same app. Since Android reverse-engineering is so much easier, we can spend a little time looking at the Android code before moving onto the iOS app to get a feel for how the app functions. If I'm attacking the back-end servers, I don't have to reverse-engineer the iOS version of the app; the Android version will do just fine.