Getting Started

This article walks through the process of extracting Android applications from an un-rooted device, reverse engineering those applications, and using auxiliary tools such as automation frameworks and malware analysis tools to identify if the application’s configuration is identified as malware. During this article the following tools are showcased and used:

DROID DETECTIVE 

DroidDetective is a Python tool for analysing Android applications (APKs) for potential malware related behaviour and configurations. When provided with a path to an application (APK file) Droid Detective will make a prediction (using it’s ML model) of if the application is malicious.

 

AUTO DROID 

AutoDroid is a Python tool for programmatically scripting bulk interactions with one or more Android devices. Useful for downloading and extracting all APKs from all connected devices, testing a developed application on multiple devices at once, and more.

 

ADB 

Android Debug Bridge (adb) is a command-line interface tool for communicating with Android devices. The adb command allows for a plethora of device interaction types – including acquiring a shell, installing / uninstalling apps, and interacting with the screen and other hardware accessories. 

Structure of an Application (APK)

To get things started it’s first important to understand the structure of Android applications. Android application’s are commonly written in either Java or Kotlin. When a software engineer wants to create an APK (the Android pacKage), that contains the code and materials that are run on an Android device, they will need to compile that Java or Kotlin source code to a Dalvik executable/ bytecode. This Dalvik executable is a binary that is run on the Android device. This works where each process on the device uses its own virtual machine (VM) which segregates applications. Prior to Android API level 21 (Android 5), this would have been a Dalvik Virtual Machine, and in later versions will instead use the Android Runtime (ART). Both operate in similar fashions, where they simulate a device’s CPUs, registers, and other features while running an application’s compiled Dalvik bytecode.

Decompiling and Disassembling An APK

While it is the Dalvik bytecode that needs to be run on a device, this is not human readable and so if we are to reverse engineer an application we’ll need to decompile it back into a human readable form. This is where Jadx comes in. Using Jadx we can decompile the Dalvik bytecode back into Java. This is often called pseudo Java, as it is not a one for one representation of what the original source code would have been, and instead is the decompiler’s best guess. 

Android APK files also include a file detailing the application configuration, called AndroidManifest.xml. The Android manifest includes information such as:

  • Package name and application ID
  • Application components
  • Intent filters
  • Icons and labels information
  • Permissions
  • Device compatibility information

Retrieving an Application From A Device

Being able to retrieve applications from a device is key in identifying if one of those applications is potentially malware. Before continuing ensure that ADB is enabled on the device being tested – This can be done by going to Settings, About phone, and by tapping Build number seven times. After this go to developer settings and enable USB debugging. Now connect the device and accept any prompts that are displayed. 

Android application’s are not encrypted at rest and so if an APK’s location on a device can be identified it can be retrieved. There are two shell commands that can be used when using ADB on a device (via adb shell) to help with this. These being the pm list packages command which will list all packages on the target device, and pm path <package name> which will return the path to that package’s apk file on device. Once the path has been located the adb pull <path to apk> command can be used to retrieve the APK from a device.

Automating Retrieving and reverse engineering apks

AutoDroid wraps the ability to retrieve Android applications from a device, along with other functionality, to allow for the configurable bulk interaction with an Android device. AutoDroid is configurable with a JSON file, using the below configuration all applications from all connected devices will be extracted from the device, and their manifest files extracted and saved locally to an XML format. 

{
  "devices": ["*"],
    "apps": ["*"],
    "commands": {
      "get_app": ["!adb_connect !app_path !app_id.apk"],
      "reverse_app":["reverse: !app_id.apk;manifest"]
    }
}

Ensure all AutoDroid dependencies are installed by running the below installation command:

pip install -r REQUIREMENTS.txt

After creating a JSON config file, AutoDroid can be run by providing the path to the config file as a command line parameter:

python AutoDroid.py <JSON config path>

It would now be possible to iterate through these manifest files one by one to identify trends and malicious configurations commonly seen in malware. As, on average, most users have upwards of 80 applications on a single device this would, however, take a considerable amount of time. In the next section machine learning is used to combat this issue and automate the analysis of these APKs.  

Using machine learning to identify malware

As mentioned previously, the manual process of reviewing every single APK on an Android device can be tedious. This article pitches using machine learning to serve as a first pass to help save some of this analysis time. DroidDetective is a Python tool for analysing Android applications (APKs) for potential malicious configurations in the AndroidManifest.xml file.

Dependencies for DroidDetective are installed in the same fashion to AutoDroid. DroidDetective also requires an apk_malware.model (the pre-trained ML model) at the execution root.

pip install -r REQUIREMENTS.txt

After this DroidDetective can be run as follows

python AutoDroid.py <path to APK> <optional JSON output file>

DroidDetective works by training a Random Forest binary classifier on information derived from both known malware APKs and legitimate APKs. This tooling comes pre-trained, however, the model can be re-trained on a new dataset at any time. This model currently uses permissions from an APKs AndroidManifest.xml file as a feature set. This works by creating a dictionary of each standard Android permission and setting the feature to 1 if the permission is present in the APK. Similarly, a feature is added for the amount of permissions in use in the manifest and for the amount of unidentified permissions found in the manifest.

Putting it all together 

Using what we’ve implemented so far in this article, DroidDetective can be used alongside AutoDroid to automatically retrieve applications from a device and identify if they contain malicious configurations in their manifest file. 

For this, ensure that all requirements and required files are present, and run AutoDroid with the following configuration:

{
  "devices": ["*"],
    "apps": ["*"],
    "commands": ["!adb_connect pull !app_path !app_id.apk",
    "python DroidDetective.py !app_id.apk output.json"]
}

This will result in all APKs on the target device(s) being analysed by DroidDetective. As an optional json output file is provided all of these results are appended to output.json. An example of this ca be seen below:

{
    "com.google.android.uvexposurereporter": false,
    "com.google.android.networkstack.tethering": false,
    "com.amazon.mShop.android.shopping": false,
    "com.google.omadm.trigger": false,
...
    "com.google.android.apps.cultural": false,
    "com.android.companiondevicemanager": false,
    "com.verizon.obdm_permissions": false,
    "com.android.mms.service": false,
    "com.google.android.apps.docs.editors.sheets": false
}

 

 

