Android Application Basics Notes

By Hacktricks

Note: This information is taken from https://book.hacktricks.xyz/mobile-pentesting/android-app-pentesting/android-applications-basics

Android Security Model

There are two layers:

  • The OS, which keeps installed applications isolated from one another.

  • The application itself, which allows developers to expose certain functionalities and configures application capabilities.

UID Separation

Each application is assigned a specific User ID. This is done during the installation of the app so the app can only interact with files owned by its User ID or shared files. Therefore, only the app itself, certain components of the OS and the root user can access the apps data.

UID Sharing

Two applications can be configured to use the same UID. This can be useful to share information, but if one of them is compromised the data of both applications will be compromised. This is why this behaviour is discourage. To share the same UID, applications must define the same android:sharedUserId value in their manifests.

Sandboxing

The Android Application Sandbox allows to run each application as a separate process under a separate user ID. Each process has its own virtual machine, so an appโ€™s code runs in isolation from other apps. From Android 5.0(L) SELinux is enforced. Basically, SELinux denied all process interactions and then created policies to allow only the expected interactions between them.

Permissions

When you installs an app and it ask for permissions, the app is asking for the permissions configured in the uses-permission elements in the AndroidManifest.xml file. The uses-permission element indicates the name of the requested permission inside the name attribute. It also has the maxSdkVersion attribute which stops asking for permissions on versions higher than the one specified. Note that android applications don't need to ask for all the permissions at the beginning, they can also ask for permissions dynamically but all the permissions must be declared in the manifest.

When an app exposes functionality it can limit the access to only apps that have a specified permission. A permission element has three attributes:

  • The name of the permission

  • The permission-group attribute, which allows for grouping related permissions.

  • The protection-level which indicates how the permissions are granted. There are four types:

    • Normal: Used when there are no known threats to the app. The user is not required to approve it.

    • Dangerous: Indicates the permission grants the requesting application some elevated access. Users are requested to approve them.

    • Signature: Only apps signed by the same certificate as the one exporting the component can be granted permission. This is the strongest type of protection.

    • SignatureOrSystem: Only apps signed by the same certificate as the one exporting the component or apps running with system-level access can be granted permissions

Pre-Installed Applications

These apps are generally found in the /system/app or /system/priv-app directories and some of them are optimised (you may not even find the classes.dex file). Theses applications are worth checking because some times they are running with too many permissions (as root).

  • The ones shipped with the AOSP (Android OpenSource Project) ROM

  • Added by the device manufacturer

  • Added by the cell phone provider (if purchased from them)

Rooting

In order to obtain root access into a physical android device you generally need to exploit 1 or 2 vulnerabilities which use to be specific for the device and version. Once the exploit has worked, usually the Linux su binary is copied into a location specified in the user's PATH env variable like /system/xbin.

Once the su binary is configured, another Android app is used to interface with the su binary and process requests for root access like Superuser and SuperSU (available in Google Play store).

Note that the rooting process is very dangerous and can damage severely the device

Implications

Once a device is rooted, any app could request access as root. If a malicious application gets it, it can will have access to almost everything and it will be able to damage the phone.

Android Application Fundamentals

  • Android applications are in the APK file format. APK is basically a ZIP file. (You can rename the file extension to .zip and use unzip to open and see its contents.)

  • APK Contents (Not exhaustive)

    • AndroidManifest.xml

    • resources.arsc/strings.xml

    • resources.arsc: a file containing precompiled resources, such as binary XML for example.

      • res/xml/files_paths.xml

    • META-INF/

      • Certificate lives here!

    • classes.dex

      • Dalvik bytecode for application in the DEX file format. This is the Java (or Kotlin) code compiled that the application will run by default.

    • lib/

      • Native libraries for the application, by default, live here! Under the lib/ directory, there are the cpu-specific directories.

        • armeabi: compiled code for all ARM based processors only

        • armeabi-v7a: compiled code for all ARMv7 and above based processors only

        • x86: compiled code for X86

        • mips: compiled code for MIPS processors only

    • assets/

      • Any other files that may be needed by the app.

      • Additional native libraries or DEX files may be included here. This can happen especially when malware authors want to try and โ€œhideโ€ additional code, native or Dalvik, by not including it in the default locations.

    • res/

      • the directory containing resources not compiled into resources.arsc

