Analyzing Android Malware Samples

With the rise of mobile devices, the name Android has become well-known to most of the world, even to those who are far from the IT world. It was originally developed by Android Inc. and later acquired by Google in 2005. The Android name is derived from the nickname of the founder of the company, Andy Rubin. This open source operating system is based on a modified version of the Linux kernel and there are several variants of it, such as Wear OS for wearable devices, and Android TV, which can be found on multiple smart TVs.

As mobile devices store or can provide access to more and more sensitive information, it's no surprise that mobile platforms are increasingly becoming targets for attackers exploring ways to leverage their power for malicious purposes. In this chapter, we are going to dive into the internals of the most popular mobile operating system in the world, explore existing and potential attack vectors, and provide detailed guidelines on how to analyze malware targeting Android users.

To facilitate learning, this chapter is divided into the following sections:

  • (Ab)using Android internals
  • Understanding Dalvik and ART 
  • Malware behavior patterns
  • Static and dynamic analysis of threats

(Ab)using Android internals 

Before analyzing the actual malware, let's first become familiar with the system itself and understand the principles it is based on. This knowledge is vital when performing analysis as it allows the engineer to better understand the logic behind malicious code and not miss any important part of its functionality.

File hierarchy

As Android is based on the modified Linux kernel, its file structure resembles the one that can be found on various Linux distributions. The file hierarchy is a single tree, with the top of it called the root directory or root (generally specified with the / symbol), and multiple standard Linux directories, such as /proc, /sbin, and so on. The Android kernel is shipped with multiple supported filesystems; the exact selection varies depending on the version of the OS and the device's manufacturer. It has been using EXT4 as the default main filesystem since Android 2.3, but prior to that YAFFS was used. External storage and SD cards are usually formatted using FAT32 to maintain compatibility with Windows.

In terms of the specifics of the directory structure, the official Android documentation defines the following data storage options:

  • Internal: On modern versions of Android, internal storage is mainly represented by the /data/data/ directory and its symlink /data/user/0 directory.
    The main purpose of it is to securely store files private to apps. What this means is that no other apps, or even the user, have direct access to them. Each app gets its own folder, and if the user uninstalls the application, all its content will be deleted. Thus, the usual applications don't store anything that should persist independently of them here (for example, photos taken by a user with an app's help). Later, we will see what the corresponding behavior of malicious apps is.
  • External: Nowadays, this is generally associated with the /storage/emulated/0 path. In this case, /storage/self/primary is a symlink to it that, in turn, has /sdcard and /mnt/sdcard symlinks pointing to it. /mnt/user/0/primary is another common symlink pointing to /storage/emulated/0. This space is shared across all apps and is world-readable, including the end user. This is where users see well-known folders such as Downloads or DCIM. For apps themselves, its presence is not actually guaranteed, so availability should be checked each time it is accessed. In addition, apps have the option to have their own app-specific directory (in case they need more space), which will be deleted with the app once it is uninstalled. The main location for this data on modern forms of Android is /storage/emulated/0/Android/data/<app_name>. Again, this location is world-accessible.

In addition, the documentation describes shared preferences and databases, which are outside the scope of this book.

