10mm10mm

assets/logos/InIT.pdf  .
Master of Science in Engineering FirmwareDroid:
Security Analysis of the Android Firmware Eco-System

Author

Thomas Sutter
Supervisor

Prof. Dr. Bernhard Tellenbach
Date
31.01.2021

## DECLARATION OF ORIGINALITY

### Declaration concerning the independent drafting of a project at the School
of Engineering

By submitting this Master’s thesis, the undersigned student confirms that this
thesis is his/her own work and was written without the help of a third party.

The student declares that all sources in the text (including Internet pages)
and appendices have been correctly disclosed. This means that there has been
no plagiarism, i.e. no sections of the Master’s thesis have been partially or
wholly taken from other texts and represented as the student’s own work or
included without being correctly referenced.

Any misconduct will be dealt with according to paragraphs 39 and 40 of the
General Academic Regulations for Bachelor’s and Master’s Degree courses at the
Zurich University of Applied Sciences (Rahmenprüfungsordnung ZHAW (RPO)) and
subject to the provisions for disciplinary action stipulated in the University
regulations.

City, Date: Signature:

## Abstract

The Android Open Source Project (AOSP) is probably the most used and
customized operating system for smartphones and IoT devices worldwide. Its
market share and high adaptability makes Android an interesting operating
system for many developers. Nowadays, we use Android firmware in smartphones,
TVs, smartwatches, cars, and other devices by various vendors and
manufacturers.

The sheer amount of customized Android firmware and devices makes it hard for
security analysts to detect potentially harmful applications. Another fact is
that many vendors include apps from 3rd party developers. Such bloatware
usually has more privileges than standard apps and cannot be removed by the
user without rooting the device. In recent years several cases were reported
where 3rd party developers could include malicious apps into the Android built
chain. Media reports claim that pre-installed malware like Chamois and Triade
we able to infect several million devices. Such cases demonstrate the need for
better strategies for analyzing Android firmware.

In our study, we analyze the Android firmware eco-system in various ways. We
collected a dataset with several thousand Android firmware archives and show
that several terabytes of firmware data are waiting on the web to be analyzed.
We develop a web service called FirmwareDroid for analyzing Android firmware
archives and pre-installed apps and create a dataset of firmware samples.
Focusing on Android apps, we automated the process of extracting and scanning
pre-installed apps with state of the art open-source tools.

We demonstrate on real data that pre-installed apps are, in fact, a a threat
to Android’s users, and we can detect several hundred malware samples using
scanners like VirusTotal, AndroGuard, and APKiD. With state of the art tools,
we could scan more than 900’000 apps during our research and give unique
insights into Android custom ROMs. Moreover, we enhanced FirmwareDroid with
fuzzy hashing algorithms and used them to detect similarities between
binaries.

We show that automated security testing of Android firmware is feasible and
that we can detect pre-installed malware with open-source analysis tools. We
explain the challenges of dynamic analysis of Android pre-installed apps and
discuss the limits of fuzzy hashing algorithms for similarity detection.

## Glossary

Firmware archive

    A compressed file that contains all parts of an Android firmware images like the kernel or the system partition
Fs-verity

    A integrity protection system for read+write partitions
Root of Trust

    A cryptographic key that starts a chain of trust
Smali

    a Android specific programming language for the DEX files
Sparse image

    A partition format for Android
Ssdeep

    A fuzzy hashing technique
Standard App

    An Android app without special system permissions that can be installed over an app market
System App

    An Android app with special system permissions that is pre-installed in the Android firmware
TLSH

    A fuzzy hashing technique created by Trend Micro
Tracker

    A piece of software use to collect user usage data. Often used in advertisement
Yaffs2

    Yet Another Flash File System is a log-structured file-system for flash devices

## Acronyms

AID

    Android ID
AOSP

    Android Open Source Project
AVB

    Android Verified Boot
DAC

    Discretionary access control
DBI

    Dynamic Binary Analysis
FEC

    Forward-Error-Correction
GKI

    Generic Kernel Image
MAC

    Mandatory access control
ODM

    Original Design Manufacturer
OEM

    Original Equipment Manufacturer
OTA

    over-the-Air
PM

    Package Manager
RRO

    Runtime Resource Overlays
SoC

    System-on-Chip
UBIFS

    Unsorted Block Image File System

###### Contents

  1. 1 Introduction
    1. 1.1 Project Goals, Conditions and Scope
    2. 1.2 Literature Search
    3. 1.3 Related Work
      1. 1.3.1 Conference Talks
  2. 2 Fundamentals
    1. 2.1 Android Firmware Structure
    2. 2.2 Collecting Firmware Samples
    3. 2.3 Extracting pre-installed Apps
    4. 2.4 Version Identification
    5. 2.5 Verified Boot
    6. 2.6 Modifying Firmware
    7. 2.7 APK signing and permissions
  3. 3 Dataset Analysis
    1. 3.1 Selecting State of the Art Tools
    2. 3.2 Build Property Analysis
    3. 3.3 AndroGuard Scan Result Analysis
      1. 3.3.1 Permissions
        1. 3.3.1.1 Android 10: Permissions statistics
        2. 3.3.1.2 Android 9: Permissions statistics
        3. 3.3.1.3 Android 8: Permission statistics
      2. 3.3.2 Certificates
    4. 3.4 APKiD Scan Result Analysis
    5. 3.5 Androwarn Report Analysis
    6. 3.6 VirusTotal Report Analysis
    7. 3.7 TLSH Fuzzy Hashing
      1. 3.7.1 Performance of TLSH filtering
      2. 3.7.2 Complexity of Filtering
  4. 4 FirmwareDroid Implementation
    1. 4.1 Architecture and Technologies
      1. 4.1.1 FirmwareDroid REST API
    2. 4.2 Experimental Features and Ideas
      1. 4.2.1 Diffing Firmware and Android apps
      2. 4.2.2 AndroGuard String Enrichment
    3. 4.3 Dynamic Analysis of pre-installed Apps
  5. 5 Results and Discussion
    1. 5.1 Results
    2. 5.2 Project Goals Review
    3. 5.3 Discussion
      1. 5.3.1 Limitations of our work
      2. 5.3.2 Android Customization
  6. 6 Future Work and Conclusion
    1. 6.1 Future Work
      1. 6.1.1 Future of FirmwareDroid
    2. 6.2 Conclusion
    3. 6.3 Acknowledgment
  7. 7 Directories
  8. Appendix
    1. D Android Verified Boot code snippets and examples
    2. E AndroGuard Permission Statistics
    3. F Androwarn Native Code Loading
    4. G FirmareDroid Rest API
    5. H Literature Search Results

##  Chapter 1 Introduction

In this thesis, we introduce a new security framework for Android,
FirmwareDroid. Our study analyzes pre-installed apps with static analysis
tools and gives unique insights into Android’s firmware eco-system.

In recent years, several incidents happened where attackers could infiltrate
different vendors’ supply chain and include malicious apps to Android
firmware, exposing several millions of users to potential security and privacy
risks. Malware families like Cosiloon [1], Chamois [2] and Triada [3] are just
some examples. Attackers seem to focus on pre-installed apps specifically, and
it is unknown how much malware is still present in Android firmware today.

In recent years several open-source tools for static [4, 5, 6, 7, 8] and
dynamic [9, 10, 11] analysis of Android apps were published. To our knowledge,
there are no open-source tools that allow automated analysis of Android
firmware and the containing Android pre-installed apps. Therefore we developed
FirmwareDroid– a tool to automated Android firmware analysis. FirmwareDroid
allows to extract files like apps from Android firmware and does an automated
static analysis of the extracted apps.

Since every year a new Android version is released, and firmware updates are
more frequently rolled-out, the need for automated analysis tools grows. We
use Android as an operating system on smartphones; other devices like TVs and
cars use customized AOSP builds as firmware. The demand for automated security
assessment is high enough for large IT companies like Google, Facebook, and
Amazon to invest in security certifications like the ioXt [12].

Most studies in Android App Security have focused on analyzing apps from the
Google Playstore or other markets. Some studies examine Android pre-installed
apps, and firmware [13, 14, 15], but to our knowledge, none of these studies
released an open-source tool for analyzing pre-installed apps. With
FirmwareDroid, we aim to provide an open-source framework to analyze large
datasets of Android pre-installed apps in a reasonable amount of time. Our
goal is to provide one tool that can extract apps from all major Android
versions and is extendable for further research.

Furthermore, we use FirmwareDroid to conduct a large scale study on 5’931
Android firmware archives and over 900’000 apps. We explain how we collected
firmware archives from various vendors and will give some unique insight into
the Android firmware eco-system.

At the beginning of this thesis, we conduct a literature search in Section 1.2
and discuss related work in the following Section 1.3. In Chapter 2 we explain
our methodology to collect Android firmware and some of the fundamental
concepts of Android’s security system. At the beginning of Chapter 3 we
describe which static analysis tools we selected for our study. After that, we
progress with analyzing the data we gathered using these static analysis tools
in Sections 3.2 to 3.6. To further explore Android pre-installed apps we
integrated TLSH into FirmwareDroid and evaluate its performance in Section
3.7. In Chapter 4 we describe our software architecture and give an overview
of FirmwareDroid’s REST API, and in Chapter 5 we summarize our findings and
discuss them. We end the thesis in Chapter 6 by discussing future work and our
conclusion of this project.

###  1.1 Project Goals, Conditions and Scope

We conduct a study on Android Firmware and pre-installed app analysis and
define the following research questions:

  * •

Can we automate the extraction of Android pre-installed apps from existing
android firmware archives?

  * •

Can we detect android malware within the standard Android apps like
calculator, calendar, browsers etc.?

  * •

Can we automate the static and dynamic analysis of Android firmware and apps
with the existing open-source tools?

Additional to the defined research questions we define a hypothesis to test:

  * •

0.1% of the Android apps in our corpus are malicious.

We define technical goals for the implementation of the FirmwareDroid
framework:

  * •

Automate the process of scanning several thousand Android app’s with state of
the art static and dynamic analysis tools.

  * •

Use fuzzy hashing techniques to detect similarities between Android apps.

Due to the time limitation of this master thesis, we have to focus on specific
parts of the Android firmware and define some elements to be out of scope for
this project:

  * •

It is not part of this work to analyze all aspects of android firmware. The
main focus is on analyzing pre-installed android apps (.apk).

  * •

The main focus of this study lies on newer (>= 8) Android versions. Other
versions can be mentioned but are not in the focus of this research.

  * •

We focus on analyzing the system partition of the Android firmware. Other
parts of the firmware like for example, the kernel, is out of scope for this
study.

  * •

It is not part of this study to analyse malware in detail or to provide
exploits.

###  1.2 Literature Search

In this section, we describe our methodology for our literature search, and in
Section 1.3 we discuss related work. We use the tool Publish or Parish [16] to
conduct a keyword-based literature search on schoolar.google.com. Table 1.1
shows all the keywords used for our investigation. We search every time for a
main keyword together with one of the search terms. For every combination of
keyword and search term, we save the top 20 search results. In total, this
results in a list of 980 publications. We filter patents, HTML, or any other
kind of reports that are not scientific publications and not available as pdf
files. As the next step, we removed all older publications than ten years and
published before 01.01.2011. Moreover, we filter all papers that are not in
English. As the final step, we read from the remaining 902 papers the title,
abstract, and, if necessary, the results section to determine if the
publication is relevant for our work or related to our study. We show the
results of this literature search in Appendix H.

Main Keyword | Search terms
---|---
Fuzzy Hashing |  | tools, ssdeep, TLSH, TLSH clustering, lempel-ziv jaccard, sdhash,
---
performance, clustering
Android |  | emulator detection, root detection, obfuscator, deobfuscator,
---
packer, unpacker, code analysis, app fuzzing,
malware analysis, permissions, privacy,
verified boot, verified boot 2.0, avb, dm-verity
Android firmware |  | analysis, dataset, samples, extraction,
---
kernel fuzzing, kernel extraction, app extraction
Android pre-installed apps |  | bloatware analysis, analysis, static analysis, dynamic analysis,
---
malware
Android library | detection, fingerprinting
Android static analysis |  | tools, reverse engineering, permission extraction,
---
manifest parsing
Android dynamic analysis |  | firmware, pre-installed app, traffic analysis,
---
docker, emulator, frida, api monitoring, file access monitoring

Table 1.1: Overview of search terms used for our literature search in Appendix
H.

###  1.3 Related Work

Our literature search in the Section 1.2 shows that several studies exist with
similar aims when it comes to analyzing Android firmware or pre-installed app.
In this section, we review literature related to Android pre-installed app
analysis and other related topics.

Android firmware analysis: One of the first publications analyzing the pre-
installed app eco-system is from 2014 by Zheng et al. [13]. Min Zheng et al.
studied in [13] 250 Android firmware archives for vulnerabilities and found
that 19 firmware samples contained malware. Moreover, Zheng et al. found out
that 1’947 apps had vulnerable signatures. A study from Julien Gamba et al.
[14] scanned pre-installed apps of over 200 vendors for vulnerabilities and
analyze the traffic of the apps with the
Lumen111https://androidobservatory.com/datasets// dataset. Their work
identified 36 potentially privacy-intrusive behaviors of pre-installed apps.
Furthermore, Julien Gamba et al. identified the top 15 advertising and
tracking services and identified the most requested permissions. Another
recent study from Mohamed Elsabagh et al. analyzed in [15] 2’017 firmware
archives and extracted 331’342 apps. Their work claims to find over 850 new
vulnerabilities for pre-installed apps using a novel static taint analysis
tool.

In another direction goes the Uraniborg [17] project. It is a collaboration of
the University of Cambridge and the Johannes Kepler University and aims to
create a security risk scoring system for Android firmware. Similar to [12]
it’s aim is to create a verification and certification process for Android
firmware to increase the security of Android firmware overall.

Grant Hernandez et al. show in [18] that it is possible to develop a tool for
testing Android’s permission policies on static Android firmware. Their
approach can test DAC and MAC policies without actually running the firmware
on a real device. They demonstrate the capabilities of their framework by
detecting novel privilege escalation attacks on Android firmware.

Fuzzy hashing: Like cryptographic hash functions, fuzzy hash algorithms create
a hash of any given data like strings or files. In contrast to cryptographic
hash functions like MD5 or SHA1, we use fuzzy hashes to detect similarities
between binaries and not exact matches. Therefore, small changes in the data
do not significantly impact the fuzzy hash’s digest like it would have with a
cryptographic hash. Several implementations of fuzzy hash algorithms exist.
For example, TLSH [19], Ssdeep [20], Sdhash [21], Lempel-Ziv Jaccard distance
[22]. All of these hashes have different approaches to detecting similarities.