Learn More On Android Internals

In 2021 I released my first book with Apress publishing, Android Software Internals Quick Reference. If you work with or find programming and Android interesting please consider picking the book up for yourself! 

 

 

 

10% off Android Malware Reverse Engineering Cheat Sheets

Free and premium resources, available on everything from Android and iOS security fundamentals, reverse engineering basics, and study guides for my Udemy courses. Use code ‘MALWARE-ARTICLE’ for 10% off on the Android Malware Reverse Engineering Cheat Sheet.

 

Some people might remember the video chat application Houseparty. Similar to others like Zoom, Skype, and What’s App, it provided light-hearted group video chat functionality alongside games and entertainment activities. In early 2020 Houseparty, developed by Epic, was at it’s peak and was hit by an unproven social media rumour that claimed the app caused users’ other online accounts (including Netflix, eBay, Instagram and Spotify) to be hacked. Epic later offered a $1m reward to anyone who could prove it was targeted by a smear campaign (however, the bounty went unclaimed). Later in 2020 Epic withdrew Houseparty from the app store and later discontinued it completely

Back when these allegations first erupted in 2020, I took a few hours out of my “busy lockdown schedule” to take apart the application and see how it was ticking behind the scenes. This article will take us through a whistle stop tour of this analysis, breaking down some of the key functions of the app, and finally conclude with my personal opinion on if I think these allegations were true and if at all possible.

Manifest

The Android manifest is a central configuration file used on an app-by-app basis. Manifests are consistently structured across all Android applications and hold information such as the application entry points, permissions, and the services that the application uses. Android as a whole is a fairly robust operating system, meaning that if an application is acting alone and inside the confines of the Android sandbox (i.e. not using any exploits or vulnerabilities) then if something isn’t in it’s manifest file, then it won’t be able to perform that action. For example, if you want your application to take a photo and tag the location, if the camera and location permissions are not set, then the application will error when it attempts to take the picture. It it possible to dynamically declare some of these permissions in the code base, but for the most part the manifest file is used.

Permissions

So to start with, lets have a look at permissions. When it comes to permissions (and especially when looking at if an application is malicious) the goal is normally to identify elements that are out of the ordinary for the type of application being reviewed. For example, having a camera application that has the premium SMS permission would be seem a bit odd. When it comes to Houseparty, there are quite a few permissions listed, below is an excerpt of some of the most interesting:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-feature android:name="android.hardware.microphone"/>
<uses-permission android:name="com.android.vending.BILLING"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>

Some of these permissions are self explanatory, however, lets take a closer look at a few.

  • READ_PHONE_STATE  – An application with this permission can access a device’s phone number, information about ongoing calls, and cellular network information.
  • FOREGROUND_SERVICE – A fairly harmless permission, this permission allows for an application to run in the background while the application is not actively running or in the Android task stack. However, to do this, it must show a constant notification to the user. This means that unless a  notification for Houseparty is in the device notification drop-down then it isn’t running on a device (outside of one or two edge cases).
  • RECEIVE_BOOT_COMPLETED – Boot Complete is one of these edge cases. This permission means that when the device restarts, the application can be ‘woken up’ and begin running. Without this, an application would need to be restarted by either another application or by the user manually each time the device restarted.
  • WAKE_LOCK – Another fairly simple permission. This permission allows the application to stop the screen from dimming. Such functionality is usually used for call applications to force the screen to stay active while on video calls.
  • REQUEST_INSTALL_PACKAGES – This permission allows Houseparty to request to install third party applications on the device. This is, however, not as scary as it sounds as there are several safeguards in place to stop the abuse of this permission. Unless you have the  Unknown Sources option ticked in your Android settings this will fail, and even if you do, you will receive a yes/no prompt before an application is installed through this method.
  • BILLING – Another scary sounding permission, however, not as bad as it sounds. Here we can see the difference between com.android.vending (for this permission) and android.permission (for the others). This means that this permission doesn’t reside in core Android and instead in vending, which is the internal name for the Google Play Store. Instead of what it may sound like, this permission doesn’t give the application the ability to access any of your financial information, instead it allows the application to request transactions through the Play Store. This will also display a yes/no prompt when it occurs.

Services

The term ‘Services’ in Android is a general catch all term. In this context services will refer to anything that allows the application to run in the background or foreground when the application isn’t being manually and directly run, and is visible, to the user. Services, such as this, can be declared in the manifest file as well as dynamically in the codebase. Some examples of services being declared in the Houseparty manifest can be seen below:

<service android:name="com.instabug.chat.network.InstabugPushNotificationTokenService" android:permission="android.permission.BIND_JOB_SERVICE"/>
<service android:name="com.lifeonair.houseparty.core.sync.video.BackgroundVideoService" android:enabled="true" android:exported="false"/>
<service android:name="com.instabug.library.internal.video.ScreenRecordingService"/>

There are a considerable amount of services in the manifest, to many to list here, however many of these belonged to a package named InstaBug, which on their website describe themselves as:

Instabug empowers mobile teams to release with confidence through comprehensive bug and crash reports, in-app surveys, and real-time user feedback

As for the other services listed here, the BackgroundVideoService seems to be the main service used by the application. Earlier I mentioned that Foreground services must show a notification to the user when the activity is running. This restriction is only in place from Android 8.0 Oreo (API Level 26). In the Houseparty decompiled codebase we can see this notification being created, for this service, here:

public static void a(Context context, Notification notification) {
  hxw.a(4, "Start service to keep alive and show active party notification", (Throwable) null);
  Intent intent = new Intent(context, BackgroundVideoService.class);
  intent.setAction(b.SHOW_ACTIVE_PARTY_NOTIFICATION.name());
  intent.putExtra("ACTIVE_PARTY_NOTIFICATION", notification);
  b = true;
  if (Build.VERSION.SDK_INT >= 26) {
    context.startForegroundService(intent);
  } else {
    context.startService(intent);
  }
}

The next service, ScreenRecordingService, is for recording the screen of the device. This uses an Android system service named media_projection. Below we can see Houseparty retrieve the Media Projection system service and start an activity with it. However, as this service declaration in the manifest is part of the Instabug class, my gut instinct is that this is part of some bug reporting functionality.

