玛卡巴卡的卡巴卡玛 发表于 2024-7-19 14:54:24

Android 模仿器检测

最近看到某客户端有一个检测模仿器的方法,我正常手机结果被判定是模仿器了,很好奇,于是找了一下原因。
广泛检测代码如下:

public boolean isEmulator() {
    String url = "tel:" + "123456";
    Intent intent = new Intent();
    intent.setData(Uri.parse(url));
    intent.setAction(Intent.ACTION_DIAL);
    // 是否可以处理跳转到拨号的 Intent
    boolean canResolveIntent = intent.resolveActivity(mContext.getPackageManager()) != null;

    return Build.FINGERPRINT.startsWith("generic")
      || Build.FINGERPRINT.toLowerCase().contains("vbox")
      || Build.FINGERPRINT.toLowerCase().contains("test-keys")
      || Build.MODEL.contains("google_sdk")
      || Build.MODEL.contains("Emulator")
      || Build.SERIAL.equalsIgnoreCase("unknown")
      || Build.SERIAL.equalsIgnoreCase("android")
      || Build.MODEL.contains("Android SDK built for x86")
      || Build.MANUFACTURER.contains("Genymotion")
      || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
      || "google_sdk".equals(Build.PRODUCT)
      || ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
            .getNetworkOperatorName().toLowerCase().equals("android")
      || !canResolverIntent;
}
这个代码检测模仿器有两个问题:
1、拨号检测,Android10.0及以上均为false
2、Build.SERIAL,Android8.0以上均为unknown
这导致8.0以上体系均会被误判
推荐模仿器检测方法:

设备信息检测代码:

private static final String[] known_numbers = {"15555215554", "15555215556", "15555215558", "15555215560", "15555215562", "15555215564", "15555215566", "15555215568", "15555215570", "15555215572", "15555215574", "15555215576", "15555215578", "15555215580", "15555215582", "15555215584",};