One of the challenges when using fuzzy hashes is how to compare the hashes
efficiently and at scale. In a naive approach, we can compute all fuzzy hashes
of a dataset and then compare them against each other. The result will be a
matrix of $n*n$ rows and columns with an exponential growth of
$\mathcal{O}(n^{2})$ for the computation of all values. More computational
efficient approaches use a Locality-sensitive hashing where similar hashes lay
near each other in the vector space or other optimizations like filtering the
search space to reduce the number of needed comparisons.

One use case of fuzzy hashes is to identify malware families. For example,
Nitin Naik et al. use in [23] fuzzy hashes combined with the fuzzy c-means
clustering to detect ransomware families. A different approach in clustering
malware families was proposed by Parvez Faruki et al. in [24]. With SDHash,
their prototype can cluster known malware families with an accuracy of 76%.
Another more recent study from Muqeet Ali, Josiah Hagen, and Jonathan Oliver
[25] shows that a multi-stage clustering with k-means and HAC-T is applicable
for clustering TLSH digests on the scale.

Library detection: 3rd party libraries are commonly used on Android apps.
Several researchers propose techniques to detect these 3rd party libraries for
vulnerability detection. However, in some cases, obfuscation makes detection
of such libraries a challenging task.

Michael Backes et al. describe in [26] their approach to detect vulnerable
libraries for apps in the Google Play Store. Their results suggest that apps
have slow library patching circles and that 296 apps have severe misuse of
cryptographic APIs.

Ziang Ma et al. claim in [27] that their approach based on the frequency of
different Android API calls is in most cases resilient to obfuscation. Their
system collects features by pre-processing 1’027’584 apps from the Google Play
Store and using these features to identify similar libraries. As a result,
they have created a list of 29,279 potential libraries for Google Play apps.

Another approach to overcome the problem of obfuscated library code is shown
by Menghao Li et al. in [28]. Their solution is based on feature hashing, and
the usage of internal code dependencies. In their work, they were able to
detect 60’729 different libraries. A different solution is proposed by Yuan
Zhang et al. in [29]. Their system, called LibPecker, adopts signature
matching of application and library classes to find similarities with high
precisions and recall. LibPecker outperforms other state-of-the-art tools with
91% recall and 98.1% precision.

Vulnerability analysis: There is a vast number of tools and papers that
attempt to automate the process of vulnerability analysis. For example,
Francisco Palma et al. developed a system to detect app vulnerabilities for
app stores in [30]. Or Amr Amin et al. describes in [31] a web-service to
automate the process of static- and dynamic app analysis.

####  1.3.1 Conference Talks

There is also a large number of conference talks providing insights into many
aspects of the Android eco-system. We found the talks listed in Table 1.2 to
be very insightful for anyone wanting to do a deep-dive into the topic of
Android security and the analysis of Android apps. However, these lectures are
not relevant for this work. They do not have a direct relation to the
contributions.

Conference | Author - Title
---|---
RSAConference 2020 |  | Łukasz Siewierski - Challenges in Android Supply
---
Chain Analysis [32]
IEEE Symposium on Security and Privacy 2020 |  | Julien Gamba et. al. - An Analysis of Pre-installed
---
Android Software [33]
BlackHat 2020 |  | Maddie Stone - Securing the System: A Deep Dive into Reversing
---
Android Pre-Installed Apps [34]
RSAConference 2018 |  | Giovanni Vigna - How Automated Vulnerability Analysis Discovered
---
Hundreds of Android 0-days [35]
BlackHat EU 2015 |  | Yu-Cheng Lin - Androbugs Framework: An Android
---
Application Security Vilnerability Scanner [36]
Black Hat 2013 | Kevin McNamee - How to Build a SpyPhone [37]
DFRWS EU 2019 |  | Lorenz Liebler and Harald Baier - Toward Exact and Inexact
---
Approximate Matching Of Executable Binaries [38]

Table 1.2: List of topic related conference talks.

##  Chapter 2 Fundamentals

This chapter explains how we created our dataset and how to extract pre-
installed apps from Android firmware. One of the first challenges we have to
overcome in analyzing pre-installed apps is to collect firmware archives, and
that we need to know where the pre-installed apps within the firmware are
stored.

Moreover we introduce and discusses (Android) concepts and knowledge which is
essential to understand the challenges and solutions presented in the reminder
of this thesis.

###  2.1 Android Firmware Structure

A firmware archive is a compressed file that contains all parts of the Android
firmware. An Android firmware has several partitions or image files [39].
Depending on the Android version, these partition files have other formats and
are named differently [40]. Their content may as well vary depending on the
smartphone vendor. For example, the content and basic structure of an Android
10 firmware image might look as follows:

  * •

bootloader.img: As the name suggests, it contains the smartphone’s bootloader.
The bootloader on Android assures that only genuine partitions are loaded at
start [41]. The bootloader starts the recovery partition or the kernel of the
OS.

  * •

boot.img: This image contains the kernel and ramdisk image. Android uses the
ramdisk image to start the initial process initd, and it includes a file-
system with the /init directory.

  * •

system.img: The system image contains Android’s main framework with generic
code meant for sharing on multiple devices. This partition is usually mounted
read-only and contains the main file system. The file-system structure is
similar to the one shown in Figure 2.1, but instead of the odm folder, it uses
the system folder. In the folders /app and /priv-app contain most of the pre-
installed apps.

  * •

vendor.img: The vendor partition is used for including proprietary binaries
into Android’s file-system. It allows to overlay existing files or to add new
ones [42]. Its purpose is that vendors can integrate customizations for their
smartphones without having to modify the system image.

  * •

oem.img and odm.img: Similar to the vendor image an Original Design
Manufacturer (ODM) or Original Equipment Manufacturer (OEM) can include
customizations over the oem.img or odm.img partitions. These images are
optional and represent an extension to the vendor images. They can be used to
create Runtime Resource Overlays (RRO) for android apps [43] or to add any
customizations for board-specific components. Figure 2.1 shows an example odm
image file-system. From Figure 2.1 we can see that an ODM can include any new
file like for example: native libraries, selinux policies, system apps or
kernel modules.

Figure 2.1: Overview of ODM-specific components. Image source [44]

  * •

userdata.img: Another possibility to include customized data into the
operating system is over the user-data image. This partition is optional and
can consist of user-installed apps and data [44].

  * •

radio.img: Usually, this image is a proprietary binary that includes the base-
radio firmware.

Note: More information about partition files can be found on the official
Google developer website. See [40, 39, 44] fore more information.

The images mentioned above are just an example for Android 10. Other Android
versions have different partitions. For example, in Android 11, changes to the
boot image were made [45]. Android 11 introduced so-called Generic Kernel
Images (GKIs) [46] to separate generic kernel code from System-on-Chips (SoCs)
code. However, we do not focus on the Android kernel and its boot images for
this project. Our goal is to analyze pre-installed apps, and therefore our
main focus is on analyzing the system image. Other images with pre-installed
apps like the optional OEM image are interesting for our analysis but out of
scope.

###  2.2 Collecting Firmware Samples

Most smartphone vendors do not publish download links for their firmware. At
the time of writing, Google is one of the only vendors with its firmware
available for free. From their official webpage, [47] we can download all
releases for their devices, allowing us to get a dataset of around 1TB of
firmware samples.

To check whether other vendors offer the same service, we searched through
their official webpages. We show the result of this search in Table 2.1. To
our knowledge, it seems that except for Google and Sony, all other vendors do
not offer the possibility to download their firmware images for free.
Therefore, to have a wider variety of samples, we used alternative firmware
sources from unofficial webpages.

Vendor | Link | Firmware
---|---|---
Alcatel | https://www.alcatelmobile.com/ | None
Google | https://developers.google.com/android/images | Free complete
Hitec Mobile | https://hitecmobile.com.sg/ | None
Huawei | https://www.huawei.com/ | None
Intex | https://www.intex.in/ | None
Karbonn | https://www.karbonnmobiles.com/ | None
LG | https://www.lg.com | None
Maximus | http://www.maximus-mobile.com/ | None
Micromax | https://www.micromaxinfo.com/ | None
Mobicel | https://mobicel.co.za/smart-phones/ | None
Motorola | https://www.motorola.com/ | None
Nokia | https://www.nokia.com/ | None
Oppo | https://www.oppo.com/in/ | None
Panasonic | https://mobile.panasonic.com/in/ | None
Samsung | https://www.samsung.com/ | None
Sony | https://developer.sony.com/develop/open-devices/ | Partially
Symphony | https://www.symphony-mobile.com/ | None
Tecno | https://www.tecno-mobile.com/home/ | None
Vivo | https://www.vivo.com/in/ | None
Walton | https://waltonbd.com/smart-phone | None
Xiamoi | https://www.mi.com/in/ | None
ZTE | https://www.ztedevices.com/de/ | None

Table 2.1: Overview of Android OS vendors and the checked links.

When we search the web for Android firmware, we can find many websites
offering firmware files for more or less any known vendor on the market. Some
websites provide their Android firmware for free, and some even have built
commercial service around custom firmware. We visited these websites and found
out that their firmware is, in many cases, accessible for everyone. Most sites
use file hosters like Google Drive, Mega.nz, Uploaded.net, MediaFire.com, and
AndroidFileHost.com to store their firmware. With this information in mind, we
decided to test if we could use the webpages in Table 2.2 as an additional
source of Android firmware for our study. To download the firmware, we
developed a web crawler with puppeteer [48] and a headless browser that
collected all download links from the webpage in Table 2.2.

# | Custom ROM Website | Estimated Firmware Data
---|---|---
1 | https://firmwarefeeds.com/ |  4.17TiB
2 | https://firmwarefile.com |  4.18TiB
3 | https://vnrom.net/ |  0.72TiB
4 | https://firmwarex.net/ |  2.64TiB
5 | http://huawei-firmware.com/ | Not Crawled
6 | https://androidfilehost.com/ | Not Crawled
7 | https://mirrors.lolinet.com/firmware/ | Not Crawled
8 | https://firmware.center/firmware/ |  2.84TiB
9 | https://fire-firmware.com/ | Not Crawled
10 | https://droidfilehost.com/ | Not Crawled
11 | https://www.ytechb.com/ |  17.2Gib
12 | https://stockromfiles.com/ |  4.52GiB
13 | https://www.androidinfotech.com/ |  8.24GiB
14 | https://www.xda-developers.com/ | Not Crawled
15 | https://androidfre.com/ | Not Crawled
16 | https://samsungfirmware.net/ |  7.51GiB
17 | https://www.samsungsfour.com/ | Not Crawled
18 | https://www.androidsage.com/ |  1.39TiB
19 | https://addrom.com/ |  13.73TiB
20 | https://www.getdroidtips.com/ |  7.04TiB
21 | https://www.teamandroid.com/ |  0.67TiB
22 | https://www.entertainmentbox.com/ | Not Crawled
23 | https://androidtvbox.eu/ |  0.15TiB
24 | https://androidpctv.com/ |  0.12TiB
25 | https://www.cubot.net/ | Not Crawled

Table 2.2: List of websites offering Android firmware. Note: the crawled
number of bytes is without duplicates links.

To test our approach we started with two web pages, number one and two in
Table 2.2. These two pages were selected, because they offer firmware for more
than 50 vendors and therefore seemed to have a reasonable variety of Android
versions. Against our expectation our crawler was able to collect unique links
of around 7’000 files with a storage need of around 10TB only using these two
webpages. As shown in Table 2.2 we further crawled through other webpages and
found several thousand potential links with Android firmware. We then filtered
the list of links in JDownloader2 [49] to remove duplicates, files with small
size (<=100MB) and files which filename indicates that they are not Android
firmware like for example, drivers or hacking tools. Since our storage
capacity is limited we decided to download only the firmware archives from
firmwarefeeds.com and firmwarefile.com as a starting point for our study.
Using firmware from these unofficial sources has some drawbacks we would like
to mention at this point.

First, since we use unofficial firmware samples from untrusted sources, we
cannot assume that it is the vendor’s original content. We have to consider
that a third party could have manipulated all downloaded firmware. The only
exception is for the Google firmware sample since we download them from the
official source.

Second, another drawback is that we cannot filter the firmware by version
before we have downloaded them. We cannot distinguish which Android version
the file is if the filename does not contain the version name or number. In
some cases, it is possible to filter older Android versions by their filename,
but the files do not have a naming schema in most cases. Therefore, it is
likely that we will download many older Android versions, which are not
interesting for our study.

Nevertheless, after collecting around 10TB of firmware samples from official
and unofficial sources, we have to solve two problems to continue our
analysis:

  * •

How do we access the data within the firmware images?

  * •

How do we identify the version of the firmware?

We will discuss how we solved these problems in the next two Sections.

###  2.3 Extracting pre-installed Apps

Figure 2.2: Overview of the extraction process.

To access the firmware data, we have to understand where the data of interest
is stored and then access it. As explained in Section 2.1 pre-installed apps
are stored in the system.img image. If we want to extract a file from the
system.img or any other image, we need to mount or extract it. Since Android
is customizable, vendors use different file formats, naming schemas, and
compression algorithms for their images. These facts make automation more
challenging since we have to deal with those vendor-specific customizations if
we want to extract the data from their firmware.

We have designed a process to export android apps from the system.img. We show
an overview of our approach in Figure 2.2. To extract the Android apps, we
implemented a process with seven steps:

  1. 1.

Decompress archives: Android vendors compress firmware archives with various
compression formats. If we want to access the data, it is necessary to expand
these archives. Following an incomplete list of archive formats we have
detected in our dataset:

     * •

.zip

     * •

.tar and tar.md5

     * •

.pac

     * •

.bin

     * •

.dat

     * •

.lz4

     * •

.nb0

In some cases, vendors pack their firmware files more than once, and
consequently, it is necessary to expand the nested archives as well. We can
recursively expand the nested archives to get the data. A problem that can
occur is that the libraries are encrypted and need a password to extract. In
these cases, we cannot expand the archive without the password or key. Another
problem is the use of unknown compression formats. In this case, we cannot
extract the archive without adding the support for the additional format. The
list of formats above shows which formats we currently support in
FirmwareDroid.

  2. 2.