if (bundle == null) {
  boolean z = true;
  this.a = getIntent().getBooleanExtra("isVideo", true);
  this.b = getIntent().getBooleanExtra("isInitial", true);
  Intent createScreenCaptureIntent = ((MediaProjectionManager) getSystemService("media_projection")).createScreenCaptureIntent();
  if (!this.a) {
    startActivityForResult(createScreenCaptureIntent, 101);
  } else if (SettingsManager.getInstance().getAutoScreenRecordingAudioCapturingState() == Feature.State.ENABLED) {
    if (ContextCompat.checkSelfPermission(this, "android.permission.RECORD_AUDIO") != 0) {
      z = false;
    }
    if (!z) {
      ActivityCompat.requestPermissions(this, new String[]{"android.permission.RECORD_AUDIO"}, 2022);
    } else {
      a();
    }
  } else {
    a();
  }
}

Misc

Before we stop talking about the Manifest there are one or two honourable mentions that are worth discussing. These being the use of the Facebook marketing and the HockeyApp providers, where on their website HockeyApp describe themselves as:

HockeyApp is the best way to collect live crash reports, get feedback from your users, distribute your betas, and analyze your test coverage.

<provider android:name="com.facebook.marketing.internal.MarketingInitProvider" android:exported="false" android:authorities="com.herzick.houseparty.MarketingInitProvider"/>
<activity android:name="net.hockeyapp.android.LoginActivity"/>

As with Instabug above, there are a considerable number of third-party libraries being used inside of the Houseparty application. This is not out of the ordinary for applications of this size, however, does pose an additional attack surface where if a vulnerable or malicious third party service is used it can provide an additional risk to the end user.

Side Loading / Hot Swapping

Earlier it was briefly mentioned how the REQUEST_INSTALL_PACKAGES permission could be used, if user consent was provided, to install third-party applications on some devices. Here we’ll be diving into other methods that the application uses for dynamically running code/ content. 

Here the term side loading is used to refer to the process of programmatically running third party code, or data, without going via the Google Play Store. Loading code in this form would mean that it typically wouldn’t be visible as part of a static code review such as this – meaning that potentially malicious code **could** be installed when then application is running.

After an initial look into the Houseparty decompiled codebase there isn’t an immediate indication that the application is doing this. However, Houseparty does have several dynamic elements, primarily it’s ability to dynamically update what games can be played in the application. While the specific games are hard coded into the app (e.g. Trivia, Heads Up, etc) the packs used in these games aren’t hard coded. Instead they are downloaded and stored in a Realm Database. I’ve only taken a look at the Heads Up game however, it seems likely that the same logic is applicable across all of their game offerings. 

It’s important to stress here that while these games are dynamically downloaded there doesn’t appear to be any code downloaded, and instead just elements that can be plugged into the game engine. As below we can see the elements for one of these ‘Heads Up Card Packs’ being updated with this data.

public static HeadsUpDeckModel buildFromParcel(Parcel parcel) {
  Builder builder = new Builder();
  String unused = builder.id = parcel.readString();
  List unused2 = builder.skus = parcel.createStringArrayList();
  String unused3 = builder.name = parcel.readString();
  String unused4 = builder.description = parcel.readString();
  String unused5 = builder.imageUrl = parcel.readString();
  boolean z = true;
  if (parcel.readInt() != 1) {
    z = false;
  }
  boolean unused6 = builder.free = z;
  List unused7 = builder.cards = parcel.createStringArrayList();
  return builder.build();
}

Conclusion

Some questions on if Houseparty was truly malicious may still stand: “well, what if they were to implement the side loading code in the future?” or “what if another one of the game packs side loads code?“. As a whole Google has very stringent rules on the side loading of code, with them stating that:

Apps or SDKs that download executable code, such as dex files or native code, from a source other than Google Play… are explicitly prohibited.

In general, Google also have fairly good automated systems for picking up these types of applications before they enter the Play Store, known as Google Play Protect, and scans over 50 billion applications, on user devices, per day.

To conclude, in my personal opinion I don’t believe Houseparty was doing anything malicious behind the scenes, however, I do recommend the advice noted by the team at NakedSecurity, across the board for all users/ applications, it’s a good read.

 

Reverse Engineering Android Malware Course

I’m in the process of developing a Udemy course on reverse engineering Android malware. Enter your email address below to receive an update and early-bird discount code once the course is live, along with updates on other resources I make available.


 

Learn More On Android Internals

In 2021 I released my first book with Apress publishing, Android Software Internals Quick Reference. If you work with or find programming and Android interesting please consider picking the book up for yourself! 

 

 

 

10% off Android Malware Reverse Engineering Cheat Sheets

Free and premium resources, available on everything from Android and iOS security fundamentals, reverse engineering basics, and study guides for my Udemy courses. Use code ‘MALWARE-ARTICLE’ for 10% off on the Android Malware Reverse Engineering Cheat Sheet.

 

This article covers the building blocks of Android malware analysis, getting you ready to go, with everything needed when it comes to reverse engineering malware on Android! 

Types of Android Malware

For Android devices running Google Play Services, and in turn using the Google Play Store, one of the biggest application security defences is the Google Play Protect utility. Google Play Protect identifies malware in two forms; on device, and off device (also known as Cloud). On device protection works by daily scanning all applications installed on Android devices, while cloud protection works by vetting and reviewing applications that are uploaded to the Google Play Store. 

As an authority on Android Malware, we’ll be using the definitions provided by Google Play Protect for Android Malware (also referred to as Potentially Harmful Applications). In addition to device malware, some antivirus providers also class personally unwanted software (POS) or Mobile Unwanted Software (MUwS) as harmful to a device. These won’t be included here as, while they pose a danger to the device ecosystem,  they do not strictly fall into the category of malware. These can include:

  • Ad fraud
  • Unauthorized Use or Imitation of System Functionality
  • Disruptive ads
  • Social Engineering
  • Data collection and restricted permissions abuse

