Tamper protection by detecting the installer, emulator, and debug flag

In this recipe, we will look at three additional checks that may indicate a tampered, compromised, or hostile environment. These are designed to be activated once you are ready for release.

How to do it...

These tamper checks can be located anywhere in your app, but it makes the most sense to allow them to be called from multiple places at a separate class or parent class.

  1. Detect if Google Play store was the installer:
      public static boolean checkGooglePlayStore(Context context) {
        String installerPackageName = context.getPackageManager()
            .getInstallerPackageName(context.getPackageName());
        return installerPackageName != null
            && installerPackageName.startsWith("com.google.android");
      }
  2. Detect if it runs on an emulator:
    public static boolean isEmulator() {
      try {
    
        Class systemPropertyClazz = Class
        .forName("android.os.SystemProperties");
    
        boolean kernelQemu = getProperty(systemPropertyClazz,
              "ro.kernel.qemu").length() > 0;
          boolean hardwareGoldfish = getProperty(systemPropertyClazz,
              "ro.hardware").equals("goldfish");
          boolean modelSdk = getProperty(systemPropertyClazz,
              "ro.product.model").equals("sdk");
    
        if (kernelQemu || hardwareGoldfish || modelSdk) {
          return true;
        }
      } catch (Exception e) {
        // error assumes emulator
      }
      return false;
    }
    
    private static String getProperty(Class clazz, String propertyName)
          throws Exception {
      return (String) clazz.getMethod("get", new Class[] { String.class })
          .invoke(clazz, new Object[] { propertyName });
    }
  3. Detect if the app has the debuggable flag enabled—something that should only be enabled during development:
    public static boolean isDebuggable(Context context){
        return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
      }

How it works...

Detecting if the installer was the Google Play store is a simple check that the package name of the installer app matches that of the Google Play store. Specifically, it checks if the installer's package starts with com.google.android. It is a useful check if you are distributed solely through the Google store.

The Java Reflection API makes it possible to inspect classes, methods, and fields at runtime; and in this case, allows us to override the access modifiers that would prevent ordinary code from compiling. The emulator check uses reflection to access a hidden system class, android.os.SystemProperties. A word of warning: using hidden APIs can be risky, as they can change between Android versions.

When debuggable is enabled, it is possible to connect via the Android Debug Bridge and preform detailed dynamic analysis. The debuggable variable is a simple property of the <application> element in the AndroidManifest.xml file. It is perhaps one of the easiest and most targeted properties to alter in order to perform dynamic analysis. In step 3, we saw how to check the value of the debuggable flag on the application info object.

There's more...

See the Application signature verification (anti-tamper) recipe for suggestions on what to do if you detect tampering. Once released to the Play store, on detecting that the app is running on an emulator or is being debugged, it is reasonable to assume that the app is under analysis and/or attack. Therefore, in these scenarios, it would be justified to take more aggressive actions to frustrate attackers, such as wiping app data or the shared preferences. Although, if you are going to wipe user data, ensure this is noted in your license agreement to avoid any potential legal issues.

See also

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

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