Find system.img: As soon as we have decompressed all nested archives on the
file system, we search for the system.img file. One of the main problems when
we search for this file, is that there is no strict naming convention.
Consequently, vendors name the system.img file in many ways, for example,
system.rfs, system.bin, system.ext4.img, system-sign.img, sign-system.img,
system.img_sparsechunk.0, system_6.img and so on. To solve this problem, we
use a priority list of regex patterns to search for the correct file. This
approach is not 100% error resistance but shows good enough results to import
several thousand firmware samples. With the regex priority list, we search for
exact matches, then for small changes, and at the end for larger changes in
the naming. If we cannot find the file, the process stops, and the firmware
cannot be import.

  3. 3.

Mount: In case the system.img file is found, we can attempt to mount the file
with the Linux mount command. The system.img can be a Yaffs2 or a sparse image
[39]. In case it is a sparse image we can use simg2img [50] to reformat the
file into an ext4 or f2fs partition and mount the file. This approach works
for many firmware files, but it does not work for all samples since some
vendors use custom ext4 headers, encrypted firmware files, or other formats
that we cannot mount without further processing. To mount as many samples as
possible, we tested several pre-processing strategies and came up with the
following one:

    1. 1.

Simg2img and mount (Std. / fuse)

    2. 2.

mount

    3. 3.

fuse and fuseext2 [51]

    4. 4.

Resize and mount (Std.)

    5. 5.

Repair, resize and mount (Std.)

Testing showed that using the Linux kernel extension fuse allows mounting some
ext4 partitions with customized headers. It seems that fuse on Debian ignores
some customer headers, where mount often refuses to perform the mount
operation. Therefore we use fuseext2 as a supplement tool for performing mount
operations.

Another problem is when vendors split the system.img files into chunks.
Simg2img can process some chunk formats and generate one complete file from
the chunks. Nevertheless, these files often could not be mounted in our
process due to invalid sparse formats. Therefore, the current FirmwareDroid
version cannot mount chunked firmware files. Moreover, we have password-
protected zip files, and we cannot unpack them without the correct password.
In the current version of FirmwareDroid we ignore these files.

  4. 4.

UBI extract: Some vendors use the Unsorted Block Image File System (UBIFS)
alternative to ext4. To extract the data from such files, we use an open-
source python code [52] that allows us to extract such UBI partitions directly
to the file-system without mounting.

  5. 5.

Find build.prop or default.prop: After it is possible to mount the system
partition, we can search through the file-system. Like other studies [15, 14]
one of the files we extract is the build.prop file. It contains a key-value
store with the system properties. We can use it to extract the meta-data of
the firmware. Figure 1 shows an example build.prop file. For example, we can
find some data like the Android version, brand, manufacturer, language, or
build version in the build.prop file, and we can parse the file to store it in
a database.

  6. 6.

Find .apk files: Similar to the build.prop file, we can extract apks from the
mounted or extracted file-system. We search for filenames with the .apk
extension and store their location.

  7. 7.

Store .apk files: All the found apks are then copied from the system.img
partition to the host file-system for further processing. Copying the apks has
the advantage that we can use other analysis tools directly on the files
without the need to extract and mount the system.img on every access. One
drawback of this approach is that we need more disk storage for storing the
files. Together with copying the files, we create some meta-data of the apks
and store them in the database.

We tested the process shown in Figure 2.2 and could import 5’931 firmware
archives to our database successfully. However, with the current design, we
were not able to import another 3’224 potential firmware files. We think this
is due to customized, old, or unknown file formats, unique naming schemas, or
files that aren’t Android firmware.

###  2.4 Version Identification

There are various ways to identify the version of an Andrioid firmware. For
example, we can look for files that only exist on specific Android versions.
Such a file can be, for example, the ’com.android.egg’ app, which is different
on every Android version and always has the name in the form of "Android Q
Ester Egg" or any other system app which is unique to an Android version.
Another way is to read the contents of the build.prop or default.prop file. As
shown in Listing 1 this file holds a key-value store with properties. The key-
value pairs represent the system properties of the operating system. As shown
on Line 18 in Listing 1 we can identify the version by the property
ro.build.version.release. Moreover, we can find other information like the
phone manufacturer, the last security patch date, or the product model in the
build.prop file.

⬇

1# PRODUCT_OEM_PROPERTIES\part{title}

2import /oem/oem.prop ro.config.ringtone

3import /oem/oem.prop ro.config.notification_sound

4import /oem/oem.prop ro.config.alarm_alert

5import /oem/oem.prop ro.config.wallpaper

6import /oem/oem.prop ro.config.wallpaper_component

7import /oem/oem.prop ro.oem.*

8import /oem/oem.prop oem.*

9# begin build properties

10# autogenerated by buildinfo.sh

11ro.build.id=MDA89D

12ro.build.display.id=MDA89D

13ro.build.version.incremental=2294819

14ro.build.version.sdk=23

15ro.build.version.preview_sdk=0

16ro.build.version.codename=REL

17ro.build.version.all_codenames=REL

18ro.build.version.release=6.0

19ro.build.version.security_patch=2015-10-01

20ro.build.date=Wed Sep 30 00:50:26 UTC 2015

21ro.build.date.utc=1443574226

22ro.build.type=user

23ro.build.user=android-build

24ro.build.host=wpix10.hot.corp.google.com

25ro.build.tags=release-keys

26ro.build.flavor=angler-user

27ro.product.model=Nexus 6P

28ro.product.brand=google

29ro.product.name=angler

30ro.product.device=angler

31ro.product.board=angler

32# ro.product.cpu.abi and ro.product.cpu.abi2 are obsolete,

33# use ro.product.cpu.abilist instead.

34ro.product.cpu.abi=arm64-v8a

35ro.product.cpu.abilist=arm64-v8a,armeabi-v7a,armeabi

36ro.product.cpu.abilist32=armeabi-v7a,armeabi

37ro.product.cpu.abilist64=arm64-v8a

38ro.product.manufacturer=Huawei

39ro.product.locale=en-US

40ro.board.platform=msm8994

41# ro.build.product is obsolete; use ro.product.device

42ro.build.product=angler

43# Do not try to parse description, fingerprint, or thumbprint

44ro.build.description=angler-user 6.0 MDA89D 2294819 release-keys

45ro.build.fingerprint=google/angler/angler:6.0/MDA89D/2294819:user/release-
keys

46ro.build.characteristics=nosdcard

Listing 1: Contens of an exmple build.prop file.

A drawback of using the build.prop file is that customized Android ROMs may
modify the file’s values and show us false information. Therefore, we cannot
completely trust the found information in the build.prop file for custom ROMs,
and when using it for the Android version detection, we have to keep in mind
that we could detect a false version. Nevertheless, in FirmwareDroid we use
the build.prop file to detect the firmware version.

###  2.5 Verified Boot

Our dataset is likely to contain modified Android firmware because we
downloaded the most samples from untrusted sources. To understand how we can
distinguish between an original firmware file and a modified one, we need to
know Android’s integrity, and boot protection. We, therefore, explain in this
section the main components of Android Verified Boot (AVB) 2\. We will not go
through all details of AVB because this would go beyond this project’s scope.
We will explain parts of the AVB also called Verified Boot 2.0 that Google
introduced with Android Oreo. We do not discuss earlier versions of Android
that use Verified Boot 1.0.

First of all, the implementation of the Android Boot process depends on the
actual phone. Smartphone manufacturers like for example, Samsung [53] or
Huawei [54], have their implementations of Secure Boot with different designs
depending on the CPU architecture. Nevertheless, we describe an example design
to give the reader some insights into modern smartphones’ security
measurements. Figure 2.3 illustrates an overview of the firmware signing
process at the development and the verification process on the Android device.
We will go through every step of the process, beginning at the Android
firmware’s build phases.

Figure 2.3: Android Verified Boot Architecture.

1

AOSP Build: When we build the AOSP we need to provide at least four platform
keys for signing different parts of the operating system. We can add as well
additional keys for signing specific apps. The default configuration uses the
following four keys:

  * •

Platform: A key used for the main packages of the Android framework. We use
this key for signing the pre-installed system apps and the Android core
framework package (framework-res.apk) if not explicitly configured different.

  * •

Shared: We sign with this keys packages of he home/contacts system.

  * •

Media: We sign with this key packages of the media/download system.

  * •

Testkey: The key is used as default if no other key is defined.

If we do not provide custom private keys, then the AOSP default keys are used.
We shouldn’t use the default keys for a release builds because they are
publicly available online [55] and everyone could use them for signing. These
keys are not directly necessary for Android Verified Boot, but we use them
later for signing system apps. We will discuss in Section 2.7 how we use the
platform keys. After building the AOSP, we have several build artifacts that
we want to protect with Android Verified Boot.

Type | Variable Name | Code Comment
---|---|---
uint8_t | magic[4]; | 0: Four bytes equal to "AVB0" (AVB_MAGIC).
uint32_t | required_libavb_version_major; | 4: The major version of libavb required for this header.
uint32_t | required_libavb_version_minor; | 8: The minor version of libavb required for this header.
uint64_t | authentication_data_block_size; | 12: The size of the signature block.
uint64_t | auxiliary_data_block_size; | 20: The size of the auxiliary data block
uint32_t | algorithm_type; | 28: The verification algorithm used, see |AvbAlgorithmType| enum.
uint64_t | hash_offset; | 32: Offset into the "Authentication data" block of hash data.
uint64_t | hash_size; | 40: Length of the hash data.
uint64_t | signature_offset; | 48: Offset into the "Authentication data" block of signature data.
uint64_t | signature_size; | 56: Length of the signature data.
uint64_t | public_key_offset; | 64: Offset into the "Auxiliary data" block of public key data.
uint64_t | public_key_size; | 72: Length of the public key data.
uint64_t | public_key_metadata_offset; | 80: Offset into the "Auxiliary data" block of public key metadata.
uint64_t | public_key_metadata_size; |  | 88: Length of the public key metadata. Must be set to zero if there
---
is no public key metadata.
uint64_t | descriptors_offset; | 96: Offset into the "Auxiliary data" block of descriptor data.
uint64_t | descriptors_size; | 104: Length of descriptor data.
uint64_t | rollback_index; | 112: The rollback index which can be used to prevent rollback to older versions.
uint32_t | flags; |  | 120: Flags from the AvbVBMetaImageFlags enumeration. This
---
must be set to zero if the vbmeta image is not a top-level image.
uint32_t | rollback_index_location; |  | 124: The location of the rollback index defined in this header.
---
Only valid for the main vbmeta. For chained partitions, the rollback
index location must be specified in the AvbChainPartitionDescriptorand
this value must be set to 0.
uint8_t | release_string[256]; |  | 128: The release string from avbtool, e.g. "avbtool 1.0.0" or "avbtool 1.0.0
---
xyz_board Git-234abde89". Is guaranteed to be NUL terminated.
Applications must not make assumptions about how this string is formatted.
uint8_t | reserved[80]; | 176: Padding to ensure struct is size 256 bytes. This must be set to zeroes.

Table 2.3: AvbVBMetaImageHeader struct from avb_meta_image.h. Table source:
[56]

2

Partition Signing: As mentioned in Section 2.1 an Android firmware archive
consists of several partition files. With Android Verified Boot we can protect
these images with a cryptographic signature. We use the avbtool [56] as shown
in Figure 2.3 and generate a verification partition called vbmeta.img. Before
we can understand how we can us the vbmeta.img we need some background
information about the data-structure it contains, called VBMeta struct.

We explain the data-structure shown in Table 2.3 which is used in the one of
the official avbtool implementations [56]. Within the repository (see [56]),
we can find a C implementation of avb in the libavb directory with C code
comments in various header files. We know that a VBMeta struct has three parts
from the comments and the code: header, authentication, and auxiliary. In
version 1.2.0 of the avblib, the header has a fixed size of 256 bytes.
Moreover, it includes the block sizes of the authentication and auxiliary
parts. The authentication and auxiliary parts have as shown in Table 2.3
variable sizes. The authentication part contains a signature for verification,
and the auxiliary part a list of descriptors and a public key.

As shown on Lines 1-4 in in Listing 2 a basic descriptor contains two
variables: tag and num_bytes_following. All other descriptors extend this
basic structure with additional variables. From the libavb implementation, we
can see that there are five types of descriptors:

  1. 1.

Property descriptor: As shown on Lines 6-7 in Listing 2 this descriptor is for
general purposes and can contain any meta-data in key-value form

  2. 2.

Hash-Tree descriptor: A Merkle-tree is calculated over the partition bytes and
later verified by libavb and dm-verity to ensure the partition integrity. The
hash-tree descriptor holds the Merkle-tree information necessary to verify the
integrity of a partition as shown in Listing 2 on Lines 13-28. In other words,
this structure holds information about the root hash of the Merkle-tree and
the salt used for verification and other variables for Forward-Error-
Correction (FEC).

  3. 3.

Hash descriptor: Like the hash-tree descriptor holds the hash descriptor, the
cryptographic data necessary for integrity verification. As shown on Lines
31-40 in Listing 2 the AvbHashDescriptor struct has variables for the hash
algorithm, digest length and salt length. We use this descriptor when we
create a hash over the complete partition instead of a hash tree. We think
this is usually the case for the boot.img and the ramdisk.img image files.

  4. 4.

Kernel cmdline descriptor: We use this descriptor for passing arguments to a
kernel shell. For example, we can add here a flag that deactivates dm-verity.
The boot-loader then passes the flag to the kernel at startup. Depending on
the kernel build, we can use other descriptors.

  5. 5.

Chain partition descriptor: The last descriptor type is for delegating the
authority over a specific partition. With this descriptor, we add a partition
that is signed and verified by another asymmetric key pair. In this case, we
either create a second vbmeta image (see 3 in Figure 2.3) for verifying the
signature, or we add a vbmeta footer to the existing partition. In both cases,
we save the public key of the delegated partition in the chain partition
descriptor to build a verification chain. A footer, as shown in Listing 2 on
Lines 56-64 contains a complete VBMeta struct with header, authentication, and
auxiliary blocks. Using a footer is optional. As we can see from Line 50 in
Listing 2 and from Table 2.3 avb includes a rollback index for chained
partitions and the vbmeta image. The rollback index is used to prevent
downgrade attacks and should be updated with every new firmware version.

⬇

1typedef struct AvbDescriptor {

2 uint64_t tag;

3 uint64_t num_bytes_following;

4} AVB_ATTR_PACKED AvbDescriptor;

5

6typedef struct AvbPropertyDescriptor {

7 AvbDescriptor parent_descriptor;

8 uint64_t key_num_bytes;

9 uint64_t value_num_bytes;

10} AVB_ATTR_PACKED AvbPropertyDescriptor;

11