TypeDescription
TrojanUsed in combination with other malware categories, a Trojan will usually appear as something it is not. For example a legitimate game, application, or useful piece of software. While it may appear to be benign it will then perform undesirable actions against the user.
SpywareSpyware is any form of application or software that transmits personal or personally identifiable information to a third party without adequate control, notice, or consent - this can include contact information, photos or other files, messages from email, call logs or sms, web history and bookmarks and information from the device '/data/' directory. This can also include actions such as recording video, audio, calls, and acquiring application data.
StalkerwareA subset of this type of malware and is often seen used as a commercial/ spyware-as-a-service, where the data is often sent to a third party that is not the PHD provider. Legitimate versions of such software can be used by parents to track their children, however, a persistent notification should be displayed at all times.
SpamApplications that send unsolicited messages to the user's contacts, the user themselves, or others without adequate consent from the user.
Rooting - An application or code that roots the target device without consent from the user and in turn executes some form of further malicious code onto the device.
RansomwareDefined as an application or code that gains partial or full control over a device and in turn offers to relinquish that control for a performed action such as payment. This can include encrypting device data or enabling device admin controls to lock the user out of the device.
Elevated privilege abuseSimilar to rooting, this is where an application or code compromises system integrity by breaking the app sandbox, gaining elevated privileges, or changing or disabling access to core security-related functions. This can include everything from disabling SELinux, abusing features so that the application cannot be uninstalled, abusing permission or authentication models.
PhishingSimilar to a Trojan, this is where an application or code masquerades as a legitimate piece of software and requests user authentication credentials or other personal and private information. This data is then sent to a malicious third party.
Non-Android threatThis malware category applies to Android applications and code that do not provide a direct threat to the device ecosystem or user, and instead leverage the device to target other platforms - such as connected devices or devices on the same network.
Hostile downloadersThis category covers applications and code that are utilised to download other malware. Google Play Protect has a collection of rules it uses for identifying if a given piece of downloader software if classed as hostile, these being:
There is reason to believe it was created to spread PHAs and it has downloaded PHAs or contains code that could download and install apps; or
At least 5% of apps downloaded by it are PHAs with a minimum threshold of 500 observed app downloads (25 observed PHA downloads).
They don't drive downloads without user interaction
All PHA downloads are initiated by consenting users.
Denial of service (DoS)An application or code that performs a denial of service (DoS) / distributed DoS attack against a third party system or resource.
Billing fraudBilling fraud summarises several types of an application or code that leads to the user being charged for a service in an intentionally deceptive way. This is commonly broken down into: SMS, Call, and Toll fraud.
BackdoorA backdoor will often allow for a malicious actor to gain unwanted, unauthorised, and potentially harmful remote control of the target device.

Android Applications 101

Android application’s are commonly written in either Java or Kotlin. When a software engineer wants to create an APK (the Android pacKage), that contains the code and materials that are run on an Android device, they will need to compile that Java or Kotlin source code to a Dalvik executable/ bytecode. This Dalvik executable is a binary that is run on the Android device. This works where each process on the device uses its own virtual machine (VM) which segregates applications. Prior to Android API level 21 (Android 5), this would have been a Dalvik Virtual Machine, and in later versions will instead use the Android Runtime (ART). Both operate in similar fashions, where they simulate a device’s CPUs, registers, and other features while running an application’s compiled Dalvik bytecode.

Decompiling and Disassembling An APK

While it is the Dalvik bytecode that needs to be run on a device, this is not human readable and so if we are to reverse engineer an application we’ll need to decompile it back into a human readable form. This is where Jadx comes in. Using Jadx we can decompile the Dalvik bytecode back into Java. This is often called pseudo Java, as it is not a one for one representation of what the original source code would have been, and instead is the decompiler’s best guess.  

Android application architecture

An Android application (APK) is an archive-like file format, that contains several other files and folders. This including:

  • assets— A directory for application assets. This is for arbitrary storage; anything provided by the application creator can be stored here.
  • res— A directory with all resources that are not compiled into arsc (icons, images, etc.).
  • lib— A directory for native libraries used by the application. Contains multiple directories for each supported CPU architecture that the application has been compiled for.
  • META-INF— A directory for APK metadata – including signatures.
  • xml— The application manifest in a binary XML formatted file that contains application metadata — for example, its name, version, permissions, etc.
  • dex— The classes.dex file contains the compiled application code in the Dex file format. There can be additional .dex files (named classes2.dex, etc.) when the application uses multidex.
  • arsc— This file contains precompiled resources—such as strings, colours, or styles.

Android Manifest File

Android APK files also include a file detailing the application configuration – AndroidManifest.xml. The Android manifest includes information such as:

  • Package name and application ID
  • Application components
  • Intent filters
  • Icons and labels information
  • Permissions
  • Device compatibility information

Building and Reverse Engineering an ordinary application

First things first, especially if you’re new to Android as a whole, my recommendation would be to build a simple Android application. As an example open up Android Studio and create one of the following simple applications. This will give you a better understanding of Java, how Android applications are written, and some experience using a device/ emulator when running an application.

  • A simple note-taking application
  • A quote of the day application
  • A simple password manager
  • An Android file explorer

After compiling the created application to an APK, your next step will be to decompile that application to pseudo-Java, using Jadx. This will provide you with an understanding of how code goes from source code, to Dalvik assembly, then back to decompiled pseudo Java.

Reverse Engineering Android Malware

Kicking things off, it’s important to bear in mind that any malware analysis should be performed on a segregated system, such as a VM, with minimal connection to the outside world. 

All of the malware samples used today can be found on the Android Malware GiHub repository by Ashishb.

Malicious Skype Application

In the rouge_skype folder you can find a file named skype.apk. If loaded onto a device this application would present itself as a regular, if old, Skype application.  That being the case, we can use some tools to identify a more nefarious purpose. 

Virus Total

Before this, however, we can upload the APK onto Virus Total (a tool for analysing and sharing suspicious files, domains, IPs and URLs). With an immediate look, we can see that we’re not the first people to be looking at this APK, with the first submission of the file to Virus Total (VT) being back in 2015. Straight off the bat, VT gives us a clear indication that this APK is potentially (and probably)malicious

Reverse Engineering

The next step is to disassemble this APK and begin diving into it’s contents. Using APKTool, the contents of the APK archive can be identified (for information on these files see the Android Application Architecture section above).

