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. :)