12typedef struct AvbHashtreeDescriptor {

13 AvbDescriptor parent_descriptor;

14 uint32_t dm_verity_version;

15 uint64_t image_size;

16 uint64_t tree_offset;

17 uint64_t tree_size;

18 uint32_t data_block_size;

19 uint32_t hash_block_size;

20 uint32_t fec_num_roots;

21 uint64_t fec_offset;

22 uint64_t fec_size;

23 uint8_t hash_algorithm[32];

24 uint32_t partition_name_len;

25 uint32_t salt_len;

26 uint32_t root_digest_len;

27 uint32_t flags;

28 uint8_t reserved[60];

29} AVB_ATTR_PACKED AvbHashtreeDescriptor;

30

31typedef struct AvbHashDescriptor {

32 AvbDescriptor parent_descriptor;

33 uint64_t image_size;

34 uint8_t hash_algorithm[32];

35 uint32_t partition_name_len;

36 uint32_t salt_len;

37 uint32_t digest_len;

38 uint32_t flags;

39 uint8_t reserved[60];

40} AVB_ATTR_PACKED AvbHashDescriptor;

41

42typedef struct AvbKernelCmdlineDescriptor {

43 AvbDescriptor parent_descriptor;

44 uint32_t flags;

45 uint32_t kernel_cmdline_length;

46} AVB_ATTR_PACKED AvbKernelCmdlineDescriptor;

47

48typedef struct AvbChainPartitionDescriptor {

49 AvbDescriptor parent_descriptor;

50 uint32_t rollback_index_location;

51 uint32_t partition_name_len;

52 uint32_t public_key_len;

53 uint8_t reserved[64];

54} AVB_ATTR_PACKED AvbChainPartitionDescriptor;

55

56typedef struct AvbFooter {

57 uint8_t magic[AVB_FOOTER_MAGIC_LEN];

58 uint32_t version_major;

59 uint32_t version_minor;

60 uint64_t original_image_size;

61 uint64_t vbmeta_offset; // The offset of the |AvbVBMetaImageHeader| struct

62 uint64_t vbmeta_size; // size of the vbmeta block (header + auth + aux
blocks)

63 uint8_t reserved[28];

64} AVB_ATTR_PACKED AvbFooter;

Listing 2: Overview of avb descriptor structs from [56].

We create descriptors for every partition of the firmware in the vbmeta.img.
Depending on the partition, we use different descriptors. We use a hash
descriptor for the boot partition because its file size isn’t too large to get
entirely loaded into the RAM and verified in a short time. For the system,
vendor, and oem partitions, we use either hash-tree descriptors or chain
partition descriptors because these partitions are usually too large to verify
in time within the memory. After creating all descriptors and some parts of
the header, avb creates the authentication block. This block contains a
cryptographic signature over the complete vbmeta partition. As shown in Figure
2.3 it is signed by the private key of the operating system vendor, and the
vendor includes its public key into the VBMeta struct.

The VBMeta structure allows that the bootloader can verify the integrity of
the boot image at startup. The verification process is done depending on the
descriptor used. For a hash descriptor, the bootloader creates a digest over
the complete partition and compares it to the digest in the vbmeta.img. For a
hash-tree descriptor is the verification different. The official documentation
[56] does not explain how avb verifies hash-trees descriptors, but we find the
answer in the avb_slot_verify.c file. Looking at the avb_slot_verify and
load_and_verify_vbmeta methods, we can go through every step of the
verification process step by step. However, we will not go through every line
of code. Instead, we will follow the program flow to see where the descriptors
are verified.

We go through the code in the avb_slot_verify method of the avb_slot_verify.c
file in [56]. We added a copy of the method’s code to Appendix 12. At Line 93
of the avb_slot_verify method the script executes a call to the
load_and_verify_vbmeta depending on the existence of the vbmeta partition or
footer. If we follow the program flow and look at the load_and_verify_vbmeta
method, we can find the descriptor verification process in a switch case
statement. Listing 3 shows parts of the switch cases statement with the
verification of the hash-tree descriptor and the original code comments. The
code comments state that avb only verifies a hash-tree descriptor when we use
a persistent digest. Otherwise, the OS should conduct the checks and not avb.
Even if the comments state that avb does no verification, we can see from the
code that avb calls the method avb_hashtree_descriptor_validate_and_byteswap.
This method checks if the descriptor is in the right format and contains all
necessary fields. At this point, avb makes no comparison between the hash-tree
descriptor and the actual data on disk. To our knowledge, the official
documentation does not explain why avb’s implements the verification process
like this. We can only assume that the hash descriptors’ verification in
combination with dm-verity is enough to ensure the partition’s integrity.
Another possibility is that the use of persistent digests is more common. As
explained in [56] a persistent digest is not stored as a descriptor; instead,
avb sets the hash length in the hash-tree descriptor to zero, and it uses a
named persistent value. Vendors store named persistent values on tamper-
evident storage in a key-value store. AVB can retrieve these values from the
tamper-evident store by using a combination of the partition name and a prefix
(avb.persistent_digest.) as a key. Avb can then use the persistent digest for
comparison.

In conclusion, if a vendor uses a persistent digest, they store the hash
tree’s root digest within a tamper-evident storage. AVB can access this
storage and use its values for verification with the data found in the
vbmeta.img. Moreover, we know that avb verifies hash descriptors by
calculating a complete hash over the data loaded in memory. We can verify this
by looking at the load_and_verify_hash_partition method. Consequently, avb can
protect the kernel from being tampered under the assumption that a hash
descriptor is used for the boot.img and correctly verified. Other partitions
like the system.img, which uses a hash-tree descriptor, are verified by the
kernel with dm-verity.

⬇

1…

2 /* Now go through all descriptors and take the appropriate action:

3 *

4 * - hash descriptor: Load data from partition, calculate hash, and

5 * checks that it matches what’s in the hash descriptor.

6 *

7 * - hashtree descriptor: Do nothing since verification happens

8 * on-the-fly from within the OS. (Unless the descriptor uses a

9 * persistent digest, in which case we need to find it).

10 *

11 * - chained partition descriptor: Load the footer, load the vbmeta

12 * image, verify vbmeta image (includes rollback checks, hash

13 * checks, bail on chained partitions).

14 */

15 descriptors = avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read,

16 &num_descriptors);

17for (n = 0; n < num_descriptors; n++) {

18 AvbDescriptor desc;

19

20 if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {

21 avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);

22 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;

23 goto out;

24 }

25 switch (desc.tag) {

26 case AVB_DESCRIPTOR_TAG_HASH: {

27 AvbSlotVerifyResult sub_ret;

28 sub_ret = load_and_verify_hash_partition{…};

29 if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {…}

30 }

31 break;

32 case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {…}

33 break;

34 case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {…}

35 case AVB_DESCRIPTOR_TAG_HASHTREE: {

36 AvbHashtreeDescriptor hashtree_desc;

37 if (!avb_hashtree_descriptor_validate_and_byteswap(

38 (AvbHashtreeDescriptor*)descriptors[n], &hashtree_desc)) {

39 avb_errorv(

40 full_partition_name, ": Hashtree descriptor is invalid.\n", NULL);

41 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;

42 goto out;

43 }

44 /* We only need to continue when there is no digest in the descriptor.

45 * This is because the only processing here is to find the digest and

46 * make it available on the kernel command line.

47 */

48 if (hashtree_desc.root_digest_len == 0) {…}

49 } break;

50 case AVB_DESCRIPTOR_TAG_PROPERTY:

51 /* Do nothing. */

52 break;

53 }

54}

55…

Listing 3: Descriptor validation found in the load_and_verify_vbmeta method.
filename: avb_slot_verify.c

For interested readers, we have added the python code for the verification
process in Appendix 12. The python code verification process is different from
the C implementation. In python, a hash-tree is generated over the complete
image file and compared to the data in the vbmeta.img. The C code example with
all files can be found in the official avb repository [56].

4

Hardware-based crypto module: So far, we have discussed how the partitions are
created, signed, and verified in the development environment. We now proceed
with how Android Verified Boot runs on the device. In the literature, the term
secure element tends to be used to refer to hardened software and hardware
environments with limited access. To avoid confusion, we use in our example a
smartphone with a hardware-based crypto module as illustrated in Figure 2.3
and do not discuss the boot process with software-based secure elements.

Smartphone manufacturers tend to implement crypto modules with unchangeable
and programmable memory parts. In the immutable memory of our device is a
symmetric key stored. The devices uses this key for encryption and decryption
operations, and the key is unique for every device. The key itself is burnt
into the device during manufacturing and, in theory, cannot directly be
accessed or changed by any other component. Within the programmable part of
the chip is the OS vendor’s public key stored, the so-called Root of Trust.

5

ROM bootloader: This bootloader is in literature often referred to as the
first stage or SoC bootloader. The ROM bootloader verifies the flash
bootloader (or second stage bootloader) integrity. The ROM bootloader does
this by verifying the flash bootloader’s signature with a public key stored in
the hardware crypto module.

6

Libavb: The flashable bootloader integrates a version of the libavb library
and implements the interfaces to the tamper-evident storage if necessary. The
libavb will then go through the verification process of the vbmeta.img and all
the read-only partitions as mentioned above. Keep in mind that Android
verified boot can only assure the integrity of read-only partitions. Read-
write partitions like the user data partition are not integrity protected by
AVB. In case the verification succeeds, the bootload loads the kernel from the
boot.img. Some Android phone manufacturers allow their users to installed
custom firmware. In this case, the user can sign the custom firmware with an
own private key and store the public key as the new root of trust. The flash
bootloader will then load the custom Root of Trust instead of the OS vendors
Root of Trust for verification.

7

Dm-verity: The dm in dm-verity stands for device-mapper. Verity is a Linux
kernel extension that allows integrity protection for read-only block devices
using the kernels crypto API. Android has a custom implementation of the Linux
kernel extension dm-verity [57, 58] and uses it for the verification of the
partitions at mount and runtime. As mentioned before, libavb does not validate
the integrity of the tree-hash descriptors in the vbmeta.img to the actual
data on disk. Therefore, AVB can only ensure the integrity of partitions with
hash descriptors or persistent digests. However, dm-verify checks the hash-
tree descriptors by comparing the bytes on disk to the hash-tree at runtime.

One of the problems with using hash-trees over block devices is that blocks
can have bit-errors. In the case of a bit-error, the hash would differ, and
the dm-verity verification would fail. A forward error correction code like
Reed-Solomon is used [59] to solve this problem.

Another problem is that generating hash-trees over relatively large block
devices can take a significant amount of time and system resources. To solve
this problem, dm-verity only verifies a block when it’s accessed. Dm-verity
can even be configured only to verify a block once when it’s loaded the first
time into the memory [60].

More information about AVB and dm-verity can be found in the official
repository [56] of avb, and on the Google developers webpage [60, 61].

###  2.6 Modifying Firmware

In Section 2.5 we explained Android’s integrity protection for partitions.
This section discusses how we can modify existing Android firmware to create
our own custom ROM. We have two ways to create a custom ROM— building from
source or modifying an existing build. We will not discuss how to build the
AOSP from source since it is outside of this project’s scope, and there are
plenty of tutorials on the web on how to do it. However, we will explain how
we can modify an existing firmware and customize some of the apps within the
firmware. Figure 2.4 shows the process of modifying an existing firmware
archive, and we will go through the numbered steps in detail.

  1. 1.

When we have a firmware archive, we need to extract the firmware partitions
first and then create an ext4 image from Android’s sparse image format. We can
use the tool simg2img [50] to convert a partition file from sparse format into
ext4 format.

  2. 2.

After we have converted the sparse image into an ext4 image, we can mount it
in read+write mode; this allows us to modify the partition. For example, we
want to change an existing app without having the source code of the app.

  3. 3.

If we do not have the source code, we need to decompile the apk; otherwise, we
could have compiled a new version from the app’s source code. One technique to
modify android apps without the source code is to decompile the app into smali
or java code, add modifications and then recompile the modified source code to
dex byte code. Such modifications can be done for example with the jadx [62]
or apktool [63] tools. When modifying an app like this, an attacker has to
resign the app. Otherwise, the system will detect an incorrect app signature
and not allow it to be installed/updated.

  4. 4.

Depending on the kind of apk we are modifying, we have to use another key to
sign the apk. If we modify a standard app we can sign it with a self-signed
certificate. If we change a system app we need to resign it with the right
platform key; otherwise, the app may not have the correct permissions. We will
discuss the app signing process in detail in Section 2.7

  5. 5.

In case we do not have access to the platform keys used for building the
firmware, we need to replace the existing ones. When we use custom platform
keys, we have to resign all the system apps. Otherwise, the verification of
the apks signature would fail.

  6. 6.

After we have finished modifying the partition, we can use img2simg to convert
our ext4 partition into a sparse image.

  7. 7.

Since we have modified an existing firmware, we will need to resign all
partitions as described in Section 2.5 with the avbtool. After signing, we
need to pack the partition back into the firmware archive and then load it
onto the device.

  8. 8.

To successfully flash our custom Android ROM to a device, we either unlock the
bootloader or sign the ROM with the device manufacturer’s private key. In our
example, we modify an existing ROM, and we do not have the manufacturer’s
private key. Therefore we need to unlock the bootloader and add our public key
to the device as the root of trust. We can then use tools like fastboot to
load the firmware to the device. If we have signed everything correctly, the
device should start with our custom firmware.

Figure 2.4: Process of modifying an existing Android firmware.

As described above, the process of modifying an existing Android firmware only
works if we have an unlocked bootloader. Otherwise, the Android Verified Boot
would detect a signature mismatch and would stop the boot process. In the next
section, we will go through the app signing process of system apps and explain
how the system and standard apps are differentiated.

###  2.7 APK signing and permissions

In this section, we discuss Android’s permission architecture for app
processes. We start by explaining how standard and system apps are signed. We
then move forward and explain how SELinux policies work together with the
Android framework permissions to ensure app sandboxing. At the time of
writing, the app signature schema has four versions [64, 65] and we will only
discuss the newest version v4 [66]. We will not explain all of the v4 signing
schema features because this goes outside of our project scope, but we will
show what benefit the v4 schema has compared to the v3 schema.

