Thursday, October 4, 2012

Building a Better Emulator - Part 1

I prefer using the Android emulator to a real phone for some application assessments for many reasons.  Unfortunately, not all apps run properly on the emulator.  This series of posts will focus on modifications we can make to our emulators to allow more control and flexibility during application assessments.  This first post will focus on controlling device identifiers and numbers.

Sometimes an application will obtain the device phone number and device identifiers and submit these to a remote server, maybe for authentication or authorization (such as white-listing phone numbers per provider).  The easiest way to obtain this information in an application is the use the TelephonyManager class.  We will focus on the following methods of the TelephonyManager class:
  • getDeviceId()
  • getLine1Number()
  • getVoiceMailNumber()
  • getSubscriberId()
  • getSimSerialNumber()
Some details about how this class works can be found here.  Basically these methods are used to access some values that are stored in the base-band emulator.  On Linux, the emulator is a file called  "$ANDROID_SDK_HOME/tools/emulator-arm" and the values are contained in this binary.  By default, the device ID (on the emulator it's the IMEI) is hard-coded as 000000000000000, and our phone number is  1555521%s, where "%s" is the 4 digit TCP port that the emulator is running on.  If we want to control these values on the emulator we are out of luck (without doing some modifications).  It is possible to do a find/replace in the "emulator-arm" binary for the IMEI and this post provides a patch to recompile the "emulator-arm" file to allow for these values to be set in a configuration file which is another alternative.  But even with this patch we can not change the phone number and voicemail number.  The method in this post will involve modifying some Android system libraries to allow for control of these values.

We have two options for performing the modifications: 1) Download the Android source code from the AOSP page, make the modifications in the Java source, and then build a custom version of Android, or 2) we can make the modifications to the compiled system libraries that are present on our Android emulator.  I chose to take option two because of the hardware requirements and testing speed of options one (building Android can take awhile).  So the first step was to find the TelephonyManager files in the Android source.  Note: For the remainder of this post, I will be using Android API 10.

 Not hard to find, they're in the "/frameworks/base/telephony/java/android/telephony/" directory.


Being in the "framework" directory gives us some hints as to where the files exist on the device.  When we build Android, all of these sources will eventually make their way into Dalvik DEX byte-code, and are zipped (but with JAR extension + META-INF directory) along with any other necessary files. They are placed in the "/system/framework/" directory on the device.


When the system boots, the Android system will take the "classes.dex" from each of these system library JARs, verify and optimize them, then store them on the "data" partition in the directory "/data/dalvik-cache/".  We'll need to modify the JARs if we want to make any system library changes.  The JAR that contains our compiled TelephonyManager DEX code is "/system/framework/framework.jar".

We first need to pull this file off the device.  We can then unzip the "framework.jar", and use "baksmali" to disassemble the "classes.dex" file.  Now we can do a simple grep to find our class of interest.


Now lets switch gears quick and get the replacement code ready.  I decided to replace our methods of interest with code that opened a file on the SD card and read the values from there.  The following code can be used as replacement code for the getDeviceId() method.


The code is pretty straightforward.  It reads "/mnt/sdcard/device_ids.txt" and uses some matching to get the desired value.  If at any point an exception occurs, the method logs this and just returns the default value.  The other methods were slightly different, but the concept was the same.

To get the Smali equivalent code, I used "ant" to build the app, them used "apktool" to decode the APK file. From here, it was just a direct replacement into the getDeviceId() method of the "TelephonyManager.smali" file.


With the modifications complete we can reverse the process: convert the Smali code back to DEX with "smali", zip the files back up as "framework.jar", and push the new archive to the "/system/framework/" directory.


The final step is to create a new system partition, and we can use the method posted here.  Restarting the emulator with the new system partition will result in our custom library being loaded.

And there we go! The return of any of these methods is now controlled by the contents of the "/mnt/sdcard/device_ids.txt" file.  For those who want to just make the changes and go, I've included a working version of the "framework.jar" for API 10 if people would like to grab it, push it to your emulator, then build a new system image.  If at any point you no longer want to control these values, you can just remove the "/mnt/sdcard/device_ids.txt" file, and the "real" getXX() method will be called.  If anyone observes any unusual instability or errors, please contact me!  Note: Use this library at your own risk.  I do not suggest using this library on a real device!