Entering the assets folder of the application we can see several obfuscated file names. Using the file command it can be identified that one of these files, a , is actually a jar file. As an APK is simply an instance of a Jar (Java Archive) file, with some additional Android files dotted in there, this can be reverse engineered with ease.

Using APKTool a second time, this time on the Jar file, it can be seen that the jar file is successfully de-bundled into it’s core components, and the internals of a second APK can be seen. This is a good indication that the original Skype application was patched in some way and is dynamically loading the jar file inside of the assets directory at runtime. 

Further analysis could be performed on both this APK and the jar file, including reviewing the manifest file, reviewing interesting functions, and identifying the link between the two files. 

 

Dendroid

The next malware sample we’ll be reviewing can be found in the dendroid folder in the GitHub repository. Dendroid malware was quite sophisticated in it’s time, being first identified in 2014 by Symantec. Falling into several of the above categories, Dendroid was capable of deleting call logs, opening web pages, dialling numbers, recording calls, SMS interception, uploading files, opening applications, and performing denial of service attacks.

APKLab

Instead of manually reviewing the file structure and disassembled SMALI of this application, we’ll be using APKLab (A Mobile Threat Intelligence Platform by Avast), as an example of automated reverse engineering tooling (if you do not have access to APKLab, you can use other automated tooling such as Quark).

Using APKLab, this APK can be uploaded and an analysis performed on it. Some key information that APKLab provides, includes:

  • Suspicious permissions
  • URL strings
  • Generated files
  • Emulator check for known build properties
  • A network dump
  • Entrypoints
  • More…

 

By now, you have an entry level understanding into the internals of Android applications, Android malware types, and several areas and variables to look out for during Android malware analysis. See below for additional resources on the topic!

 

Reverse Engineering Android Malware Course

I’m in the process of developing a Udemy course on reverse engineering Android malware. Enter your email address below to receive an update and early-bird discount code once the course is live, along with subscribing to my mailing list.

 

 

Introduction To Reverse Engineering Course

I’ve released an Android reverse engineering course inspired by my interest in game design. This course walks through the fundamentals of reverse engineering and uses Android games as a fun and practical starting point.

 

10% off Android Malware Reverse Engineering Cheat Sheets

Free and premium resources, available on everything from Android and iOS security fundamentals, reverse engineering basics, and study guides for my Udemy courses. Use code ‘MALWARE-ARTICLE’ for 10% off on the Android Malware Reverse Engineering Cheat Sheet.

Continue reading “Android Malware Reverse Engineering”

 

Let’s start things off with a question; what does the TV show Black Mirror, the series Person of Interest, and Android Google Play devices all have in common? Well it’s not the fact that they all involve technology, nor is it the fact that they all include mobile devices, instead it’s the fact that they all include elements of using machine learning and AI to detect malicious activity. In the case of Android Google Play devices this is via the Safety Net APIs  – and it’s this we’ll be talking about today. By the end of this article we’ll have answered the bellow, by reverse engineering the Android SafetyNet Attestation API and framework.

How do app developers identify if a device an application is running on is legitimate?

Google Play Safety Net Attestation API

What is SafetyNet?

Google SafetyNet (also known as SNet) is a suite and umbrella of functionality available on Android devices that have Google Play Services available. Google Play Services comes with most Android devices and allows devices to have applications such as the Google Play Store installed on them. Some devices, such as a selection of Huawei devices, do not have Google Play Services available, and so SNet is not available on these devices. 

The SNet umbrella is broken down into the following:

SNet Safe Browsing API

The SNet Browsing API provides services to application developers, running application’s on device’s with Google Play Services, the ability to check a given URL for if it has been identified as a known threat by Google. For example a web browsing application could use this API to identify if the URL a user was visiting was malicious and in turn the URL could be blocked.

SNet Verify Apps API

The SNet Browsing API provides services to application developers, running application’s on device’s with Google Play Services, the ability to check if there are any malicious or harmful applications running on the same devices as the application. For example a banking application could use this API to ensure it is not used on the same device as malware.

SNet reCAPTCHA API

This API extends the Google reCAPTCHA framework and allows application developers to use reCAPTCHA checks inside of their application. For example these reCAPTCHA checks could be used to validate user requests or form submissions.

SNet Attestation API

The SNet attestation API is one of the most interesting of these APIs and the one that we’ll be focusing on moving forward. The Attestation API is an anti-abuse API that allows application developers to assess the Android device their application is running  on – in turn being able to identify if the application the device is running on is rooted or compromised in some way. As an example, banking applications can use this API to ensure they’re not running on a rooted device.

Rooting and Root Detection

Both Android and other mobile operating systems have a concept of privileged control on a device. Here, when talking about privileged control, it refers to providing a user with extensive controls over the device, which the manufacturer did not intend for the end-user to have and can normally allow for actions such as breaking application sandboxing, accessing and modifying system actions, and accessing the underlying kernel. For Android this is commonly referred to as rooting. From the above it can been seen why some applications would not want to run on rooted devices, including user security, intellectual property controls, and it leading to future exploitation or control of an application. Below can be seen a sample of application’s on Android that implement root detection – this comes in many forms; from instructing the user the device is rooted, closing the application completely, or silently logging that the device is rooted.

One of the most common root detection mechanisms in place in Android applications is the Google Play SNet API. Later on this article will dive into the internals on how the SNet API operates, however, for now the below demonstrates a sample wrapper application (an application that’s sole purpose is to call the API and display the results to the screen) using the API on both a standard and rooted Android device. 

How Developers get Attestation data from SNet

Now that we can see that applications using the SNet API are magically able to identify if a device is rooted or not, the next question is, how? The process for a developer is a fairly simple one. At first Google Play Services periodically runs on the device and downloads a jar file (Java archive), this code is then dynamically run and aggregates an assortment of data (Described later) on the device. This information is then sent to an unknown Google server for analysis. After this point third party applications running on the device can then call the API and will receive several variables in response.

The variables received by the application from the API include:

  • ctsProfileMatch: The strictest identifier on the device’s integrity.  If false then the device has failed Android compatibility testing and is not a Google-certified Android device.
  • basicIntegrity: The more lenient identifier of device integrity. If false then it is likely that the device has been tampered with in some way.

