TL;DR: I'll talk about some Android protections and a way to bypass the anti-emulation process using apktool and a java decompiler to gain the goal. This is the Part I and I'll talk about introductory topics
Introduction:
This is the first of a series of posts where we will focus in solving Android Reversing challenges. The challenge is focused on a binary protection called 'anti-emulation', (you can find more info in the OWASP Top Ten 2014/2016 article:). In the upcoming entries we will talk about other protections like root checker, certificate pinning, anti-tampering, obfuscation techniques, along with ways to protect our app from differents tools (Xposed tool, Frida, etc).
I found this challenge on my personal repository. It came from a Blackhat course I took last year, thanks! @din3zh and @prateekg147.
The download link for the apk is and the sha1 signature is:
a2d88143cc3de73387931f84439a4c5e4fdfe123 ReverzeMe1.apk
How to use Android online emulator. Click on the extension button and then click on “Run Android online emulator”. A new tab will open, here click on “Start” and once the emulator loads, click on “Enter”. The emulator will load and you should be able to see the home screen in a tablet layout. You can navigate the emulator using your.
- Here we bring a list of the best Android Emulators for Linux desktops that you can use to run any android application freely. Android emulator is a software application that wholly acts as a real.
- Android emulators can be used for many purposes such as developers testing apps & gamers playing on a large screen, If you are switching from iPhone, Android, or you want to test out a Custom ROM, the possibilities with Android Emulators on Windows 10 are endless, BlueStacks has always topped the list of phone emulators for PCs.
- Writable-system for the emulator. When launching the emulator after a build with, you must use. Build/envsetup.sh lunch aospx8664-eng emulator -show-kernel -verbose -writable-system Then, for future runs, you must keep the -writable-system option, or else image changes will not be visible: emulator -show-kernel -verbose -writable-system.
Before the analysis of the challenge itself I will introduce the concept of 'Anti-Emulation' on Android. A good reference for this topic is the Mobile Security Testing Guide by OWASP. They show some examples about these techniques, and different ways to analyze them. There is also an API called SafetyNet, which is an Android API that creates a profile of the device using software and hardware information which is useful for checking different Android protections.
If we see inside the Emulator Detection Examples section, an application has several ways to detect the emulation process.
For example, by checking differents methods like 'Build', 'TelephonyManager','android.os.SystemProperties', 'ro.product.device', 'ro.kernel.qemu', etc. Depending on the response it can infer if it is running on a physical device in an Android Emulator. To check if the app has this implementation in place, we can try to obtain its code. This can be done through differents techniques and we can use some tools such as apktool, jadx or cfr, etc.
We will see how we can make use of some of those tools to obtain a really good approximation of the application code. For example, using apktool we can decode resources to nearly original form. We can even rebuild them after making some modifications. With “jadx' or 'cfr' (boths java decompilers) we can analyze the 'java code' obtained after the decompilation process. This practice, allows us to look at the code in more natural way, since the output from the java decompilers are '.java' files whereas the output from apktool are '.smali' code files.
I will not get into Java decompilers in this post, because it is a out of the scope. will simply use them to analyze the code for the application in the challenge. Then, we will modify the application from the .smali code. We will show how to use apktool to obtain a good an approximation of the code, to be able to modify it as we need to and then re-build it.
With this in mind, we will take a look at which is the process to create an APK file, since it will be useful to start trying to solve the challenge.
The process of creating an APK file:
- First, the developer creates its application in .java to then be compiled into into .class files.
- Once these .class files are created, they are converted into .dex (Dalvik EXecutables) files. These files contain byte code for the Dalvik Virtual Machine (DVM) which is a non-standar JVM that runs on Android devices.
- The DVM runs the DEX files while ART runs OAT (ELF) files.
- Some other XML files are converted to a binary format optimized for space.
- The last step is the APK creation from the .dex files, binary XML files and other resources needed to run the application and are packaged into an Android Package file (.apk).
- After the APK file is signed by the developer (we’ll come back to this in the 'Manual patching with apktool' section), the APK is ready to be installed.
- If we want to look at the APK file, we can check its content by unpacking it, for example: $unzip -e example.apk -d example_folder
In short, the APK file is just a signed zip file that we can unzip them using the unzip command:
$unzip ReverseMe1.apk -d reverseme_unzipped
If we take a look at the manifest, we notice that the resources are encoded, we can use apktool to decode them later.$more AndroidManifest.xml
Anti-Emulation Checks:
As we mentioned earlier, there are several checks that an application can perform in order to detect whether we are running it on an emulated environment or an actual device. Usually malware APKs have these kind of protections to avoid any analisis. Some common validations are listed here (anti-emulation process), along with some examples.
Below are some code examples of different validations that I have encountered on applications while writing this post:
Some validation methods are even called “isEmulator()”, “carrierNameFromTelephonyManager()”, or my personal favorite so far, “smellsLikeAnEmulator()”. All of them look for the same, or similar validations. They test with “equals”, “contains”, “startsWith” or “endsWith” against some hardcoded strings that can be interpreted as being set by an emulator. But they all look pretty much the same.
I asked myself why this happened? I google it and I had the answer, of course, the first result was a stackoverflow response.
I started looking into some others apps, and I found some many more quite similar implementations:
The difference with the previous set of validation methods is that, while the first set validates through “string comparisons”, the second one does by looking at the “Android system properties” to try to detect emulated environments.
Then, by simply analyzing the implementation methods, we can identify two main approaches to implement an anti-emulation protection. We can use this link.
Strings comparisons:
Let’s take look at the “isEmulator()” example and their validations:
I wrote this reference table:
We can check them in a easy way using the following command in our computers with adb:
╰─$ adb shell getprop ro.build.fingerprint generic/vbox86p/vbox86p:5.1/LMY47D/genymotion08250738:userdebug/test-keys
Basically we can use $adb shell getprop < key > to check the differents values.
Android System Properties validations:
Now that we know how to check for validation through strings, we can do the same with the Android System Properties validations.
Android has a set of properties about the device that can be read using the getprop command line utility, like we saw recently. Those System Properties are stored in a key value pair format in the property files (default.prop, local.prop, etc). And we'll read those to check the Anti-Emulation process.
If we want to understand more about the property files, using “adb shell cat default.prop” we can check the property output:
$adb shell cat default.prop
# ADDITIONAL_DEFAULT_PROPERTIES#
ro.lockscreen.disable.default=true
ro.secure=1
ro.allow.mock.location=0
ro.debuggable=1
ro.zygote=zygote32
dalvik.vm.dex2oat-Xms=64m
dalvik.vm.dex2oat-Xmx=512m
dalvik.vm.image-dex2oat-Xms=64m
dalvik.vm.image-dex2oat-Xmx=64m
persist.sys.usb.config=adb
But if we returned to the previous image:
Android Emulator Roms
They are checking ro.hardware, ro.kernel.qemu, ro.serialno, ro.product.name, ro.product.model, ro.hardware, etc. We can check this output too using:
╰─$ adb shell getprop ro.product.name
vbox86p
╰─$ adb shell getprop ro.product.device
vbox86p
╰─$ adb shell getprop ro.product.model
Custom Phone - 5.1.0 - API 22 - 768x1280
╰─$ adb shell getprop ro.kernel.qemu
1
╰─$ adb shell getprop ro.hardware
vbox86
╰─$ adb shell getprop qemu.hw.mainkeys
0
╰─$ adb shell getprop ro.bootloader
unknown
╰─$ adb shell getprop ro.bootmode
unknown
╰─$ adb shell getprop ro.secure
1
╰─$ adb shell getprop ro.build.fingerprint
generic/vbox86p/vbox86p:5.1/LMY47D/genymotion08250738:userdebug/test-keys
╰─$ adb shell getprop ro.build.version.sdk
22
And again if the value of ro.secure is 1, the app is running on a emulator. The same with ro.kernel.qemu and the others.
Now is easy to understand which part of the code we need to modify to bypass the emulation process. We need to check all the implementations inside the code to bypass the application.
And we'll discuss that in the next entry. Follow me at @juanurss bye!!
Since Android 7, apps ignore user provided certificates, unless they are configured to use them.As most applications do not explicitly opt in to use user certificates, we need to place our mitmproxy CA certificate in the system certificate store,in order to avoid having to patch each application, which we want to monitor.
Please note, that apps can decide to ignore the system certificate store and maintain their own CA certificates. In this case you have to patch the application.
# 1. Prerequisites
Android Studio/Android Sdk is installed (tested with Version 4.1.3 for Linux 64-bit)
An Android Virtual Device (AVD) was created. Setup documentation available here
- The AVD must not run a production build (these will prevent you from using
adb root
) - The proxy settings of the AVD are configured to use mitmproxy. Documentation here
- The AVD must not run a production build (these will prevent you from using
Emulator and adb executables from Android Sdk have been added to $PATH variable
- emulator usually located at
/home/<your_user_name>/Android/Sdk/emulator/emulator
on Linux systems - adb usually located at
/home/<your_user_name>/Android/Sdk/platform-tools/adb
on Linux systems - I added these lines to my
.bashrc
- emulator usually located at
Mitmproxy CA certificate has been created
- Usually located in
~/.mitmproxy/mitmproxy-ca-cert.cer
on Linux systems - If the folder is empty or does not exist, run
mitmproxy
in order to generate the certificates
- Usually located in
# 2. Rename certificate
CA Certificates in Android are stored by the name of their hash, with a ‘0’ as extension (Example: c8450d0d.0
). It is necessary to figure out the hash of your CA certificate and copy it to a file with this hash as filename. Otherwise Android will ignore the certificate.By default, the mitmproxy CA certificate is located in this file: ~/.mitmproxy/mitmproxy-ca-cert.cer
# Instructions
- Enter your certificate folder:
cd ~/.mitmproxy/
- Generate hash and copy certificate :
hashed_name=`openssl x509 -inform PEM -subject_hash_old -in mitmproxy-ca-cert.cer | head -1` && cp mitmproxy-ca-cert.cer $hashed_name.0
# 3. Insert certificate into system certificate store
Now we have to place our CA certificate inside the system certificate store located at /system/etc/security/cacerts/
in the Android filesystem. By default, the /system
partition is mounted as read-only. The following steps describe how to gain write permissions on the /system
partition and how to copy the certificate created in the previous step.
# Instructions for API LEVEL > 28
Starting from API LEVEL 29 (Android 10), it seems to be impossible to mount the “/” partition as read-write. Google provided a workaround for this issue using OverlayFS. Unfortunately, at the time of writing this (11. April 2021), the instructions in this workaround will result in your emulator getting stuck in a boot loop. Some smart guy on Stackoverflow found a way to get the /system
directory writable anyway.
Keep in mind: You always have to start the emulator using the -writable-system
option if you want to use your certificate. Otherwise Android will load a “clean” system image.
Tested on emulators running API LEVEL 29 and 30
# Instructions
- List your AVDs:
emulator -list-avds
(If this yields an empty list, create a new AVD in the Android Studio AVD Manager) - Start the desired AVD:
emulator -avd <avd_name_here> -writable-system
(add-show-kernel
flag for kernel logs) - restart adb as root:
adb root
- disable secure boot verification:
adb shell avbctl disable-verification
- reboot device:
adb reboot
- restart adb as root:
adb root
- perform remount of partitions as read-write:
adb remount
. (If adb tells you that you need to reboot, reboot againadb reboot
and runadb remount
again.) - push your renamed certificate from step 2:
adb push <path_to_certificate> /system/etc/security/cacerts
- set certificate permissions:
adb shell chmod 664 /system/etc/security/cacerts/<name_of_pushed_certificate>
- reboot device:
adb reboot
# Instructions for API LEVEL <= 28
Tested on emulators running API LEVEL 26, 27 and 28
Keep in mind: You always have to start the emulator using the -writable-system
option if you want to use your certificate. Otherwise Android will load a “clean” system image.
Android Emulator With Custom Rom
- List your AVDs:
emulator -list-avds
(If this yields an empty list, create a new AVD in the Android Studio AVD Manager) - Start the desired AVD:
emulator -avd <avd_name_here> -writable-system
(add-show-kernel
flag for kernel logs) - restart adb as root:
adb root
- perform remount of partitions as read-write:
adb remount
. (If adb tells you that you need to reboot, reboot againadb reboot
and runadb remount
again.) - push your renamed certificate from step 2:
adb push <path_to_certificate> /system/etc/security/cacerts
- set certificate permissions:
adb shell chmod 664 /system/etc/security/cacerts/<name_of_pushed_certificate>
- reboot device:
adb reboot