Fake droids: Your new Android device is actually an old Android 6

During a digital forensices investigation, we found a cheap burner device that purported to be an Android 10 was actually and old Android 6. In this blog, we present how attackers can ‘fake’ the shutdown screen on iOS to achieve persistence.

August 16 2022 by

Jamf Threat Labs

Person behind a mask appearing to be something they are not

Now, we demonstrate how device-fakers sell old Android devices as a new device, with fake specifications including faking of the CPU speed, Android version, patch level, memory and even screen resolution.

It all started during a digital forensics investigation of a phone that was purchased from AliExpress as a cheap burner device was not how it presented itself.

Cheap Android 10 phone?

Following a brief investigation, we were able to locate the phone below on AliExpress. Shortly after the delivery, we were able to confirm our findings.

Fake Android listing on AliExpress

The link to the device we purchased is here. The phone looks stunning and is very cheap! What possibly can go wrong?

After inspecting the phone, the problem became clear: the device was recognized by our system as an Android 6, not an Android 10.

Wait, what ?

First thing we did was go to Settings > About phone. We found:

Fake Android phone specifications in settings indicating it is an Android 10 with 8 GB RAM and 512 MB ROM

As you can see, the device shows that it is an Android 10 with 10 processor cores. We then used a known software called “CPU-Z”. This app is used to check the hardware properties.

Deeper dive into the world of fake Android devices

We checked the kernel version and device properties:

Terminal session showing the fake phone has kernel version 3.18.19 and Android version 6.0

According to the output, the kernel version is 3.18.19 and Android version is 6.0. The Settings app, as well as CPU-Z, is trying to fool the end-user.

Let’s check the processor:

Terminal session showing the fake phone has 8 instead of 10 cores like the Settings app claimed

Here we see MT6753. This processor has 8 cores, instead of 10 cores, as was displayed in the Settings app.

Let’s check the API version:

Terminal session displaying the fake phone's API version as

The API version corresponds with Android 6 — consistent with previous findings.

Furthermore, we’ve made several observations about the UI of this phone, which is similar to Android 6 variants we previously used.

Examining where the Android faking happens

Now we've confirmed the phone is fake. But we can’t stop here — let’s examine where the interception of the data happens and how deep this device-faking goes:

We do know that the Settings app and CPU-Z app are reporting the same fake hardware details.

In order to understand where the data-faking happens, let’s focus on the Android version and check if all other apps do see the same device properties as CPU-Z and let’s do it in the same way CPU-Z or Settings app do.

First of all, let’s check if this fake is global, this will help us to guess the right component where the faking is happening. We already know that with ADB we can obtain the correct OS version number, which is consistent with both SDK version and the kernel version.

Let’s start with a simple check and establish a starting point: write our own program to check the actual version loaded with the precompiled framework.

The code (placed to onCreate of the basic project template):

Output:

So here everything is displayed correctly and consistently with adb output. We need to check the Settings app next.

Extracting and apktool’ing of the corresponding apk gives us the id of the Android version string resource id; it is “firmware_version”, but no classes.dex inside. It’s OK, it is the usual situation for the Settings app.

After deodexing /system/priv-app/Settings/oat/arm/Settings.odex with baksmali and getting the code we can grep it for the firmware_version constant and see that it is taken from os.android.Build.VERSION.

In DeviceInfoSettings.smali, and we’ll see something like this:

This corresponds to the code in onCreate in the DeviceInfoSettings.java file.

However the line number in the debug information does not correspond to the exact line, but it is around the needed code.

After decompiling the code back to Java we can finally see something more interesting:

onCreate file that modifies the display of the Android version

Now everything is clear. The code which is similar to original implementation is under condition that never actually happens, because the actual value of “persyst.sys.hdf.androidsdk” on this phone is 1.

There are funny nuances here, including the replacement of the Security Patch Level from 2018 to 2019!

Now we know where the fake Android version came from: it comes from HdfUtil.GetHrfAndroidString, along with a lot of other fake properties.

Let’s further examine how the fake Android version is configured:

As we can see at the start of onCreate function SystemProperties.getInt(“persyst.sys.hdf.androidsdk”, 0) is called.

We can verify this value with getprop utility and see that the returned value is 1, so the value that will be displayed as android version comes from HdfUtil.getHrfAndroidString .

Below is the source of this function:

This function actually returns the value “10.0” according to the real value returned from SystemProperties.getInt(“persist.sys.hdf.androidv”, 0) which can be checked with getprop utility and equals 7.

The similar exercise happens with all the other parameters.

Almost all the onCreate function of the DeviceInfoSettings class refers to this class, instead of doing what the original Android source says (which refers mostly to os.android.Build.VERSION class, see below)

os.android.Build.VERSION class being modified

All the hardware-faking happens in HdfUtil.java. This file wasn’t obfuscated.

When we understand what exactly happened here, we can compare the real hardware properties of this device with what our flattering Settings app says:

  • Android version: 10 (Settings) vs. 6.0 (real)
  • RAM: 8 GB (Settings) vs. 8388608 K (real)
  • ROM: 512 GB (Settings) vs. 8 GB (real)
  • CPU: MTK6799 10 cores (Settings) vs. MTK6753 (real)
  • Screen resolution: 2320x1280 (Settings) vs. 720x1520 (real)
  • Security patch: January 5, 2019 (Settings) vs. January 5, 2019 (real)

So the mystery of the phone is partially solved:

  • The fakers made changes in the sources of existing Android 6 environment.
  • They compiled this from the Java source code — we see it due to valid debug information existing in the smali code.
  • They added some build parameters which we can see in /system/build.prop and the outputs via adb, which define what exactly the customized Settings app should show to the user. The original parameters remained intact, so all the untouched framework works fine.
  • Number of harware variants in the HdfUtil.java shows that this framework was probably used for faking other phones too.
  • We can see that this is enough to fool the undemanding user, searching for a cheap Android 10 burner/regular phone.

There are three mysteries left to address:

  • How exactly did they fool the CPU-Z application, which was not installed on the phone when it arrived?
  • Are there other similar phones, who is responsible for faking the specs and can we find these phones automatically?
  • Is there another malware on the phone allowing the sellers to obtain remote access to the device?

Fooling The CPU-Z Application

After spending a some time tracing how exactly the android.os.Build.VERSION works, rooting the device (mtk-su works perfectly), going down to reversing the framework and its native part, it appears that it was more important to focus on how they display the fake data rather than how they get the version number and string.

It appears that they simply changed the code of the class android.widget.TextView to make it display the required fake values in specific applications. Sometimes, things are more simple than they appear to be.

In order to verify that we should extract boot.oat from the device, convert it to dex files with oat2dex utility, and then decompile the resulting dex files.

This is how it looks (the following code is from public final void setText(CharSequence var1) ):

public final void setText(CharSequence var1) function showing how the device showed a fake version to CPU-Z software

The main idea behind it is the following: if the name of the package is com.cpuid.cpu_z (which corresponds to the CPU-Z package name) and the previous string that was set with function is one of the faked parameters, the text is magically changing to the value encoded in the way similar to that was used in the Settings application based on the same build parameters that can be inspected with getprop.

Similar code snippets related to the following packages also found in this code:

  • com.antutu.ABenchMark
  • com.mediatek.camera
  • com.mediatek.filemanager
  • com.qiku.android.filebrowser
  • com.finalwire.aida64
  • com.ludashi.benchmark
  • ru.andr7e.deviceinfohw

This increases the suspicion that not only CPU-Z was fooled, but also other common applications to check for device specs/device benchmark.

After further analyzing various interesting code pieces, we decompiled all the framework and surprisingly found yet another interesting finding that shares light on how the fakers deal with other benchmarking/specs applications.

It appears that there is some suspicious activity in other classes of the specs-faking framework, specifically in the Package Manager.

After reversing the Package Manager, it appears that in addition to fooling these applications the specs-fakers also fooled the Package Manager with an interesting approach: instead of installing the APKs that were downloaded from Google Play, they used pre-stored and tampered copies from /system/data . Following a brief analysis we concluded that these APKs are not malicious. This change was made to assure that the version of the fake apps that they were dealing with was properly tested and displayed fake values.

Code showing how the fake phone shows the wrong version in Package Manager

Finally, the authors blocked crashes reports of the Google Play protect in activity manager, and modified the shutdown animation according to ro.hdf.shutdown.ani parameter.

Subscribe to the Jamf Blog

Have market trends, Apple updates and Jamf news delivered directly to your inbox.

To learn more about how we collect, use, disclose, transfer, and store your information, please visit our Privacy Policy.