MASTG-KNOW-0031: Emulator Detection
In the context of anti-reversing, the goal of emulator detection is to increase the difficulty of running the app on an emulated device. This increased difficulty forces the reverse engineer to defeat the emulator checks or use a physical device, thereby limiting the access required for large-scale device analysis.
Note
Emulator detection is inherently a cat-and-mouse game. Detection methods and bypass techniques evolve continuously, and determined attackers with sufficient time and resources can circumvent these protections, for example, by developing custom AOSP builds. These techniques should be part of a defense-in-depth strategy, not a standalone solution.
There are several indicators that the device in question is being emulated.
Build Characteristics¶
Apps can read build properties through android.os.Build. Emulators often ship with default or vendor-specific values.
| Field | Example emulator values or patterns |
|---|---|
Build.FINGERPRINT |
starts with generic, contains test-keys, contains generic/sdk/generic, generic x86, vbox86p, ttvm |
Build.MODEL |
sdk, google_sdk, emulator, android sdk built for x86, android sdk built for x86_64, droid4x, tiantianvm, genymotion, andy, nox |
Build.MANUFACTURER |
unknown, genymotion, droid4x, tiantianvm, andy |
Build.HARDWARE |
goldfish, ranchu, vbox86, nox, ttvm |
Build.PRODUCT |
sdk, google_sdk, sdk_x86, sdk_google, vbox86p, droid4x, andy, ttvm, nox, starts with itoolsavm |
Build.BRAND / Build.DEVICE |
start with generic, include generic x86, vbox86p, ttvm, andy, nox |
Build.BOARD |
unknown, contains nox |
Build.SERIAL |
unknown; deprecated, check for Build.getSerial() instead |
Build.ID |
frf91 |
Build.RADIO |
blank or unknown; deprecated, check for Build.getRadioVersion() instead |
Build.TAGS |
test-keys |
Build.USER |
android-build |
Notes: It is recommended to normalize to lowercase when checking these values.
Telephony Characteristics¶
Check telephony only when the device reports the relevant telephony feature, such as FEATURE_TELEPHONY or FEATURE_TELEPHONY_CALLING, depending on the API being used. Emulators often return fixed identifiers through TelephonyManager.
| Method | Example emulator values |
|---|---|
getLine1Number() |
15555215554 ... 15555215584 (even suffixes) |
getNetworkOperatorName() |
android |
getVoiceMailNumber() |
15552175049 |
Permission notes:
getLine1Number()requires phone-number access, such asREAD_PHONE_NUMBERS,READ_SMS, default SMS app status, or carrier privileges. On older target SDK versions,READ_PHONE_STATEmay also apply.getLine1Number()is deprecated as of Android 13 (API level 33). UseSubscriptionManager.getPhoneNumber(int)instead.getVoiceMailNumber()requiresREAD_PHONE_STATE.
Package Name Indicators¶
Use PackageManager to inspect installed packages or launcher activities for known emulator prefixes:
com.vphone., com.bignox., com.nox.mopen.app, me.haima., com.bluestacks, cn.itools., com.kop., com.kaopu., com.microvirt., com.bignox.app, and the exact package com.google.android.launcher.layouts.genymotion. Some checks also flag Build.PRODUCT starting with iToolsAVM.
On Android 11 (API level 30) and later, package visibility restrictions affect package-based emulator detection. If a package is installed but not visible to the app, getPackageInfo behaves the same as if the package were not installed, typically by throwing PackageManager.NameNotFoundException. This can create false negatives for package-based emulator detection.
Developers can query specific packages on Android 11 (API level 30) and later by declaring them in the app manifest using the <queries> element:
<queries>
<package android:name="com.bignox.app" />
</queries>
Otherwise, they can use the QUERY_ALL_PACKAGES permission, which grants visibility to all installed apps but is subject to Google Play restrictions and may not be justifiable for many use cases.
Available Activities and Services¶
Apps can query launcher activities with Intent.ACTION_MAIN and Intent.CATEGORY_LAUNCHER and look for emulator package prefixes, often com.bluestacks..
Launcher activity discovery through PackageManager.queryIntentActivities() is also affected by Android 11 (API level 30) and later package visibility restrictions. Apps should declare the matching intent signature in the <queries> element so it can return relevant launcher activities:
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent>
</queries>
ActivityManager.getRunningServices is restricted on Android 8.0 (API level 26) and later and only returns the app's own services.
File System Artifacts¶
Apps can check for emulator-specific files, sockets, and device nodes using standard file APIs such as java.io.File.exists(). Common examples include:
| Path | Description |
|---|---|
/dev/socket/qemud |
QEMU daemon socket |
/dev/qemu_pipe |
QEMU communication pipe |
/dev/goldfish_pipe |
Goldfish emulator pipe |
/sys/qemu_trace |
QEMU trace marker |
/dev/socket/genyd |
Genymotion daemon socket |
/dev/socket/baseband_genyd |
Genymotion baseband socket |
OpenGL Renderer¶
Create an EGL context and read GLES20.glGetString(GL_RENDERER). Renderer strings that contain Bluestacks or Translator can indicate emulators.
Deprecated or Advanced Techniques¶
Starting in Android 10 (API level 29), non-resettable identifiers, such as IMEI, serial number, SIM serial number, and subscriber ID, are restricted. Apps must have the privileged READ_PRIVILEGED_PHONE_STATE permission in order to access the device's non-resettable identifiers. Affected methods include Build.getSerial(), TelephonyManager.getImei(), getDeviceId(), getMeid(), getSimSerialNumber(), and getSubscriberId(). If an app targets Android 10 (API level 29) or higher and tries asking for information about non-resettable identifiers without the permission, a SecurityException occurs. If the app is the device or profile owner app, it needs only the READ_PHONE_STATE permission, even if it targets Android 10 (API level 29) or higher. If the app has special carrier permissions, it does not need any permissions to access the identifiers. See Android 10 privacy changes.
netcfg-based IP detection no longer works on modern Android and has been deprecated since Android 6.0 (API level 23).
Google Play Integrity API¶
The app can also use the Google Play Integrity API to request an integrity verdict for the app and device environment. This API performs checks that can help detect requests from emulated environments. See Google Play Integrity API for more details on the Google Play Integrity API.