When we develop an app in Android Studio, we will need to compile the Java or
Kotlin code into an ART compatible dex byte code. If we want to upload our app
to an app market like, for example, the Google Play Store, the market usually
enforces that we have to sign our app. The signing will assure the app’s
integrity and allow us to use Android’s app update mechanism. Android’s
package manager verifies the signature of every app at installation. Android
apps do not use a public key infrastructure for app certificates. Without a
PKI, it is possible to use self-signed certificates for signing Android apps.
Depending on the signature schema used, we have to use other tools to generate
a valid signature. To generate a v4 signature, we can sign an apk with the
apksigner tool [67] as shown in Figure 2.5. Before we can sign an apk, we need
to use the zipalign tool [68] to optimize the alignment of files within the
apk. After signing the apk, we can upload it to an app store or directly
install it on a device. Android’s Package Manager (PM) will assure that the
signature is valid and then install the apk into the /system/data/ folder.

Figure 2.5: Overview of the standard app signing process.

In v3, the apksinger will append the signing data to the apk in a so called
signing block. In v4, the signature schema uses parts of the v2 or v3 schema
to generate a new separate signature file. The apk digest is first verified
and then integrated into the v4 signature file. As stated in [66] the
signature file contains a fs-verity [69, 70] compatible data structure. Fs-
verity is similar to dm-verity and is used to generate a Merkle-tree over a
read-only file on read+write partitions. It ensures a file’s integrity by
verifying the data and signature each time it is paged into the memory.
According to the fs-verity documentation [69, 70] These runtime checks ensure
that the data can’t be corrupted during runtime, even running on malicious
firmware. The fs-verity approach helps to prevent an app from being tampered
at runtime, and it is an additional protection on read+write partitions. As we
have already discussed, the system and vendor partitions are integrity
protected by dm-verity. However, dm-verity cannot detect the corruption of a
file on read+write partitions like the user-data partition. In this case, fs-
verity could ensure the integrity of specific files by making them read-only
and verifying the signature at runtime. However, we will not further discuss
how fs-verity is implemented in detail and discuss system apps’ signing
schema. Interested readers can find more information about fs-verity and the
signature v4 schema in [69, 66, 70].

System apps use the same apk signature schemas as standard apps. One of the
key questions to ask when we talk about system apps’ security is how Android
knows the difference between standard- and system apps? Answer: We sign
system- and standard apps with different keys. App developers sign Android
apps with their app keys and OS vendors sign system apps with their platform
keys. As mentioned in Section 2.5, Android has at least four platform keys
used for signing system apps. It is possible to add additional platform keys
for signing specific apps. A reason for including more platform keys is when a
3rd party app vendor wants to be pre-installed on the system. In this case,
the OS vendor has, to our knowledge, three ways to include it into the system.
The first way is the 3rd party vendor signs it’s app with their private key
and then sends the signed apk to the OS vendor. The OS vendor will then add
the apk to the firmware as illustrated in Figure 2.6. Usually, this type of
app is then placed within the firmware in the /system/app/ folder or it can be
placed in other partitions like the /vendor/app/ and /product/app/ folders.
Apps in these folders are called system apps and cannot be removed by the user
because it is then stored on a read-only partition. However, as long as this
app is not signed with a platform key, they inherit no special permissions.

In case a developer wants to update its system app, then the new version of
the app is installed on the writable user-data partition. The package manager
will check the signature and version of the update and install the new apk
into the /data folder. The user can remove the update but not the original
system app residing in the ../app/ folder. If an OS vendor wants to remove or
update the system app on one of the read-only partitions, it needs to roll-out
an Over-the-Air (OTA) update. In such an update, the device is booted into
recovery mode to load a new firmware version. These changes are then
permanently stored on the phone.

Figure 2.6: Example build process for system apps.

Another way to integrate a system app is to sign it with a platform key and
place it in the ../priv-app/ folder, which is read-only. Apps signed by the
platform key can request system permissions that grant access to protected or
hidden APIs in the framework. Since Android Oreo, apps have to be allow-listed
in a ../etc/permissions/privapp-permissions.xml111Filename is variable and can
be changed. file of the partition to grant or deny access to a specific system
permission [71]. This permission check can be activated with the build
property ro.control_privapp_permissions=enforce. According to [71] the device
will not boot if an app has permissions that are not allow-listed. When we
want to understand how Android handles system app permissions, we need some
information about Android’s security architecture.

Android uses a Discretionary access control (DAC) [72] and a Mandatory access
control (MAC) [73] to manage access to specific API- and OS resources. The DAC
uses users- (UID), groups-(GID), and access mode bits (RWX) to determine the
access rights of a process. In Android, every app gets a custom UID/GID in the
range of 10’000 to 19’999 at installation time. As with other Linux
distributions, the UID/GID 0 is reserved for the root user and hardcoded into
the kernel. The Android framework defines differently from other Linux
distributions that all UIDs in range 1’000 to 9’999 are for system use as
partly shown in Listing 4. Moreover, it defines the term Android ID (AID) for
identifying the human-readable username and UID/GID [72]. We can find a
complete list of pre-defined system users and other defined ranges in the
android_filesystem_config.h file [74]. The listed aid are used at the built
time to create the users and groups.

⬇

1…

2#define AID_SYSTEM 1000 /* system server */

3#define AID_RADIO 1001 /* telephony subsystem, RIL */

4#define AID_BLUETOOTH 1002 /* bluetooth subsystem */

5#define AID_GRAPHICS 1003 /* graphics devices */

6#define AID_INPUT 1004 /* input devices */

7#define AID_AUDIO 1005 /* audio devices */

8#define AID_CAMERA 1006 /* camera devices */

9…

Listing 4: Lines 48 to 55 from android_filesystem_config.h. Source [74]

The kernel maps the system services shown in Listing 4 to the Android
framework’s permissions. The XML file platform.xml can be found in the
<partition>/etc/permissions folder on every Android firmware. It contains a
mapping of the GID to Android API permission for one partition. The Android
framework has a set of pre-defined API permissions that change with every API
version. We can find a complete list of all Android permissions on the Google
developers webpage (see [75]). The mapping between Android’s API permission
and the GID assures that an app can access a specific resource if it has the
API permission. When an app needs permission to a specific service, for
example, Bluetooth, the app needs to request this permission during
installation or runtime. Android’s package manager service will then check
that the app is allowed to have the permission and, if so, adds the app’s UID
to the group (GID) of the service. The kernel will then grant or denied access
to the resources with DAC and MAC.

One problem with DAC is that if misconfigured, it allows setting world-
writeable files. In the worst case, world-writable files can lead to
privileged escalation attacks. SELinux is used to enhance Android’s security
architecture further and to prevent such misconfiguration. It enforces
mandatory access control for every process, even for processes running under
the root user. Per default, SELinux denies all access that is not explicitly
granted by a policy. It hardens Android’s sandbox model by ensuring that even
when a malicious process runs under root, it cannot access all system
resources unless allowed by the SELinux policies. In contrast to DAC, we
cannot change SELinux policies during runtime. The SE-policies of AOSP is
available online [76]. OS vendors can customize their policies and extend the
existing AOSP policies. It is a fact that the SELinux files are stored on
different directories depending on the OS vendor’s customizations. Per default
the SELinux policy files are store in /system/etc/selinux. The folder contains
the context files with the policies that SELinux enforces. A list of key files
can be found on the official Google developers page [77]. We will not further
discuss how to create SELinux policies. Instead, we will explain how DAC and
MAC are used in the framework to control app permissions. More information
about the SELinux implementation can be found in [78, 79].

Android stores the core files of the framework in the /system/framework
directory. It contains the framework-res.apk and the Java libraries. The
framework-res.apk contains the graphical user interface’s resources, and its
AndroidManifest.xml contains the framework’s initial permission definitions.
In Android, every app can define its custom permissions in the
AndroidManifest.xml. An example permission is shown in Listing 5 on Lines 2-7.
When an app wants to access a service outside of the sandbox, like, for
example, the internet, it needs to add the permission defined in the
framework-res.apk in its own AndroidManifest.xml with a <uses-permission> XML
tag. An example of the <uses-permission> tag is shown in Listing 5.

⬇

1…

2<permission

3 android:description="@string/permdesc_createNetworkSockets"

4 android:label="@string/permlab_createNetworkSockets"

5 android:name="android.permission.INTERNET"

6 android:protectionLevel="normal"

7/>

8..

9<permission

10 android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"

11 android:protectionLevel="installer|signature|verifier"

12/>

13…

14<uses-permission

15 android:name="android.permission.INTERNET"

16/>

17…

Listing 5: Example of a xml permission defintion and usage.

Android defines a set of base permissions as shown in Figure 2.7. Depending on
the base permission and protection level flags the system follows other
procedures when an app requests permissions. Moreover, the protection levels
indicate the risk to the user. A base permission level can have zero or more
flags, and they can extend the base permission with additional permissions as
shown in Listing 5. For example, the flag vendorPrivileged with value 8000 can
grant additional permissions for vendor apps. Permission must have a unique
name attribute. The package manager will not install an app that defines an
already existing permission name.

Figure 2.7: Overview of Androids access levels. Image source [80]

As mentioned before, every app has its UID and runs in a sandboxed
environment. However, apps can share data by using the same signing key and
the same UID. Two apps can define in their AndroidManifest.xml the
sharedUserId attribute to use the same UID. Before Android10, system apps
could set the sharedUserId to  “android.uid.system" to use Android’s pre-
defined system user and run in the same context. With Android API 29, this
function is deprecated because it leads to unpredictable behavior in the
package manager [81]. As described in Figure 2.7 the signature base permission
allows an app with the same certificate to use the permission. As already
mentioned, pre-installed apps can be signed with the platform key and can
therefore use the signature permissions of the framework-res.apk without
notifying the user.

In summary, we have discussed the basic structure of Android firmware images,
and we gave some insights on the build process of Android firmware. This
section explains how apk’s are signed and how DAC, together with MAC, are used
in Android to implement a permission architecture that allows process
sandboxing and API protection. In terms of analyzing the Android firmware eco-
system, we have seen that Android stores pre-installed system apps on read-
only partitions and that AVB and dm-verity ensures integrity protection. In
conclusion, we can say that Android’s security framework is a complex
structure, and we cannot go through all details of the framework within this
work, but we have described in Section 2.6 how we can extract pre-installed
apps from the system partition at scale. We will progress in Chapter 3 with
analyzing the extracted pre-installed apps.

##  Chapter 3 Dataset Analysis

As described in Chapter 2 we were able to collect a dataset of 5’931 firmware
archives from various sources. From these firmware archives, we extracted
902’262 Android apps by only crawling the system partitions of the firmware
archives. In Chapter2 we explained how custom ROM’s were built and which
security techniques ensure partition integrity. Before we progress with
analyzing the pre-installed apps in detail, we will present our analysis
methodology:

  1. 1.

Create a dataset: First, we collect the necessary data to conduct our study.
In our case, we collect Android firmware and pre-installed apps as described
in Section 2.2.

  2. 2.

Experiment: As the next step of our experiment, we select tools to extract
security-relevant data from the Android apps. In detail, that means we search
for tools that can extract security-relevant data like certificates,
permissions, call graphs, and runtime information like network traffic or
memory states. We follow a similar approach to that used by other researchers
[15, 14] and use mainly static analysis tools for our experiment. We will
evaluate available tools analysis in Section 3.1 and discuss the scan results
in the following sections.

  3. 3.

Analyse Data: After we have scanned the pre-installed apps, we will analyze
the collected data. We will see which data we can extract at scale and what we
can learn from the data in Sections 3.2 to 3.6.

  4. 4.

Improve experiment: Depending on the results, we will see if we have to
improve our experiment setup. Possible enhancements could be the use of more
tools or other analysis techniques. We will discuss potential improvements of
our approach in Chapter 6.

In the next Chapter 4 we will then explain how we developed FirmwareDroid to
automate the data analysis.

###  3.1 Selecting State of the Art Tools

The open-source community has created many tools to analyze Android apps. It
is outside of this project’s scope to test every tool on the market in detail
and integrate it into FirmwareDroid. However, we attempted to identify up to
date static and dynamic analysis tools that we could include in our project,
serving our interests. It’s not the goal of this evaluation to find the best
analysis tool or make any assumptions about a tool’s quality. The purpose is
to determine potential tools that we could use for our analysis, which would
work within our environment. We, therefore, define the following criteria for
our selection process:

  1. A

Purpose: Does the tool’s purpose fits our project goal?

  2. B

Maintenance: Is the tool still maintained, and is it likely to be maintained
in the future? (Yes/No)

  3. C

Compatibility: Is the integration of the tool into our environment possible?
This includes if the tools is compatible with docker and python 3.8. (Yes/No)

  4. D

Scaling: Is it possible to use parallel computation, and can it scan our
dataset in the given project time? (Yes/No/Unknown)

  5. E

Dependencies and Requirements: Can the tools requirements and dependencies be
fulfilled in our environment? (Yes/No)

  6. F

Copyright: Does the tool has an open-source license with free usage for non-
commercial use? (Yes/No/Unknown)

Tool Criteria | Purpose | Maintenance | Compatibility | Scaling | Dependencies | Copyright
---|---|---|---|---|---|---
Androbug [36] | Yes | No | No | Yes | No | Yes
AndroGuard [7] | Yes | Yes | Yes | Yes | Yes | Yes
Androwarn [6] | Yes | Yes | Yes | Yes | Yes | Yes
AndrODet [82] | No | Yes | Yes | Yes | No | Yes
AndroPyTool [9] | Yes | No | No | Yes | Yes | Yes
apkanalyzer [83] | Yes | Yes | No | Yes | Yes | Unknown
APKiD [4] | Yes | Yes | Yes | Yes | Yes | Yes
Armandroid [10] | Yes | No | No | No | No | Yes
ClassyShark [84] | Nes | Yes | Yes | No | Yes | Yes
Droidbox [85] | Yes | No | No | Yes | No | Unknown
DroidSafe [86] | No | No | Unknown | No | Yes | Yes
Droidstatx [87] | Yes | Yes | Yes | Unknown | Yes | Yes
Exodus [8] | Yes | Yes | Yes | Yes | Yes | Yes
FlowDroid [88] | Yes | Yes | No | No | Yes | Yes
Maldrolyzer [89] | Yes | No | No | Unknown | No | Yes
Medusa [90] | Yes | Yes | Yes | Yes | Yes | Unknown
Mobile-Security-Framework [91] | Yes | Yes | No | Yes | No | Yes
QARK [5] | Yes | Yes | Yes | Unknown | Yes | Yes
Quark-Engine [92] | Yes | Yes | Yes | Yes | No | Yes
RiskInDroid [93] | Yes | Yes | Yes | Yes | Yes | Yes
SmaliCFGs [94] | No | No | No | No | No | U
SUPER Android Analyzer [95] | Yes | Yes | Yes | Yes | Yes | Yes

