反调试——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;
    }
}

 

 

 

小结

虚拟机和本机肯定是有一些不同的,抓住这些验证不同的办法就可以来检测是否是在虚拟机里了。