Dalvik & Smali

Most Android applications are written in Java. Kotlin is also supported and interoperable with Java. For ease, for the rest of this workshop, when I refer to โ€œJavaโ€, you can assume that I mean โ€œJava or Kotlinโ€. Instead of the Java code being run in Java Virtual Machine (JVM) like desktop applications, in Android, the Java is compiled to the _Dalvik Executable (DEX) bytecode_** format**. For earlier versions of Android, the bytecode was translated by the Dalvik virtual machine. For more recent versions of Android, the Android Runtime (ART) is used. If developers, write in Java and the code is compiled to DEX bytecode, to reverse engineer, we work the opposite direction.

Smali is the human readable version of Dalvik bytecode. Technically, Smali and baksmali are the name of the tools (assembler and disassembler, respectively), but in Android, we often use the term โ€œSmaliโ€ to refer to instructions. If youโ€™ve done reverse engineering or computer architecture on compiled C/C++ code. SMALI is like the assembly language: between the higher level source code and the bytecode.

Intents

Intents are the primary means by which Android apps communicate between their components or with other apps. These message objects can also carry data between apps or component, similar to how GET/POST requests are used in HTTP communications.

So an Intent is basically a message that is passed between components. Intents can be directed to specific components or apps, or can be sent without a specific recipient.

To be simple Intent can be used:

  • To start an Activity, typically opening a user interface for an app

  • As broadcasts to inform the system and apps of changes

  • To start, stop, and communicate with a background service

  • To access data via ContentProviders

  • As callbacks to handle events

Improper implementation could result in data leakage, restricted functions being called and program flow being manipulated.

Intent-Filter

An Intent Filter specify the types of Intent that an activity, service, or Broadcast Receiver can respond to. It specifies what an activity or service can do and what types of broadcasts a Receiver can handle. It allows the corresponding component to receive Intents of the declared type. Intent Filters are typically defined via the AndroidManifest.xml file. For Broadcast Receiver it is also possible to define them in coding. An Intent Filter is defined by its category, action and data filters. It can also contain additional metadata.

In Android, an activity/service/content provider/broadcast receiver is public when exported is set to true but a component is also public if the manifest specifies an Intent filter for it. However, developers can explicitly make components private (regardless of any intent filters) by setting the ** exported attribute to false** for each component in the manifest file. Developers can also set the permission attribute to require a certain permission to access the component, thereby restricting access to the component.

Implicit Intents

Intents are programatically created using an Intent constructor:

Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));

The Action of the previously declared intent is ACTION_SEND and the Extra is a mailto Uri (the Extra if the extra information the intent is expecting).

This intent should be declared inside the manifest as in the following example:

<activity android:name="ShareActivity">
	<intent-filter>
       <action android:name="android.intent.action.SEND" />
       <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

An intent-filter needs to match the action, data and category to receive a message.

The "Intent resolution" process determine which app should receive each message. This process considers the priority attribute, which can be set in the intent-filter declaration, and the one with the higher priority will be selected. This priority can be set between -1000 and 1000 and applications can use the SYSTEM_HIGH_PRIORITY value. If a conflict arises, a "choser" Window appears so the user can decide.

Explicit Intents

An explicit intent specifies the class name it's targeting:

Intent downloadIntent = new (this, DownloadService.class):

In other applications in order to access to the previously declared intent you can use:

Intent intent = new Intent();
intent.setClassName("com.other.app", "com.other.app.ServiceName");
context.startService(intent);

Last updated