Table 3.1: Results of the tools evaluation.

We searched the web for analysis tools and then evaluated them according to
the defined criteria above. Table 3.1 shows the result of our evaluation. With
the info from Table 3.1 we can select some of the tools for integration into
FirmwareDroid. As we can see from Table 3.1 some Android tools are no longer
maintained and outdated. Other tools are regularly maintained but do not scale
well in our infrastructure or seem to have compatibility problems. We,
therefore, selected four tools that would meet our criteria for the static
analysis. The static analysis tools used are AndroGuard (v. 3.3.5), Androwarn
(v. 1.6.1), APKiD (v. 2.2.1), and QARK (v. 4.0.0). As the next step, we will
explain why we selected these tools and what features the tools offer.

  * •

AndroGuard [7]: AndroGuard is a static analysis tool that has been used in
another study as well [14, 9]. AndroGuard implements a command-line tool that
can decompile apks and extract meta-data from the manifest and the decompile
smali code. Its main API allows to extract of the following data:

    * –

AndroidManifest.xml parsing: this allows to extract apk meta-data like the
version of the apk. Moreover, AndroGuard can extract the permissions,
activities, services, and receivers declared and used in the manifest.

    * –

String extraction: AndoGuard can extract strings from the smali code.
AndoGuard uses specific upcodes in the smali code to detect strings.

    * –

App certificates: The integrated certificate parser allows to extract the
signing certificate of the apk in DER format. The API offers as well the
possibility to export the certificate date in a human-readable form.

    * –

Call Graph: AndroGuard has an integrated crossreference module. This module
allows the creation of call graphs for classes, methods, and fields.

We choose AndroGuard because it is well maintained, documented, and offers
essential features for our study. The extraction of the AndroidManifest.xml
data and the app certificates can help us understand how pre-installed apps
are configured and by whom.

  * •

Androwarn [6]: Androwarn is a malware scanner based on AndroGuard. It can scan
apps for potentially harmful behavior and can generate a JSON report. One of
Androwarn’s main features is detecting dynamic code loading techniques like
JNI to load dex files or UNIX commands execution. We choose Androwarn because
it scales well and gives us insights into commonly known malicious behavior
and privacy issues.

  * •

APKiD [4]: In 2016 Eduardo Novella Lorente et al. released a tool called APKiD
[4]. With APKiD, we can fingerprint Android app compilers and packers by
pattern matching. The tools collect features from the classes.dex and
Manifest.xml and match them to a compiler or packer if possible. The APKiD
developers use in [4] APKiD to detect malicious apps by fingerprinting
suspicious compilers. Their work shows that APKiD is a useful tool to detect
repackaged apps.

  * •

QARK [5]: QARK is a vulnerability scanner that decompiles an app to find
vulnerabilities. The QARK scanner can check for vulnerabilities like leaked
private keys, activated debug flags, or weak cryptography usage. QARK is the
only of our tool that uses Java, and from other studies, it is not clear how
well it scales. Nevertheless, we decided to integrate QARK into FirmwareDroid
since its vulnerability report has more information than Androwarn.

Additional to the above-mentioned tools we use VirusTotal [96] for scanning.
VirusTotal is well known in the security community, and its API allows to scan
binaries against the most common anti-virus products on the market. We used
all the scanners mentioned above to scan all the apks in our dataset, and we
will discuss the results of these scans in the next sections. In Chapter 4 we
will see that our software architecture allows us to integrate more tools in
future versions of FirmwareDroid.

###  3.2 Build Property Analysis

Before we can discuss our static analysis scan results, we give the reader an
overview of the firmware data in this section. We have extracted from every
firmware archive the build.prop or default.prop file to get the firmware
version by using the ro.build.version.release key. Table 3.2 shows the result
of this extraction. Moreover, we show the numbers of apps and package names by
version.

| Android version
---
(ro.build.version.release)
Firmware count | App count |  | Unique
---
packagename
count
| Firmware size
---
on Disk
2 | 18 (0.30%) | 1’876 (0.2%) | 407 | 0.003TB
3 | 1 (0.01%) | 151 (0.02%) | 151 | 0.397GB
4 | 2’511 (42.31%) | 317’250 (35.61%) | 8’203 | 1.447TB
5 | 1’000 (16.85%) | 141’575 (15.69%) | 4’806 | 0.950TB
6 | 795 (13.98) | 114’406 (12.68%) | 4’290 | 0.924TB
7 | 685 (11.54%) | 134’254 (14.88%) | 3’968 | 1.119TB
8 | 400 (6.74%) | 72’976 (8.09%) | 1’911 | 0.658TB
9 | 234 (3.94%) | 55’965 (6.02%) | 1’375 | 0.568TB
10 | 136 (2.91%) | 15’078 (1.67%) | 242 | 0.243TB
Unknown | 154 (2.6%) | 48’731 (5.40%) | 1’922 | 0.502TB
Total | 5’934 | 902’262 | 27’275 | 6.4TB

Table 3.2: Number of firmware archives by version.

The numbers in Table 3.2 show that our dataset contains mostly Android 4
(42.31%) samples followed by Android 5 with 16.85%. The dataset contains
around 13.59% of firmware archives from major (>=v8) Android versions. From
902’262 apps, we have a total number of 27’275 unique packages with 3’528 apps
from major versions. These numbers show the variance of package names or, in
other words, how many different app builds we have. Comparing the number of
unique package names to the app total tells us that we have more apps with
different builds than individual apps. We think this is not surprising because
system apps on other firmware usually uses the same package name. For example,
the settings app uses the "com.android.settings" package name over several
Android versions. Another fact is that we have 154 unknown firmware versions
because we couldn’t detect the ro.build.version.release in the build property
file. These files are likely newer versions that use multiple build property
files or have modified build properties.

In total, we have detected 862 brands and 796 manufacturers. The difference
between the manufacturer property and the brand property is that a company can
produce a phone, but the phone can have another companies brand. For example,
HTC manufactured the first Pixel device, but the branding is by Google. The
model property is the name of the phone series—for example, Pixel 2 or
SM-A605G.

| Brands
---
(ro.product.brand)
| Manufacturers
---
(ro.product.manufacturer)
| Model
---
(ro.product.model)
6 | 5 | 16
1 | 1 | 1
414 | 370 | 2004
193 | 186 | 760
134 | 120 | 543
81 | 79 | 407
21 | 24 | 186
10 | 9 | 101
- | - | -
2 | 2 | 2
862 | 796 | 420

Table 3.3: Overview of unique values in brand, manufacturer, and model build
properties by Android version

The numbers in Table 3.3 show that we have various brands, manufacturers, and
phone models in our dataset. Note that we could not extract the Android 10
build properties for the model, brand, and manufacturer due to the mentioned
problem of using referenced build property files on other partitions.
Nevertheless, if we look at Table 3.4 we can see the distribution of brands
for Android 8 and 9. We have mostly firmware branded by Google and Samsung. We
show similar results in Table 3.5 where Samsung and Google are on top of the
most detected manufacturers.

Brand Version | 8 | 9
---|---|---
Allview | 1 | 0
Alps | 1 | 2
Fih | 1 | 0
Google | 147 | 102
Helio | 1 | 0
Infinix | 11 | 21
Itel | 52 | 0
Kddi | 1 | 1
Lava | 19 | 1
Lmkj | 1 | 0
Micromax | 10 | 0
Motorola | 0 | 3
Nokia | 2 | 2
Samsung | 106 | 96
Symphony | 23 | 0
Tecno | 6 | 0
Verizon | 2 | 0
Vivo | 6 | 5
Vkworld | 2 | 0
Walton | 3 | 0
Wiko | 3 | 0
Zte | 2 | 1
Table 3.4: Count of detected brands
for Android 8 and 9.
Manufacturer Version | 8 | 9
---|---|---
Allview | 1 | 0
Alps | 3 | 4
Asus | 2 | 0
Fih | 1 | 0
Google | 102 | 102
Helio | 1 | 0
Hmd Global | 0 | 2
Huawei | 22 | 0
Infinix Mobility Limited | 11 | 19
Itel | 52 | 0
Lava | 19 | 1
Leimin | 1 | 0
Lge | 21 | 0
Micromax | 10 | 0
Motorola | 0 | 3
Samsung | 109 | 97
Symphony | 23 | 0
Tecno Mobile Limited | 6 | 0
Vivo | 6 | 5
Vkworld | 2 | 0
Walton | 3 | 0
Wiko | 3 | 0
Zte | 2 | 1
Table 3.5: Count of detected manufacturers
for Android 8 and 9.

We extracted as well how many apps set security-relevant build properties to
true (1) or false (0). Table 3.6 shows the result of this extraction in
numbers. What we can see is that seven firmware archives deactivate SELinux
(ro.secure), twelve deactivate ADB authentication (ro.adb.secure), and nine
firmware archives activate debugging (ro.debuggable). We can assume that these
firmware archives are insecure custom ROMs and not made for production.
Moreover, the numbers in Table 3.6 show that we cannot extract all the build
properties for every firmware archive using the build property file on the
system partition. Since build.prop files can have import statements, it is
possible to refer to other build.prop files. These files can lay on another
partition, and we would need to extract all the data from all partitions to
get a complete overview of build properties. However, for some build
properties, we can extract the complete numbers.

Build property key | 1 | 0
---|---|---
ro.secure | 153 | 7
ro.adb.secure | 810 | 12
ro.debuggable | 9 | 153
ro.oem.unlock.supported | 177 | 0
Table 3.6: Detected numbers of security relevant build properties.

The ro.build.tags property gives us some insight on which keys the developers
used to build the firmware. 3’675 firmware archives have the ro.build.tags set
to "release-keys", 1’871 use "test-keys", 194 use"dev-keys" and the rest (194)
has set a custom string or does not set the property at all in the build.props
file. We conclude that we have at least 2’065 (34.8%) firmware builds in our
dataset that shouldn’t be used for productive builds due to possible insecure
key usage.

In summary, we can say that our dataset contains a larger amount of old (< v8)
Android versions. Having a lot of old Android firmware is one of the drawbacks
of our crawling web approach. We cannot determine the Android version until we
have downloaded the data. However, one of the benefits of this dataset is that
we have a wide range of firmware samples and enough pre-installed apps to test
our software. We will progress with discussing the results of the individual
scanners in the next sections.

###  3.3 AndroGuard Scan Result Analysis

In this section, we will discuss how we can use AndroGuard reports to analyze
our Firmware dataset. When we scan an app with AndroGuard, we can parse and
export the data from the AndroidManifest.xml. Within the manifest, we find the
component and permission decelerations. Using FirmwareDroid, we can scan every
app in our dataset with AndroGuard and store all the extracted data from the
AndroidManifest.xml in our database. We use the data to create firmware
specific statistics about the permission usage of the pre-installed apps.

In general, extracting permission data allows us to generate a various number
of statistics. We implemented the functionality to aggregate the app data over
any set of firmware archives. We can use this function to compare arbitrary
sets of firmware to each other. For example, we can generate statistics for
firmware samples of two OS vendors and compare them against each other.

With AndroGuard, we cannot only extract manifest data. As we will see in
Sections 3.3.2 and 4.2.2 we can use AndroGuard to extract app certificates and
strings. Moreover, AndroGuard can create a complete code call graph with
class, method, and field references. However, due to the high performance
necessary to create complete call graphs with AndroGuard we do not use this
feature in the current version of FirmwareDroid.

####  3.3.1 Permissions

In this section, we discuss the permissions per Android version and do not
compare them to each other because this could lead to wrong conclusions.
Comparing arbitrary sets of firmware is not always meaningful. In some cases,
it can give us misleading information if we compare groups of unequal size or
different Android versions. As shown in Tables 3.2 and Table 3.3 we have an
unbalanced number of android apps per firmware version, and the number of
brands per Android versions differs as well. Our goal for this analysis is to
show different statistics for Android 8, 9, and 10 to demonstrate how we can
use the permission data extracted with AndroGuard and not to compare the
versions to each other.

#####  3.3.1.1 Android 10: Permissions statistics

Figure 3.1: Android10: Permission usage by protection level.

We start with examining the app permissions of our Android 10 firmware by
showing some permission usage statistics. We extracted all the permissions and
corresponding protection flags for every app and aggregate the data to see how
common some protection levels are. Figure 3.1 illustrates the protection
levels and their frequency. We can see that the base permission normal is used
the most times with a frequency of 61’696. The signature|privileged and
dangerous permission are used the second and third most with 39’058 and 18’262
times. We can see from Figure 3.1 that we have some protection levels compared
to others with a rather low count. For example, the signature|system or the
dangerous|runtime times. Note: That to our knowledge, the official Google
developers page for permissions [75] does not even list some of these
protection levels. Without further investigation, we cannot determine their
purpose. Anyways, we group the protection levels by their base permission to
better illustrate the permission usages in Figure 3.2. As shown in Figure 3.2
our pre-installed apps on Android 10 use 45.4% normal (total: 77’950), 41.1%
signature (total: 70’552) and 13.4% dangerous (total: 23’034) permissions.

Figure 3.2: Android10: Total permission usage grouped by base permissions.

We determine as well how many apps declare custom permissions. Figure 3.3
shows that 44,9% of our Android 10 apps request at least on third party
permission. Figure 3.4 illustrates the number of apps that define at least one
custom permission. We see that 24% of our Android 10 apps declare at least one
custom permission.

Figure 3.3: Android10: Percentage of apps that request at least one 3rd party
permission. True = Requests at least one 3rd party permission, False =
requests no 3rd party permission.

Figure 3.4: Android10: Percentage of apps that declare at least one permission
in their AndroidManifest.xml. True = Declares at least one permission, False =
declares no permission.

#####  3.3.1.2 Android 9: Permissions statistics

We have extracted 2’806 different permissions and counted the frequency of
their usages from our Android 9 dataset. Figure 3.5 shows the top 30 most used
permissions for our Android 9 apps. Please note that we added in Appendix E a
graphic with the top 100 permissions. We can see from the top 30 that the
internet and network state permission seems to be on top of the most used
permissions. Moreover, we have several dangerous permissions in the top 30. To
be more precise, eight dangerous, 13 normal, eight signature, and one
permission that Google lists as "not used by third-parties
applications"111android.permission.WRITE_SECURE_SETTINGS according to [75].
Nearly every third app (33,64%) in our Android 9 dataset has write access to
the external storage, and 26.67% have read access. 26.15% apps use the read
phone state permission, which gives access to the unique phone identifiers.
Overall we conclude that the use of dangerous permissions for our Android 9
apps seems to be common.

