《Anti-VM》虛擬機偵測工具 快速閱讀精華
🚀 核心功能: 一款號稱比 VMP 和 Themida 更強悍的虛擬機(VM)偵測工具,專為保護你的程式而生。 🔧 三大偵測原理:
硬體WMI查詢: 檢查風扇、CPU快取、主機板電壓等虛擬機難以完整模擬的硬體資訊。BIOS 特徵碼: 深入分析系統韌體(SMBIOS)中的隱藏標記,虛擬機的簡易BIOS將無所遁形。CPU時間差攻擊: 利用 `CPUID` 指令在虛擬機中執行時間會異常變長的破綻來進行判斷。
💻 適用對象: 遊戲 開發者、資安研究員、反作弊工程師等需要防止程式被逆向分析的專業人士。 🔽 檔案資源: 文末提供完整C++原始碼、編譯指令教學,以及編譯好的執行檔成品供大家研究。
本文章目錄
這款Anti-VM工具有多強?
各位開發者或資安研究員,是不是常常為了保護自己的心血結晶,不被有心人士拿到虛擬機(Virtual Machine)裡面輕鬆破解或分析而感到頭痛?市面上雖然有 VMP (VMProtect) 或 Themida 這類強大的保護殼,但今天我們要分享的,是一款號稱偵測能力有過之而無不及的 Anti-VM 工具。
這款工具的厲害之處在於,它不只用單一方法,而是採取了「海陸空三軍聯合作戰」的策略,從三個完全不同的角度去識破虛擬機的偽裝。這讓傳統虛擬機很難透過簡單的修改就繞過偵測。接下來,我們就來深入拆解它的偵測原理,並提供完整的原始碼讓大家學習參考!
【重要提醒】 本工具與原始碼主要作為學術研究與資安防護技術交流之用,請勿用於非法用途。
偵測原理大解密:它是如何抓出虛擬機的?
這套偵測機制的精髓,就是「專找麻煩」,它會去詢問一些真實電腦視為理所當然,但虛擬機卻懶得或很難去模擬的底層資訊。一旦虛擬機回答不出來或回答得支支吾吾,立刻就會被抓包。主要分為以下三大手法:
👉 GM後台版 遊戲 推薦 ⬇️⬇️⬇️ 快速玩各種二次元動漫手遊app
- WMI硬體資訊探測
首先是WMI(Windows Management Instrumentation)查詢。你可以把WMI想像成是Windows系統內建的一套「電腦硬體戶口名簿」,記錄了所有硬體的詳細資料。
【偵測邏輯】
程式會去查詢一些非常細節的硬體資訊,例如:
Win32_Fan: 實體電腦的風扇資訊。Win32_CacheMemory: CPU的快取記憶體資訊。Win32_VoltageProbe: 主機板的電壓感測器。
想像一下,虛擬機就像一個軟體模擬出來的空殼電腦,它為了效能,很難也沒必要去逼真模擬出「風扇轉速」或「主機板即時電壓」這些物理細節。所以,當程式查詢這些資訊卻得到「查無此項目」的回應時,這台「電腦」有鬼的機率就非常高了!
- BIOS韌體特徵碼掃描
第二招是直接檢查電腦的「身分證」— SMBIOS(System Management BIOS)韌體資訊。每台實體電腦的主機板,其BIOS資訊都是獨特且複雜的。
【偵測邏輯】
程式會直接讀取系統韌體表(識別碼為 `0x52534D42`,即'RSMB'),然後分析其中的一組64位元的「特徵碼」。
在真實電腦上,這組特徵碼通常會有許多被設定的位元(bits),代表各種不同的硬體特性。 然而,在虛擬機環境中,為了通用性,這份BIOS資訊通常會非常簡陋,甚至帶有虛擬機廠商的特定標記。
程式中的判斷非常直接:如果這組特徵碼中被設定的位元數量少於10個 ,就直接判定為虛擬機。這招對於大多數使用通用BIOS模板的VM來說,可說是一擊斃命。
- CPU指令時間差攻擊
最後這招,可以說是最經典也最狡猾的「時間差攻擊」。它利用了虛擬機在執行某些特定CPU指令時,會比實體電腦慢上許多的物理破綻。
【偵測邏輯】
這就像你在用模擬器玩遊戲,當模擬器需要動用到你真實電腦的底層硬體資源時,就必須先「暫停」一下模擬的環境,跟真實電腦溝通完再切換回來。這個「暫停、溝通、切換」的過程,在電腦世界裡被稱為「VM-Exit」,雖然速度極快,但終究會產生微乎其微的時間延遲。
我們的程式就利用了 `CPUID` 這個指令特別容易觸發 VM-Exit 的特性:
在執行 `CPUID` 指令前 ,用 `__rdtsc` 記錄一次當下的CPU時脈週期數(T1)。 執行 `CPUID` 指令。 在執行 `CPUID` 指令後 ,再用 `__rdtsc` 記錄一次時脈週期數(T2)。 計算兩者的時間差 (T2 - T1)。
在實體電腦上,這個過程快如閃電。但在虛擬機上,因為VM-Exit的延遲,時間差會明顯變大。程式設定了一個1200個時脈週期 的門檻,只要超過這個時間,就高度懷疑是跑在虛擬機上!此外,程式還會檢查 `RDTSCP` 指令是否存在,作為一個輔助的判斷。
完整C++原始碼與編譯指令
底下我們為大家提供了完整的C++原始碼,讓你可以親自研究或編譯。
原始碼 (main.cpp):
```cpp
#include <windows.h>
#include <iostream>
#include <vector>
#include <intrin.h>
#include <wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
using u64 = unsigned long long;
using u32 = unsigned int;
using u8 = unsigned char;
#define FLG_BIOS 0x1
#define FLG_CPU 0x2
#define FLG_WMI 0x4
#define FLG_TIME 0x8
int wmi_cnt(IWbemServices* svc, const wchar_t* q) {
IEnumWbemClassObject* e = 0;
if(FAILED(svc->ExecQuery(SysAllocString(L"WQL"), SysAllocString(q), 32, 0, &e))) return 0;
IWbemClassObject* o = 0;
ULONG r = 0;
int c = 0;
while(e) {
e->Next(-1, 1, &o, &r);
if(!r) break;
c++; o->Release();
}
e->Release();
return c;
}
int main() {
u32 res = 0;
// qemu/vmware dont emu mobo sensors - they would have to emulate with custom drivers.
HRESULT hr = CoInitializeEx(0, 0);
if(SUCCEEDED(hr)) {
hr = CoInitializeSecurity(0, -1, 0, 0, 0, 3, 0, 0, 0);
IWbemLocator* loc = 0; IWbemServices* svc = 0;
if(SUCCEEDED(CoCreateInstance(CLSID_WbemLocator, 0, 1, IID_IWbemLocator, (void**)&loc))) {
if(SUCCEEDED(loc->ConnectServer(SysAllocString(L"ROOT\\CIMV2"), 0, 0, 0, 0, 0, 0, &svc))) {
CoSetProxyBlanket(svc, 10, 0, 0, 3, 3, 0, 0);
// check for fans, cache, voltage. of what i could find nobody has been able to properly emulate this yet, so probably the most reliable.
if(!wmi_cnt(svc, L"SELECT * FROM Win32_Fan")) res |= FLG_WMI;
if(!wmi_cnt(svc, L"SELECT * FROM Win32_CacheMemory")) res |= FLG_WMI;
if(!wmi_cnt(svc, L"SELECT * FROM Win32_VoltageProbe")) res |= FLG_WMI;
svc->Release();
}
loc->Release();
}
CoUninitialize();
}
// 0x52534D42 is 'RSMB'
DWORD sz = GetSystemFirmwareTable(0x52534D42, 0, 0, 0);
if(sz) {
std::vector<u8> buf(sz);
GetSystemFirmwareTable(0x52534D42, 0, buf.data(), sz);
u8* p = buf.data() + 8;
u8* end = buf.data() + sz;
while(p < end) {
if(*p == 127) break;
if(*p == 0 && *(p+1) > 0x12) {
u64 chars = *(u64*)(p + 8);
if((chars >> 3) & 1) res |= FLG_BIOS;
// count set bits - real bios usually have more then 10
int n = 0;
for(int i=0; i<64; ++i) n += ((chars >> i) & 1);
if(n < 10) res |= FLG_BIOS;
break;
}
p += *(p+1);
while(p < end-1 && (*p || *(p+1))) p++;
p += 2;
}
}
// timing n cpuid
int cpu[4];
// rdtscp check
__cpuid(cpu, 0x80000001);
if(!((cpu[3] >> 27) & 1)) res |= FLG_CPU;
u64 t1 = __rdtsc();
__cpuid(cpu, 0);
u64 t2 = __rdtsc();
// increased threshold slightly for more stability
if((t2 - t1) > 1200) res |= FLG_TIME;
if(res) {
printf("vm detected. mask: %x\n", res);
return 1;
}
printf("clean.\n");
return 0;
}
```
編譯指令 (在Linux環境下使用MinGW-w64交叉編譯):
如果你想自己動手編譯,可以使用以下指令。這是在Linux系統上編譯出Windows可執行的 `.exe` 檔案。
x86_64-w64-mingw32-g++ main.cpp -o antivm.exe -static -LOL e32 -loleaut32 -lwbemuuid
Anti-VM 執行檔下載 🔽
如果你懶得自己編譯,我們也準備好了編譯完成的執行檔,可以直接下載回來在你的Windows環境中測試效果。
以下廣告滑動後還有帖子內容
https://pixeldrain.com/u/xNRrAbgV
Anti-VM偵測工具 常見問題Q&A
Q:這段程式碼可以在 Visual Studio (VS) 上直接編譯嗎?
A:理論上是可以的,但你需要手動調整專案的屬性設定。原文提供的是在 Linux 環境下使用 MinGW-w64 交叉編譯的指令,這是最快速直接的方式。如果你堅持要在 VS 中編譯,請務必到「連結器(Linker)」->「輸入(Input)」->「其他相依性(Additional Dependencies)」中,加入 `ole32.lib`、`oleaut32.lib` 和 `wbemuuid.lib` 這幾個函式庫。
Q:為什麼要檢查風扇、電壓這些看似無關的東西?
A:這正是這個工具高明的地方!大多數虛擬機軟體為了追求效能和簡潔,根本不會去完整模擬這些實體硬體感測器的數據。因此,當一個作業系統回報「我找不到任何風扇或電壓感測器」時,它就有極高的機率是一台虛擬機,而非我們日常使用的實體電腦。
Q:執行後,偵測到的 `mask` 數值代表什麼意思?
A:`mask` 是一個十六進位的回傳值,它能精確地告訴你是哪一種或哪幾種方法偵測到了虛擬機。程式碼中定義了幾個旗標:`FLG_BIOS (0x1)`, `FLG_CPU (0x2)`, `FLG_WMI (0x4)`, `FLG_TIME (0x8)`。舉例來說,如果結果顯示 `mask: c`,`c`在十六進位中等於十進位的12,也就是 `4 + 8`,這就代表是「WMI硬體查詢」和「CPU時間差攻擊」這兩種方法同時觸發了警報。
Q:這個方法能100%防堵所有虛擬機嗎?
A:這世界上沒有任何Anti-VM技術是100%無法被繞過的,這是一場永無止境的攻防戰。更先進的虛擬機或經過客製化的Hypervisor(虛擬機監視器)可能會特別針對這些偵測方法進行偽裝(例如:偽造假的WMI資訊)。但是,這個工具結合了多種非常規且難以偽裝的檢測點,已經足以擋下絕大多數市面上通用的虛擬機,能有效地大幅提高逆向工程的門檻和成本。