反调试——8——虚拟机检测
其实虚拟机检测也无外乎就是检测一些虚拟机特有的特征,然后来判断是否是在虚拟机里面,比如说这里(查看系统中运行的服务):
但是不能直接盲目的通过VMware这六个关键字母就判断是在虚拟机里面了,因为你的电脑如果开了虚拟机,也会有一些VMware开头的虚拟机服务:
所以我们必须要选取一些比较唯一的,比如说这里我们选这个VMware SVGA Helper Service这个把,大家可以自行选择。然后需要做的就是遍历系统中的服务,看看有没有这个东西就行了。
遍历系统中的服务:
这里会用到一个API:
EnumServicesStatusA function (winsvc.h) - Win32 apps | Microsoft Docs
BOOL EnumServicesStatusA(
SC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
LPENUM_SERVICE_STATUSA lpServices,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned,
LPDWORD lpResumeHandle
);
然后这个API的第一个参数需要用OpenSCManager这个API来使用:OpenSCManagerA function (winsvc.h) - Win32 apps | Microsoft Docs
SC_HANDLE OpenSCManagerA(
LPCSTR lpMachineName,//如果值为0表示本机
LPCSTR lpDatabaseName,
DWORD dwDesiredAccess
);
然后这个服务数据库的句柄必须调用一个API来关闭:
CloseServiceHandle()
void TestVirtual() { auto hSCM = OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); /* 第一个为NULL表示是本机, 第二个参数是指定值, 第三个参数表示权限,如果要调用枚举服务API就需要是这个权限。 */ if (hSCM == NULL) { cout << "打开系统服务数据库错误" << endl; return; } LPENUM_SERVICE_STATUSA lpServiceStatus = NULL; lpServiceStatus = (LPENUM_SERVICE_STATUSA)malloc(0x8000); DWORD servieceSize = 0; DWORD needSize = 0; DWORD resumeHandle = 0; auto ret = EnumServicesStatusA(hSCM, SERVICE_WIN32, SERVICE_STATE_ALL, lpServiceStatus, 0x8000, &needSize, &servieceSize, &resumeHandle); /* 第一个参数:是服务数据库的句柄 第二个参数:是要的服务的类型,这里不直到怎么查看我就全部加上了 第三个参数:服务的状态,是否启动 第四个参数:服务结构体的缓冲区 第五个参数:缓冲区大小 第六个参数:如果缓冲区大小不够,需要的剩下的大小是多少 第七个参数:得到的服务的数量 第八个参数:缓冲区不够的时候下一个服务的结构体指针 */ if(needSize>0x8000) { cout << "缓冲区过小" << endl; return; } for (int i = 0; i < servieceSize; i++) { if (strcmp(lpServiceStatus->lpDisplayName, "VMware SVGA Helper Service")==0) { cout<<"检测到了虚拟机"<<endl; return ; } lpServiceStatus++; } cout << "没有检测到虚拟机" << endl; CloseServiceHandle(hSCM); }
还有很多方式,大家可以入手,只要是可以唯一标识虚拟机就好。
特殊的办法
这个办法我也不知道为什么。不是虚拟机的环境运行下面的代码会崩溃。是虚拟机则安然无恙。
push edx push ecx push ebx mov eax, 'VMXh' mov ebx, 0 mov ecx, 10 mov edx, 'VX' in eax, dx cmp ebx, 'VMXh' pop ebx pop ecx pop edx
//代码实现: void testAssemer() { int FLAG = FALSE; __try { __asm { push edx push ecx push ebx mov eax, 'VMXh' mov ebx, 0 mov ecx, 10 mov edx, 'VX' in eax, dx cmp ebx, 'VMXh' pop ebx pop ecx pop edx } } __except(1) { FLAG = TRUE; } if (FLAG == FALSE) { cout << "检测到了虚拟机" << endl; } else { cout << "未检测到虚拟机" << endl; } }
小结
虚拟机和本机肯定是有一些不同的,抓住这些验证不同的办法就可以来检测是否是在虚拟机里了。