Figure 3.5: Android 9: Top 30 most used permissions.

To further investigate the usage of the permissions we list in Figure 3.6 the
top 30 most requested 3rd party permissions. On top of the most requested
permissions is access to the Google Play service. Looking at the top 30, it
seems that we have mainly custom Google and Samsung permissions. For most
permission, we can only assume their purpose, and without manually analyzing
each of the permissions, we cannot conclude if their usage is a risk for the
user.

Figure 3.6: Android 9: Top 30 most used 3rd party permissions.

#####  3.3.1.3 Android 8: Permission statistics

Another way to use the permission data is to aggregate the total number of
permissions grouped by protection level to show the protection levels’
distribution. Figure 3.7 shows a boxplot of the dangerous protection level
without any additional protection flags. Thy y-axis represents the total
number of permissions an app uses for the individual protection level. The
illustration shows that we have several out-liners with unusually high usage
of dangerous permissions. On top is one app that uses 25 dangerous
permissions. Overall, most apps that use dangerous permissions do not use more
than five dangerous permissions. The median lays at two permissions.

Figure 3.7: Android 8: Distribution of the dangerous protection level. Figure
3.8: Android 8: Distribution of the signature protection level.

We illustrate in Figure 3.8 the signature protection level distribution
without any additional flags. Similar to the dangerous protection level, we
have out-liners with rather high usage of signature permissions. Overall,
signature permissions’ usage lies between one and four, with a median of two
signature permissions. If we look at Figure 3.9 we see the distribution of the
normal permission level. Note that the scale of normal permissions compared to
the dangerous and signature permissions is higher. The x-axis in Figure 3.9
shows the number of normal permissions used, and we have out-liners that use
more than 100 normal permissions. Overall the Q1 and Q3 percentiles show that
most apps use between five to 20 normal permissions.

Figure 3.9: Android 8: Distribution of the normal protection level.

In summary, we have seen the percentages of apps that declare and use custom
permissions on Android 10. For Android 9, we have shown which permissions pre-
installed app developers use the most overall and which 3rd party permissions
are more used than others. For Android 8, we showed the distribution of
dangerous, signature, and normal permissions, and we show that we can identify
unusual permission usages by looking at the out-liners in Figures 3.7, 3.8 and
3.9. Keep in mind that the shown numbers only represent the trend in our
dataset. We cannot generalize these trends to all Android 8, 9, or 10
firmware. The depicted examples demonstrate that the collected data is useful
to identify out-liners and trends. As mentioned before, we can generate such
statistics for any arbitrary set of firmware with FirmwareDroid and compare
the results.

####  3.3.2 Certificates

With AndroGuard, we extract as well the certificates of all pre-installed
apps. Keep in mind that we cannot check Android app certificates against a
PKI. Therefore we cannot verify that the certificate data provided is genuine.
It’s unlikely that all certificates are fake and not from an official vendor;
however, some certificates contain counterfeit data.

As with the permissions, we can use the data to generate statistics per
Android firmware and over arbitrary sets of apps. For example, if we are
interested in a specific app, we can query FirmwareDroid’s database for one
app and search for all apps with the same signing certificate. Another
possibility is to query how common a specific certificate is to determine how
many apps are using the same certificate. Table 3.7 shows how many
certificates we have extracted and how many unique certificates we have for
every Android version. Note that an app can have more than one certificate.

| Android
---
Version
| Total number
---
of certificates
extracted
| Number of
---
unique
certificates
| Ratio unique
---
packagename to
unique certificate
8 | 72’076 | 447 | 1’991/447
9 | 55’291 | 320 | 1’375/320
10 | 15’130 | 92 | 242/92
Table 3.7: Number of unique certificates in our database.

We can calculate the average of how many apps use the same certificates by
dividing the unique number of package names with the unique number of
certificates. Our Android 8 certificates are, on average, used by 4.45 apps,
our Android 9 by 4.3 apps, and our Android 10 by 2.63 apps. These numbers show
that, on average, the companies use their app certificates more than once. We
give a further example of how often certificates are reused by searching for
AOSP development keys. To be more precise, we search for how common the AOSP
platform certificate (sha1: 27 19 6E 38 6B 87 5E 76 AD F7 00 E7 EA 84 E4 C6 EE
E3 3D FA) is in our dataset. As a result, we can say that we have 108’983
(12,07%) apps that use the AOSP certificate. Note that the certificate is
insecure since its private keys are publicly available [97] and everyone can
sign apps with this certificate. To further explore the most common
certificates, we analyze the top ten for Android 8, 9, 10.

| App developer
---
and
example packagename
Certificate SHA1 |  | Number of certificates
---
in database
| Percantage of total
---
apps in database
(902’262)
Android 10
| Google Inc.
---
com.quicinc.cne.CNEService
| E3 22 16 17 B1 D6 B5 10 DB 06
---
4E DB 38 15 02 BD FD 3B AC 47
1316 | 0.15%
Google Inc. |  | 38 91 8A 45 3D 07 19 93 54 F8
---
B1 9A F0 5E C6 56 2C ED 57 88
1134 | 0.13%
| Google Inc.
---
com.android.sharedstoragebackup
| 38 D8 1C FB 64 BD 5D 78 BA
---
ED 39 3C 25 E7 E9 2B 91 60 20 0E
869 | 0.10%
| Google Inc.
---
Android Easter Egg
| 69 25 F4 EE 29 7C 96 E8 30 5C
---
59 EA 02 6B FA 74 A8 DC E1 91
869 | 0.10%
| Google Inc.
---
com.android.vpndialogs
| 81 C2 B1 2C BA 14 66 FE CF
---
45 29 BE 3F 08 14 B7 F5 0B 44 83
814 | 0.09%
| Google Inc.
---
com.android.vpndialogs
| 81 90 2F C3 62 B6 A8 85 40 B2
---
7F 04 90 9C 2C 85 0A E8 46 85
814 | 0.09%
| Google Inc.
---
com.quicinc.cne.CNEService
| 2A 5F D0 80 D1 5E D5 C6 91 36
---
B3 9A 9F 3E 64 C6 65 B9 91 A2
703 | 0.08%
| Google Inc.
---
android
| D4 D3 D7 EF 20 B8 59 8A 43 71
---
49 9C AD 13 01 37 AA 30 FF 3B
703 | 0.08%
| Google Inc.
---
X Google enrollment
| 5F 3F 5A D9 2D 23 D6 40 2A 26
---
31 70 D8 7A 0D 8A 44 C5 90 AC
634 | 0.07%
| Google Inc.
---
Default Print Service
| 70 62 71 04 12 02 F8 0C E2 AB
---
09 DD 7C 22 95 9D 2D 92 DB 0C
634 | 0.07%
Android 9
| Samsung
---
com.samsung.aasaservice
| 9C A5 17 0F 38 19 19 DF E0 44
---
6F CD AB 18 B1 9A 14 3B 31 63
21272 | 2.36%
Google Inc. |  | 38 91 8A 45 3D 07 19 93 54 F8 B1
---
9A F0 5E C6 56 2C ED 57 88
5577 | 0.62%
| InfinixMobility
---
android
| BF D5 79 80 68 4E B3 7C 5E 86
---
DA 0D D0 8A 9D DF E4 81 87 41
1869 | 0.21%
| Samsung (DMC)
---
com.android.dreams.basic
| 97 41 A0 F3 30 DC 2E 86 19 B7
---
6A 25 97 F3 08 C3 7D BE 30 A2
1686 | 0.19%
| Samsung Electronics Co. Ltd.
---
com.samsung.aasaservice
| 29 C6 47 CB CC 9A 5F BD 6C 0C
---
96 1E 05 71 2B D1 53 52 A1 F5
1333 | 0.15%
| Google Inc.
---
com.android.bluetooth
| 73 69 74 B3 71 23 FA 90 07 CF 05
---
CD C1 FB 43 D9 15 91 76 22
1116 | 0.12%
| Google Inc.
---
com.android.bluetooth
| B8 41 56 6D C2 B4 69 F3 11 14
---
BB 27 17 14 B5 DC A6 44 FD 80
1116 | 0.12%
Google, Inc |  | 24 BB 24 C0 5E 47 E0 AE FA 68
---
A5 8A 76 61 79 D9 B6 13 A6 00
926 | 0.10%
| Google Inc.
---
android
| D4 D3 D7 EF 20 B8 59 8A 43 71
---
49 9C AD 13 01 37 AA 30 FF 3B
919 | 0.10%
| Google Inc.
---
com.quicinc.cne.CNEService
| 2A 5F D0 80 D1 5E D5 C6 91 36
---
B3 9A 9F 3E 64 C6 65 B9 91 A2
919 | 0.10%
Android 8
| Samsung
---
com.samsung.aasaservice
| 9C A5 17 0F 38 19 19 DF E0 44 6F
---
CD AB 18 B1 9A 14 3B 31 63
19837 | 2.20%
Google Inc. |  | 38 91 8A 45 3D 07 19 93 54 F8
---
B1 9A F0 5E C6 56 2C ED 57 88
8731 | 0.97%
| Transission
---
com.mediatek.batterywarning
| BE 8C B9 F9 5B CB 5B FB 04
---
04 50 34 E5 18 26 34 A2 FC A1 FA
2421 | 0.27%
| Samsung
---
com.samsung.aasaservice
| 29 C6 47 CB CC 9A 5F BD 6C
---
0C 96 1E 05 71 2B D1 53 52 A1 F5
1921 | 0.21%
Google, Inc |  | 24 BB 24 C0 5E 47 E0 AE FA 68
---
A5 8A 76 61 79 D9 B6 13 A6 00
1852 | 0.21%
Samsung Corporation (DMC) |  | 97 41 A0 F3 30 DC 2E 86 19 B7
---
6A 25 97 F3 08 C3 7D BE 30 A2
1720 | 0.19%
| Zhantang
---
com.sprd.engineermode
| F1 A5 4A 3F 02 4A 8D 1B 74 D1
---
FF 1F 74 D3 BE 66 ED 79 31 2E
1478 | 0.16%
| Google Inc.
---
com.android.egg
| 69 25 F4 EE 29 7C 96 E8 30 5C
---
59 EA 02 6B FA 74 A8 DC E1 91
1407 | 0.16%
Tecno |  | 48 19 D1 56 9B D0 64 AD 33 94
---
61 73 79 32 FB 76 1C 1B E1 77
1323 | 0.15%
| Lava
---
com.adups.fota
| FB 01 33 26 78 40 78 4C A3 00
---
9E 26 F2 69 F7 43 2C 09 19 EC
1184 | 0.13%

Table 3.8: Top ten most used certificates for Android 8, 9, and 10 in our
database.

In Table 3.8 we show the most common certificates for Android 8, 9, and 10 in
our database. For Android 10, we have only Google certificates in the top ten.
We think this is not surprising as we have for Android 10 mostly official
stock firmware from Google. For Android 8 and 9, we have two certificates from
Samsung at the top followed by Google certificates. We have as well other
Samsung certificates in the top ten. If we compare the numbers of certificates
for Samsung, we can see that there seems to be a large gap between the first
certificate and the others in numbers. We compare the three Samsung
certificates for Android 9 to see if we can manually spot an anomaly in the
certificate data. Most of the data like subject or issuer seem to be the same,
but the validity timestamps aren’t. Two of the certificates have a "not-valid-
before" field from 2011, and the other certificate (sha1: 29 C6 47 CB CC 9A 5F
BD 6C 0C 96 1E 05 71 2B D1 53 52 A1 F5) has it set to 2018. It seems odd that
an Android 9 device from Samsung would use a not-valid-before date from
November 2018 since Android 9 was released in August 2018. However, it could
be possible that they created a new certificate at that time, so we have to
investigate further to see if that certificate is part of a malicious
campaign. So we check the first apk in our database that shows up when we
search for the certificate (md5:ad5803db6c96b5494a4fd822cb7812ec, package
name:com.Samsung.aasaservice) in our list with FirmwareDroid:

  * •

VirusTotal shows that three scanners detect the apk as malicious.

  * •

APKiD does not detect a suspicious compiler. It detects the dx compiler.

  * •

Qark lists 36 issues. Twenty-five issues are general infos, and eleven are
warnings. We list only the warnings that we think are relevant:

    * –

This permission can be obtained by malicious apps installed prior to this one,
without the proper signature. Applicable to Android Devices prior to L
(Lollipop).

    * –

Backups enabled: Potential for data theft via local attacks via adb backup, if
the device has USB debugging enabled (not common).

    * –

The receiver com.adups.library.ac.NetworkReceiver is exported, but not
protected by any permissions. Failing to protect receiver tags could leave
them vulnerable to attack by malicious apps. The receiver tags should be
reviewed for vulnerabilities, such as injection and information leakage.

    * –

The activity com.adups.fota.GoogleOtaClient is exported, but not protected by
any permissions. Failing to protect activity tags could leave them vulnerable
to attack by malicious apps. The activity tags should be reviewed for
vulnerabilities, such as injection and information leakage.

    * –

This results in AMS either resuming the earlier activity or loads it in a task
with same affinity or the activity is started as a new task. This may result
in Task Poisoning.

  * •

Androwarn reports that at least two UNIX commands are executed and that the
app accessed some phone identifiers and can conduct phone calls.

  * •

AndroGuard shows us that the application accesses four dangerous permissions
and eleven normal permissions. Looking at the normal permissions, we think it
is interesting that the app requests permission to install and remove
shortcuts. The app uses the following dangerous permissions:

    * –

android_permission_GET_ACCOUNTS

    * –

android_permission_READ_PHONE_STATE

    * –

android_permission_READ_EXTERNAL_STORAGE

    * –

android_permission_WRITE_EXTERNAL_STORAGE

The point that VirusTotal reports this apk as malicious undermines our
assumption that the certificate is malicious. However, APKiD does not detect
that the apk is repackaged, and it could be a coincidence. We check ten other
apks of the same certificate with FirmwareDroid but could not detect any
anomalies. Therefore, we decide two compare an apk with the same package name
but signed with one of the other Samsung certificates (sha1: 9C A5 17 0F 38 19
19 DF E0 44 6F CD AB 18 B1 9A 14 3B 31 63). Following the scanner results for
the potential genuine com.samsung.aasaservice apk
(md5:8ca66bf726e316c79590399ab00377ab):

  * •

VirusTotal does not detect any findings.

  * •

APKiD shows that the Jack 3.x and dx compilers are used.

  * •

Qark lists four issues– two warnings and two infos. Following the warnings
reported by Qark:

    * –