There are also several optional variables that can be returned:

  • error: Error information relating to the current API request.
  • advice: Recommendations for fixing the device state.
  • evaluationType: How the device evaluation was performed, i.e. is it backed by hardware?

Taking apart the mystery Jar file

As previously mentioned, Google Play Services periodically aggregates data from an Android device and sends it to a server for analysis. While the decision making, on if a device is tampered with or not, is performed on the server the data aggregation occurs on the device. This means that by reverse engineering the Jar file that is downloaded by SNet a picture can be put together of what data goes into identifying the integrity of a device. 

Timeframe of SNet Attestation versions

There have been many versions of SNet over the years, and with each new version comes new forms of data aggregation that occur on the device. Below shows an incomplete timeframe of SNet versions (put together in part by the research from Collin Mulliner & John Kozyrakis) up to 2019, however, there have been many more versions both between these dates and after. 

SNet Attestation Modules

The data aggregation performed by the SNet Jar file is broken down into several categories based on their functionality. From this point I’ll walk through a handful of the modules available in SNet version 10000700. 

Device State Checker

DeviceStateChecker.java | SNet Version: 10000700

Including variables: the verify boot state, verifying mode, security patch level, and if OEM unlock is supported on the device.

Settings Finder

SettingsFinder.java | SNet Version: 10000700

Including variables: if ADB is enabled, the device fingerprint status, the lock screen timeout, lock screen type, if non-market apps are enabled, notification visibility at lock screen, Android smart lock, and the storage encryption status.

SD Card Analyzer

SdCardAnalyzer.java | SNet Version: 10000700

Process: this module saves a JPG file to the external storage of the device and periodically checks in on it. If the image has been altered, removed, or changed in any way it’s reported as a indicator or compromise. 

Rooting File Finder 

RootingFileFinder.java | SNet Version: 10000700

Process: this module looks for the presence of several files and file paths on the device, including: “/system/bin”, “/dev/block/loop”, “/system/xbin”, “/bin”, “/xbin”, “/proc/self/mountinfo”, and more. 

Preferred Package Finder

PreferredPackageFinder.java | SNet Version: 10000700

Process:  this module aggregates the set default installer and web browser on the device (i.e. Google Play Store and Chrome).

Captive Portal Detector

CaptivePortalDetector.java | SNet Version: 10000700

Process: this module sends a request to a hardcoded Google server and saved the IP address, response body, and response code. Presumably this is compared with the known response by the integrity check on the server to identify if a captive portal or man-in-the-middle was present on the device.

Wrap-Up

In addition to the above sampled aggregated variables, there are many more that SNet aggregates and sends to the Google server for integrity reviews. In late 2019 the version of SNet I reviewed included approximately 55 variables that it was aggregating. 

In past research I’ve previously developed a tool called Tamper, which seeks to replicate some of the key functionality of SNet. I may write a follow on article on this process, however, for now you can see it’s development over on GitHub.

 

 

Develop Your Reverse Engineering Skills

I’ve released an Android reverse engineering course inspired by my interest in game design. This course walks through the fundamentals of reverse engineering and uses Android games as a fun and practical starting point.

Learn More On Android Internals

In 2021 I released my first book with Apress publishing, Android Software Internals Quick Reference. If you work with or find programming and Android interesting please consider picking the book up for yourself! 

 

 

 

ANDROID CHEAT SHEETS AND STUDY GUIDES

Free and premium resources, available on everything from Android and iOS security fundamentals, reverse engineering basics, and study guides for my Udemy courses.

 

The most common tools used for obfuscation in Android include ProGuard, DexGuard and R8. For most of this article the terms R8, DexGuard, and ProGuard will be used interchangeably as functionality is loosely the same between them, however, the main differences will be detailed below. ProGuard analyses and optimizes the Java bytecode rather than the direct Java/Kotlin code base. ProGuard implements a collection of techniques, these being:

  • Shrinking – Identifies and removes dead code that is not reachable or is unused. Including classes, fields, methods, and attributes.
  • Optimizer – Performs optimization on code and code flow where performance changes can be made.
  • Obfuscator – Renaming aspects of the codebase (i.e., classes, fields, and methods) to names that are deliberately obscure and meaningless.
  • Preverifier – Performs preverification checks on the bytecode, where if the checks are successful, the classfiles are annotated with preverification information. This is required for Java Micro Edition and for Java 6 and higher.

R8 and ProGuard

When enabled, in  Android Gradle plugin 3.4.0 and above ProGuard is no-longer used by default for obfuscation, optimization, and other tasks. Instead, R8 is used. R8 provides a similar suite of functionality to ProGuard (and DexGuard, it’s premium alternative), however, is being actively developed by the team at Android. By default, when compiling a release build of an Android application R8 will automatically perform these functions (as described above) on the codebase. Neither R8 nor ProGuard are categorically better than one another, instead they each come with their own benefits and drawbacks. Some reasons for why R8 was adopted in the Android Gradle plugin include: 

  • With ProGuard, the compiled Java bytecode is taken and converted into optimized Java bytecode and then further converted into optimized Dalvik bytecode. The process for R8 skips a step, taking the Java bytecode straight to optimized Dalvik bytecode – in turn saving time during the building process.   
  • It’s estimated that ProGuard reduces a shrunken application’s size by ~8.5%, while R8 reduces it by ~10%.
  • R8 comes with more widespread Kotlin support and optimizations.

Enabling Obfuscation 

Depending on the version of the Android Gradle plugin being used, the below will either enable ProGuard by default or R8. Edit the ‘buildTypes’ tag in the ‘gradle.build’ file to ‘minifyEnabled true’. To enable obfuscation on a debug build, switch out ‘release’ for ‘debug’. An example of using obfuscation on a release build can be seen below:

buildTypes {

    release {

        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 
        proguardFile 'proguard-project.txt' 

    }

}

For the above, if using an older version of the Android Gradle Plugin, and you wish to enable ProGuard over R8, you may need to manually disable R8 in your ‘gradle.properties’, as below:

android.enableR8=false 
android.enableR8.libraries=false

For steps including how to enable ProGuard on the newest versions of the Android Gradle Plugin see their official documentation

The Mapping File

After following the above when making a release build, using Gradle, the Java bytecode will have been analysed by ProGuard. ProGuard will provide a log file of the stages undergone. This is saved at the following relative path to the application project root.

