检测虚拟机环境(一)

VMware 虚拟机环境的检测有多种方法,这里以注册表痕迹检测法为例,谈谈如何快速检测虚拟环境。

一、理论分析

注册表是 Windows 操作系统的重要概念,对注册表的操作直接涉及系统的核心配置,具有牵一发而动全身的作用。在 HKEY_LOCAL_MACHINE 项下,有 HARDWARE 键,这是我们今天的主角。

HARDWARE 键中包含了计算机硬件信息的子项。在启动系统时,该项都会被重新创建,这样就很容易向系统中添加硬件了。该项是系统根据硬件信息在启动时自己填写的,而不是根据数据去启动硬件,所以用户对该项的修改不会生效。在该项下面的四个项中含有 CPU、FPU、系统总线、 PCI 总线的设备、即插即用总线、高级控制电源接口、键盘、打印机端口、鼠标、屏幕等信息,有些信息要在 BIOS 才能看见(比如高级控制电源接口)。

通过对比客户机和虚拟机的硬件信息,就可以发现它们存在较多不同点,这篇文章以 SCSI 信息为例,讲解如何区分虚拟机和物理机环境。

首先打开虚拟机:依次展开左侧导航栏中的 HKEY_LOCAL_MACHINE > HARDWARE > DEVICEMAP > Scsi

SCSI 下有很多端口 SCSI Port XX,其中至少有一个端口下包含的 Identifier 数据值包含 VMware 厂商名称,如图所示:

我们再尝试打开物理机上的该路径,可以看出他显示的是真实设备的厂商名称,而不是虚拟设备:

显然,可以根据该特征来判断环境是不是虚拟环境。

二、代码实现

从编写程序的角度上来讲,这里由于我们并不知道特征值会位于 SCSI 下的哪个子键内,所以我们需要利用递归的方法,遍历每一层每一个 Identifier 值,看是否有特征值,只要找到了特征值,就算作是虚拟环境。

首先,使用 RegOpenKeyEx 函数打开注册表项。在每一层,我们都需要利用 RegQueryInfoKeyW 和 RegEnumKeyEx 函数的组合来枚举指定打开的注册表项的子项。使用 RegEnumValueW 获取对应值项的数据,并比较获取到的字符串是否包含 VMware 字样。将这些操作写入到一个 SearchKey 函数中,然后对于找到的键(而不是值)递归调用它本身,即可对每一层每一个值项进行遍历。

调好的代码如下,需要以管理员身份启动,我用的 VMware 是 17 版本,不知道其他版本是否一致:


#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383


DWORD GetRegKeyCount(HKEY hKey, DWORD dwIndex, TCHAR* achKey, DWORD dwKeyLen, BOOL bEnable)
{
    LONG   lRet = ERROR_SUCCESS;
    DWORD  cSubKeys = 0;
    DWORD cValues = 0;
    DWORD  cMaxKeyLens = 0;
    DWORD  cMaxValueLens = 0;
    lRet = RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &cSubKeys, &cMaxKeyLens, NULL, &cValues, &cMaxValueLens, NULL, NULL, NULL);
    if (lRet != ERROR_SUCCESS)
    {
        return 0;
    }

    if (cSubKeys != 0 && achKey != NULL)
    {
        lRet = RegEnumKeyEx(
            hKey,
            dwIndex,
            achKey,
            &dwKeyLen,
            NULL,
            NULL,
            NULL,
            NULL
        );
        if (lRet != ERROR_SUCCESS)
        {
            return 0;
        }
    }
    if (bEnable) return cSubKeys;
    else return cValues;
}

