Android Hacking - Part 4

Decompiling, AndroidManifest revisited, Permissions and more

·

5 min read

Decompiling

Preparation

  1. 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>
    

  2. Once we've grabbed our apk, we can use apktool for Decompiling and building

     apktool 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

  1. 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.

  2. package - It's a unique identifier for this application. If we install another app with the same identifier then we'll get an error.

  3. <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.

  4. <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 the protectionLevel 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)

  5. <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.

  6. <application>

    1. allowBackup="true" - Test out to see what data is being backed up

    2. android:debuggable="true" - This means we can debug this app, typically false. But we can always enable it and recompile, build and install the application.

    3. 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.

    4. 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.

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

  1. 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.

  2. 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.

  3. 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!

  4. signatureOrSystem: Don't worry about this one.