虛擬機運行環境檢測
虛擬機運行環境檢測,指的是軟件能夠判斷當前是不是在虛擬機中運行,根據判斷結果,做對應的處理。從惡意軟件的視角,它可以在虛擬機中改變自身行為,加大分析難度。從軟件自身安全出發,用於防止被逆向調試以及某些場景下的非正常使用。
檢測思路
要實現這個功能,可有如下幾個入手點:
- 硬件檢測
- 虛擬機會創建具有特定標示符的硬件設備以及驅動。例如vmware會虛擬出兩個網卡設備VMnet1(Host Only方式)和VMnet8(NAT方式),vbox會創建
VirtualBox Host-Only Network
- 虛擬機會創建具有特定標示符的硬件設備以及驅動。例如vmware會虛擬出兩個網卡設備VMnet1(Host Only方式)和VMnet8(NAT方式),vbox會創建
- 運行環境檢測
- vmware虛擬機會默認開啟幾個硬件端口與宿主機通訊。
- 利用特權指令在虛擬機和真實機器上執行結果不一致來區分。目前在網上找到的方法大部分是用來檢測Vmware,不適用於VirtualBox以及VirtuaPC。
- 應用程序檢測
- 虛擬機會安裝一些特定軟件以及服務,比如
vmtoolsd.exe
、vboxserivce.exe
等。 - 在特定路徑下,存在特殊標識,例如注冊表、系統驅動文件等。
- 虛擬機會安裝一些特定軟件以及服務,比如
分享一個網上各虛擬機的硬件區別,原文點此進入。
安裝虛擬機以及測試的注意事項
通過VirtualBox
安裝虛擬機時,有時會出現如下錯誤:
通過查閱網上相關資料,發現是因為權限問題,重新以管理員權限打開VirtualBox
,就可以繼續安裝。
本次測試發現Virtaul Box
和Virtual PC
兩款虛擬機會相互沖突,就是說,當Virtaul box
啟動時,再啟動Virtual PC
,Virtaul box
會彈出如下提示:
可能這兩種虛擬機不兼容,讀者在自行測試時,需要注意這一點。
安裝VirtualBox
的增強功能時,需要安裝多個驅動,有時候安裝界面會把驅動安裝確認界面給蓋住,此時安裝界面會出現類似卡死的情況,因此,建議把安裝界面移到一邊,這樣當驅動確認界面出現時,可確認並繼續安裝。
為了便於在不同虛擬機下測試,選擇原版XP系統。在構建測試軟件時,注意,要使用兼容XP模式的平台工具集來編譯,否則測試軟件無法在xp上運行。同時,將程序運行需要的運行庫放在同一個共享目錄中,各個虛擬機都訪問該共享目錄。
通過VirtualPC
安裝虛擬機時,安裝集成組件后,無法查看共享目錄。網上解答連接在此,需要設置登陸用戶名和密碼,然后重新啟動,在打開VirtualPC
虛擬機之前,輸入用戶名和密碼,方可看到共享目錄。
實踐
以下給出三種實例來檢測虛擬機是否存在,分布是基於進程名、基於注冊表鍵以及基於硬盤驅動器檢測,更多檢測方案,參考文末實例代碼鏈接。
基於進程名檢測
通過檢測檢測指定進程名是否存在,來判斷是否運行在虛擬機。
bool IsExist(const wchar_t* pName)
{
if (nullptr == pName)
return false;
const wchar_t* list[] = {
//Vmware
L"vmtoolsd.exe",
L"vmacthlp.exe",
L"vmwaretray.exe",
L"vmwareuser.exe",
//virtuablBox
L"vboxserivce.exe",
L"vboxtray.exe",
//virtualPC
L"vmsrvc.exe",
L"vmusrvc.exe",
L"vpcmap.exe",
};
std::wstring strProcessName(pName);
std::transform(strProcessName.begin(), strProcessName.end(), strProcessName.begin(), ::tolower);
for (int i = 0; i < sizeof(list)/sizeof(list[0]); i++)
{
if (0 == strProcessName.compare(list[i]))
return true;
}
return false;
}
BOOL CheckVMByProcessName()
{
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcessSnap)
return false;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
BOOL bMore = Process32First(hProcessSnap, &pe32);
while (bMore)
{
char szName[MAX_PATH] = { 0 };
if (IsExist(pe32.szExeFile))
{
_tprintf(L"進程名: %s 進程PID: %d", pe32.szExeFile, pe32.th32ProcessID);
break;
}
bMore = Process32Next(hProcessSnap, &pe32);
}
CloseHandle(hProcessSnap);
return bMore;
}
基於注冊表鍵檢測
利用注冊表鍵值是否存在來檢測,具體如下:
LONG registerOpenKey(char *value)
{
HKEY HK = 0;
return RegOpenKeyExA(HKEY_LOCAL_MACHINE, value, 0, KEY_READ, &HK);
}
bool CheckVMByReg()
{
std::string stringVmRegKeys[] =
{
//VMWare
"SOFTWARE\\Clients\\StartMenuInternet\\VMWAREHOSTOPEN.EXE",
"SOFTWARE\\VMware, Inc.\\VMware Tools",
"SYSTEM\\CurrentControlSet\\Enum\\SCSI\\Disk&Ven_VMware_&Prod_VMware_Virtual_S",
// Virtual PC or VirtualBox
"SYSTEM\\CurrentControlSet\\Control\\VirtualDeviceDrivers",
};
bool bCheckflag = false;
for (size_t i = 0; i < sizeof(stringVmRegKeys) / sizeof(stringVmRegKeys[0]); i++)
{
if (ERROR_SUCCESS == registerOpenKey((char *)stringVmRegKeys[i].c_str()))
{
bCheckflag = true;
printf("Analysis environment detected (%s)\n", stringVmRegKeys[i].c_str());
}
}
return bCheckflag;
}
基於硬盤驅動器名稱檢測
基於特定硬盤驅動器標題名稱來檢測。
BOOL CheckVMByDiskName()
{
std::vector<std::wstring> vtBlockHardDisc({ L"vmware", L"vbox", L"virtual"});
std::vector<std::wstring> vtDrivers;
CWmiDataHelper querier;
if (querier.ExecComQuery(L"select * from Win32_DiskDrive", L"Caption", vtDrivers) && vtDrivers.size())
{
std::transform(vtDrivers[0].begin(), vtDrivers[0].end(), vtDrivers[0].begin(), tolower);
for (unsigned int i = 0; i < vtBlockHardDisc.size(); i++)
{
if (wcsstr(vtDrivers[0].c_str(), vtBlockHardDisc[i].c_str()))
{
_tprintf(L"local disk name: %s. find key word:%s \n", vtDrivers[0].c_str(), vtBlockHardDisc[i].c_str());
return TRUE;
}
}
}
return FALSE;
}
測試結果
測試環境:
- VMware 10.0.1
- Virtual Box 6.1.18
- Virtual PC 6.1.7601
在沒有進行任何反檢測措施的情況下,下表為檢測結果匯總。
檢測方法 | Vmware | Virtual Box | Virtual PC | 反檢測手段 |
---|---|---|---|---|
特定進程名檢測 | 可以 | 可以 | 可以 | 刪除特定進程 |
硬盤名稱檢測 | 可以 | 可以 | 可以 | 修改驅動或者配置文件vmx |
MAC地址檢測 | 可以 | 可以 | 可以 | 修改MAC地址 |
CPUId檢測 | 可以 | 不行 | 可以 | 未找到 |
特定服務檢測 | 可以 | 可以 | 可以 | 卸載對應服務程序 |
特定文件檢測 | 可以 | 可以 | 可以 | 修改特定文件 |
注冊表檢測 | 可以 | 可以 | 可以 | 修改特定注冊表選項 |
IN特權指令 | 可以 | 不可以 | 不可以 | 未找到 |
IDT基址 | 不可以 | 不可以 | 不可以 | 未找到 |
LDT基址 | 不可以 | 不可以 | 不可以 | 未找到 |
GDT基址 | 不可以 | 不可以 | 不可以 | 未找到 |
STR | 不可以 | 不可以 | 不可以 | 未找到 |
通過上表可以知道,三種虛擬機環境都可以檢測的方法有
- 特定進程名
- 硬盤名
- MAC地址
- 注冊表檢測
- 特定文件
- 特定服務
特定進程名、硬盤名以及MAC
地址這三種很容易反檢測,不建議使用。注冊表選項也很容易繞過,不建議。
最后剩下特定文件以及特定服務,經過實際測試發現,即使禁用掉特定服務,只要沒有卸載掉服務程序,還是可以檢測到的。一般來說,虛擬機提供的服務是為了方便與宿主機通訊的,共享文件的,卸載后會很麻煩。
最終結論,優先使用特定文件檢測,具體檢測文件可根據實際虛擬機環境來設定,其次使用特定服務檢測。
上述每一種方法,均不能百分百保證檢測正確,各位讀者可根據具體情況來使用。
總結
本文搜集網上現有總結,並介紹基於進程、注冊表鍵以及硬盤驅動器名稱等多種檢測虛擬機運行環境的方法,給出優先使用特定文件檢測,其次檢測特定后台服務的方案。
參考資料:
本文工程代碼鏈接在此
軟件如何判斷自己運行在虛擬機中?
反虛擬機和沙箱檢測的一些小技巧
sems
修改虛擬機中的硬盤ID等信息
[原創]虛擬機檢測技術剖析
VMware | ESXi 等虛擬軟件的反虛擬機檢測技術方法探討
VIrtual Machine Detection Techniques