内容简介:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011133213/article/details/83417421
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011133213/article/details/83417421
Android模拟器检测方案
项目背景:由于美柚当前检测模拟器的方案存在识别率(指模拟器没被检测出来)和准确率(错误地将真机判定为模拟器)都比较低的情况。导致黑产猖獗,所以提出该方案用于改善检测Android模拟器的识别率和准确率
转载请注明出处哈,CSDN 胖虎 : https://blog.csdn.net/ljphhj/
PS: 经过309台真机测试
目前市面上所有的模拟器如下:
Android模拟器名 | 支持平台 | Android内核版本 | CPU架构方式 | Adb连接方式 |
---|---|---|---|---|
Android原生模拟器 | Mac、 Linux 、Windows | All | x86 | adb connect 127.0.0.1:5555 |
Genymotion | Mac、Linux、Windows | All | x86 | adb connect 127.0.0.1:5555 |
海马玩模拟器(Droid4X) | Windows、Mac | 4.2.2 | x86 | adb connect 127.0.0.1:26944 |
Bluestacks(蓝叠)模拟器 | Windows | 4.4.2 | arm | adb connect 127.0.0.1:5555 |
雷电模拟器 | Windows | 5.1.1 | x86 | adb connect 127.0.0.1:5555 |
逍遥安卓模拟器 | Windows | 5.1.1 | x86 | adb connect 127.0.0.1:21503 |
天天模拟器 | Windows | 4.4.4、6.0 | arm | adb connect 127.0.0.1:6555 |
网易MuMu安卓模拟器 | Mac、Windows(为荒野求生) | 6.0.1 | x86 | adb connect 127.0.0.1:7555 |
夜神安卓模拟器 | Windows、Mac | 4.4.2 | x86 | adb connect 127.0.0.1:62001 |
靠谱助手模拟器 / 猩猩助手模拟器 | Windows | 4.4.2、4.4.4、6.0 | x86、arm | 蓝叠、天天模拟器集成的 |
PS:后面的测试都会基于这些模拟器的基础上做测试,并且附加条件范围内能拿到的其他Android真机
目前市场上主流的模拟器:一种是基于Qemu,另一类是基于Genymotion
网上现在流行用一些模拟器特征进行鉴别,比如:
1.通过判断IMEI是否全部为0000000000格式,判断手机号码是否特殊的模拟器值,判断IMSI是否特殊值
2.判断Build中的一些模拟器特征值
3.匹配Qemu的一些特征文件以及属性
4.通过获取cpu信息,将x86的给过滤掉(真机一般都是基于ARM)
一、Android模拟器初级检测方案(基础特征值检测[原APP中只检测了部分,不够全面])
-------旧版本方案-----
(较落后了,Emulator检测源码: https://github.com/strazzere/anti-emulator/blob/master/AntiEmulator/src/diff/strazzere/anti/emulator/FindEmulator.java)
1.已知模拟器的IMEI:“000000000000000”, “e21833235b6eef10”, “012345678912345”
2.已知模拟器的手机号:“15555215554”, “15555215556”, “15555215558”, “15555215560”,“15555215562”, “15555215564”, “15555215566”, “15555215568”,“15555215570”, “15555215572”, “15555215574”, “15555215576”,“15555215578”, “15555215580”, “15555215582”, “15555215584”
3.已知模拟器的IMSI:“310260000000000”
4.已知模拟器的Build信息(可能误判):
private static Property[] known_props = {new Property("init.svc.qemud", null), new Property("init.svc.qemu-props", null), new Property("qemu.hw.mainkeys", null), new Property("qemu.sf.fake_camera", null), new Property("qemu.sf.lcd_density", null), new Property("ro.bootloader", "unknown"), new Property("ro.bootmode", "unknown"), new Property("ro.hardware", "goldfish"), new Property("ro.kernel.android.qemud", null), new Property("ro.kernel.qemu.gles", null), new Property("ro.kernel.qemu", "1"), new Property("ro.product.device", "generic"), new Property("ro.product.model", "sdk"), new Property("ro.product.name", "sdk"), // Need to double check that an "empty" string ("") returns null new Property("ro.serialno", null)};
5.特殊手机的运营商:“android”
((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).getNetworkOperatorName().toLowerCase().equals(“android”)
[2] 检测模拟器特征文件是否存在“/dev/socket/qemud”,
“/dev/qemu_pipe”,
"/system/lib/libc_malloc_debug_qemu.so",
“/sys/qemu_trace”,
"/system/bin/qemu-props(不可靠,可能误判,很多真机有这项)",
"/dev/socket/genyd",
“/dev/socket/baseband_genyd”
-------新版本方案-----
(184个特征文件检测)
// =================== 主要证据 =================== /** * 特殊的模拟器特征文件 * 186项文件,查到一个文件就是百分百模拟器,权重最高 * * 模拟器内核GoldFish * /data下的特征文件需要权限才可以访问,其他目录下的特征文件不需要 * 因为模拟器的话,都是root权限,所以并不需要担心权限问题。 * 转载请注明出处:CSDN 胖虎 * https://blog.csdn.net/ljphhj/ */ static final String[] emulatorFiles = { // vbox模拟器文件 "/data/youwave_id", "/dev/vboxguest", "/dev/vboxuser", "/mnt/prebundledapps/bluestacks.prop.orig", "/mnt/prebundledapps/propfiles/ics.bluestacks.prop.note", "/mnt/prebundledapps/propfiles/ics.bluestacks.prop.s2", "/mnt/prebundledapps/propfiles/ics.bluestacks.prop.s3", "/mnt/sdcard/bstfolder/InputMapper/com.bluestacks.appmart.cfg", "/mnt/sdcard/buildroid-gapps-ics-20120317-signed.tgz", "/mnt/sdcard/windows/InputMapper/com.bluestacks.appmart.cfg", "/proc/irq/9/vboxguest", "/sys/bus/pci/drivers/vboxguest", "/sys/bus/pci/drivers/vboxguest/0000:00:04.0", "/sys/bus/pci/drivers/vboxguest/bind", "/sys/bus/pci/drivers/vboxguest/module", "/sys/bus/pci/drivers/vboxguest/new_id", "/sys/bus/pci/drivers/vboxguest/remove_id", "/sys/bus/pci/drivers/vboxguest/uevent", "/sys/bus/pci/drivers/vboxguest/unbind", "/sys/bus/platform/drivers/qemu_pipe", "/sys/bus/platform/drivers/qemu_trace", "/sys/class/bdi/vboxsf-c", "/sys/class/misc/vboxguest", "/sys/class/misc/vboxuser", "/sys/devices/virtual/bdi/vboxsf-c", "/sys/devices/virtual/misc/vboxguest", "/sys/devices/virtual/misc/vboxguest/dev", "/sys/devices/virtual/misc/vboxguest/power", "/sys/devices/virtual/misc/vboxguest/subsystem", "/sys/devices/virtual/misc/vboxguest/uevent", "/sys/devices/virtual/misc/vboxuser", "/sys/devices/virtual/misc/vboxuser/dev", "/sys/devices/virtual/misc/vboxuser/power", "/sys/devices/virtual/misc/vboxuser/subsystem", "/sys/devices/virtual/misc/vboxuser/uevent", "/sys/module/vboxguest", "/sys/module/vboxguest/coresize", "/sys/module/vboxguest/drivers", "/sys/module/vboxguest/drivers/pci:vboxguest", "/sys/module/vboxguest/holders", "/sys/module/vboxguest/holders/vboxsf", "/sys/module/vboxguest/initsize", "/sys/module/vboxguest/initstate", "/sys/module/vboxguest/notes", "/sys/module/vboxguest/notes/.note.gnu.build-id", "/sys/module/vboxguest/parameters", "/sys/module/vboxguest/parameters/log", "/sys/module/vboxguest/parameters/log_dest", "/sys/module/vboxguest/parameters/log_flags", "/sys/module/vboxguest/refcnt", "/sys/module/vboxguest/sections", "/sys/module/vboxguest/sections/.altinstructions", "/sys/module/vboxguest/sections/.altinstr_replacement", "/sys/module/vboxguest/sections/.bss", "/sys/module/vboxguest/sections/.data", "/sys/module/vboxguest/sections/.devinit.data", "/sys/module/vboxguest/sections/.exit.text", "/sys/module/vboxguest/sections/.fixup", "/sys/module/vboxguest/sections/.gnu.linkonce.this_module", "/sys/module/vboxguest/sections/.init.text", "/sys/module/vboxguest/sections/.note.gnu.build-id", "/sys/module/vboxguest/sections/.rodata", "/sys/module/vboxguest/sections/.rodata.str1.1", "/sys/module/vboxguest/sections/.smp_locks", "/sys/module/vboxguest/sections/.strtab", "/sys/module/vboxguest/sections/.symtab", "/sys/module/vboxguest/sections/.text", "/sys/module/vboxguest/sections/__ex_table", "/sys/module/vboxguest/sections/__ksymtab", "/sys/module/vboxguest/sections/__ksymtab_strings", "/sys/module/vboxguest/sections/__param", "/sys/module/vboxguest/srcversion", "/sys/module/vboxguest/taint", "/sys/module/vboxguest/uevent", "/sys/module/vboxguest/version", "/sys/module/vboxsf", "/sys/module/vboxsf/coresize", "/sys/module/vboxsf/holders", "/sys/module/vboxsf/initsize", "/sys/module/vboxsf/initstate", "/sys/module/vboxsf/notes", "/sys/module/vboxsf/notes/.note.gnu.build-id", "/sys/module/vboxsf/refcnt", "/sys/module/vboxsf/sections", "/sys/module/vboxsf/sections/.bss", "/sys/module/vboxsf/sections/.data", "/sys/module/vboxsf/sections/.exit.text", "/sys/module/vboxsf/sections/.gnu.linkonce.this_module", "/sys/module/vboxsf/sections/.init.text", "/sys/module/vboxsf/sections/.note.gnu.build-id", "/sys/module/vboxsf/sections/.rodata", "/sys/module/vboxsf/sections/.rodata.str1.1", "/sys/module/vboxsf/sections/.smp_locks", "/sys/module/vboxsf/sections/.strtab", "/sys/module/vboxsf/sections/.symtab", "/sys/module/vboxsf/sections/.text", "/sys/module/vboxsf/sections/__bug_table", "/sys/module/vboxsf/sections/__param", "/sys/module/vboxsf/srcversion", "/sys/module/vboxsf/taint", "/sys/module/vboxsf/uevent", "/sys/module/vboxsf/version", "/sys/module/vboxvideo", "/sys/module/vboxvideo/coresize", "/sys/module/vboxvideo/holders", "/sys/module/vboxvideo/initsize", "/sys/module/vboxvideo/initstate", "/sys/module/vboxvideo/notes", "/sys/module/vboxvideo/notes/.note.gnu.build-id", "/sys/module/vboxvideo/refcnt", "/sys/module/vboxvideo/sections", "/sys/module/vboxvideo/sections/.data", "/sys/module/vboxvideo/sections/.exit.text", "/sys/module/vboxvideo/sections/.gnu.linkonce.this_module", "/sys/module/vboxvideo/sections/.init.text", "/sys/module/vboxvideo/sections/.note.gnu.build-id", "/sys/module/vboxvideo/sections/.rodata.str1.1", "/sys/module/vboxvideo/sections/.strtab", "/sys/module/vboxvideo/sections/.symtab", "/sys/module/vboxvideo/sections/.text", "/sys/module/vboxvideo/srcversion", "/sys/module/vboxvideo/taint", "/sys/module/vboxvideo/uevent", "/sys/module/vboxvideo/version", "/system/app/bluestacksHome.apk", "/system/bin/androVM-prop", "/system/bin/androVM-vbox-sf", "/system/bin/androVM_setprop", "/system/bin/get_androVM_host", "/system/bin/mount.vboxsf", "/system/etc/init.androVM.sh", "/system/etc/init.buildroid.sh", "/system/lib/hw/audio.primary.vbox86.so", "/system/lib/hw/camera.vbox86.so", "/system/lib/hw/gps.vbox86.so", "/system/lib/hw/gralloc.vbox86.so", "/system/lib/hw/sensors.vbox86.so", "/system/lib/modules/3.0.8-android-x86+/extra/vboxguest", "/system/lib/modules/3.0.8-android-x86+/extra/vboxguest/vboxguest.ko", "/system/lib/modules/3.0.8-android-x86+/extra/vboxsf", "/system/lib/modules/3.0.8-android-x86+/extra/vboxsf/vboxsf.ko", "/system/lib/vboxguest.ko", "/system/lib/vboxsf.ko", "/system/lib/vboxvideo.ko", "/system/usr/idc/androVM_Virtual_Input.idc", "/system/usr/keylayout/androVM_Virtual_Input.kl", "/system/xbin/mount.vboxsf", "/ueventd.android_x86.rc", "/ueventd.vbox86.rc", "/ueventd.goldfish.rc", "/fstab.vbox86", "/init.vbox86.rc", "/init.goldfish.rc", // ========针对原生Android模拟器 内核:goldfish=========== "/sys/module/goldfish_audio", "/sys/module/goldfish_sync", // ========针对蓝叠模拟器=========== "/data/app/com.bluestacks.appmart-1.apk", "/data/app/com.bluestacks.BstCommandProcessor-1.apk", "/data/app/com.bluestacks.help-1.apk", "/data/app/com.bluestacks.home-1.apk", "/data/app/com.bluestacks.s2p-1.apk", "/data/app/com.bluestacks.searchapp-1.apk", "/data/bluestacks.prop", "/data/data/com.androVM.vmconfig", "/data/data/com.bluestacks.accelerometerui", "/data/data/com.bluestacks.appfinder", "/data/data/com.bluestacks.appmart", "/data/data/com.bluestacks.appsettings", "/data/data/com.bluestacks.BstCommandProcessor", "/data/data/com.bluestacks.bstfolder", "/data/data/com.bluestacks.help", "/data/data/com.bluestacks.home", "/data/data/com.bluestacks.s2p", "/data/data/com.bluestacks.searchapp", "/data/data/com.bluestacks.settings", "/data/data/com.bluestacks.setup", "/data/data/com.bluestacks.spotlight", // ========针对逍遥安卓模拟器=========== // 虚拟化网卡和pci,可能存在误判,不可靠 // "/sys/module/virtio_net", // "/sys/module/virtio_pci", "/data/data/com.microvirt.download", "/data/data/com.microvirt.guide", "/data/data/com.microvirt.installer", "/data/data/com.microvirt.launcher", "/data/data/com.microvirt.market", "/data/data/com.microvirt.memuime", "/data/data/com.microvirt.tools", // ========针对Mumu模拟器=========== "/data/data/com.mumu.launcher", "/data/data/com.mumu.store", "/data/data/com.netease.mumu.cloner" };
新旧方案在模拟器上的表现:从表中可以看出,旧方案在针对一些较新的版本的模拟器时已经无效了,模拟器都无法准确识别出来,旧版本识别模拟器为30%识别率,新版本方案是100%识别率,所以旧的方案决定摒弃不再使用。
Android模拟器名 | 旧方式(imei,imsi,phonenumber,build,files) | 新特征判断(模拟器特征文件) |
---|---|---|
Android原生模拟器 | 模拟器-build,imsi,pipies,emuprops | 模拟器 |
Genymotion | 模拟器-build,imei,files | 模拟器 |
海马玩模拟器(Droid4X) | 真机(000000) | 模拟器 |
Bluestacks(蓝叠)模拟器 | 真机(000000) | 模拟器 |
雷电模拟器 | 真机(000000) | 模拟器 |
逍遥安卓模拟器 | 真机(000000) | 模拟器 |
天天模拟器 | 真机(000000) | 模拟器 |
网易MuMu安卓模拟器 | 模拟器-build | 模拟器 |
夜神安卓模拟器 | 真机(000000) | 模拟器 |
靠谱助手模拟器 / 猩猩助手模拟器 | 真机(000000) | 模拟器 |
采用云测平台TestIn,测试真机309台,判断模拟器,新旧方案对比:
旧方案:误判为模拟器的概率为18% , 新方案:误判率为0%
对应的Excel结果表格为:
309台真机_模拟器检测方案_识别统计结果.xls ( http://git.meiyou.im/Android/AndroidDoc/blob/master/309台真机_模拟器检测方案_识别统计结果.xls )
**二、Android模拟器中级判断方案==[辅证,权重低]== **
1.传感器判断:判断模拟器上不存在的传感器类型,而真机上普遍存在的,最后决定辅证传感器为:【计步传感器,光线传感器,距离传感器】这三个传感器的存在与否用来作为辅助验证条件。
传感器类型 | 在上述10款模拟器中检测是否可靠(模拟器上有支持 or 大部分真机上没有支持) |
---|---|
TYPE_STEP_DETECTOR or TYPE_STEP_COUNTER //计步传感器(硬件) | 不完全可靠(少数机器没有) |
TYPE_LIGHT //光线传感器(硬件) | 相对可靠(300台真机仅几台没有此传感器) |
TYPE_PROXIMITY //距离传感器(硬件) | 不完全可靠(少数机器没有) |
TYPE_PRESSURE //压力传感器(硬件) | 不可靠(大部分真机没有) |
TYPE_ACCELEROMETER //加速度传感器(硬件) | 不可靠(有模拟器支持) |
TYPE_MAGNETIC_FIELD //磁场传感器(硬件) | 不可靠(有模拟器支持) |
TYPE_ORIENTATION //方向传感器(软件传感器,数据来自重力和磁场传感器) | 不可靠(有模拟器支持) |
TYPE_GYROSCOPE //陀螺仪传感器(硬件) | 不可靠(有模拟器支持) |
TYPE_GRAVITY //重力传感器(硬件或软件) | 不可靠(有模拟器支持) |
TYPE_LINEAR_ACCELERATION //线性加速度传感器(硬件或软件) | 不可靠(有模拟器支持) |
TYPE_ROTATION_VECTOR //旋转矢量传感器(硬件或软件) | 不可靠(有模拟器支持) |
TYPE_RELATIVE_HUMIDITY //湿度传感器(硬件) | 不可靠(大部分真机没有) |
TYPE_AMBIENT_TEMPERATURE or TYPE_TEMPERATURE //温度传感器(硬件) | 不可靠(大部分真机没有) |
2.CpuInfo检测CPU是否是PC
/** * cat /proc/cpuinfo * 从cpuinfo中读取cpu架构 */ public static boolean isPcKernel(){ String str = ""; try { Process start = new ProcessBuilder(new String[]{"/system/bin/cat", "/proc/cpuinfo"}).start(); StringBuffer stringBuffer = new StringBuffer(); String str2 = ""; BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(start.getInputStream(), "utf-8")); while (true) { String readLine = bufferedReader.readLine(); if (readLine == null) { break; } stringBuffer.append(readLine); } bufferedReader.close(); str = stringBuffer.toString().toLowerCase(); } catch (IOException e) { } if (str.contains("intel") || str.contains("amd")) { return true; } return false; }
3.SO库确认CPU架构
/** * 获取CPU架构模式, * -1 : so库加载失败,不能使用jni函数 * 0 : 三种cpu架构模式都不符合(jni函数判断有误了) * 1 : x86 * 2 : mips * 3 : arm * @return */ public static int getCpuType(){ if (CpuTypeHelper.successLoad){ if (isX86Cpu()){ return CPU_TYPE_X86; }else if (isMipsCpu()){ return CPU_TYPE_MIPS; }else if (isArmCpu()){ return CPU_TYPE_ARM; } return CPU_TYPE_UNKNOWN; }else{ return LOAD_SO_FAILED; } }
4.[so可能导致闪退,不采用]利用真机和模拟器(pc)的cache设计不同来区分
原理文档: https://juejin.im/post/5983e07b518825260753a322
大致思路:真机的cache为一级,模拟器的cache为两级(指令cache和数据cache分开), 因此执行一段相同的机器码往一个address地址中赋值,得到的结果真机和模拟器上是不会一样的
5.System.loadlibrary加载异常检测cpu架构
通过加载一个不存在的so库,使系统抛出异常load堆栈信息,匹配异常堆栈信息中的nativeLibraryDirectories值,arm的so会去找arm64,再寻找arm32,而x86会去lib/x86中寻找so,从堆栈中就可以得出cpu架构模式
有些模拟器堆栈中只加载到/lib,而没有细分(如:夜神模拟器[Couldn’t load noexits_lib from loader dalvik.system.PathClassLoader[DexPathList[[zip file “/data/app/com.meiyou.demo.detector-1.apk”],nativeLibraryDirectories=[/data/app-lib/com.meiyou.demo.detector-1, /system/lib]]]: findLibrary returned null]),这样的话这个项便仅仅只能作为辅证,后端发现异常后作为一个判断参考依据。
6.[不采用]电池电量、手机信号、Location位置(电池需要两个时间点差值检测,不方便也不靠谱,手机信号的检测7.0后检测不了,定位信息模拟器完全可以模拟器,不靠谱)
三、Android模拟器进阶判断方案(黑产,番外篇)[以上仅仅防君子]
XPOSED HOOK (JAVA)
PLT and Inline Hook (Native)
Virtual HOOK (JAVA and Native)
自制ROM HOOK (JAVA and Native)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- QEMU 4.0.0 发布,几乎可以模拟任何硬件设备的模拟器
- QEMU 4.0.0 发布,几乎可以模拟任何硬件设备的模拟器
- iOS 模拟器调试大法了解一下?
- Android QEMU 模拟器移植 - 编译
- 如何判断安卓模拟器的型号(品牌)
- QEMU 2.11.1 发布,开源模拟器
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。