#define MAX_DATA_NAME 300
bool IsFindVMKey = FALSE;
// QueryKey - Enumerates the subkeys of key and its associated values.
//     hKey - Key whose subkeys and values are to be enumerated.
BOOL SearchKey(HKEY hKey, LPCTSTR lpSubKey)
{
    IsFindVMKey = FALSE;
    HKEY hSubKey = NULL;
    TCHAR subKeyName[MAX_PATH + 1] = { 0 };
    TCHAR  achValue[MAX_VALUE_NAME]{};
    TCHAR  lpData[MAX_DATA_NAME]{};
    DWORD cchValue = MAX_VALUE_NAME;
    DWORD cbData = MAX_DATA_NAME;
    DWORD DataType = REG_SZ;
    if (ERROR_SUCCESS == RegOpenKeyEx(hKey, lpSubKey, 0, KEY_ALL_ACCESS, &hSubKey))
    {
        DWORD dwValueNum = GetRegKeyCount(hSubKey, 0, NULL, 0, FALSE);
        for (DWORD j = 0, retCode = ERROR_SUCCESS; j < dwValueNum; j++)
        {
            // 枚举指定的开放注册表项的值。该函数每次调用键时都会复制一个索引值名称和键的数据块。
            cchValue = MAX_VALUE_NAME;
            cbData = MAX_DATA_NAME;
            achValue[0] = '\0';
            lpData[0] = '\0';
            retCode = RegEnumValueW(hSubKey, j,
                achValue,
                &cchValue,
                NULL,
                &DataType,
                (PBYTE)&lpData,
                &cbData);

            if (retCode == ERROR_SUCCESS)
            {
                _tprintf(TEXT("(%d) %s\n"), j + 1, achValue);

                if (!wcsncmp(achValue, L"Iden", 4) && wcsstr(lpData, L"VMware"))
                {
                    //printf("Value: %ws\n", lpData);
                    IsFindVMKey = TRUE;
                    return TRUE;
                    //break;
                }

                //SearchKey(hSubKey, subKeyName);
            }
        }
        //获取lpSubKey下面有多少个子项
        DWORD dwSubKey = GetRegKeyCount(hSubKey, 0, NULL, 0, TRUE);
        for (DWORD i = 0; i < dwSubKey; i++)
        {
            if (ERROR_SUCCESS == RegEnumKey(hSubKey, i, subKeyName, MAX_PATH))
            {
                //打印项的名字
                printf("%ws\n", subKeyName);
                SearchKey(hSubKey, subKeyName);
            }
        }
        
        //关闭
        if (hSubKey)
        {
            RegCloseKey(hSubKey);
        }
    }
    else {
        IsFindVMKey = TRUE;
        return FALSE;
    }

    return IsFindVMKey;
}


int __cdecl _tmain()
{
    HKEY hTestKey;
    DPI_AWARENESS_CONTEXT OldTidDpiAware = NULL;
    OldTidDpiAware = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
    if (OldTidDpiAware == NULL)
        printf("设置线程上下文DPI配置失败。\n");
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
        TEXT("HARDWARE\\DEVICEMAP"),
        0,
        KEY_READ,
        &hTestKey) == ERROR_SUCCESS
        )
    {
        if (SearchKey(hTestKey, L"Scsi") && IsFindVMKey == true)
        {
            MessageBoxW(NULL, L"程序运行环境异常,请不要在虚拟机中运行该程序!", L"Ooops!", MB_SYSTEMMODAL | MB_ICONWARNING | MB_OK);
            RegCloseKey(hTestKey);
            exit(1033);
        }
        else if(IsFindVMKey == false)
        {
            MessageBoxW(NULL, L"恭喜你,Handware注册表检验通过,程序认定当前环境为物理机。", L"Congratulations!", MB_SYSTEMMODAL | MB_ICONINFORMATION | MB_OK);
        }
        else {
            MessageBoxW(NULL, L"程序运行环境异常,请重启计算机!", L"Ooops!", MB_SYSTEMMODAL | MB_ICONWARNING | MB_OK);
            RegCloseKey(hTestKey);
            exit(1034);
        }

    }

    RegCloseKey(hTestKey);

    system("pause");
    return 0;
}

下面是代码实测的结果:

递归遍历注册表特征
虚拟机运行结果

本文属于原创文章,转载请注明出处:

https://blog.csdn.net/qq_59075481/article/details/133661342

更新于:2023.10.24 

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
VMware虚拟机检测主要是指识别和判断计算机系统中是否安装有VMware虚拟化软件。 在进行VMware虚拟机检测时,可以通过以下几种方法进行: 1. 查看计算机硬件信息:VMware虚拟机通常会使用虚拟硬件设备来模拟真实的计算机环境。因此,在检测中可以查看计算机的硬件信息,如处理器、内存、显示适配器等,如果发现这些信息与实际计算机环境不符或者存在异常,则可能表明系统中存在VMware虚拟机。 2. 检查系统文件和注册表:VMware虚拟机在安装和运行时会在系统文件夹和注册表中留下一些痕迹。通过检查系统文件夹和注册表中是否存在VMware相关的文件或者注册表项,可以判断系统中是否安装了VMware虚拟机软件。 3. 检测网络连接:VMware虚拟机通常会创建虚拟网络适配器来实现与主机系统和其他虚拟机之间的网络通信。因此,在检测中可以检查计算机的网络连接情况,查看是否存在虚拟网络适配器或者跟VMware相关的网络配置。 4. 利用专门的工具:目前有一些第三方的工具或软件可以辅助进行VMware虚拟机检测。这些工具可以通过扫描计算机系统,识别出系统中存在的虚拟机软件,包括VMware等。 需要注意的是,VMware虚拟机检测一般用于安全审计、软件授权验证等场景,对于正常的虚拟机使用并无影响,并不是对VMware虚拟机的歧视或者禁止。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涟幽516

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值