Mapping file relative location:

app/build/outputs/mapping/release/mapping.txt

This file shows the changes that ProGuard has implemented. An example of part of this file is below. In this example it can be seen that the
function ‘showString’ in ‘MainActivity’ has been allow-listed while the other function in ‘MainActivity’ named ‘loadMe’ has not and is now renamed to ‘n’.

Example of mapping file:

com.example.java_dexloadable.MainActivity -> com.example.java_dexloadable.MainActivity:
java.lang.String loadMe() -> n
1:1:java.lang.String com.example.java_dexloadable.StringsClass.stringGetter(int):0:0 -> showString
1:1:void showString(android.content.Context,int):0 -> showString
2:2:void showString(android.content.Context,int):0:0 ->showString

If a function or class is not in this mapping, then it has been shrunken out (meaning that it wasn’t being used in the code), or it has not been
obfuscated (due to being allow-listed).

The ProGuard Allow-List

By default, ProGuard will shrink, optimize, and obfuscate everything in the Java bytecode. This can be controlled by editing the ProGuard
file located at ‘app\proguard-rules.pro’, in the root of an application directory. This file can be renamed and moved and is specified in the
‘gradle.build’ file.

The following example rule allow-lists the ‘showString’ function in the class ‘com.example.java_dexloadable.MainActivity’. Here you need
to specify the access level of the class and function (‘public’, ‘private’, ‘package-private’, etc.) as well as the parameters for the function:

-keep class com.example.java_dexloadable.MainActivity {
    public showString(android.content.Context, int);
}

The following example is the same; however, in this example all functions in the ‘MainActivity’ are allow-listed:

-keep class com.example.java_dexloadable.MainActivity {
    public *;
}

Entry Points

ProGuard automatically allow-lists (also known as white-lists) entry points to an application (e.g., an activity with the MAIN or LAUNCHER category). It’s important to bear in mind that entry points used as part of reflection will not be automatically allow-listed, and so if using refection, these entry points will have to be manually allow-listed. This, however, will minimize the effectiveness of obfuscation as the frequency of plain text components will be higher. The entry points that are automatically added to an allowlist by ProGuard typically include classes with main methods, applets, MIDlets, activities, etc. This also includes classes that have calls to native C code.

The Different Types of Keep

In the preceding two examples, the ‘keep’ keyword is used. There are, however, several different types of keep keyword.

  • No Rule – Shrinks Classes, Shrinks Members, Obfuscates Classes, Obfuscates Members
  • -keep – None
  • -keepclassmembers – Shrinks Classes, Obfuscates Classes
  • -keepnames – Shrinks Classes, Shrinks Members

Example Rules

In the following example, the Java Package Name is ‘java_dexloadable’, and all rules have been added to the ‘Proguard-rules.pro’ file.

Keeps (allow-lists) all methods in the ‘MainActivity’ class:

-keep class com.example.java_dexloadable.MainActivity {
    public *;
}

Keeps (allow-lists) the ‘showString’ function in the ‘MainActivity’ class as well as the ‘MainActivity’ class itself:

-keep class com.example.java_dexloadable.MainActivity {
    public showString(android.content.Context, int);
}

Keeps (allow-lists) everything under the top-level package (shouldn’t be used):

-keep class com.example.java_dexloadable.** { *; }

Keeps (allow-lists) the function stringGetter but not the class StringsClass itself:

-keepclassmembers class com.example.java_dexloadable.
StringsClass {
    public stringGetter(int);
}

Repackage whole package into a single root:

-repackageclasses

Doesn’t perform the ProGuard shrink step:

--dontshrink

 

Read More

This article was derived from a chapter in my book Android Software Internals Quick Reference. If you found it interesting please consider picking the book up for yourself! 

 

 

 

Adverts





 

Reflection is one of the many aces up the sleeve when it comes to taking apart Android applications and getting them running in a state that
suits you. To put it simply reflection is an API that can be used to access, examine, and modify objects at runtime – this includes fields, methods,
classes, and interfaces. 

Some examples of components reflection can be used on when working from Java (or Kotlin) include:

  • Classes – A class is a blueprint/template where when used individual objects can be created from them.
  • Methods – A method is a segment of code, with a specific purpose, which is run when called and can be part of a class or standalone.
  • Constructors – A constructor is a special type of method that is used as part of the initialization of an object (e.g., a class) to set variables and call methods.
  • Interfaces – An interface is an abstract class that contains a collection of methods with empty bodies.

Class Loading

Java Class Loaders are a component of the Java Runtime Environment (JRE) which load Java classes into a Java Virtual Machine (JVM)/Dalvik Virtual Machine (DVM)/Android Runtime (ART). Not all classes are loaded simultaneously, nor with the same ClassLoader. The context method
getClassLoader() can be used to get the current class loader. There are several types of class loading in Android, these being:

  • PathClassLoader – This is used by the Android system for its system and application class loader(s).
  • DexClassLoader – This loads file types containing a .dex file (e.g., .jar and .apk or .dex file directly). These .dex files (Dalvik executable) contain Dalvik bytecode.
  • URLClassLoader – This is used to retrieve classes or resources via URL paths. Paths ending with / are assumed to be directories, while otherwise they are assumed to be .jar files.

Below shows how to retrieve the current application context class loader:

ClassLoader loader = getApplicationContext().getClassLoader();

Below shows how a new class loaded can be created:

dexLoader = new DexClassLoader(filePath, dexCacheDirectory.getAbsolutePath(), null, loader);
//After creating a dex class loader, choose the class to load, as a string:
loadedClass = dexLoader.loadClass("me.jamesstevenson.dexloadable.MainActivity"); //alter path for your use case
//At this stage the uninitialized class can be used as normal. The following shows how to safely
initialize this class:
initialisedClass = loadedClass != null ? loadedClass.newInstance() : null;
method = loadedClass != null ? loadedClass.getMethod("loadMeAndIllTakeContext", Context.class) : null;
Object methodResponse = method != null ? method.
invoke(initialisedClass, getApplicationContext()) : null;

Reflection Examples

The two supporting classes for these reflection examples can be found on GitHub under DeviceData.Java and Loadable.Java.

