Android 模拟器检测

news/2024/10/18 5:43:20/

文章目录

    • 普遍检测代码如下:
    • 推荐模拟器检测方法:
        • 设备信息检测代码:
        • 蓝牙检测代码:
        • 光传感器检测代码:
        • CPU检测代码:

最近看到某客户端有一个检测模拟器的方法,我正常手机结果被判断是模拟器了,很好奇,于是找了一下原因。

普遍检测代码如下:

public boolean isEmulator() {String url = "tel:" + "123456";Intent intent = new Intent();intent.setData(Uri.parse(url));intent.setAction(Intent.ACTION_DIAL);// 是否可以处理跳转到拨号的 Intentboolean 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系统的更新,模拟器的增多,我们需要具体研究对应的一些变动来更新上述代码。

我们检测要注意一个问题,不一定能检测出所有的模拟器,但是一定不能误杀真机。
在这里插入图片描述


http://www.ppmy.cn/news/1283204.html

相关文章

Checkpoint 执行机制原理解析

在介绍Checkpoint的执行机制前&#xff0c;我们需要了解一下state的存储&#xff0c;因为state是Checkpoint进行持久化备份的主要角色。Checkpoint作为Flink最基础也是最关键的容错机制&#xff0c;Checkpoint快照机制很好地保证了Flink应用从异常状态恢复后的数据准确性。同时…

Pikachu靶场 “Http Header”SQL注入

1. 先在 pikachu 打开 Http Header 注入模块&#xff0c;点击提示 查看登录 账号 和 密码&#xff0c;登陆后去 Burp 中找到登陆的 GET请求 2. 设置payload1 &#xff1a;在 User-Agent最后 输入 查看 数据库名 or updatexml(1,concat(0x7e,database()),0) or 查看 用户名…

promise的使用和实例方法

前言 异步,是任何编程都无法回避的话题。在promise出现之前,js中也有处理异步的方案,不过还没有专门的api能去处理链式的异步操作。所以,当大量的异步任务逐个执行,就变成了传说中的回调地狱。 function asyncFn(fn1, fn2, fn3) {setTimeout(() > {//处理第一个异步任务fn1…

【toolschain algorithm cpp ros】cpp工厂模式实现--后续填充具体规划算法,控制器版的已填充了算法接入了仿真器

写在前面 现在局势危机&#xff0c;于是想复习一下之前写的设计模式&#xff0c;之前提到&#xff0c;做过一个闭环仿真器&#xff08;借用ros&#xff09;&#xff0c;见https://blog.csdn.net/weixin_46479223/article/details/134864123我的控制器的建立遵循了工厂模式&…

Java web汽车销售管理系统JavaServelet Jsp(Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

【SpringCloud笔记】(11)消息驱动之Stream

Stream 技术背景 底层不同模块可能使用不同的消息中间件&#xff0c;这就导致技术的切换&#xff0c;微服务的维护及开发变得麻烦起来 概述 官网&#xff1a; https://spring.io/projects/spring-cloud-stream#overview https://cloud.spring.io/spring-cloud-static/spring…

Hive-数据模型详解(超详细)

文章目录 一、Hive数据模型1. 概述2. 数据库和表(1) 创建数据库(2) 使用数据库(3) 创建表格(4) 查看表结构 3. 分区与桶(1) 分区(2) 桶 4. 数据加载与查询(1) 数据导入(2) 查询语句 5. 总结 一、Hive数据模型 1. 概述 Hive是基于Hadoop的数据仓库工具&#xff0c;它提供了类似…

git远程操作,推送【push】,拉取【pull】,忽略特殊文件,配置别名,标签管理

文章目录 前言&#xff1a;新建远程仓库克隆推送【push】拉取【pull】 配置git忽略特殊文件给命令配置别名 标签管理理解标签创建标签操作标签 前言&#xff1a; 大家如果没有看过前几章git的基础操作的话&#xff0c;推荐先看一下&#xff0c;看完再来看这个远程操作&#xf…