Backups enabled: Potential for data theft via local attacks via adb backup, if
the device has USB debugging enabled (not common).

    * –

This permission can be obtained by malicious apps installed prior to this one,
without the proper signature. Applicable to Android Devices prior to L
(Lollipop).

  * •

Androwarn does not report any suspicious findings.

  * •

AndroGuard shows that the app uses one dangerous and one signature permission
as shown below. In total, only 6 permissions are used.

    * –

android_permission_REAL_GET_TASKS

    * –

android_permission_WRITE_EXTERNAL_STORAGE

Comparing these two apps shows significant differences in permission usages
and findings by the individual scanners. A detailed analysis of the apps
signed with the potential malicious Samsung certificate (sha1: 29 C6 47 CB CC
9A 5F BD 6C 0C 96 1E 05 71 2B D1 53 52 A1 F5) is out of the scope of this
project. However, even if it seems likely that we have found at least one
malicious app singed with a suspicious-looking Samsung certificate, we cannot
prove that the certificate is fake. Without a PKI, the only way to check the
authenticity of this certificate is by asking Samsung if it is, in fact, one
of their certificates. In case the certificate is malicious, we could assume
that all the apps signed with this certificate are harmful.

In summary, analyzing our certificate data for anomalies can help detect
potentially harmful applications, but without a PKI, we cannot prove a
certificate’s authenticity. If vendors would begin to publish their official
app certificates, we could confirm every certificate’s authenticity in our
dataset and find more potential malicious certificates. A manual analysis of
every certificate in our database is not feasible during this project, and as
shown in Table 3.8 we have more certificates that we could check.
Nevertheless, we have demonstrated a possible use of the collected certificate
data. We can use the data in various other ways, such as showing the relations
between firmware and app vendors like other researchers [14] have done. We
continue in the next section with our APKiD scan result analysis.

###  3.4 APKiD Scan Result Analysis

In this section, we will discuss the scanning result of the APKiD tool. We
will provide for every APKiD feature a table with the raw scanning result and
discuss some of the results in detail.

Compiler | Decompiler | Obfuscators / Packers | Deobfuscators / Unpackers
---|---|---|---
Jack [98] | backsmali [99] | AAMO [100] | GDA(GJoy Dex Analysizer) [101]
Dx | Jad [102] | ADVobfuscator [103] | Deoptfuscator [104]
D8 |  | Alipay | JEB [105]
smali [99] |  | Allatori [106] | apktool [63]
Mercury |  | AntiSkid | jadx [62]
C++Builder |  | ApkProtect [107] | deobf [108]
Intel C++ Compiler (icc) |  | AppSuit [109] | Paranoid Deobfuscator [110]
Visual C++ (cl) |  | Arxan GuardIT |
Iodine |  | ByteGuard |
B4X |  | DashO [111] |
|  | Dexguard [112] |
|  | DexProtector [113] |
|  | Firehash |
|  | Gemalto [114] |
|  | Kiwi encrypter [115] |
|  | Obfuscapk [116] |
|  | Obfuscator-LLVM [117] |
|  | Safeengine [118] |
|  | Shield4j |
|  | SnapProtect |
|  | Stringer [119] |
|  | PromonShield [120] |
|  | Enigma [121] |
|  | Paranoid [122] |
|  | Simple-obfs-android [123] |
|  | AndroidLibrary [124] |
|  | AESJniEncrypt [125] |
|  | Obfuscapk [116] |
|  | AabResGuard [126] |
|  | rotacsufbo [127] |
|  | Robfuscate [128] |
|  | AndrOpGAN [129] |
|  | AEON [130] |
|  | ICFGO [131] |

Table 3.9: Incomplete list of compilers, decompilers, de-/obfuscators and
un-/packers for Android.

To fully understand the potential of APKiD, we need some more information
about Android compilers and decompilers. In Table 3.9 we collected a list of
de-/compilers, de-/obfuscators and un-/packers. The list is not complete, but
it shows some common tools used on Android. When we look at the first column
"Compiler", we can see the entries Jack and DX. These two are the main
toolchains used for building Android apps since there are the official tools
supported by Google. Jack and DX were deprecated in 2017 [98], and the
migration to the newer D8 toolchain is currently in progress [132].

With APKiD, we can scan an apk, and in some cases, it can detect which
compiler was used based on pattern recognition with Yara [133]. We can then
use this data to detect if an attacker has used an unknown or suspicious
compiler. For example, tools like Jadx [62] and the apktool [63] use smali and
backsmali [99] for de-/compiling. Such compilers have different patterns than
the DX compiler since they use dexlib for compiling. We considered it unlikely
that the original app developer would need to use a tool like Jadx to compile
their source code. In this case, we think the app was likely re-packaged, or
the developer uses a packer to protect the app.

Pre-installed apps are protected by AVB against re-packaging. As we have
already discussed in Section 2.5 Android Verified Boot prevents an attacker
from corrupting a firmware partition after it is signed. Therefore system apps
are protected by dm-verity and can’t be re-package under the assumption that
AVB is secure and active. However, to our knowledge, during the build process
and before the OS vendor signs the pre-installed apps and partitions, no known
protection mechanisms are in use. OS vendors like Google likely have their
processes to verify a pre-installed app’s integrity and authenticity before
adding the app to a firmware build. Nevertheless, we can assume that some OS
vendors do not have such security processes or less mature ones and that re-
packaging of 3td party apps is possible before the OS vendor adds the app to
the firmware.

Another reason for re-packaging pre-installed apps is for customization
purposes. Since custom ROMs use their key material, it is possible for their
developers to re-package a pre-installed app and resign it with their platform
key. Taking this into consideration, we have scanned all the pre-installed in
our dataset with APKiD (v. 2.2.1). We were able to scan 897’570 out of 902’837
apps. We could not scan 5’267 due to incompatibility and technical problems
with APKiD. Table 3.10 shows the result of APKiD’s compiler detection.

Compiler | Unknown | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Total
---|---|---|---|---|---|---|---|---|---|---|---
dx | 100530 | 597 | 43 | 187553 | 55468 | 66722 | 160542 | 98872 | 91087 | 3946 | 765360
dx (possible dexmerge) | 4230 | 3 | 0 | 11633 | 3183 | 3902 | 12122 | 4923 | 4765 | 234 | 44995
Jack (unknown version) | 0 | 0 | 0 | 9 | 101 | 10535 | 966 | 2 | 2 | 0 | 11615
Jack 4.12 | 0 | 0 | 0 | 0 | 0 | 1 | 60 | 48 | 35 | 0 | 144
Jack 4.x | 604 | 0 | 0 | 0 | 0 | 8 | 517 | 22928 | 297 | 0 | 24354
Jack 3.x | 9 | 0 | 0 | 0 | 0 | 52 | 39079 | 52 | 8 | 0 | 39200
dexlib 2.x | 89 | 0 | 0 | 1054 | 1272 | 1018 | 1156 | 125 | 255 | 0 | 4969
dexlib 1.x | 33 | 5 | 0 | 10283 | 354 | 386 | 1239 | 133 | 40 | 0 | 12473
Unknown | 24430 | 2 | 0 | 905 | 718 | 1822 | 1543 | 405 | 32943 | 11134 | 73902

Table 3.10: APKiD scan result for compilers.

If APKiD can’t detect the compiler, it flags it either as unknown or does not
show any report results. Moreover, APKiD can detect several compilers,
obfuscators, or packers per apk because an apk can contain more than one dex,
elf, or other binary files. In Table 3.10 we can see that APKiD detected apps
compiled with dexlib one and two. As mentioned before, attackers use the
dexlib compiler for re-packaging, or developers use packers for protection. As
a consequence, we assume that some of these samples may be malicious but not
necessarily. For example, packers can use re-packaging techniques to secure
and apk.

A detailed analysis of every potential re-packaged app is not feasible during
this project. However, we pick one of the dexlib 2.x detected apks as an
example to show how we can progress after finding it. We take the
"SkinPackViVo.apk" (md5: 5f73cf1c9018514954387aed3547f3d4) that was detected
in Android 9 firmware archives.

First, we can search in our database for more information about the
SkinPackViVo.apk. It seems that the SkinPackViVo.apk is only 379KB in size and
stored in /system/app/SkinPackViVo. We search for another sample of the same
apk, which was not compiled with dexlib. If we find one sample, we may have a
version of the apk that we can use for comparison and not re-packaged. In the
case of the SkinPackViVo.apk we do have a sample in our database that was
compiled with dx (md5: 3e6334e22abc18a355aa5ab2f088fe16). So we can compare
the certificates of these apk’s to each other to see if there is any
difference. In this case, we see that both certificates are identical and,
therefore, from the same developer. We think this is an indicator that not a
third party has tampered with the apk because otherwise, we would have two
different certificate signatures. The only other possibility would be that an
attack has managed to steal the original key material to sign the re-packaged
apk.

As the second step, we scan the apk with VirusTotal. The VirusTotal online
scan [134] shows that one scanner (Ikarus) detects the file as malicious with
the category PUA.AndroidOS.Cootek. Searching the web for the apk and the
malware category shows that we have found an app plugin developed by the
Chinese company CooTek. Some online articles claim [135, 136] that CooTek apps
have shown overaggressive advertising and were temporary removed from the
Google Play Store. We were not expecting these results when looking for re-
packaged apps, but it still shows that we can find suspicious apps with APKiD.
We will progress with other APKiD results.

If we have a look at the obfuscator detection results of APKiD in Table 3.11
it seems that most pre-installed apps don’t use an obfuscator, or APKiD can’t
detect it at least. We could detect 6’986 obfuscated files in 897’570 apps
with APKiD. There is so far no study for APKiD that compares the detection
rate for obfuscators to our knowledge. Other tools like [137, 138] may have
better detection rates but comparing these tools is outside of our project
scope. However, it seems unlikely that the official Android Studio
obfuscators, ProGuard [139] and R8, are not detected. We think it seems that
APKiD’s obfuscator and packer detection is still in development and that these
are likely to be added in later versions. At the time of writing, several
Github issues on the official APKiD repository [4] are open for adding new
detection rules for obfuscators and packers. We can conclude that the numbers
from Table 3.11 are not representative of all obfuscators that exist. Still,
for DexGuard and Arxan, we can say that app developers use them on all Android
versions in our dataset.

Obfuscator | Unknown | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Total
---|---|---|---|---|---|---|---|---|---|---|---
DexGuard | 128 | 0 | 0 | 309 | 602 | 785 | 544 | 156 | 425 | 68 | 3017
Arxan | 23 | 0 | 0 | 32 | 22 | 168 | 570 | 245 | 158 | 34 | 1252
Arxan (multidex) | 0 | 0 | 0 | 25 | 0 | 0 | 0 | 0 | 0 | 0 | 25
Obfuscator-LLVM version 3.4 | 5 | 0 | 0 | 47 | 18 | 75 | 240 | 10 | 12 | 0 | 407
Obfuscator-LLVM version 3.5 | 1 | 0 | 0 | 21 | 8 | 5 | 44 | 75 | 0 | 0 | 154
Obfuscator-LLVM version 3.6.1 | 634 | 0 | 0 | 1 | 4 | 0 | 9 | 6 | 0 | 0 | 654
unreadable method names | 27 | 0 | 0 | 48 | 60 | 281 | 120 | 69 | 49 | 0 | 654
unreadable field names | 99 | 0 | 0 | 48 | 74 | 279 | 166 | 84 | 66 | 0 | 816
DexProtector | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 1
ADVobfuscator | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 2
Allatori demo | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 3
Alipay | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1

Table 3.11: APKiD obfuscators scan results for different Android versions.

Another fact is that we detected the Obfuscator-LLVM in all versions except
Android 10. We think it seems unlikely that an obfuscator is used in all
versions before, and then app developers stopped using it. However, we have to
keep in mind that not all versions of Obfuscator-LLVM are detected and that we
have 634 detected files from 154 unknown firmware versions. It could be that
some of the unknown firmware are Android10 or even a higher Android version.
Moreover, it could be just a coincidence since we have different samples of
firmware for every version.

Packer | Unknown | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Total
---|---|---|---|---|---|---|---|---|---|---|---
APKProtect | 0 | 0 | 0 | 38 | 14 | 0 | 0 | 0 | 0 | 0 | 52
Jiagu | 0 | 0 | 0 | 14 | 7 | 11 | 4 | 0 | 0 | 0 | 36
UPX 3.91 (unmodified) | 0 | 0 | 0 | 34 | 26 | 2 | 0 | 0 | 0 | 0 | 62
Unicom SDK Loader | 1 | 0 | 0 | 71 | 2 | 0 | 0 | 0 | 0 | 0 | 74
Ijiami | 0 | 0 | 0 | 11 | 3 | 0 | 3 | 2 | 0 | 0 | 19
Ijiami (UPX) | 0 | 0 | 0 | 14 | 3 | 0 | 0 | 0 | 0 | 0 | 17
SecNeo.A | 0 | 0 | 0 | 1 | 2 | 16 | 6 | 0 | 0 | 0 | 25
Mobile Tencent Protect | 0 | 0 | 0 | 0 | 4 | 10 | 4 | 0 | 1 | 0 | 19
Bangcle | 0 | 0 | 0 | 40 | 7 | 0 | 0 | 0 | 0 | 0 | 47
newer-style Bangcle/SecNeo (UPX) | 0 | 0 | 0 | 74 | 14 | 0 | 0 | 0 | 0 | 0 | 88
SecNeo.B | 0 | 0 | 0 | 0 | 0 | 1 | 5 | 0 | 0 | 0 | 6
Bangcle/SecNeo (UPX) | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0 | 0 | 3
Bangcle (SecShell) | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 3
UPX (unknown, modified) | 0 | 0 | 0 | 0 | 0 | 0 | 6 | 24 | 0 | 0 | 30
sharelib UPX | 3 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 5
DexProtector | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1
Tencent’s Legu | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1

Table 3.12: APKiD scan result for packers.

When we look at the packer detection rates in Table 3.12 we can see that we
have detected 487 packers in total. This number seems rather small compared to
the number of apps we have scanned. However, as mentioned before, the APKiD’s
packer detection is still under development, and additional packers are likely
to be added in future versions.

Anti-VM | Unknown | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Total
---|---|---|---|---|---|---|---|---|---|---|---
Build.FINGERPRINT check | 9656 | 71 | 7 | 24944 | 6912 | 17659 | 26963 | 15586 | 16438 | 2504 | 120740
possible Build.SERIAL check | 12679 | 13 | 2 | 17345 | 5596 | 13442 | 20012 | 10948 | 12421 | 510 | 92968