Initializing a class:

try {
    Object initialisedDeviceData= DeviceData.class.
    newInstance();
    initialisedDeviceData.getClass().getDeclaredMethod("setDeviceInfo").invoke(initialisedDeviceData);
    String model = (String) initialisedDeviceData.getClass().
    getDeclaredField("model").get(initialisedDeviceData);
    Log.v(TAG, model);
} catch (...) {
    // Todo catch all exceptions
}

Retrieving class methods:

Static method example:
try {
    Method getDeviceName = Loadable.class.getDeclaredMethod("getDeviceName");
    getDeviceName.setAccessible(true);
    Log.v(TAG,(String) getDeviceName.invoke(Loadable.class));
} catch (...) {
    // Todo catch all exceptions
}

Retrieve all methods for a class:

getMethods() example:
    for (Method method : Loadable.class.getMethods()){
    Log.v(TAG, method.getName());
}

The following is an example of constructing a class with a private constructor:

try {
    Constructor<?> constructor = Loadable.class.getDeclaredConstructor(Context.class, long.class);
    constructor.setAccessible(true);
    Object instance = constructor.newInstance(getApplicationContext(), (Object) 12); // constructor takes a context and an id.
    Field uniqueIdField = instance.getClass().getDeclaredField("uniqueId");
    uniqueIdField.setAccessible(true);
    long uniqueId = (long) uniqueIdField.get(instance);
    Log.v(TAG, ""+uniqueId);
} catch (...) {
    // Todo catch all exceptions
}

Instance class example:

try {
    // The loadable class has a static method that can be used to construct it in this example
    Object instance = Loadable.class.getDeclaredMethod("construct", Context.class).invoke(Loadable.class, getApplicationContext());
    // Retrieve the field device data which is the class we're looking to get the data of.
    Field devicdDataField = instance.getClass().getDeclaredField("deviceData");
    devicdDataField.setAccessible(true);
    Object initialisedDeviceData = devicdDataField.get(instance);
    // After accessing the value from the field we're looking to access the fields of, we can use the same type of reflection again after getting it's class
    Field modelField = initialisedDeviceData.getClass().getDeclaredField("device");
    modelField.setAccessible(true);
    String model = (String) modelField.get(initialisedDeviceData);
    Log.v(TAG,model);
}  catch (...) {
    // Todo catch all exceptions
}

 

 

Read More

This article was derived from a chapter in my book Android Software Internals Quick Reference. If you found it interesting please consider picking the book up for yourself! 

 

 

 

Adverts





 

Android is saturated with Inter Process Communication (IPC) mechanisms used for both cross system and process communication (i.e. Binder, Sockets, and IOCTL calls) and for inter application communication (i.e. Intents and Broadcasts). This article will focus on Android Intents, one of the simplest and most used IPC techniques for inter app communication in Android. 

WHat Is an Intent?

Intents allow for applications to communicate (e.g., send data or initiate an action) with other Android components on the device, even if the recipient is not currently running. This means that an application can send intents to a wide variety of Android components – including application activities (using startActivity() or startActivityForResult()), background services (using startService()), and broadcast receivers (usingsendBroadcast() or sendOrderedBroadcast()). An application can send an intent that will fall into one of two (or three, depending on how you look at it) categories, these being:

  • Explicit – Explicit intents are intents that specify the application or both the application and component that will action the request.
  • Implicit – Implicit intents are more vague and specify a type of action that is desired (e.g., opening a camera or location application).
  • Broadcasts – These broadcast messages, which can be sent by the Android system or applications, are simultaneously received by all applications on the device that have previously registered for the specific broadcast action type.

An Intent class object is created in Java or Kotlin and has several core and additional attributes. These can be seen below:

  • Action (Core) –  Settable using an initialized Intent object’s setAction method. The action defines the high-level action to be performed.
  • Category (Core) –  Settable using an initialized Intent object’s setData method. The data field includes the data this intent is operating on (e.g., a file to open in an image editing app).
  • Type (Additional) – Settable using an initialized Intent object’s addCategory method. Categories provide additional context about the action to be performed by the intent. Only activities that can facilitate all specified categories can be chosen to receive the intent.
  • Component (Additional) – Settable using an initialized Intent object’s setComponent method. This attribute identifies the name of a component class to use for the intent. This is an optional attribute as it is normally identified based on the content of the intent.

intent filters

All components should have an android:exported tag. This is false by default, and if it is false, then the component can only receive messages from inside of its application. By adding any intent filters, this is automatically true and means that external applications can interact with the component. These intent filters are also used to advertise the component when the system receives an implicit intent.

The following is an example of a typical entry point (as defined in the Android Manifest) to an application with the MAIN action and LAUNCHER category set. The main action defines that this component should be started as the entry point to the application and that it does not receive any data. The launcher category defines that the activity should be displayed in the top-level launcher.

<intent-filter> 
     <action android:name="android.intent.action.MAIN" /> 
    <category android:name="android.intent.category.LAUNCHER" /> 
</intent-filter>

Receiving and Sending

Below are several examples of how intents can be used inside of an application to communicate with internal or external components:

Starting an internal activity with data:

public void sendIntentToActivityInApp(){
    Intent intent= new Intent(this, IntentReceiver.class);
    // Update class to be internal class (to the application) to receive the intent
    Bundle bundle= new Bundle();
    bundle.putString("key", "value");
    intent.putExtras(bundle);
    startActivity(intent);
}

Receiving an intent bundle in an activity:

protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getIntent().hasExtra("key")) {
        String value = getIntent().getExtras().getString("key");
        Log.v(this.getClass().getSimpleName(), value);
    }
}

Starting an external application:

public void startActivityViaIntent(){
    Intent launchIntent = getPackageManager().
    getLaunchIntentForPackage("com.android.chrome");
    startActivity(launchIntent);
}

Starting a specific activity of an external application:

public void sendIntentToAnotherActivity(){
    Intent intent = new Intent();
    intent.setClassName("com.android.chrome", "com.google.android.apps.chrome.Main");
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ;
    startActivity(intent);
}

 

Read More

This article was derived from a chapter in my book Android Software Internals Quick Reference. If you found it interesting please think about picking the book up for yourself! 

 

 

 

Adverts