Android Hacking - Part 4
Decompiling, AndroidManifest revisited, Permissions and more
Photo by Markus Spiske on Unsplash
Decompiling
Preparation
Downloading an .apk from Google App Store. We use
adb
to grab app files from the play store from our emulated device / physical device.$ adb connect <IP of emulator/device> $ adb shell $ pm list packages $ pm path $ adb pull <PATH>
Once we've grabbed our apk, we can use
apktool
for Decompiling and buildingapktool d <APK> #Decompiling apktool b <APP PATH> #Building
💡Unzipping vs Decompiling an app is very different. Unzipping provides a non readable AndroidManifest.xml file whereas decompiling gives us a nice plaint text xml document. Further, the classes.dex file is available while unzipping however it is decompiled into smali code when decompiling.
Hands-on Decompiling - Part 1
Let's use apktool
to decompile our test application.
Now, we can see we've successfully decompiled the application and the same folder now shows something similar to what we saw when unzipping but the structure is a little different and all the usual suspects can be found in the original
folder. We have the smali
directory which is the decompiled classes.dex
We can see that the AndroidManifest.xml
is no longer the garbled text but is in plaintext XML and is readable. Feel free to open this in VSCode to scroll through the decompiled code or jadx-gui
which doesn't need apktool
to decompile as it can do that once the apk is loaded.
Take some time to just walk through these files and notice the differences.
AndroidManifest.xml
One of the most important files to analyze when hacking Android apps. Let's take this privacy.apk
example app from this Udemy course. You can use apktool
or jadx
for this purpose.
Let's jump in now! We start top to bottom line by line, let's begin with the first line
compileSDKVersion="30"
,compileSdkVersionCodename="1"
- This is the API level and the Android version which can help understand if there are lower versions supported with known vulnerabilities to attack this apk.package
- It's a unique identifier for this application. If we install another app with the same identifier then we'll get an error.<uses-permission>
- Application has the ability to use these, doesn't mean it uses it. In this case, it can read contacts, access internet but also can read external storage. Whenever an app needs access these are included in the AndroidManifest file.<permission>
- This is an application describing its own permission (Exploitable fun evil laugh). It has a label describing it and the name is for requesting this permissions and theprotectionLevel
shows dangerous. If it's performing a sensitive task and it can use permissions to share information with other apps if approved by user. (Important entry)<queries>
- If application wants to exchange information from another application. It tells the mentioned application that I'm on the smartphone and I will ask for data. If we write our own exploitation apps we will need this.<application>
allowBackup="true"
- Test out to see what data is being backed upandroid:debuggable="true"
- This means we can debug this app, typically false. But we can always enable it and recompile, build and install the application.android:extractNativeLibs="false"
- This flag tells us if the libraries are compressed or not. When we talk about FRIDA later, we will need it to be false to inject libraries.android:networkSecurityConfig="@xml/network_security_config"
- This is a VERY important file. If this file doesn't exist then we can create our own. This is talking about certificate pinning and more.
Providers, receiver, service, activity and intent which will be discussed in detail in the upcoming blog posts.
Permissions
We've discussed the sandboxing nature of the Android architecture in an earlier post here. I highly recommend reading it before proceeding.
The Android system assigns a user_id to every application and all the permissions are defined in the /etc/permissions/platform.xml
specifically user_ids.
If User_2
wants to access to a different application that only User_1 has access to, we can define this in the /data/system/packages.xml
. It is tracked if the user has been granted permissions to access other application data. This file gives us or denies us access to things like photos, camera etc.
We would have some system users like adb shell which have predefined user_ids at a specific range and are defined in the android_filesystem_config.h
file.
We've seen the permissions in the AndroidManifest.xml
and we have to define them there. If not, the application would crash.
Custom Permissions
Applications can exchange data between each other, say this could be custom to suit our needs. When creating a custom permission it can look like this
<permission
android:label="Allow reading secrets"
android:name="com.text.example.READ_SECRETS"
android:protectionLevel="dangerous"
/>
Now this is problematic because we can create an attacking app which can use these permissions like the following
<uses-permission ns0:name="android.permission.INTERNET"/>
<uses-permission ns0:name="com.text.example.READ_SECRETS"/>
Protection Levels
The different protection levels are the following:
Dangerous : Provides a popup to the user to Allow or Deny, however this can be a bad decision given users cannot be trusted to be vigilant.
Normal : Users are not being informed and the permissions are being granted. We can't use this level for high risk permissions like keys/camera/microphone etc. Thankfully, Android does this automatically for us unless we create custom permissions.
Signature : Applications signed with the same key can access the data. We would need the private key of the app to access the data which is kept well ......private!
signatureOrSystem: Don't worry about this one.