如何判斷Android設備是真機還是模擬器?

不要說採用IMEI的方式哈。模擬器的IMEI可以修改的。而且平板是沒有IMEI的。


系統在啟動的時候會做一次判斷,看看SystemServer.java里是怎麼判斷的:

boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");

然後,如果是模擬器,是不會起bluetooth服務的:

if (isEmulator) {

Slog.i(TAG, "No Bluetooh Service (emulator)");

} else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {

Slog.i(TAG, "No Bluetooth Service (factory test)");

} else if (!context.getPackageManager().hasSystemFeature

(PackageManager.FEATURE_BLUETOOTH)) {

Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");

} else if (disableBluetooth) {

Slog.i(TAG, "Bluetooth Service disabled by config");

} else {

Slog.i(TAG, "Bluetooth Service");

mSystemServiceManager.startService(BluetoothService.class);

}

關於SystemServer,我在另一個答案里有說到,可以參考下:

Android Framework 如何學習,從應用到 Framework 層怎麼平穩過度? - 知乎用戶的回答


參考研究:

strazzere/anti-emulator · GitHub

Android Anti-emulator

【原創】APK自我保護方法

609 afw block

MindMac/HideAndroidEmulator · GitHub


原理就是利用模擬器和真機之間的小差異來檢測Android設備是否是模擬器。

模擬器檢測手段也常用於APP的應用安全防護上,防止利用模擬器進行刷單,刷流量等惡意操作,所以也需要獲取設備返回的一些信息來鑒別設備的真偽。

模擬器檢測技術分為4類:

基於用戶層行為和數據檢測模擬器

檢測通話記錄,聯繫人,簡訊,相冊等是否為空

檢測應用程序安裝數量很少或者只有模擬器上默認的應用程序

檢測是否裝有常見的應用(國內) Q Q,微信,淘寶等。

檢測API Demos、Dev Tools等其他模擬器特有的應用程序或特有的屬性

利用撥號盤的crash判斷是否在模擬器環境

基於Android系統層特徵檢測模擬器

1. 通過調用TelephonyManager API的模擬器參數的檢測手段

通過模擬器和真機在通信狀態和信息上的不同,來檢測模擬器。

2. 通過Build靜態欄位檢測模擬器

android.os.Build類包含設備硬體和版本信息。可以通過提取該類的靜態欄位來檢測模擬器。

3. 電池狀態與電量和充電狀態

模擬器,真機在電池狀態上的區別

通過模擬器的電池溫度為0和電量始終為50%等特性,檢測是否為模擬器。

4. 檢測真機特有的wifi,GPS,藍牙,溫度感測器等

5./system/build.prop屬性文件檢

/system/build.prop 是一個屬性文件,在Android系統中.prop文件定義了系統初始(或永久)的一些參數屬性、功能的開放等

Systemproperties類在android.os下,但這個類是隱藏的,上層程序開發無法直接使用。用java的反射機制可以使用這個類來設置和獲

基於Linux系統層特徵檢測模擬器

1通過內核文件系統/proc目錄檢測模擬器

2通過設備文件特徵檢測模擬器

模擬器上存在/dev/qemu_pipe,/dev/socket/qemud等特有的文件。

3通過執行shell命令檢測模擬器

cat,getprop等shell命令可以獲取當前系統的屬性信息

Cat查看文件在模擬器和真機上的區別

基於模擬器體系結構特徵檢測模擬器

大部分真機都是使用ARM架構,而模擬器運行在PC上的X86架構。因此可以利用ARM與X86的區別。來判斷是否是真機。

  1. 利用任務調度檢測模擬器

對於使用qume的模擬器,可以通過qemu二進位翻譯(Binary Translation)的一個優化特性來檢測模擬器

物理CPU會在每執行一條指令以後,就把程序計數器加一,程序計數器永遠都是最新的值。Qemu是在遇到需要返回最新值的時候才會更新程序計數器,其他時候不會每次都更新,來作為一種優化措施。因此,程序計數器會指向一個代碼塊的最開始位置,因為每次進行分支跳轉的時候才需要更新程序計數器。

參考:Android analysis framework

2.利用cache特性檢測Android模擬器

ARM採用的哈佛架構將指令存儲跟數據存儲分開,與之對應的,ARM的一級緩存分為I-Cache(指令緩存)與D-Cahce(數據緩存),而X86隻有一塊緩存,將一段代碼可執行代碼動態映射到內存,在執行的時候,X86架構上是可以修改這部分代碼的,而ARM的I-Cache可以看做是只讀,因為,當我們往PC對應的地址寫指令的時候,其實是往D-Cahce寫,而I-Cache中的指令並未被更新,這樣,兩端程序就會在ARM與x86上有不同的表現,根據計算結果便可以知道究竟是還在哪個平台上運行

參考:利用cache特性檢測Android模擬器 - leonnewton

https://wiki.koeln.ccc.de/images/d/d5/Openchaos_qemudetect.pdf


看這個,可能是沒戲

跑prop里看是不是godlfish可能也做不到

M66B/XPrivacy · GitHub


所有基於模擬器特徵和api返回值的檢測方法都可以通過修改安卓源碼的方式輕鬆繞過。模擬器與真機的本質區別在於運行載體。鑒於大多數的安卓模擬器基於qemu,qemu在執行程序時實際上是將其翻譯成宿主機的指令,比如將安卓的arm指令翻譯成PC的x86指令。為了效率上的考慮,qemu在翻譯執行arm指令時並沒有實時更新模擬的pc寄存器值,只會在一段代碼翻譯執行完之後再更新,而真機中pc寄存器是一直在更新的。基於這一點,可以設計一段CPU任務調度程序來檢測模擬器 。具體的你可以參鑒DexLab上的一篇文章。當然,這個方法也是可以被繞過的,可以在理解qemu源碼的基礎上,修改qemu源碼,但很明顯這個門檻很高 。


嘗試調用一下各種感測器,比如相機、振動器、光線感應器啥的


我試了幾個簡單的模擬器發現一個問題就是模擬器是沒有真實手機的無線信號的(只用WIFI的當我沒說),用業務感知這個軟體可以取到手機的RSRP SINR等無線參數,但是手機模擬器是取不到的,所以或許可以通過這個手段確定是否為手機模擬器。


說一個前幾天折騰的時候發現的吧。。

虛擬機沒有/dev/keychord這個設備,真機有。

樣本不夠多,不保證100%是這樣。


這個修改源碼就能搞定


最好是結合現有的模擬器,比如什麼天天模擬器,bluestacks, genymotions等等,針對各個平台總結出它們的特徵。


可以檢測設備的MAC地址,模擬器的MAC地址是固定的幾種。


推薦閱讀:

Windows Phone 和 Android 手機哪個更適合父母使用?
現在學習安卓還有錢途嗎?
如何評價 Google 的 Nexus 系列手機?
當你掌握什麼Android技能時,面試官會非常想要你?

TAG:Android開發 | Android |