There may be a considerable level of confusion here in terms of naming, as many file-manager apps call the external file storage internal when they want to distinguish it from SD cards (which are treated by the OS in pretty much the same way as the embedded phone's external storage). The truth is, unless the device is rooted, the internal storage can't be accessed and therefore won't be visible to a normal user:

Figure 1: File manager referring to external storage as internal

Apart from this, here are some of other important file paths unique to Android:

  • /data/app and its modern symlink /factory: Contains APK and ODEX files for installed apps.
  • /data/dalvik-cache: Optimized bytecode for installed apps.
  • /system: This is the location of the operating system itself. It contains directories that are normally found in the root directory.
  • /vendor: A symbolic link to /system/vendor. This path contains vendor-specific files.
  • /system/app/: Contains pre-installed Android system apps, for example, to interact with the camera or messages.

Later, we will see what paths malware generally uses during the deployment stage.

Android security model

There are multiple mechanisms implemented in Android in order to complicate the lives of attackers. The system has evolved gradually over time, and the latest versions differ quite significantly from the earlier editions in terms of security. In addition, modern Android systems are based on the newer Linux kernel 4.x+ starting from version 7.0.

Process management

Android implements Mandatory Access Control (MAC) over all processes and uses the Security-Enhanced Linux (SELinux) model to enforce it. SELinux is based on the default denial principle, where everything that is not explicitly allowed is forbidden. Its implementation has evolved over different versions of Android; the enforcing mode was enabled in Android 5.0.

On Android, each app runs as an individual process and its own user is created. This is how process sandboxing is implemented: to ensure no process can access the data of another one. An example of the generated username in this case is u2_a84, where 2 is the actual user ID with the offset 100000 (the actual value will be 100002) and 84 is the app ID with the offset 10000 (which means the value itself is 10084). The mappings between apps and the corresponding user IDs can be found in the /data/system/packages.xml file (see the userId XML attribute) as well as in the matching, more concise packages.list file.

In addition to actual users, Android has many system accounts with predefined IDs. Apart from AID_ROOT (0), which is used to run some native daemons, here are some other examples:

  • AID_SYSTEM (1000): This is a regular user account with special permissions to interact with system services
  • AID_VPN (1016): This is associated with the Virtual Private Network (VPN) system
  • AID_SHELL (2000): This is the account the user gets when they use the adb tool with the shell argument
  • AID_INET (3003): Can create AF_INET/AF_INET6 sockets

A full, up-to-date list of these can be found in the android_filesystem_config.h file in the Android source code, which is easily accessible online.

In order to support Inter-Process Communication (IPC), a dedicated Binder mechanism has been introduced. It provides a remote method invocation functionality, where all communication between client and server apps passes through a dedicated device driver.

Filesystem

As we know now, all generic user data and shared app data is stored in /storage/emulated/0. It is available for read and write access, but setting executable permissions for files located there is not allowed. The idea here is that the user won't be able to simply write to a disk and then execute a custom binary directly, even by mistake or as the result of a social-engineering attack.

In contrast, each installed app has full access to its own directory in /data/data, but not to the directories of other apps unless they explicitly allow it. This is done so that one app won't be able to affect the work of another one or get access to sensitive data.

App permissions

The main purpose of app permissions is to protect user privacy by giving them control over what data and system functionalities can be accessed by each application. By default, no app can affect the work of another app, unless it is explicitly allowed to do so; the same applies to accessing sensitive user data. Depending on the version of Android and the settings, some permissions may be granted automatically, while others will require manual user approval.

The default behavior of requesting user consent depends on the Android version and the SDK version used to build the app. For Android 6.0+ and SDK version >= 23, the user is not notified about it at installation time. Instead, the app has to ask permission at runtime using a standard system dialog window. For older Android and SDK versions, all permissions are requested at installation time. The user is presented with groups rather than individual permissions; otherwise, it might be overwhelming to go through all of them.

Each app has to announce what permissions it requires in its embedded manifest file. For this purpose, dedicated <uses-permission> tags can be used. Permissions are split into three protection levels:

  • Normal: These entries may pose very little risk to the device's operation or a user. Examples of such permissions include:
    • ACCESS_NETWORK_STATE
    • BLUETOOTH
    • NFC
    • VIBRATE
  • Signature: These permissions are granted at installation time if the app is signed, for example:
    • BIND_AUTOFILL_SERVICE
    • BIND_VPN_SERVICE
    • WRITE_VOICEMAIL
  • Dangerous: These entries might pose a significant risk and therefore require manual approval. Unlike the previous two levels, they are split into groups, and if an app is granted at least one of the permissions within a group, it is supposed to get the rest without any interaction with the user. Here are some examples of these groups:
    • CONTACTS:
      • READ_CONTACTS
      • WRITE_CONTACTS
      • GET_ACCOUNTS
    • LOCATION:
      • ACCESS_FINE_LOCATION
      • ACCESS_COARSE_LOCATION

An example of permissions requested by a sample in its manifest file can be found in the figure below:

Figure 2: Example of permissions requested by malware in the manifest file

It is worth mentioning that the list of permissions evolved over time, with multiple new permissions being enforced eventually, making the system more secure. The exact API version where a particular permission is added (or deprecated) can be found in the most recent official Android documentation.

Apart from this, there are also so-called special permissions that don't behave like normal or dangerous ones. They are particularly important, so an app should also ask for user authorization, in addition to declaring them in the manifest file. Examples of such permissions are SYSTEM_ALERT_WINDOW and WRITE_SETTINGS.

As different devices may have different hardware features, another manifest tag, <uses-feature>, was introduced. In this case, if the android:required attribute is set to True, then Google Play won't allow that app to be installed on the device without the feature being supported by it.

Security services

Multiple services have been introduced on the Android platform in order to improve the overall security structure:

  • Android updates: As long as vulnerabilities are being identified and fixed, users receive updates to improve reliability and security
  • Google Play: Introduces several security features, such as application security scanning aiming to prevent malicious authors from uploading and promoting malicious software
  • Google Play Protect: A system that runs safety checks on apps downloaded from Google Store and checks the device for potentially malicious apps coming from other sources
  • SafetyNet: Provides several APIs, aiming to give apps processing sensitive data extra security-related information (for example, whether the current device is protected against known threats and whether the provided URL is safe)

Console

By default, the console is not available on the device itself (adb is supposed to be used from another connected device). Thus, in order to get the ability to execute basic commands, users have to install third-party apps such as Termux or Terminal Emulator:

Figure 3: Listing files in a root directory using the Terminal Emulator app

In this case, advanced commands can be used only on the rooted device with BusyBox or similar sets of tools installed separately.

Now, let's talk about rooting in greater detail.

To root or not to root?

Many everyday users encounter applications that require their device to be rooted. What exactly does it mean and how does this process actually work? In this section, we will explore the security mechanisms implemented in different Android versions and how they can be bypassed.

If the user requires some functionality not supported by standard system APIs (for example, removing certain pre-installed applications or carrier applications, and overclocking the CPU or completely replacing the OS), the only option they have—apart from logging a feature request—is to obtain root access through a known vulnerability. As a result, the user gets elevated privileges and full control over the system. The legality of this process varies depending on the country, but generally, it is either unclear (which means it falls into a grey area), acceptable for non-copyright-related activity, or regulated by some dedicated exemptions.

Sometimes, the rooting process is used interchangeably with jailbreaking, generally applied to iOS devices. However, these are different procedures in terms of scope. Jailbreaking is the process of bypassing several different types of end user restrictions; the main ones are listed here:

  • The ability to modify and replace the operating system (controlled by the locked bootloader technology on iOS)
  • Installing non-official applications (sideloading)
  • Obtaining elevated privileges (what is usually known as rooting)

Unlike iOS, on Android, it is possible to officially enable sideloading, and many devices are shipped with bootloaders unlocked, so only rooting remains an issue.

Each time a new vulnerability becomes known, the developers are expected to fix it and either release a security patch or make the next version of the OS secure. Thus, researchers have to come up with a new vulnerability to exploit in order to make rooting possible. Some rooting methods involve using the ADB, while others can be executed with the help of the usual user interface. Here are some of the most well-known privilege escalation exploits for Android OS:

Exploit name Vulnerability Vulnerability description
RAMpage CVE-2018-9442 Row hammer-based vulnerability in the kernel ION subsystem in Android
Drammer CVE-2016-6728 Row hammer-based vulnerability in the kernel ION subsystem in Android
dirtyc0w CVE-2016-5195 Race condition in the Linux kernel (mm/gup.c) allows local users to gain privileges by leveraging the incorrect handling of a Copy-on-Write (CoW) feature to write to a read-only memory mapping
PingPongRoot CVE-2015-3636 The ping_unhash function in the Linux kernel (net/ipv4/ping.c) does not initialize a certain list data structure
TowelRoot CVE-2014-3153 The futex_requeue function in the Linux kernel (kernel/futex.cdoes not ensure that calls have two different futex addresses

 

Rooting is accompanied by security risks for end users, as in this case they are no longer protected by system-embedded security mechanisms and restrictions. A common way to get root privileges is to place a standard Linux su utility, which is able to grant required privileges to custom files, to an accessible location and use it on demand. Malware can check whether this tool is already available on the compromised device and misuse it at its discretion without any extra work being required.

Many Android malware families are also bundled with rooting software in order to elevate privileges on their own. There are multiple reasons why root access is beneficial to malware authors; particularly, it allows them to obtain the following:

  • Access to crucial data
  • Improved persistence capabilities
  • Hiding capabilities

Examples of such malware families include:

  • Dvmap: Uses root privileges to modify system libraries for persistence and privilege escalation
  • Zeahache: Escalates privileges and opens a back door for other modules to enter the compromised system
  • Guerrilla: Here, root privileges are required to access a user's Google Play-related tokens and credentials and gain the ability to interact with the store directly, installing and promoting other apps
  • Ztorg: Escalates privileges, mainly to achieve better stealth and aggressively display ads
  • CopyCat: Infects Android's Zygote process (a template for other processes) and loads itself into other processes to access and alter sensitive information
  • Tordow: Steals sensitive information such as credentials from browsers

It is worth mentioning that not all malware families implement rooting, as it also increases the probability of being detected by antivirus solutions or damaging the device. In the end, it is up to the authors whether the advantages associated with it outweigh the risks, all depends on the purpose of malware.

Understanding Dalvik and ART 

The Android OS has evolved drastically over the past several years in order to address user and industry feedback, making it more stable, fast, and reliable. In this section, we will explore how the file execution process was implemented and progressed. In addition, we will dig into various original and newer file formats and learn how the Android executables are actually working.

Dalvik VM (DVM)

Dalvik was an open source process virtual machine used in Android up to version 4.4 (KitKat). It got its name after the Dalvík village in Iceland. Dalvik VM implements register-based architecture, which differs from stack-based architecture VMs such as Java VMs. The difference here is that stack-based machines use instructions to load and manipulate data on the stack and generally require more instructions than register machines in order to implement the same high-level code. In contrast, analogous register machine instructions often must define the register values used (which is not the case for stack-based machines, as the order of values on the stack is always known and the operands can be addressed implicitly by the stack pointer), so they tend to be bigger.

Usually, Dalvik programs are written in the Java or Kotlin languages before being converted to Dalvik instructions. For this purpose, a tool called dx is used, which converts Java class files into the DEX format. It is worth mentioning that multiple class files can be converted into a single DEX file.

Once DEX files are created, they can be combined together with resources and code native to the APK file ( this stands for Android Package); this is the standard way Android applications are distributed. Once the app gets executed, the DEX file is processed by the dexopt tool, producing the Optimized DEX (ODEX) file, which is interpreted by Dalvik VM.

Android 2.2 introduced the Just-In-Time (JIT) compiler for Dalvik. The way it works is that it continually profiles applications on every run and dynamically compiles the most used blocks of bytecode into native machine code. However, independent benchmark tests have shown that stack-based Java HotSpot VM is on average two to three times faster than DVM (with enabled JIT) on the same device, with the Dalvik code not taking less space. In order to improve the overall performance and introduce more features, ART was created.

Android runtime (ART)

ART was first introduced as an alternative runtime environment in Android 4.4 (KitKat) and completely replaced Dalvik in the subsequent major release of Android 5.0 (Lollipop).

In order to explore the relationships between Dalvik and ART, let's take a look at this diagram:

Figure 4: Diagram describing the differences between Dalvik and ART

As you can see, both Dalvik and ART share the same logic at the beginning and operate with the same DEX and APK files to maintain backward compatibility. The major differences are in how the files are actually processed and executed. Instead of interpreting DEX bytecode, ART translates it to machine code instructions in order to achieve better performance results. This way, instead of generating ODEX files at install time, ART compiles apps using the dex2oat tool to generate ELF files (already covered in the previous chapters) containing native code. Originally, they also contained DEX code, but on modern Android systems, the DEX code is stored in dedicated VDEX files rather than inside the OAT. This process is known as Ahead-Of-Time (AOT) compilation.

Android 7.0 (Nougat) also features a JIT compiler that complements AOT and optimizes the code execution on the fly based on the profiler output. While JIT and AOT use the same compiler, the former is able to incorporate runtime information in order to achieve better results generally, for example, via improved inlining. Here is a diagram depicting the relationship between JIT and AOT:

Figure 5: The process of compiling and executing files in ART

As you can see, if the AOT binary is available (which is not always the case), they are executed straight away, either from the JIT code cache (if it is JIT-compiled) or in the usual way. Otherwise, they are interpreted and optionally compiled by JIT, depending on how it is used throughout the system. In particular, whether it is used by other applications and whether it has a meaningful profile (profile files are recorded and created during the sample execution). The AOT compilation daemon also runs periodically and utilizes this information to (re)compile highly used files.

APIs

Most of the code for the Android platform is written in Java, so the whole infrastructure is focused on it. However, Android implements its own APIs in order to let programs interact with the OS to achieve their goals. While some classes might be quite similar to Java (for example, the System class), there are also a significant amount of differences, such as the different meaning of certain properties (or properties that lost their meaning). In addition, some introduced classes and APIs are new and aim to provide access to unique features implemented in Android. An example is the DexClassLoader class, which loads classes from JAR and APK files and can be used to execute code that wasn't part of an application. Here are some other examples of APIs and their classes, with self-explanatory names that can be commonly seen in malware:

  • SmsManager
    • sendTextMessage
  • ActivityManager
    • getRunningServices
    • getRunningAppProcesses
  • PackageManager
    • getInstalledApplications 
    • getInstalledPackages
  • DevicePolicyManager
    • lockNow
    • reboot
  • Camera
    • takePicture
  • DownloadManager.Request
    • setDestinationUri
  • DownloadManager
    • enqueue

Some functionality can also be accessed through the use of a combination of the Intent class, with a particular argument describing the requested action, and the Activity class, to actually perform an action, generally using the startActivityForResult method. 

Regarding the downloading-related functionality, many malware families obviously prefer to avoid using the standard download manager—as it tends to be more visible to the user—and instead implement it using Java classes such as java.net.URL and java.net.URLConnection. And, of course, as we know, some APIs require particular permissions to be requested prior to use. In this case, it should be at least android.permission.INTERNET.

File formats

Now that we know how Android works, it's time to go one level deeper and understand the main file formats used in its apps. 

Here are the most important file formats associated with applications written for different versions of Android.

DEX

The Dalvik EXecutable (DEX) format holds a set of class definitions and associated data. The file layout looks like the following:

 

Name Format Description
header header_item The header
string_ids string_id_item[] List of identifiers for all the strings used by this file
type_ids type_id_item[] List of identifiers for all types (classes, arrays, or primitive types) referred to by this file (whether defined here or not)
proto_ids proto_id_item[] List of identifiers for all prototypes referred to by this file
field_ids field_id_item[] List of identifiers for all fields referred to by this file (whether defined here or not)
method_ids method_id_item[] List of identifiers for all methods referred to by this file (whether defined here or not)
class_defs class_def_item[] List of class definitions; they should be ordered in a particular way so that a superclass and implemented interfaces appear in the list before the referring class
call_site_ids call_site_id_item[] List of identifiers for all call sites referred to by this file (whether defined here or not)
method_handles method_handle_item[] List of all method handles referred to by this file (whether defined in the file or not); they are not sorted and, unlike previous lists, may contain duplicates
data ubyte[] This area contains all supporting data for the previously mentioned tables, with padding bytes used before each item to achieve proper alignment
link_data ubyte[] Data with an unspecified format used in statically linked files (empty in unlinked files)

 

The rest of the fields define the sizes and offset of other data blocks:

Figure 6: DEX header with offsets described

The header starts with an 8-byte DEX_FILE_MAGIC that consists of a DEX string (x64x65x78) followed by the newline symbol (x0a), the 3 bytes defining a format version, and finally a zero byte (x00). This format aims to provide a way to identify DEX files and the corresponding layout used, and to prevent basic data corruption.

ODEX

Actively used before the appearance of ART, Optimized Dalvik EXecutable (ODEX) files are the result of optimizations made to DEX on the device in order to improve performance and decrease the result size. ODEX files consist of the already described DEX layout wrapped with a short ODEX header:

typedef struct DexOptHeader {
u1 magic[8];
u4 dexOffset;
u4 dexLength;
u4 depsOffset;
u4 depsLength;
u4 auxOffset;
u4 auxLength;
u4 flags;
u4 padding;
} DexOptHeader;

The header magic value is the same as for DEX, but features a slightly different first 3-byte signature, dey (x64x65x79) rather than dex. This format is defined in the DexFile.h source code file.

OAT

OAT files aimed to replace ODEX in the newer ART environment. To begin with, the file extensions shouldn't be trusted when dealing with Android executables. In particular, on recent Android systems, files with the .dex, .odex and .oat extensions may actually implement the OAT format. It is not very well-documented and varies for different versions of Android, but the most important thing here is that the result data is wrapped in ELF shared objects. Starting from Android Oreo, it doesn't store DEX code, leaving it to VDEX files, and is used mainly to store mapping information and the native code.

VDEX

These files were introduced in newer versions of Android (starting from Android Oreo) and are created by the dex2oattool. The idea here is to store DEX code not inside the OAT structure but independently, with some additional metadata to speed up verification. As with OAT, the file format is not documented and changes between different versions of Android. Its description can be found in Android's vdex_file.h source code file.

Apart from this, a new internal ART format called Compact DEX (CDEX) was introduced in Android 9. It aims to reduce storage and RAM usage by compacting various data structures and de-duplicating data blobs in cases where multiple DEX files are present; it may be encountered when working with VDEX files. The corresponding magic header value to recognize them in this case would be cdex. The most up-to-date description can be found in the compact_dex_file.h source code file.

ART

These files contain internal representations of certain strings and classes listed in the APK for ART, and are used to speed up application startup. The common file extension used in this case is .art. As in the previous case, this file format is not documented and changes between different versions of Android. As it is generally not used by malware, we won't go into greater detail here.

ELF

In addition to Android-specific file formats, it is also possible to execute general ELF files compiled for the corresponding architecture. Unlike Linux systems, which mostly rely on glibc, Android uses its own Bionic C library due to licensing issues. At the moment, x86, ARM, and MIPS (both 32-bit and 64-bit) architectures are supported. Apart from this, as has just been mentioned, it is also used to store OAT data blocks for optimized Android executables.

The ELF format has already been covered in great detail in Chapter 10, Dissecting Linux and IoT Malware.

APK

APK files are archive files based on the JAR format, which, as we know from Chapter 8Reversing Bytecode Languages: .NET, Java, and More, implements the ZIP format. What this means is that APK files can be unpacked using any software supporting ZIP-compressed files.

Usually, APK files contain the following files:

  • res: This directory contains various resource files (such as XMLs and pictures)
  • META-INF: Mainly stores metadata files about the package:
    • MANIFEST.MF: Manifest file containing names and SHA1/SHA2 digests of files inside the APK
    • <name>.RSA: Contains the application's signature and certificate
    • <name>.SF: Contains SHA1/SHA2 digests of the corresponding lines in the MANIFEST.MF and the list of associated resources
  • AndroidManifest.xml: Main manifest file defining various important app-related values for the system and Google Play
  • classes.dex: Compiled file containing the app's DEX bytecode; there can be several of them named classes<num>.dex
  • resources.arsc: This compiled file contains metadata associated with resources used by the app

At the moment, Android doesn't perform CA verification for application certificates, so self-signed certificates are allowed. Apart from this, other directories such as assets and files can also be commonly found inside APK files.

Regarding AndroidManifest.xml, only the <manifest> and <application> elements are required to be present. Generally, the following data can be specified there:

  • Basic app information (such as the package name)
  • App components and the corresponding types (activity, service, broadcast receiver, or content provider)
  • Required permissions (see the corresponding section Android security model)
  • Hardware and software features the app needs
  • Information about the supported Android SDK

It is worth mentioning that AndroidManifest.xml is stored in human-unreadable format inside the APK, so instead of just unzipping it, tools like apktool should be used for extraction.

Unlike programs on many other systems, generally speaking, Android apps don't have a single entry point, which means there is no main function. However, the sample's main activity can be found by searching for a component that has an associated android.intent.action.MAIN value in the app manifest. In addition, the Application subclass specified in the android:name attribute of the <application> element is instantiated before any of the application's components. As a rule, the onCreate method is executed first:

Figure 7: The onCreate method in the disassembled Android sample

Now that we know the most important file layouts used, let's talk about the bytecode instructions making the actual logic work.

Bytecode set

As we know, Dalvik is a register-based machine, which defines the syntax of bytecode. There are multiple instructions operating with registers in order to access and manipulate data. The total size of any instruction is a multiple of 2 bytes. All instructions are type-agnostic, which means they don't differentiate between values of different data types as long as their sizes are the same.

Here are some examples of what they look like in the official documentation. We'll split them into several categories for easier navigation:

  • Data access and movement:
Opcode and format Mnemonic/syntax Arguments Description Examples
01 12x move vA, vB A: destination register (4 bits)
B: source register (4 bits)
Move the contents of one non-object register to another 0110 - move v0, v1
0a 11x move-result vAA A: destination register (8 bits) Move the single-word non-object result of the most recent invoke-kind into the indicated register—this must be given as the instruction immediately after an invoke-kind whose (single-word, non-object) result is not to be ignored; anywhere else is invalid 0a00 - move-result v0
14 31i const vAA, #+BBBBBBBB A: destination register (8 bits)
B: arbitrary 32-bit constant
Move the given literal value into the specified register 1400 3041 ab00 - const v0, #11223344
1a 21c const-string vAA, string@BBBB A: destination register (8 bits)
B: string index
Move a reference to the string specified by the given index into the specified register 1a02 0000 - const-string v2, "" (where "" will be an entry #0 in the string table)
  • Arithmetic operations:
Opcode and format Mnemonic/syntax Arguments Description Examples
7b..8f 12x

unop vA, vB

  • 7b: neg-int
  • 7c: not-int
  • 7d: neg-long
  • 7e: not-long
  • 7f: neg-float
  • ...
A: Destination register or pair (4 bits)
B: Source register or pair (4 bits)
Perform the identified unary operation on the source register, storing the result in the destination register 7b01 - neg-int v1, v0
90..af 23x

binop vAA, vBB, vCC

  • 90: add-int
  • 91: sub-int
  • 92: mul-int
  • 93: div-int
  • 94: rem-int
  • 95: and-int
  • 96: or-int
  • 97: xor-int
  • ...
A: Destination register or pair (8 bits)
B: First source register or pair (8 bits)
C: Second source register or pair (8 bits)
Perform the identified binary operation on the two source registers, storing the result in the destination register 9000 0102 - add-int v0, v1, v2
b0..cf 12x

binop/2addr vA, vB

  • b0: add-int/2addr
  • b1: sub-int/2addr
  • b2: mul-int/2addr
  • b3: div-int/2addr
  • b4: rem-int/2addr
  • ...
A: Destination and first source register or pair (4 bits)
B: Second source register or pair (4 bits)
Perform the identified binary operation on the two source registers, storing the result in the first source register b010 - add-int/2addr v0, v1
  • Branching and calls: As all instructions are a multiple of 2 bytes, all branching instructions operate with words:
Opcode and format Mnemonic/syntax Arguments Description Examples
0e 10x return-void None Return from a void method 0e00 - return-void
28 10t goto +AA A: Signed branch offset (8-bits) Unconditionally jump to the indicated instruction 2803 - goto :goto_0 (goto_0 is a label of the target offset; in this example, it is located at the offset +0x03 words from the current position)
32..37 22t if-test vA, vB, +CCCC
  • 32: if-eq
  • 33: if-ne
  • 34: if-lt
  • 35: if-ge
  • 36: if-gt
  • 37: if-le
A: First register to test (4 bits)
B: Second register to test (4 bits)
C: Signed branch offset (16 bits)
Branch to the given destination if the given two registers' values compare as specified 3310 0500 - if-ne v0, v1, :cond_0 (cond_0 is a label of the target offset; in this example, it is located at the offset +0x05 words from the current position)
6e..72 35c

invoke-kind {vC, vD, vE, vF, vG}, meth@BBBB

  • 6e: invoke-virtual
  • 6f: invoke-super
  • 70: invoke-direct
  • 71: invoke-static
  • 72: invoke-interface
A: Argument word count (4 bits)
B: Method reference index (16 bits)
C..G: Argument registers (4 bits each)
Call the indicated method; the result (if any) may be stored with an appropriate move-result* variant as the immediately subsequent instruction

6e20 0100 1000 - invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V (here println will have an index 1 in the method table)

 

It is worth mentioning that some sets of instructions (for example, for optimized code) can be marked as unused in the official documentation, and it is quite unlikely they will be found in malware aiming to achieve the maximum coverage possible.

Now, let's examine the format notation used in the first column.

The first byte is the opcode of the instruction (Dalvik utilizes only one-byte values (00-0xFF) to encode the instructions themselves). In the official documentation, some similar instructions are grouped into one row with the range they belong to specified in the first column and the mappings for the corresponding instructions provided in the second column.

Supported instruction formats are described using a special format ID notation in the official documentation. Format IDs mostly consist of three characters: two digits and a letter. The first digit indicates the number of two-byte code unit in the resulting bytecode (see the Examples column) while the second digit specifies the maximum number of registers used (as some instructions support a variable amount of them). The final letter indicates the type of any extra data encoded by the format. Here is the official table describing these mnemonics:

Mnemonic Bit size Meaning
b 8 Immediate signed byte
c 16, 32 Constant pool index
f 16 Interface constants (only used in statically linked formats)
h 16 Immediate signed hat (high-order bits of a 32- or 64-bit value; low-order bits are all 0)
i 32 Immediate signed int, or 32-bit float
l 64 Immediate signed long, or 64-bit double
m 16 Method constants (only used in statically linked formats)
n 4 Immediate signed nibble
s 16 Immediate signed short
t 8, 16, 32 Branch target
x 0 No additional data

 

In addition, there are several prefixes for arguments used in the second column:

  • The v symbol is used to mark the arguments that the name registers
  • The #+ prefix specifies arguments indicating a literal value
  • The + symbol is used for arguments that indicate a relative instruction address offset
  • The kind@ prefix indicates a constant pool kind (string, type, field, and so on)

A separate official document describes all possible variants of formats:

Figure 8: Example of disassembled Dalvik bytecode

Overall, the related Android documentation is very detailed and easily accessible, so in case of doubt, it always makes sense to consult it.

Malware behavior patterns

Generally speaking, even though malware for mobile devices has its own nuances caused by the different environment and use cases of the targeted systems, many motivation patterns behind attack stays the same across multiple platforms. In this section, we are going to dive deep into various examples of mobile malware functionality and learn what methods it uses in order to achieve malevolent goals.

Attack stages

Now that we know how things are supposed to work, let's take a look at how malware authors leverage this. Here, we will go through various attack stages common for the vast majority of malware, which will enable us to see these patterns in the analyzed samples and this way understand their purpose.

Penetration

The most common ways malware gets access to devices are the following:

  • Google Play
  • Third-party markets and sideloading
  • Malicious ads and exploits

In the first two cases, malware authors generally rely on social engineering, tricking users into installing a potentially useful app. There are many techniques used to make this possible, such as the following:

  • Similar design: The app may look like and have a similar name to some other well-known, legal application
  • Fake reviews: To make the app look authentic and not suspicious
  • Anti-detection techniques: To bypass automatic malware scanners and prolongate the hosting
  • Malicious update: The original application uploaded to the store is clean, but its update contains hidden malicious functionality
  • Luring description: Promises free or forbidden content, easy money, and so on

Another option here is that the app itself will actually be legal, but will also contain hidden, embedded malicious functionality. There are multiple ways the user may come across it: by clicking fraudulent links received via messengers, texts, emails, or left on forums; encountering it during searches for particular apps due to illegal SEO (search engine optimization) techniques; and others.

The third technique involves delivering malicious code through the advertisement network with the help of exploits. An example could be lbxslt, an exploit leaked from the Hacking Team and used by attackers to spread ransomware in 2017. In addition, exploits may also be used for high-profile attacks targeting particular individuals.

Deployment

The next stage is to obtain all required permissions. Apart from the rooting options already discussed, it is possible for malware to abuse so-called administrative permissions. Originally designed for enterprise use cases to remotely administrate the mobile devices of employees, they can offer malware powerful capabilities, including the ability to wipe important data. Usually, the easiest way to get permissions is to keep asking the user and don't stop until they are granted.

As long as all required privileges are obtained, malware generally attempts to deploy its modules to a safe place. At this stage, extra modules can be downloaded after contacting the C&C server.

The most common places where malware installs itself once it gets executed include the following:

  • /data/data: Standard paths intended to be used for all Android applications. This approach poses a threat to attackers, as it is relatively easy to remediate such threats.
  • /system/(app|priv-app|lib|bin|xbin|etc): These paths require malware to use rooting exploits to get access to them. This makes it harder for the user to identify and delete the threat.

Persistence in this case can be achieved using the standard Android BroadcastReceiver functionality common to all apps using BOOT_COMPLETED action. RECEIVE_BOOT_COMPLETED permission is required in this case.

Action phase

As long as the malware completed its installation, it can switch to the main purpose it was created for. The exact implementation will vary drastically depending on that. Here are some of the most common behaviors found in mass malware:

  • Premium SMS senders: Probably the easiest way to make money straight away in mobile malware in certain countries is to send paid SMS messages to premium numbers (including the ones related to in-app purchases) or subscribing to paid services. Each of them will cost a certain amount of money, or an automatic subscription payment will be taken regularly, which eventually leads to draining the victim's balance. In order to bypass CAPTCHA protection, existing anti-CAPTCHA services may be used.
  • Clickers: A more generic group of threats that uses mobile devices to make money in multiple different ways:
    • Ad clickers: Simulate clicks on advertising websites without the user's interaction, eventually draining money from advertising companies.
    • WAP clickers: This group is similar to SMS senders in the way that it uses another form of mobile payment, this time by simulating clicks on WAP-billing web pages. The charge will be applied to the victim's phone balance.
    • Clickers that increase traffic to websites for illegal SEO purposes, for example to promote malicious apps.
    • Clickers that buy expensive apps on Google Play, for example, using accessibility services to emulate user taps or implementing their own clients to interact with the store directly.
  • Adware: These threats aim to monetize custom advertisements shown to users, often in an excessive and abusive way.
  • Banking trojans: A more advanced group of malware aiming to steal users' banking information and get access to their bank accounts. The most common ways to do this are to display fake windows simulating a real banking or popular booking app on top of the real one and let the user enter their credentials there, or to use accessibility services to make the real app perform illegitimate transactions. Access to SMS messages on a device can be used to bypass the two-factor authorization introduced by some banks.
  • Ransomware: As in the PC world, some malware families try to block access to certain files or a whole device to illegal users into paying a ransom in order to restore access. Quite often, this behavior is accompanied by threats that the affected user did something wrong (for example, watched illegal content) and requires them to pay a fine, otherwise, the information will become public.
  • Infostealers: As mobile devices often contain sensitive information, including saved credentials, photos, and private messages, it is also possible for malware authors to make money from stealing it, for example, by selling it on the underground market or extorting users. Another option possible here is cyber espionage.
  • DDoS: Multiple infected mobile devices can generate enough traffic to cause significant load for the targeted websites.
  • Proxy: Quite rarely used alone, this functionality allows malicious actors to use infected devices as a free proxy to get access to particular resources and increase anonymity. An example of such a family is Sockbot.
  • Cryptocurrency miners: This group abuses device's calculation power in order to mine cryptocurrencies. While the CPU of each device might be not very powerful, a big amount of affected devices all together can generate significant profit for attackers. For the affected user, it results in increased traffic usage, and the device slows down drastically and excessively heats up, which eventually may cause damage.

Some trojans prefer to implement backdoor functionality and then deliver customizable modules in order to achieve flexibility in extending malware functionality.

It is worth mentioning that not all malware families get their unique names based on the actual functionality. Quite often, a shared name describing its propagation method is used, for example, Fakeapp.

In terms of propagation, as malware can easily get access to a victim's contacts, usually, the spreading mechanism involves sending links or samples to people the user knows via text, messengers, and email.

As for getting the actual money, at first, malware authors preferred to get it via premium SMS messages and local payment kiosks. Later, with the rise of cryptocurrency such as Bitcoin, alternative options became an obvious choice for malicious authors due to anonymity and an easier setup process providing users with detailed instructions on how to make a payment.

Advanced techniques—investment pays off

While many mass malware families follow similar patterns in order to achieve their goals, there is also a much smaller—but at the same time, often of a higher significance—set of samples implementing advanced techniques in order to achieve more specific goals. An example is APT groups performing high-profile espionage tasks and therefore having much higher requirements in terms of stealth and effectiveness. In this section, we will go through some of the most notorious examples and cover advanced techniques that have been implemented.

Patching system libraries

An example of the malware family implementing this technique is Dvmap. It uses root privileges to back up and then to patch system libraries (particularly libdvm.so and libandroid_runtime.so), injecting its code there. The libraries are supposed to execute a standard system executable with system privileges, which is replaced by attackers to achieve persistence and escalate privileges at the same time.

Keylogging

Pure keylogging without screen capturing is not very common for Android malware. There are several reasons for this, starting with the fact that, in most cases, it is just not needed, and also because of the peculiarities of data input on mobile devices. Sometimes high-profile spying malware implements it in a pretty creative way. For example, it is possible to keep track of screen touches and match them against a pre-defined map of coordinates to deduce the keys pressed.

An example of a family implementing it is BusyGasper, which is a backdoor malware.

Self-defense

There are multiple techniques mobile malware can incorporate in order to protect itself, including the following:

  • An inaccessible location: A previously mentioned technique where malware uses rooting exploits to become able to deploy itself into locations that are not accessible with standard user privileges. Another option is to overwrite existing system apps.
  • Detecting privilege revocation: Multiple techniques are used to scare the user when permissions are revoked in an attempt to prevent it.
  • Detecting AV solutions: In this case, malware keeps looking for files associated with known antivirus products and, once detected, may display a nag window asking for its uninstallation. Such messages are shown in a loop and prevent the victim from using the device properly until the requested action is done.
  • Emulator and sandbox detection: Here, the malware checks whether it is being executed on the emulated environment or not. There are multiple ways it can be done: by checking the presence of certain system files or values inside them, such as IMEI and IMSI, build information, various product-related values, as well as the phone numbers used. In this case, malware behaves differently depending on the result in order to tamper with automatic and manual analysis. Another popular simple technique used to bypass basic sandboxes with an execution time limit is to sleep or perform benign actions for a certain period of time.
  • Icon hiding: The idea here is that the user can't easily uninstall the app using an icon. For example, a transparent image with no visible app name can be used.
  • Multiple copies: Malware can install itself in various locations in the hope that some of them will be missed. In addition, infecting the Zygote process allows malware to create multiple copies in memory.
  • Code packing/obfuscation: As many Android programs are written in Java, the same code protection solutions can also be used here. Multiple commercial options are available on the market at the moment.

Rootkits—get it covered

In previous chapters, we covered state-of-the-art malware aiming to get more control over the operating system in order to perform more advanced tasks, such as hiding files and processes from monitoring software and amending data at a lower level. These approaches can be applied to mobile operating systems as well. While still not actively used by malware due to deployment complexity, there are several open source projects proving that it is possible.

One of them is the Android-Rootkit project, based on the ideas described in Phrack Issue 68 about intercepting various system calls by hooking sys_call_table. The final goal here is to hide the presence of a sample at a low level.

Static and dynamic analysis of threats

At this stage, we have enough knowledge to start analyzing actual malware. For static analysis, the process and tools used will be mostly the same for different versions of the Android OS (regardless of whether it is based on the older Dalvik VM or newer ART technology); the differences will be in the dynamic analysis techniques used. Now it is time to get our hands dirty and become familiar with instruments that can facilitate this process.

Static analysis

Generally, static analysis of bytecode malware involves either disassembling it and digging into the bytecode instructions or decompiling to the original language and exploring the source code. In many cases, the latter approach is preferable where possible as reading the human-friendly code reduces the time associated with the analysis. The former approach is often used when decompiling doesn't work for whatever reason such as the lack of up-to-date tools or because of anti-reverse engineering techniques implemented in the sample.

Here are some of the most commonly used tools for static analysis of Android malware.

Disassembling and data extraction

These tools aim to restore Dalvik assembly from the compiled bytecode:

  • Smali/Baksmali: Smali (assembler in Icelandic) is the name of the assembler tool that can be used to compile Dalvik instructions to the bytecode and, in this way, build full-fledged DEX files. The corresponding disassembler's name is Baksmali; it can restore Dalvik assembly code from bytecode instructions as well as dump a DEX header structure and deodex files. Both tools operate with text files storing assembly code that have .smali file extensions.
    There were a handful of changes to the format between 1.* and 2.* SMALI files. To convert existing SMALI files to the new format, you can assemble the old ones with the latest Smali tool, version 1, and then disassemble them with the latest Baksmali tool, version 2.
  • Apktool: A wrapper around the Smali tool; it provides the functionality to easily process APK files:


Figure 9: The interface of the Apktool

Apart from these, there are other desktop and online solutions built on top of these two, providing convenient UIs and extra features, for example, APK Studio.

  • oat2dex (part of SmaliEx): A very useful tool to extract DEX bytecode from older ELF files, storing it as part of the OAT data so that it can be analyzed as usual.
  • vdexExtractor: This tool can be used to extract DEX bytecode from VDEX files as modern OAT files don't store it anymore.
  • LIEF: This cross-platform library provides plenty of functionality to parse and modify Android files of various formats.

While bytecode assembly can definitely be used for static analysis purposes on its own, many engineers prefer to work with decompiled code instead to save time. In this case, decompiling tools are extremely useful.

Decompiling

Instead of restoring the assembly instructions, this set of tools restores the source code, which is usually a more human-friendly option:

  • JADXDEX to Java decompiler. It provides both a command-lines and a GUI tool to obtain close to the original source code in the Java language. In addition, it provides basic deobfuscation functionality:

Figure 10. Decompiled Android sample in JADX
  • AndroChef: This commercial decompiler supports both Java and Android files and provides a handy GUI to go through the results.
  • JEB decompiler: Another powerful commercial disassembling and decompiling solution, this supports both Dalvik and machine code.
  • dex2jar: While not exactly a decompiler, this tool allows engineers to convert DEX files to JARs. After that, it becomes possible to use multiple Java decompilers to obtain Java source code, which has already been discussed in Chapter 8Reversing Bytecode Languages: .NET, Java, and More.
  • Ghidra: In addition to native executables, this powerful toolset also supports Android apps by converting them to JARs and can be used to facilitate static analysis for this platform.

Once obtained, the source code can be analyzed in any IDE or text editor with syntax highlighting that supports it.

Now it is time to explore the options engineers have to perform dynamic analysis.

Dynamic analysis

Effective dynamic analysis requires either some sort of emulation or remote debugging, as many mobile devices tend to have relatively small native screens and basic input capabilities.

Android debug bridge

Android debug bridge (ADB) is a versatile command-line tool that lets users interact with mobile devices from the PC, providing a variety of actions. It is part of the Android SDK Platform Tools and consists of three parts:

  • A client running on the PC, providing an interface to enter commands.
  • A daemon (adbd) executing entered commands on the mobile device. It runs as a background process on all devices.
  • A server running on the PC that manages communication between the client and the daemon.

On the device, ADB debugging can be enabled explicitly using the USB Debugging option under Developer options in Settings. On a modern Android OS, this option is hidden by default and can become visible by tapping the Build number option (usually, can be found in Settings | About phone) option multiple times and then returning to the previous screen. In addition to real devices, a server can also recognize and work with Android emulators.

In addition to accessing the device via USB, wireless interaction via Wi-Fi is also possible by first issuing the adb tcpip <port> command via USB and then disconnecting the device and using the adb connect <ip_address> command.

Here are some examples of other command-line options available:

  • adb devices: List the attached devices
  • adb kill-server: Reset the adb host
  • adb install <path_to_apk>: Sideload the app using its APK file
  • adb pull or adb push: Move files between the mobile device and the PC
  • adb root or adb unroot: Restart the adbd daemon with or without root permissions (not intended to be used in production builds)
  • adb shell: Run a remote interactive shell

In addition, ADB can be used to issue commands to additional modules:

  • Activity Manager (AM): Responsible for performing various system-related actions
  • Package Manager (PM): Performs actions on apps installed on the device
  • Device Policy Manager (DPM): Used for developing and testing device management apps

All commands can be found in the comprehensive official documentation.

Emulators

As for any other platform, emulators aim to facilitate dynamic analysis by emulating the executed instructions without the need to use real devices. There are several third-party solutions aiming to provide easier access to Android apps and games, for example, BlueStacks. However, for reverse engineering purposes, solutions that are more focused on giving developers the ability to create and debug apps generally provide better options. They include the following:

  • Android emulator: The official Android emulator can be installed as part of the official Android SDK tools using the SDK Manager. It provides almost all the capabilities of real physical devices and comes with predefined sets of configurations aiming to simulate various mobile devices (phones, tablets, and wearables) on the PC. Another major advantage of it is the ability to create and restore snapshots containing the entire state of an emulated machine.
  • VMWare/VirtualBox: These versatile solutions can be used to run an Android image and perform dynamic analysis in a similar way to what would be done on the Linux VM.
  • QEMU and its derivatives: Both QEMU and QEMU-based emulators such as Limbo can be used to emulate malicious code as well.
  • Genymotion: Quite a unique solution, providing both desktop and cloud-based Android virtual devices.

Behavioral analysis and tracing

An example of the behavioral analysis system is the TaintDroid project, originally created to investigate how apps use privacy-sensitive information. Tracking down other apps is implemented by integrating this software into the Android platform at a low level. As a result, it is implemented in the form of custom-built firmware.

AndroidHooker and IntroSpy are two projects aiming to provide the functionality for the dynamic analysis of Android applications; both rely on the Cydia Substrate framework.

A different approach has been taken by the developers of the AppMon solution, which includes a set of components to intercept and manipulate API calls. It is based on the Frida Project, which also provides its own tracing tool.

Another tool based on Frida is Objection, which provides access to multiple options including various memory-related tasks, the simulation of rooted environments, an SSL pinning bypass, and the execution of custom scripts.

As long as the malicious sample is decompiled, it becomes possible to embed various libraries intercepting API calls, for example, AndroidSnooper to intercept HTTP traffic.

One more powerful solution that is worth mentioning is the Xposed framework. It allows the creation of modules to extend ROMs by manipulating Zygote processes. An example of such a useful module is XposedBridge, which can hook methods and produce a log with a list of APIs called.

Finally, the jtrace tool can be used as an alternative to the traditional strace

Debuggers

Once the app of interest is decompiled back to Java code, it can be debugged like usual source code in any IDE supporting it. This part has already been covered in Chapter 8Reversing Bytecode Languages: .NET, Java, and More.

However, sometimes it is required to debug the native Dalvik instructions. Luckily, there are tools that can facilitate this process. One that deserves particular attention is smalidea. It is a plugin for IntelliJ IDEA (or Android Studio, based on it) allowing for step-by-step execution of the analyzed code. This project belongs to the Smali authors and can be found with the corresponding assembler and disassembler tools.

In addition, Android already provides several options to debug apps and processes using the console, particularly gdb and jdb:

  • gdbclient can be used to attach to already running apps and native daemons
  • Native process startup can be debugged using a combination of the gdbserver and gdbclient tools:
adb shell gdbserver64 :<port> <path_to_app> # remove "64" for 32-bit apps
gdbclient.py -p <app_pid>
  • For ARM, it may be necessary to explicitly specify the instruction set, as gdb can get confused without the source code provided:
set arm fallback-mode arm  # or thumb
  • App process startup can be debugged in the following way:
    1. Go to Settings | Developer options | Select debug app, choose the app of interest, and press Wait for debugger

    2. Start the app from the launcher or using the console; wait for the confirmation dialog to appear

    3. Attach the debugger as usual

Analysis workflow

Here is an example of the workflow, describing how the Android sample analysis can be performed:

  1. Sample acquisition: Quite often, the sample is already provided by the customer or is easily downloadable from a third-party website. However, sometimes it is required to obtain samples from Google Play. There are multiple ways this can be done: by using dedicated tools such as APK Downloader or by installing an app on the emulator and then getting its APK file from the disk. If optimized ART files are provided (particularly OAT), make sure you have all the system files required to extract the DEX bytecode, for example, the boot.oat file.
  2. Decompilation/disassembling: For apps, it always makes sense to try to get the decompiled source code, as, usually, it is much easier to read it and perform dynamic analysis, including alteration if necessary. If decompilation doesn't work and some anti-reverse engineering technique is expected, then the code can be disassembled so that the tampering logic can be amended. Native code in ELF binaries can be analyzed in the same way as described in Chapter 10Dissecting Linux and IoT Malware.
  3. Reviewing the app manifest: It is worth spending some time reviewing the app manifest first, as it can give you valuable insight into the sample's functionality, in particular, the following:
    • The permissions requested
    • The components available
    • The main activity and the Application subclass
  4. Code analysis: Now it is time to open the whole project in the IDE or any other tool providing a convenient UI to start reviewing the logic. Many engineers prefer to start with the onCreate methods of the main activity component and the Application subclass specified in the manifest, as the app execution starts there.
  5. Deobfuscation and decryption: If it has been confirmed that the sample is obfuscated, at first, it's worth trying to figure out whether it is a known Java solution and whether any ready deobfuscators exist. If not, then generic method renaming will be helpful. There are multiple tools that can do it; see the corresponding Chapter 8Reversing Bytecode Languages: .NET, Java, and More.
  6. Behavioral analysis: It always makes sense to execute a sample in the emulator with your behavioral analysis tool of choice enabled to quickly get an idea of the potential functionality. If some emulator detection technique is implemented, usually, it's pretty straightforward to identify it in the code and amend the sample to exclude these checks.
  7. Debugging: Sometimes it's hard to understand certain blocks of functionality, particularly ones where malware heavily interacts with the operating system. In this case, proper step-by-step debugging might be required to speed up the analysis. Always use emulators supporting snapshot creation so it becomes possible to go back and quickly reproduce the same situation as many times as necessary.

Obviously, each case is unique, and depending on circumstances, the selection of actions and their order may vary. Malware analysis is also an art and often requires a certain amount of creativity in order to achieve results in a prompt way.

Summary

In this chapter, we learned about the most important internals of the Android operating system and covered different runtime environments implemented on different versions of it. In addition, we described the associated file formats and went through the syntax for associated bytecode instructions.

Then, we dived deep into the world of modern mobile malware and went through the different types and their associated behavior. We also learned how attackers can bypass Android security mechanisms in order to achieve malicious goals. Finally, we became familiar with various reverse engineering tools aiming to facilitate static and dynamic analysis, and provided guidelines on how and when they can be used.

Equipped with this knowledge, you can better track threat actors that are trying to penetrate Android devices. This will allow you to stay on top of attackers and mitigate risks. In addition, the set of skills obtained can be used during the incident response process to properly understand the attack logic and eventually improve the overall security posture.

This is the last chapter of this book—we hope you enjoyed it! Malware analysis is a never-ending journey and we really hope this book will help many experienced and novice engineers analyze modern and future threats and eventually make the world a safer place.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.252.140