Detección a través de la dirección MAC
Se obtiene la dirección MAC de todas las tarjetas de red y se compara con prefijos predeterminados por cada software:
Fabricante
|
Prefijo
|
VMware
|
00:05:69:xx:xx:xx
|
VMware
|
00:0C:29:xx:xx:xx
|
VMware
|
00:1C:14:xx:xx:xx
|
Oracle VM
VirtualBox
|
08:00:27:xx:xx:xx
|
Windows Virtual
PC
|
00:03:FF:xx:xx:xx
|
QEMU
|
52:54:00:xx:xx:xx
|
La rutina puede ser observada a continuación:
BOOL mac_test()
{
unsigned char MACData[8];
WKSTA_TRANSPORT_INFO_0 *pwkti;
DWORD dwEntriesRead;
DWORD dwTotalEntries;
BYTE *pbBuffer;
NET_API_STATUS dwStatus = NetWkstaTransportEnum(NULL, 0, &pbBuffer, MAX_PREFERRED_LENGTH, &dwEntriesRead, &dwTotalEntries, NULL);
pwkti = (WKSTA_TRANSPORT_INFO_0 *)pbBuffer;
for (DWORD i = 1; i < dwEntriesRead; i++) {
swscanf((wchar_t *)pwkti[i].wkti0_transport_address, L"%2hx%2hx%2hx%2hx%2hx%2hx", &MACData[0], &MACData[1], &MACData[2], &MACData[3], &MACData[4], &MACData[5]);
if ((MACData[0] == 0 && MACData[1] == 5 && MACData[2] == 105) || // VMware
(MACData[0] == 0 && MACData[1] == 12 && MACData[2] == 41) || // VMware
(MACData[0] == 0 && MACData[1] == 28 && MACData[2] == 20) || // VMware
(MACData[0] == 0 && MACData[1] == 80 && MACData[2] == 86) || // VMware
(MACData[0] == 8 && MACData[1] == 0 && MACData[2] == 39) || // Oracle VM VirtualBox
(MACData[0] == 0 && MACData[1] == 3 && MACData[2] == 255) || // Windows Virtual PC
(MACData[0] == 82 && MACData[1] == 84 && MACData[2] == 0)) { // QEMU
dwStatus = NetApiBufferFree(pbBuffer);
return TRUE;
}
}
dwStatus = NetApiBufferFree(pbBuffer);
return FALSE;
}
Detección a través del registro de Windows
Se obtiene el valor de la cadena "0" en la clave "HKLM\SYSTEM\CurrentControlSet\Services\Disk\Enum", y se busca valores predeterminados por cada software:La rutina puede ser observada a continuación:
Fabricante
|
Prefijo
|
Oracle VM VirtualBox
|
VBOX
|
Windows Virtual PC
|
DiskVirtual
|
Windows Virtual PC
|
VIRTUAL
|
QEMU
|
QEMU
|
BOOL reg_test()
{
HKEY hKey;
CHAR szBuffer[1024];
ULONG hSize = sizeof(szBuffer);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Disk\\Enum", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
if (RegQueryValueEx(hKey, "0", NULL, NULL, (unsigned char *)szBuffer, &hSize) == ERROR_SUCCESS) {
if (strstr(szBuffer, "VBOX") != NULL ||
strstr(szBuffer, "VMware") != NULL ||
strstr(szBuffer, "DiskVirtual") != NULL ||
strstr(szBuffer, "VIRTUAL") != NULL ||
strstr(szBuffer, "QEMU") != NULL) {
RegCloseKey(hKey);
return TRUE;
}
}
RegCloseKey(hKey);
}
return FALSE;
}
Detección a través de Windows Management Instrumentation
El procedimiento realizado es similar a los dos anteriores, se busca valores predeterminados a través del uso de WMI. Dichos valores son obtenidos a través de WQL, usando las siguientes consultas y valores predeterminados por cada software:SELECT Version FROM Win32_BIOS
Fabricante
|
Prefijo
|
Oracle VM VirtualBox
|
VBOX
|
Windows Virtual PC
|
A M I - 8000914
|
QEMU
|
BOCHS
|
SELECT Model FROM Win32_ComputerSystem
Fabricante
|
Prefijo
|
VMware
|
VMware
|
Oracle VM VirtualBox
|
VirtualBox
|
Windows Virtual PC
|
Virtual Machine
|
QEMU
|
BOCHS
|
SELECT DeviceID FROM Win32_CDROMDrive
Fabricante
|
Prefijo
|
QEMU
|
QEMU
|
Oracle VM VirtualBox
|
VBOX
|
SELECT PNPDeviceID FROM Win32_DiskDrive
Fabricante
|
Prefijo
|
VMware
|
VMware
|
Oracle VM VirtualBox
|
VBOX
|
Windows Virtual PC
|
DISKVIRTUAL
|
QEMU
|
QEMU
|
SELECT Description FROM CIM_LogicalDevice
Fabricante
|
Prefijo
|
VMware
|
VMware
|
Oracle VM VirtualBox
|
VirtualBox
|
La rutina aunque un poco más compleja pero no menos importante puede ser observada a continuación:
BOOL wmi_test()
{
CHAR buffer[64];
CHAR value[256];
PSTR objects[5][6] = {{"Win32_BIOS", "Version", "VBOX", "BOCHS", "A M I - 8000914", NULL},
{"Win32_ComputerSystem", "Model", "VirtualBox", "Bochs", "VMware", "Virtual Machine"},
{"Win32_CDROMDrive", "DeviceID", "VBOX", "QEMU", NULL, NULL},
{"Win32_DiskDrive", "PNPDeviceID", "VBOX", "QEMU", "VMware", "DISKVIRTUAL"},
{"CIM_LogicalDevice", "Description", "VirtualBox", "VMware", NULL, NULL}};
HRESULT hres;
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
return FALSE;
hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
if (FAILED(hres)) {
CoUninitialize();
return FALSE;
}
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres)) {
CoUninitialize();
return FALSE;
}
IWbemServices *pSvc = NULL;
hres = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc);
if (FAILED(hres)) {
pLoc->Release();
CoUninitialize();
return FALSE;
}
hres = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
if (FAILED(hres)) {
pSvc->Release();
pLoc->Release();
CoUninitialize();
return FALSE;
}
for (int i = 0; i < 5; i++) {
IEnumWbemClassObject* pEnumerator = NULL;
memset(buffer, 0, 64);
strcpy(buffer, "SELECT * FROM ");
strcat(buffer, objects[i][0]);
hres = pSvc->ExecQuery(bstr_t("WQL"), bstr_t(buffer), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
if (FAILED(hres)) {
pSvc->Release();
pLoc->Release();
CoUninitialize();
return FALSE;
}
IWbemClassObject *pclsObj;
ULONG uReturn = 0;
while (pEnumerator) {
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (0 == uReturn)
break;
VARIANT vtProp;
wchar_t wcstring[256];
mbstowcs(wcstring, objects[i][1], 256);
hr = pclsObj->Get(wcstring, 0, &vtProp, 0, 0);
memset(value, 0, 256);
strcpy(value, _bstr_t(vtProp.bstrVal).operator char *());
for (int j = 2; j < 6; j++) {
if (objects[i][j] == NULL)
continue;
if (strstr(value, objects[i][j]) != NULL) {
VariantClear(&vtProp);
pclsObj->Release();
pEnumerator->Release();
pSvc->Release();
pLoc->Release();
CoUninitialize();
return TRUE;
}
}
VariantClear(&vtProp);
pclsObj->Release();
}
pEnumerator->Release();
}
pSvc->Release();
pLoc->Release();
CoUninitialize();
return FALSE;
}
Pruebas Finales
Haciendo uso del anterior código y ejecutando las tres rutinas de forma consecutiva:
int main(int argc, char* argv[])
{
printf("MAC Address Test: %d\n", mac_test());
printf("Registry Test: %d\n", reg_test());
printf("Wmi Test: %d\n", wmi_test());
return 0;
}
Se obtiene el siguiente resultado (True indica detección exitosa):
Fabricante
|
MAC Test
|
REG Test
|
WMI Test
|
VMware
|
True
|
True
|
True
|
Oracle
VM VirtualBox
|
True
|
True
|
True
|
Windows
Virtual PC
|
True
|
True
|
True
|
QEMU
|
True
|
True
|
True
|
Windows
7 Sin virtualizar
|
True
|
False
|
True
|
Código fuente
El archivo comprimido contiene cuatro archivos:
vmtest.c: Recopilación de las rutinas.
StdAfx.cpp, StdAfx.h: Código necesario para la compilación.
vmtest.exe: Ejecutable de prueba
Fuente
http://www.sinfocol.org/
No hay comentarios:
Publicar un comentario