因为不确定因素太多,最近公司需要禁止本程序在虚拟机上运行。
我网上找了好多,各种方法什么设备号,拨打电话,蓝牙设备,模拟器的检测往往是防作弊中的重要一关,这里把这两天收集到的代码写在这偏文章里,和大家进行一个简单的分享。
传统方法
传统的检测方法主要是对模拟器的IMSI、IDS、默认文件等几个方面进行检测。
(1)默认号码:
private static String[] known_numbers = {"15555215554", "15555215556",
"15555215558", "15555215560", "15555215562", "15555215564",
"15555215566", "15555215568", "15555215570", "15555215572",
"15555215574", "15555215576", "15555215578", "15555215580",
"15555215582", "15555215584"};
1
2
3
4
5
(2)默认ID:
private static String[] known_device_ids = {"000000000000000"};
1
(3)默认IMSI:
private static String[] known_imsi_ids = {"310260000000000"};
1
(4)默认文件路径:
private static String[] known_files = {
"/system/lib/libc_malloc_debug_qemu.so",
"/sys/qemu_trace",
"/system/bin/qemu-props"};
1
2
3
4
在得知了这些信息后,只需在运行时进行检测,如果检测结果和默认值吻合,那么检测设备便是模拟器。不过随着防反作弊技术的迭代,现在很多模拟器都可以改变这些值来逃避检测,所以上述传统方法在很多时候未曾达到开发者的预期效果。
拨打电话
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;
光传感器
/** * 判断是否存在光传感器来判断是否为模拟器 * 部分真机也不存在温度和压力传感器。其余传感器模拟器也存在。 * @return true 为模拟器 */ 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; } }
蓝牙
/* *判断蓝牙是否有效来判断是否为模拟器 *返回:true 为模拟器 */ public static 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; } } }
设备参数
/* *根据部分特征参数设备信息来判断是否为模拟器 *返回:true 为模拟器 */ public static boolean isFeatures() { 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.MODEL.contains("Android SDK built for x86") || Build.MANUFACTURER.contains("Genymotion") || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT); }
CPU
/* *根据CPU是否为电脑来判断是否为模拟器 *返回:true 为模拟器 */ public static boolean checkIsNotRealPhone() { String cpuInfo = readCpuInfo(); if ((cpuInfo.contains("intel") || cpuInfo.contains("amd"))) { return true; } return false; } /* *根据CPU是否为电脑来判断是否为模拟器(子方法) *返回:String */ 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笔记:多开/分身检测