To make things even easier, I wrote an application to help manage the "/mnt/sdcard/device_ids.txt" file, so you can make changes instantly.  You can grab the app source or APK file from my Github repositories, as well as the "framework.jar" and a sample "device_ids.txt".


I'll continue to post more changes to help with application assessments over the next few months. :)

-jakev

Friday, August 31, 2012

Maliciously Loading an Application's Native Libraries

I recently reviewed an interesting Android application that was distributed on a per-device basis.  The reason for this is that the application used a unique identifier that was hard-coded into the application.  Generally speaking this is an unsafe process.  However, usually I see secret keys hard-coded into the Java files, which would make it difficult for a malicious application to access.  This application, however, contained a per-device compiled native shared library that contained the key.  How does this affect the overall security of the key? Lets find out.

Some of the guys over at Intrepidus Group posted a few months ago about some of the "gotchas" with using native libraries in your Android application, and this post should complement it.  The first interesting thing about native libraries is that, by default, they have lax read permissions when installed on your device.



The fact that it is world-readable introduces an interesting question - is a third party application able to load this library?  The answer to the question is, well, yes!

For anyone who has read my post on debugging native code, I'm going to use the code from that post here as well (application "DebugNative").  As a refresher for those who have not read it, the application contained a native library which checked a user supplied password against a password generated within the native shared library.  The Java section of the code passed the supplied password to the native library using the JNI, the verification occurred, and the return value indicated if the password was correct.

Lets suppose this password is dynamic generated, or is a per-device password, and we want to access it.  We have a copy of the application so we can investigate!

First I pulled the application APK file off the device and decoded using "apktool".  Next I inspected the "lib/armeabi/" directory for the native libraries.  Running the "file" command on "lib/armeabi/libnative.so" shows that it is stripped, meaning that the symbol table (.symtab) has been removed, but that doesn't mean we cannot call functions from this library by viewing the dynamic symbol table.

 

"generatePassword" seems like a good start.  Using IDA, we can derive the prototype of this function.



Pretty straightforward - it doesn't look like anything is being passed to the function, and the return value (R0) and UI supplied password are compared with the "strcmp" function.  We can assume this function looks like:  char *generatePassword();

Next, we write our own malicious application that trie to load the DebugNative's shared library and use this function.  Our application will start, load its own shared library, execute a function using JNI, and print the result to the log.  All the magic will take place from within our shared library.  The main activity looks like the following (imports omitted):



Now we implement our shared library, "aunative.c".



I'll explain what this function does:
  • First we attempt to open the shared library "/data/data/com.jakev.debugnative/lib/libnative.so" using dlopen().
  • Next we attempt to resolve the symbol for the function "generatePassword" using dlsym().  We store the return in a function pointer, getpassword, that mimics the prototype of the "generatePassword" function.
  • We call the getpassword() function pointer and store the return in the buffer password.
  • We open the file "/mnt/sdcard/password.txt" for binary writing (just in case) and write the contents of password to the file.  We then close the file.
  • Finally, we unload the "libnative.so" shared library with dlclose().
If all works properly, we should see the file "/mnt/sdcard/password.txt" with our password (I hid the password just in case people wanted to try to figure it out themselves using this method or debugging the application).  It's worth noting that this application would require the "WRITE_EXTERNAL_STORAGE" permission.




So that's that problem, what can we do about this?  Googling around you can find a couple of options to help prevent this.  One I have seen used effectively is the keyword static when defining your functions.  This will effectively limit the scope of function and will help restrict access.  Thus our password generating function would look like: static char *generatePassword();

When we attempt to inspect the new shared library we notice that our string is no longer present in the file, anywhere.



Then, when I attempt to run the malicious application with the new DebugNative installed, I notice a return value of -2 in the Android logs, which indicated our call to dlsym() has failed.

I hope this post demonstrates the risk associated with inadequately protecting Android native libraries!

-jakev