private boolean detectEmulator() {
      if (Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.startsWith("unknown")
                || Build.MODEL.contains("google_sdk") || Build.MODEL.contains("Emulator")
                || Build.MODEL.contains("Android SDK built for x86") || Build.MANUFACTURER.contains("Genymotion")
                || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
                || "google_sdk".equals(Build.PRODUCT)) {
            return true;
      }
      if (Build.PRODUCT.equals("sdk") || Build.PRODUCT.equals("sdk_x86")
                || Build.PRODUCT.equals("vbox86p") || Build.PRODUCT.equals("emulator")) {
            return true;
      }
      if (Build.BOARD == null) {
            return true;
      }
      if (Build.BOARD.equals("unknown")
                || Build.BOARD.contains("android")
                || Build.BOARD.contains("droid")) {
            return true;
      }
      if (Build.DEVICE == null) {
            return true;
      }
      if (Build.DEVICE.equals("unknown")
                || Build.DEVICE.contains("android")
                || Build.DEVICE.contains("droid")) {
            return true;
      }
      if (Build.HARDWARE == null) {
            return true;
      }
      if (Build.HARDWARE.equals("goldfish")
                || Build.HARDWARE.equals("ranchu")
                || Build.HARDWARE.contains("ranchu")) {
            return true;
      }
      if (Build.BRAND == null) {
            return true;
      }
      if (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) {
            return true;
      }
      if (Build.MANUFACTURER.equals("unknown")) {
            return true;
      }
      if (Build.MANUFACTURER.equals("Genymotion")) {
            return true;
      }
      if ((Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
                || "google_sdk".equals(Build.PRODUCT)) {
            return true;
      }
      if (Build.PRODUCT == null) {
            return true;
      }
      if (Build.PRODUCT.equals("sdk")
                || Build.PRODUCT.equals("sdk_x86")
                || Build.PRODUCT.equals("vbox86p")
                || Build.PRODUCT.equals("emulator")) {
            return true;
      }
      if (Build.HARDWARE.equals("goldfish")
                || Build.HARDWARE.equals("ranchu")) {
            return true;
      }
      if (Build.FINGERPRINT.startsWith("generic")
                || Build.FINGERPRINT.startsWith("unknown")
                || Build.MODEL.contains("google_sdk")
                || Build.MODEL.contains("Emulator")
                || Build.MODEL.contains("Android SDK built for x86")
                || Build.MANUFACTURER.contains("Genymotion")
                || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
                || "google_sdk".equals(Build.PRODUCT)) {
            return true;
      }
      if (Build.PRODUCT == null) {
            return true;
      }
      if (Build.PRODUCT.equals("sdk")
                || Build.PRODUCT.equals("sdk_x86")
                || Build.PRODUCT.equals("vbox86p")
                || Build.PRODUCT.equals("emulator")) {
            return true;
      }
      if (Build.HARDWARE.equals("goldfish")
                || Build.HARDWARE.equals("ranchu")) {
            return true;
      }
      if (new File("/dev/socket/qemud").exists()
                || new File("/dev/qemu_pipe").exists()) {
            return true;
      }
      try {
            TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
            if (telephonyManager != null) {
                String deviceId = telephonyManager.getDeviceId();
                List<String> knownNumbers = Arrays.asList(known_numbers);
                if (knownNumbers.contains(deviceId)) {
                  return true;
                }
            }
      } catch (Exception e) {
      }
      return false;
    }
上述代码使用了多种方法来检测设备是否为模仿器,这些方法包罗:


[*]检测 Build.FINGERPRINT 是否以 “generic” 或 “unknown” 开头
[*]检测 Build.MODEL 是否包含 “google_sdk”、“Emulator” 或 “Android SDK built for x86”
[*]检测 Build.MANUFACTURER 是否为 “Genymotion”
[*]检测 Build.PRODUCT 是否为 “sdk”、“sdk_x86”、“vbox86p” 或 “emulator”
[*]检测 Build.BOARD 是否为 “unknown” 或包含 “android” 或 “droid”
[*]检测 Build.DEVICE 是否为 “unknown” 或包含 “android” 或 “droid”
[*]检测 Build.HARDWARE 是否为 “goldfish”、“ranchu” 或包含 “ranchu”
[*]检测 Build.BRAND 是否以 “generic” 开头,且 Build.DEVICE 以 “generic” 开头
[*]检测 Build.PRODUCT 是否为 “google_sdk”
[*]检测是否存在文件 “/dev/socket/qemud” 或 “/dev/qemu_pipe”
[*]检测设备的电话号码是否为已知的模仿器电话号码
上述方法都是基于固件信息的判定,通过测试发现很多模仿器都失效,参考网上的教程,还有蓝牙、光线传感器、cpu检测,配合上面的固件信息,基本可以搞定大部门模仿器。
蓝牙检测代码:

public boolean notHasBlueTooth() {
    BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
    if (ba == null) {
      return true;
    } else {
      // 如果有蓝牙不一定是有效的。获取蓝牙名称,若为null 则默认为模拟器
      String name = ba.getName();
      if (TextUtils.isEmpty(name)) {
            return true;
      } else {
            return false;
      }
    }
}
光传感器检测代码:

public static Boolean notHasLightSensorManager(Context context) {
    SensorManager sensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE);
    Sensor sensor8 = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); //光
    if (null == sensor8) {
      return true;
    } else {
      return false;
    }
}
CPU检测代码:

public static boolean checkIsNotRealPhone() {
    String cpuInfo = readCpuInfo();
    if ((cpuInfo.contains("intel") || cpuInfo.contains("amd"))) {
      return true;
    }
    return false;
}

public static String readCpuInfo() {
    String result = "";
    try {
      String[] args = {"/system/bin/cat", "/proc/cpuinfo"};
      ProcessBuilder cmd = new ProcessBuilder(args);

      Process process = cmd.start();
      StringBuffer sb = new StringBuffer();
      String readLine = "";
      BufferedReader responseReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "utf-8"));
      while ((readLine = responseReader.readLine()) != null) {
            sb.append(readLine);
      }
      responseReader.close();
      result = sb.toString().toLowerCase();
    } catch (IOException ex) {
    }
    return result;
}
以上检测方法也不是完全可行,随着Android体系的更新,模仿器的增多,我们需要具体研究对应的一些变更来更新上述代码。
我们检测要注意一个问题,不肯定能检测出所有的模仿器,但是肯定不能误杀真机。
https://img-blog.csdnimg.cn/direct/8489ddba9b03473bb5889909812303f9.jpeg#pic_center

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Android 模仿器检测