Scripting APKs With Ruby

While many of my colleagues were away at Blackhat, Defcon, and Bsides Las Vegas I decided to spend a day exploring through an Android app. I became interested in this particular app due to it being the “official” app of a popular web service that included some functionality not exposed to end users through the API that they’ve provided and this annoyed me, as I was reasonably sure that some spammers on this web service were using this functionality and I was interested to see just how difficult it was to do. Fun began.

The first part of the project was fairly standard. Traffic between the app and the service was SSL wrapped, so I needed to get in between them to get an idea about the endpoints. Theres several tutorials about this process that have been written by others, so I will link to those and mention a few of the highlights. ProxyDroid and Burpsuite were my tool of choice. The former for sending all the traffic from my Android device through my laptop and the latter to generate the certificate and analyze the request/response pairs. Figuring out the correct common name to use for the man-in-the-middle cert took a bit of trail and error, looking through DNS requests in the captured PCAPs, triggering the functionality on the Android device, repeating, as the way that ProxyDroid works Burp cannot accurately generate this (update: yes, it can, new feature added to do this very thing was added between doing this and my write up). Step one was accomplished, I could see the request, but with this particular app the requests are secured using OAuth keys/signatures, so even though I know the API endpoint I am unable to make requests without know the correct keys/secrets. Seeing the request though gives a good place to start digging into the Android binary to find them, but to get there we’re going to have to disassemble the apk.

apktool seems to be the right tool for this job, so I download the APK from my device and get to work.

$apktool d <target_apk> output/

This gives a nice output directory with a few files that will be of use later, but the important thing for now is the smali directory. This contains the disassembly of the dex format that is used by Dalvik, Androids Java Virtual Machine implementation. The usual reversing fun starts, thankfully things aren’t too obfuscated in this case, but of course all the symbols have been stripped. Class and method names like “HttpRequest” and “generate_signature” have been replaced with simple “a”, and “aa”. Smali is quite straightforward though, allowing for me to get my bearings relatively quickly. Grepping for the appropriate strings in the requests that I previously found and I’m in the right area. The secret keys aren’t in the binary plainly seen, but with tracing back a bit its easy to see when its loaded into one of the registers, so we need to do a bit of debugging. I tried to do fancy debugging, rebuilding in debug mode with apktool and trying to set breakpoints within netbeans while attached to a debug session on the android device, but came up empty. Somewhere along the lines apktool’s output became unfriendly to netbeans breakpoint setting ability, or vice versa and this was too quick of an trip down reversing road to dig deeper into that. So I turn to the best friend of every freshman computer science student, printf debugging. Making a few additions here and there to the smali code we’re on the way to getting the information we want.

 const-string v2, "First Parameter, P0"
invoke-static {v2, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

 const-string v2, "Second Parameter, P1"
invoke-static {v2, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

const-string v2, "Generated Signature"
invoke-static {v2, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I

I rebuild the application, now containing our logging additions and install it on the Android device and connect it using adb.

$apktool b modified.apk

$adb shell


From here the screen begins to scroll with various log messages from the android system itself and any apps running on the device, and as luck would have it with a little grepping I’m able to find the secret keys. Plugging this into my ruby code to make the request everything looks correct, but the signature is wrong. I’m confused here, I can see the key that the app is passing into the call, but I’m getting different results so something else must be going on. Back to the smali for some further investigation and it looks like the developers of this app are being a bit clever and doing some sort of obfuscation/encoding on the generated signature. Sneaky sneaky. After a bit more time exploring the smali I find the function that does the obfuscating, and its a mess of shifts, jumps, ands, ors, and while the code is all there to do it it’d probably be a mess to duplicate correctly and debug in my scripting language of choice, here ruby. Mulling this over for a few minutes, I remember jruby, a version of ruby implemented in java that allows the use of Java library components in ruby scripts.

I’m thinking that if it can load anything from the java librairies it can probably load and execute code within jar files without much trouble, and apk files are basically just a special breed of jar files I was on the right track. Returning to our previous apk, decompressing it, and using the dex2jar program I have a jar file representation of the target apk. My script simply needs to add

require 'java'
require './jars/target_app.jar'
require './jars/appropriate_android_version.jar'
java_import 'ca' do |classname|

I now can call the obfuscation method, and any other methods within the ca class within my script. With this, mission was accomplished, I was able to include any behaviour exposed to the android app within my script.

  obs_arr = ApkObsfuscator.a(byte_arr)
  signature = String.from_java_bytes(obs_arr)

Knowing what I know now I would have leveraged jruby in the beginning and wrote minimal amount of glue code while calling the methods that the app developer created to do the brunt of the work. I believe that this opens up quite a few interesting possibilities for things to do with apks as far as code reuse, nicely scriptable testing, dynamic analysis for reversing, and whatever other creative things that anyone reading this can come up with. The nice thing is that the better written and more modular the code from the apk the more pathways open up. After completing this I searched around to see if anyone else had taken the same approach, and came up empty, perhaps I went the long way around on this and theres easier ways of getting the same effect?