Hacking Android is a huge topic, you have the Linux kernel, native code applications and normal Android applications that run on top of the Dalvik VM, a huge attack surface with the wireless, bluetooth, USB, NFC and various other interfaces.
This post is going to be a very short introduction to the platform as well as introducing some very basic analysis techniques for analyzing an Android application.
For this post I will be using a HTC Desire HD running an unrooted Android 2.3.5, this is an old version of Android, running on an old device but it will be fine for the purposes of this post.
The host machine that I'll be using is running 64bit Gentoo running the Linux kernel version 4.0.5.
Setting Up The Environment
The first thing you need to do if you want to analyze an Android device is to install the SDK.
Depending on your system, you might need to install both the Android Studio as well as the platform tools, its important that you have the platform-tools directory because that is the directory that contains the adb binary.
adb is the Android Debug Bridge and it's used to do any sort of debugging of any android device. Without this application, debugging Android will be very difficult.
On my Windows computer this was installed to C:\Users\User\AppData\Local\Android\sdk\platform-tools.
On my Debian-based system it was installed to $HOME/Android/Sdk/platform-tools and on my Gentoo system it was installed to /usr/bin.
Where ever it is installed to, it's best to include this directory in your PATH variable so that you can run it with cd'ing to that directory or having to put the whole file path in every time.
This is optional but on Linux I've been unable to get adb to work with running it as root, instead of having to use sudo all the time I set the permissions to the adb binary to 4750
and the ownership to root:wheel
, this makes it a setuid binary and so will run with root permissions but only for users in the wheel group.
The permissions look as follows:
| user@exploit ~ $ ls -l `which adb`
-rwsr-x--- 1 root wheel 156128 Aug 9 01:13 /usr/bin/adb
|
Exploring The System Using ADB
Firstly the Android device needs to be connected to the host machine using USB.
After that we need to enable USB debugging, on my test device the setting is in Settings->Applications->Development:
You will need to confirm this:
We can now use adb to get a shell on the Android device and take a look around, first let's check the version of the Linux kernel that it's running:
| user@exploit ~ $ adb shell
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
$ pwd
/
$ uname -a
uname: permission denied
$ cat /proc/version
Linux version 2.6.35.10-g931a37e (htc-kernel@and18-2) (gcc version 4.4.0 (GCC) ) #1 PREEMPT Wed Nov 9 14:04:03 CST 2011
|
So as you can see it is, in fact, running Linux version 2.6.35 but in some sort of restricted environment.
Let's check to see some details of the user that we have been logged in as:
| $ whoami
whoami: permission denied
$ w
w: permission denied
$ cat /etc/passwd
/etc/passwd: No such file or directory
|
As you can see due to the restricted environment, the normal methods aren't working.
But there is an easy way to figure this out:
| $ ps | grep ' ps'
grep: permission denied
|
So that didn't work either, but there is a way to use grep on the output of these commands:
| $ exit
user@exploit ~ $ adb shell ps | grep ' ps'
shell 5968 5967 944 332 00000000 afd0b83c R ps
|
Here we can see we're running at the user shell. Also note that we can run the commands using adb but then pipe the output to applications running on our host system to sort through the data.
Knowing our username we can now see what shell we are running in:
| user@exploit ~ $ adb shell ps | grep shell
shell 6062 29118 788 336 c009ccc8 afd0c78c S /system/bin/sh
shell 6063 6062 944 332 00000000 afd0b83c R ps
shell 29118 1 3464 216 ffffffff 00000000 S /sbin/adbd
|
So this is clearly a Linux system but its very different from most Linux systems, let's have a look at the directories under /:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | user@exploit ~ $ adb shell ls -l /
drwxr-xr-x root system 2015-07-28 18:35 app-cache
dr-x------ root root 2015-07-28 18:33 config
lrwxrwxrwx root root 2015-07-28 18:33 sdcard -> /mnt/sdcard
drwxr-xr-x root root 2015-07-28 18:33 acct
drwxrwxr-x root system 2015-07-28 18:33 mnt
lrwxrwxrwx root root 2015-07-28 18:33 vendor -> /system/vendor
lrwxrwxrwx root root 2015-07-28 18:33 d -> /sys/kernel/debug
lrwxrwxrwx root root 2015-07-28 18:33 etc -> /system/etc
drwxrwx--- system cache 2015-08-15 19:00 cache
drwx------ root root 2015-08-16 09:53 devlog
-rw-r--r-- root root 728 1970-01-01 01:00 ueventd.spade.rc
-rw-r--r-- root root 4429 1970-01-01 01:00 ueventd.rc
-rw-r--r-- root root 0 1970-01-01 01:00 ueventd.goldfish.rc
drwxr-xr-x root root 2012-11-18 05:06 system
drwxr-xr-x root root 2015-07-28 18:32 sys
drwxr-x--- root root 1970-01-01 01:00 sbin
dr-xr-xr-x root root 1970-01-01 01:00 proc
-rwxr-x--- root root 7423 1970-01-01 01:00 init.spade.rc
-rwxr-x--- root root 21309 1970-01-01 01:00 init.rc
-rwxr-x--- root root 1677 1970-01-01 01:00 init.goldfish.rc
-rwxr-x--- root root 107216 1970-01-01 01:00 init
-rw-r--r-- root root 118 1970-01-01 01:00 default.prop
drwxrwx--x system system 2015-02-16 07:05 data
-rw-r--r-- root root 1401 1970-01-01 01:00 cwkeys
-rw-r--r-- root root 460 1970-01-01 01:00 bootcomplete.rc
drwx------ root root 2011-11-09 05:59 root
drwxr-xr-x root root 2015-08-10 08:39 dev
|
Again, some of these are familiar (like etc, proc, dev...) but directories like system, acct and app-cache are less familiar.
I'm not going to go through the whole of Android, the point of this section was to demonstrate that this is a Linux system but not 1 that will seem totally familiar with Linux admins.
There are, however, a couple of commands I want to mention here, firstly getprop:
| user@exploit ~ $ adb shell getprop | grep build.version
[ro.build.version.incremental]: [208029.5]
[ro.build.version.sdk]: [10]
[ro.build.version.codename]: [REL]
[ro.build.version.release]: [2.3.5]
|
Here I'm just using getprop
to show some information about the build version of Android but you can get a lot of information from this.
The other 1 is logcat, which is basically the system log:
| user@exploit ~ $ adb logcat -t 8
--------- beginning of /dev/log/system
--------- beginning of /dev/log/main
D/dalvikvm(11665): GC_CONCURRENT freed 513K, 37% free 5018K/7879K, external 0K/0K, paused 3ms+2ms
D/dalvikvm(14049): GC_EXPLICIT freed 13K, 41% free 4222K/7047K, external 0K/0K, paused 102ms
D/dalvikvm(11665): GC_CONCURRENT freed 545K, 36% free 5193K/8071K, external 0K/0K, paused 2ms+2ms
D/dalvikvm(11665): GC_CONCURRENT freed 594K, 36% free 5338K/8263K, external 0K/0K, paused 9ms+2ms
D/dalvikvm(11665): GC_CONCURRENT freed 779K, 38% free 5355K/8519K, external 0K/0K, paused 3ms+11ms
D/dalvikvm(11665): GC_CONCURRENT freed 831K, 37% free 5428K/8583K, external 0K/0K, paused 2ms+2ms
D/dalvikvm(11665): GC_CONCURRENT freed 857K, 38% free 5414K/8647K, external 0K/0K, paused 2ms+3ms
D/dalvikvm(11665): GC_CONCURRENT freed 721K, 37% free 5460K/8647K, external 0K/0K, paused 4ms+6ms
|
Here I'm just outputing the last 8 lines of the log, as you can see it's an actual built in command into adb, but you can run logcat from inside the shell too.
logcat is very useful for debugging and well as showing some information disclosure vulnerabilities that might exist in an Android application, but we'll get to that a bit later :-)
Installing And Running The Challenge App
For the purposes of this post I created a little, very basic, challenge application, which you can download from here.
You can install the application using adb:
| user@exploit ~ $ adb push Android/src/challenge1.apk /data/local/tmp/
2927 KB/s (1052648 bytes in 0.351s)
user@exploit ~ $ adb shell pm install /data/local/tmp/challenge1.apk
pkg: /data/local/tmp/challenge1.apk
Success
|
Now that the application is installed we can run it and have a look at what it does.
Starting the application shows us this:
Putting in some text in to the field and clicking on the Check Password button shows us this:
So its clear what we have to try and do here.
Android Applications
Android applications come in apk format, these are just Java archive file:
| user@exploit ~/Android/src $ file challenge1.apk
challenge1.apk: Java archive data (JAR)
|
These are very similar to zip files and can be unzipped using the unzip utility:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | user@exploit ~/Android/src $ mkdir challenge1
user@exploit ~/Android/src $ cd challenge1
user@exploit ~/Android/src/challenge1 $ unzip ../challenge1.apk
Archive: ../challenge1.apk
inflating: AndroidManifest.xml
inflating: res/anim/abc_fade_in.xml
inflating: res/anim/abc_fade_out.xml
inflating: res/anim/abc_grow_fade_in_from_bottom.xml
inflating: res/anim/abc_popup_enter.xml
inflating: res/anim/abc_popup_exit.xml
inflating: res/anim/abc_shrink_fade_out_from_bottom.xml
...
inflating: res/layout/notification_template_lines.xml
inflating: res/layout/notification_template_media.xml
inflating: res/layout/notification_template_part_chronometer.xml
inflating: res/layout/notification_template_part_time.xml
inflating: res/layout/select_dialog_item_material.xml
inflating: res/layout/select_dialog_multichoice_material.xml
inflating: res/layout/select_dialog_singlechoice_material.xml
inflating: res/layout/support_simple_spinner_dropdown_item.xml
inflating: res/menu/menu_main.xml
extracting: res/mipmap-hdpi-v4/ic_launcher.png
extracting: res/mipmap-mdpi-v4/ic_launcher.png
extracting: res/mipmap-xhdpi-v4/ic_launcher.png
extracting: res/mipmap-xxhdpi-v4/ic_launcher.png
extracting: resources.arsc
inflating: classes.dex
inflating: META-INF/MANIFEST.MF
inflating: META-INF/CERT.SF
inflating: META-INF/CERT.RSA
|
As you will see there are a lot of files in res/
, I've shortened it here.
One of the most important files is AndroidManifest.xml
, this contains the configuration of the application, including activity, intent and permissions declarations.
But as you can see this is some sort of binary file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | user@exploit ~/Android/src/challenge1 $ file AndroidManifest.xml
AndroidManifest.xml: data
user@exploit ~/Android/src/challenge1 $ cat AndroidManifest.xml
P4Rvª¸.2Dx¬À,J^x.fz
versionCode
minSdkVersiontargetSdkVersion versionName
allowBackupiconlabelthemenameandroid*http://schemas.android.com/apk/res/androidpackageplatformBuildVersionCodeplatformBuildVersionNammanifest+ph.exploit.crack.cha5.1.1-181972uses-sdkge11.022
intent-filteractionandroid.intent.action.MAIcategory android.intent.category.LAUNCHER,nActivity
ÿÿÿÿ
ÿÿÿÿÿÿÿÿ
ÿÿÿÿ
ÿÿÿÿ
ÿÿÿLÿÿÿÿÿÿÿÿ
ÿÿÿÿ
ÿÿÿÿ ÿÿÿÿÿÿÿÿt
ÿÿÿÿÿÿÿÿ
ÿÿÿw
ÿÿÿÿ
ÿÿÿÿ
ÿÿÿÿÿÿÿLÿÿÿÿÿÿÿÿ
ÿÿÿÿ
$ÿÿÿÿÿÿÿÿ8ÿÿÿÿÿÿÿÿ
ÿÿÿÿÿÿÿÿ8ÿÿÿÿÿÿÿÿ
ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
|
It's actually binary XML.
We can manually convert this to plain XML using something like AXMLPrinter2 but I'll show an easier way to look at this later.
Another important file is the classes.dex
file. This contains all of our Java code.
Most code that runs on Android applications, including most of the Android Framework, is Java, but instead of compiling to Java bytecode, it is compiled into Dalvik bytecode (and stored in .dex or .odex files).
Again, this could be manually decompiled back to Java using dex2jar and looked at using jd-gui but I'll show a better way of doing this too.
Doing A Very Basic Static Analysis
To end this post I'll crack this challenge while demonstrating a quick basic analysis of the apk file using a tool called androguard created by Anthony Desnos.
Androguard is a python toolset for analyzing apk files.
Its very easy to setup, providing you have python and git installed you just run:
| git clone https://github.com/androguard/androguard.git
|
This will create a directory in the current directory called androguard.
Now you just need to make sure you have the latest version of IPython installed, you can do that by running:
Now just cd to the androguard directory and you should see the following (or something very similar):
| user@exploit ~/tools/androguard $ ls
androarsc.py androaxml.py androdd.py androdis.py androguard androlyze.py androsim.py CHANGELOG elsim LICENCE-2.0 README.md tests
androauto.py androcsign.py androdiff.py androgexf.py androgui.py androsign.py apkviewer.py demos examples Makefile setup.py tools
|
The tool we'll be using is androlyze.py
, we can start it by running:
| user@exploit ~/tools/androguard $ ./androlyze.py -s
Androlyze version 3.0
In [1]:
|
Now we need to import our apk file:
| In [1]: a,d,dx = AnalyzeAPK('/home/user/Android/src/challenge1.apk', decompiler='dad')
In [2]:
|
Here we are using the dad decompiler, created by Geoffroy Gueguen, that comes with androguard and selecting the challenge apk file.
Now we can look at this application in more detail:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 | In [2]: a.get_activities()
Out[2]: ['ph.exploit.crack.challenge1.crackchallenge1.MainActivity']
In [3]: a.get_main_activity()
Out[3]: u'ph.exploit.crack.challenge1.crackchallenge1.MainActivity'
In [4]: a.get_permissions()
Out[4]: []
In [5]: a.get_receivers()
Out[5]: []
In [6]: print a.xml['AndroidManifest.xml'].toxml()
<?xml version="1.0" ?><manifest android:versionCode="1" android:versionName="1.0" package="ph.exploit.crack.challenge1.crackchallenge1" platformBuildVersionCode="22" platformBuildVersionName="5.1.1-1819727" xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="22">
</uses-sdk>
<application android:allowBackup="true" android:icon="@7F030000" android:label="@7F060012" android:theme="@7F080077">
<activity android:label="@7F060012" android:name="ph.exploit.crack.challenge1.crackchallenge1.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN">
</action>
<category android:name="android.intent.category.LAUNCHER">
</category>
</intent-filter>
</activity>
</application>
</manifest>
In [7]:
|
As you can see this is a very basic application, but we can now see the contents of the AndroidManifest.xml file.
An activity is basically just a screen, or, to relate it to a web application, a page. The main activity is the first activity that is shown to the user.
Let's try to look at some of the code.
First we'll print the different methods which are part of the main activity:
| In [7]: for m in d.CLASS_Lph_exploit_crack_challenge1_crackchallenge1_MainActivity.get_methods():
...: print m.get_name()
...:
<init>
onClick
onCreate
onCreateOptionsMenu
onOptionsItemSelected
In [8]:
|
The first place to look here is the onCreate method.
This is the code that gets run when the application first starts:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 | In [8]: d.CLASS_Lph_exploit_crack_challenge1_crackchallenge1_MainActivity.METHOD_onCreate.source()
protected void onCreate(android.os.Bundle p15)
{
super.onCreate(p15);
android.widget.RelativeLayout v1_1 = new android.widget.RelativeLayout(this);
v1_1.setBackgroundColor(-16777216);
android.widget.RelativeLayout$LayoutParams v0_1 = new android.widget.RelativeLayout$LayoutParams(-2, -2);
android.widget.RelativeLayout$LayoutParams v2_1 = new android.widget.RelativeLayout$LayoutParams(-2, -2);
android.widget.RelativeLayout$LayoutParams v4_1 = new android.widget.RelativeLayout$LayoutParams(-2, -2);
android.widget.RelativeLayout$LayoutParams v8_1 = new android.widget.RelativeLayout$LayoutParams(-2, -2);
android.widget.RelativeLayout$LayoutParams v7_1 = new android.widget.RelativeLayout$LayoutParams(-2, -2);
v0_1.addRule(14);
v0_1.addRule(15);
this.checkButton = new android.widget.Button(this);
this.checkButton.setText("Check Password");
this.checkButton.setBackgroundColor(-1);
this.checkButton.setTextColor(-16777216);
this.checkButton.setId(1);
this.checkButton.setClickable(1);
this.checkButton.setOnClickListener(this);
this.inputBox = new android.widget.EditText(this);
this.inputBox.setBackgroundColor(-1);
this.inputBox.setTextColor(-16711936);
this.inputBox.setId(2);
v2_1.addRule(2, this.checkButton.getId());
v2_1.addRule(14);
v2_1.setMargins(0, 0, 0, 50);
android.widget.TextView v3_1 = new android.widget.TextView(this);
v3_1.setText("Please enter the secret password:");
v3_1.setTextColor(-1);
v3_1.setId(3);
v4_1.addRule(2, this.inputBox.getId());
v4_1.addRule(14);
v4_1.setMargins(0, 0, 0, 50);
android.widget.TextView v9_1 = new android.widget.TextView(this);
v9_1.setText("Welcome to Challenge 1!");
v9_1.setTextColor(-1);
v9_1.setId(4);
v8_1.addRule(2, v3_1.getId());
v8_1.addRule(14);
v8_1.setMargins(0, 0, 0, 50);
this.resultText = new android.widget.TextView(this);
this.resultText.setId(5);
this.resultText.setVisibility(4);
v7_1.addRule(3, this.checkButton.getId());
v7_1.addRule(14);
v7_1.setMargins(0, 50, 0, 0);
this.inputBox.setWidth(((int) android.util.TypedValue.applyDimension(1, 1133903872, this.getResources().getDisplayMetrics())));
v1_1.addView(this.checkButton, v0_1);
v1_1.addView(this.inputBox, v2_1);
v1_1.addView(v3_1, v4_1);
v1_1.addView(v9_1, v8_1);
v1_1.addView(this.resultText, v7_1);
this.setContentView(v1_1);
return;
}
In [9]:
|
We can see here that the actual interface for this application is created dynamically using Java.
As you can see from line 20, this main class is registered as the onClickListener for the button that checks the value of the password.
This means that when you press the Check Password button, it will run the onClick method in this class.
So let's look at the code for that method:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | In [9]: d.CLASS_Lph_exploit_crack_challenge1_crackchallenge1_MainActivity.METHOD_onClick.source()
public void onClick(android.view.View p4)
{
if (p4 == this.checkButton) {
if (this.inputBox.getText().toString().equals("supersecurepassword") != 1) {
this.resultText.setText("Incorrect password! :\'-(");
this.resultText.setTextColor(-65536);
this.resultText.setVisibility(0);
} else {
this.resultText.setText("Well done!! Challenge passed! :-)");
this.resultText.setTextColor(-16711936);
this.resultText.setVisibility(0);
}
}
return;
}
In [10]:
|
So here it's obvious that the password is supersecurepassword.
We can check that on the application itself:
It was fine this time but there are times when a decompilation will not be enough, the decompiler will not be able to recreate the source code well enough to get the right result.
In these cases you can use the disassembler like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 | In [10]: d.CLASS_Lph_exploit_crack_challenge1_crackchallenge1_MainActivity.METHOD_onClick.show()
########## Method Information
Lph/exploit/crack/challenge1/crackchallenge1/MainActivity;->onClick(Landroid/view/View;)V [access_flags=public]
########## Params
- local registers: v0...v3
- v4: android.view.View
- return: void
####################
***************************************************************************
onClick-BB@0x0 :
0 (00000000) const/4 v2, 0
1 (00000002) iget-object v0, v3, Lph/exploit/crack/challenge1/crackchallenge1/MainActivity;->checkButton Landroid/widget/Button;
2 (00000006) if-ne v4, v0, 41 [ onClick-BB@0xa onClick-BB@0x58 ]
onClick-BB@0xa :
3 (0000000a) iget-object v0, v3, Lph/exploit/crack/challenge1/crackchallenge1/MainActivity;->inputBox Landroid/widget/EditText;
4 (0000000e) invoke-virtual v0, Landroid/widget/EditText;->getText()Landroid/text/Editable;
5 (00000014) move-result-object v0
6 (00000016) invoke-virtual v0, Ljava/lang/Object;->toString()Ljava/lang/String;
7 (0000001c) move-result-object v0
8 (0000001e) const-string v1, 'supersecurepassword'
9 (00000022) invoke-virtual v0, v1, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
10 (00000028) move-result v0
11 (0000002a) const/4 v1, 1
12 (0000002c) if-ne v0, v1, 23 [ onClick-BB@0x30 onClick-BB@0x5a ]
onClick-BB@0x30 :
13 (00000030) iget-object v0, v3, Lph/exploit/crack/challenge1/crackchallenge1/MainActivity;->resultText Landroid/widget/TextView;
14 (00000034) const-string v1, 'Well done!! Challenge passed! :-)'
15 (00000038) invoke-virtual v0, v1, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
16 (0000003e) iget-object v0, v3, Lph/exploit/crack/challenge1/crackchallenge1/MainActivity;->resultText Landroid/widget/TextView;
17 (00000042) const v1, -16711936
18 (00000048) invoke-virtual v0, v1, Landroid/widget/TextView;->setTextColor(I)V
19 (0000004e) iget-object v0, v3, Lph/exploit/crack/challenge1/crackchallenge1/MainActivity;->resultText Landroid/widget/TextView;
20 (00000052) invoke-virtual v0, v2, Landroid/widget/TextView;->setVisibility(I)V [ onClick-BB@0x58 ]
onClick-BB@0x58 :
21 (00000058) return-void
onClick-BB@0x5a :
22 (0000005a) iget-object v0, v3, Lph/exploit/crack/challenge1/crackchallenge1/MainActivity;->resultText Landroid/widget/TextView;
23 (0000005e) const-string v1, "Incorrect password! :'-("
24 (00000062) invoke-virtual v0, v1, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
25 (00000068) iget-object v0, v3, Lph/exploit/crack/challenge1/crackchallenge1/MainActivity;->resultText Landroid/widget/TextView;
26 (0000006c) const/high16 v1, -1
27 (00000070) invoke-virtual v0, v1, Landroid/widget/TextView;->setTextColor(I)V
28 (00000076) iget-object v0, v3, Lph/exploit/crack/challenge1/crackchallenge1/MainActivity;->resultText Landroid/widget/TextView;
29 (0000007a) invoke-virtual v0, v2, Landroid/widget/TextView;->setVisibility(I)V
30 (00000080) goto -20 [ onClick-BB@0x58 ]
***************************************************************************
########## XREF
####################
In [11]:
|
Here we can see the actual dalvik disassembly and decompile it ourself if need be.
Conclusion
So we've learnt a bit about Android and how we can begin to analyze the system more.
We have been introduced to the basic layout of Android and Android applications, as well as a few tools that can be used to look a little closer at them.
Hopefully this blog post has done a decent job of introducing the basics of Android and given ideas for further exploration.
Further Reading
Android Hacker's Handbook by Joshua J. Drake, Zach Lanier, Collin Mulliner, Pau Oliva Fora, Stephen A. Ridley, Georg Wicherski