检测与对抗的猫鼠游戏
用模拟器跑 App 做协议分析或自动化,第一步就得过模拟器检测。检测方的思路是"找模拟器和真机的差异点",对抗方的思路是"消除这些差异"。先摸清对手检测什么,再逐项伪装。
检测点全景与逐项对抗
1. build.prop 硬件指纹(最基础的检测)
模拟器的 build 信息一眼假:
ro.product.model= sdk_gphone64_arm64 ← 模拟器特征
ro.hardware = ranchu / goldfish ← 模拟器虚拟硬件
ro.build.fingerprint = google/sdk_gphone...对抗:改机工具或直接改 prop(需要 root):
# Magisk 的 resetprop 命令
resetprop ro.product.model "SM-G998B"
resetprop ro.product.brand "samsung"
resetprop ro.hardware "qcom"
resetprop ro.build.fingerprint "samsung/p3sxxx/p3s:13/TP1A.220624.014/G998BXXU5EWA1:user/release-keys"注意成套修改:型号、品牌、硬件平台、指纹串必须来自同一款真实机型,混搭会触发一致性校验。从真实设备的 getprop 输出里整套复制最稳。
2. 文件特征检测
检测代码会探测模拟器特有文件:
/dev/socket/qemud ← QEMU 模拟器
/dev/goldfish_pipe ← goldfish 虚拟设备
/system/lib/libc_malloc_debug_qemu.so对抗:Xposed/Frida hook File.exists / access 系统调用,对这些路径返回"不存在":
var File = Java.use('java.io.File');
File.exists.implementation = function() {
var path = this.getAbsolutePath();
var fake = ['/dev/socket/qemud', '/dev/goldfish_pipe', 'qemu'];
for (var i = 0; i < fake.length; i++) {
if (path.indexOf(fake[i]) >= 0) return false;
}
return this.exists();
};3. 传感器检测(高阶检测)
真机有加速度计、陀螺仪、光线传感器且数据持续微动;模拟器要么没有传感器,要么数据恒为 0。检测代码注册传感器监听,读不到数据或数据无波动就判定模拟器。
对抗:Frida hook SensorManager.registerListener,伪造传感器数据回调:
var SensorEventListener = Java.use('android.hardware.SensorEventListener');
// 拦截注册,主动注入模拟数据
setInterval(function() {
// 构造带噪声的重力传感器数据:9.8 附近微抖动
var x = 0.1 + Math.random() * 0.05;
var y = 0.2 + Math.random() * 0.05;
var z = 9.78 + Math.random() * 0.04;
// 通过反射调用 listener.onSensorChanged(...)
}, 100);4. 电池/温度/运营商等环境项
模拟器电量常固定、无 SIM 卡信息、无基站信息。getSimOperator、getNetworkOperator 返回空是强特征。对抗同样是 hook 这些 TelephonyManager 方法返回真实值。
检测代码长什么样
了解对手才能赢。典型的综合检测实现:
public boolean isEmulator(Context ctx) {
int score = 0;
if (Build.HARDWARE.contains("goldfish") || Build.HARDWARE.contains("ranchu")) score += 3;
if (Build.MODEL.contains("sdk") || Build.MODEL.contains("Emulator")) score += 3;
if (new File("/dev/socket/qemud").exists()) score += 5;
if (getSensorCount(ctx) < 5) score += 2;
if (TextUtils.isEmpty(getSimOperator(ctx))) score += 2;
return score >= 5; // 打分制,不是单点判定
}注意是打分制——这意味着你不需要伪装所有点,把高分项(文件特征、硬件指纹)消掉,低分项(传感器)蒙混,总分不过线就能过。
精髓:对抗的三个层次
- 优先用真机云手机,其次改模拟器。红手指、雷电云手机这类是真机集群,天然免疫模拟器检测,成本允许时是最优解
- 伪装要成套。散装的伪装(改了型号没改指纹)比不伪装更可疑——一致性校验专抓这种
- 先逆向检测逻辑再动手。用 jadx 搜
isEmulator、checkEmu、goldfish等关键词,把 App 的检测点列成清单,逐条对抗,别盲改
总结
- 检测四板斧:build 指纹、文件特征、传感器、运营商信息
- 打分制检测意味着消掉高分项即可过线
- 伪装信息必须成套(同机型全套 prop)
- 先逆向检测代码列清单,再逐项对抗
交流微信:run1255