Then investigating native android apps communication, you'll sometimes need to perform a
man-in-the-middle attack on the apps, even though they communicate through SSL. Tools like
Charles Webproxy makes this pretty easy.
However Charles "dummy" certificate need to be added to your android instance's cacerts.bks in order to make android apps trust the proxy. If you dont do this, you'll end up with https connection's telling you the certificate cant be trusted. e.g.:
But its actually more problematic then this security warning. If your just looking at the browsers SSL trafic, you'll properly be fine with just clicking Continue, but meny native apps won't communicate with the internet if it can't trust the certificate.
Note: This should work with other proxy/sniffing tools as well, just find their certificate and add that instead.
The good news is this is easily done, you need to perform these steps:
- Make sure your android instance's sdcard partition is large enough to hold the entire /system (its ~100M) 200M will do.
- Pull out the cacerts.bks file
- Add the certificate to it
- Push it back
- Make it persistent (so it works when the instance reboots)
Note: You'll need to start the emulator with the `emulator` tool found in the android sdk, appending `-partition-size 128` to it, else you cant write to the /system partition, even though remounting it read-write.
So lets walk through the steps
SDcard partition size
This is done in AVD Manager. Open it through Eclipse or by typing
android avd
In your terminal. Dont forget to start the emulator from the commandline with the -partition-size parameter mentioned above. Something like
emulator -avd lille21 -partition-size 128
Where lille21 is the name of the instance.
Pull out the cacerts.bks file
This is done by issuing adb's pull command
adb pull /system/etc/security/cacerts.bks cacerts.bks
Add your certificate to cacerts.bks
This is done using keytool with the following command
keytool -keystore cacerts.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -storepass changeit -importcert -trustcacerts -alias somealias -file charles-proxy-ssl-proxying-certificate.crt -noprompt
The above command should output something like:
Certificate was added to keystore
Note: On the Mac, you'll maybe get an error about keytool not being able to find bouncycastle, fix this by getting the lastest provider from
here and put it in your $JAVA_HOME/jre/lib/ext/. (
On the Mac with Lion, thats `/System/Library/Frameworks/JavaVM.framework/Home/lib/ext/`.
Another Note: The charles-proxy-ssl-proxying-certificate.crt is found inside the Charles.app package, e.g `Charles.app/Contents/docs/charles-proxy-ssl-proxying-certificate.crt`.
Third Note: I dont know why the password is changeit, around the internets some have reported it to be "" e.g. nothing.
Push the cacerts.bks file back
First, remount the /system read-write.
adb remount
Second, change the original file's permissions.
adb shell chmod 777 /system/etc/security/cacerts.bks
Third, push the new cacerts.bks.
adb push cacerts.bks /system/etc/security/
Now the file is in place, but you need to reboot the android instance in order to make it read your new file. (And if you reboot it now, you'll loose your new file, you need to make a new system.img file.
Make it persistent (with a new system.img file)
This is done with a tool called, `mkfs.yaffs2.arm`.
Download it here.
Push the mkfs.yaffs2.arm tool to your android instance.
adb push Downloads/mkfs.yaffs2.arm /data/data/temp/mkfs.yaffs2
Make it executable.
adb shell chmod 777 /data/data/temp/mkfs.yaffs2
Make a new system.img on the sdcard partition
Jump into the shell with:
adb shell
Inside the shell type:
/data/data/temp/mkfs.yaffs2 /system /sdcard/system.img
Note: Be sure about the sdcard mount location, on android 2.1 its /sdcard while on android 2.3 its /mnt/sdcard. Check it with the mount command inside the shell
It should output something like this:
mkfs.yaffs2: Android YAFFS2 Tool,Build by PowerGUI
at http://www.openhandsetalliance.org.cn
Building...
Build Ok.
Quit the shell and download the newly generated system.img.
adb pull /sdcard/system.img system.img
Note: Again, watch the sdcard's location!
Kill the emulator and boot the new system.img.
Just kill it or exit it in whatever way you see fit, when its closed, you can put your new system.img inside the instances folder.
On the mac its by default ~/.android/avd/
<avdname>.avd/ . This is properly also true for linux boxes.
cp system.img .android/avd/lille21.avd/
As far as i know you wont be overwriting anything, the emulator normaly loads a system wide "/system" partition found in your sdk directory, but then it finds the instance has its one, it will load that instead.
Note: My instance is called lille21, you've properly called yours something else.
Now your all ready and set
Boot your instance with
emulator -avd lille21 -http-proxy http://yourinterfaceip:8888
And your ready to monitor all kinds of trafic from webpages and even native android applications!
If your using Charles webproxy remember to
enable SSL Proxying.
Ta da! No more certificate trust issues:
Final Note
Ive tried this on android 2.1 and 2.3, not sure if it works on honeycomb (3.0+).
Let me know if you find anything interesting when looking at your favorite app communication :)