Anti VM专题

4、通过注册表信息检测虚拟机

一、课程目标

本节课主要学习如何通过检查Windows注册表信息来检测虚拟机环境。虚拟机软件在安装和运行时会在注册表中留下特定的键值和条目,通过扫描这些注册表项可以判断程序是否运行在虚拟机中。通过本课的学习,你将能够:

  1. 理解Windows注册表结构和虚拟机相关键值
  2. 掌握注册表查询和枚举的技术
  3. 学会识别虚拟机软件特有的注册表特征
  4. 实现基于注册表信息的虚拟机检测代码
  5. 了解该技术的局限性和绕过方法

二、名词解释表

名词 解释
注册表 Windows操作系统的核心数据库,存储系统和应用程序配置信息
HKEY_LOCAL_MACHINE 注册表根键,包含本地计算机的配置信息
HKEY_CURRENT_USER 注册表根键,包含当前用户的配置信息
RegOpenKeyEx Windows API函数,用于打开注册表键
RegQueryValueEx Windows API函数,用于查询注册表值
RegEnumKeyEx Windows API函数,用于枚举注册表子键
虚拟机注册表项 虚拟机软件在注册表中创建的特定键值

三、技术原理

3.1 注册表检测概述

注册表检测是通过查询Windows注册表中虚拟机软件特有的键值和条目来判断是否处于虚拟化环境。

3.2 常见虚拟机注册表特征

不同虚拟机软件在注册表中会留下特定的痕迹:

  1. VMware相关注册表项

    • HKEY_LOCAL_MACHINE\SOFTWARE\VMware, Inc.\
    • HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\VMware, Inc.\
    • HKEY_CURRENT_USER\SOFTWARE\VMware, Inc.\
  2. VirtualBox相关注册表项

    • HKEY_LOCAL_MACHINE\SOFTWARE\Oracle\VirtualBox\
    • HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Oracle\VirtualBox\
  3. Hyper-V相关注册表项

    • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Hyper-V\
    • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Virtual Machine\Guest\
  4. 其他虚拟化软件

    • HKEY_LOCAL_MACHINE\SOFTWARE\Parallels\
    • HKEY_LOCAL_MACHINE\SOFTWARE\QEMU\

3.3 检测原理

通过打开和查询特定的注册表键,检查是否存在虚拟机软件特有的键值和条目来判断是否处于虚拟机环境。

四、代码实现

4.1 基础注册表检测

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

// 虚拟机注册表键列表
struct VMRegistryKey {
    const wchar_t* registryPath;
    const char* vendor;
};

VMRegistryKey g_vmRegistryKeys[] = {
    {L"SOFTWARE\\VMware, Inc.\\", "VMware"},
    {L"SOFTWARE\\Wow6432Node\\VMware, Inc.\\", "VMware"},
    {L"SOFTWARE\\Oracle\\VirtualBox\\", "VirtualBox"},
    {L"SOFTWARE\\Wow6432Node\\Oracle\\VirtualBox\\", "VirtualBox"},
    {L"SOFTWARE\\Microsoft\\Hyper-V\\", "Hyper-V"},
    {L"SOFTWARE\\Microsoft\\Virtual Machine\\Guest\\", "Hyper-V"},
    {L"SOFTWARE\\Parallels\\", "Parallels"},
    {L"SOFTWARE\\QEMU\\", "QEMU"}
};

// 检查注册表键是否存在
BOOL RegistryKeyExists(HKEY hRootKey, const wchar_t* subKeyPath) {
    HKEY hKey;
    LONG result = RegOpenKeyExW(hRootKey, subKeyPath, 0, KEY_READ, &hKey);
    
    if (result == ERROR_SUCCESS) {
        RegCloseKey(hKey);
        return TRUE;
    }
    
    return FALSE;
}

// 基础注册表检测
BOOL DetectVMViaRegistry() {
    printf("=== 基础注册表检测 ===\n");
    
    BOOL vmDetected = FALSE;
    
    // 检查已知的虚拟机注册表键
    for (int i = 0; i < sizeof(g_vmRegistryKeys) / sizeof(g_vmRegistryKeys[0]); i++) {
        if (RegistryKeyExists(HKEY_LOCAL_MACHINE, g_vmRegistryKeys[i].registryPath)) {
            printf("检测到虚拟机注册表键: %ws (%s)\n", g_vmRegistryKeys[i].registryPath, g_vmRegistryKeys[i].vendor);
            vmDetected = TRUE;
        }
        
        if (RegistryKeyExists(HKEY_CURRENT_USER, g_vmRegistryKeys[i].registryPath)) {
            printf("检测到用户级虚拟机注册表键: %ws (%s)\n", g_vmRegistryKeys[i].registryPath, g_vmRegistryKeys[i].vendor);
            vmDetected = TRUE;
        }
    }
    
    return vmDetected;
}

4.2 改进的注册表检测

// 获取注册表值
BOOL GetRegistryStringValue(HKEY hRootKey, const wchar_t* subKeyPath, const wchar_t* valueName, wchar_t* outBuffer, DWORD bufferSize) {
    HKEY hKey;
    if (RegOpenKeyExW(hRootKey, subKeyPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
        return FALSE;
    }
    
    DWORD valueType;
    DWORD valueSize = bufferSize * sizeof(wchar_t);
    
    LONG result = RegQueryValueExW(hKey, valueName, NULL, &valueType, (LPBYTE)outBuffer, &valueSize);
    RegCloseKey(hKey);
    
    return (result == ERROR_SUCCESS && valueType == REG_SZ);
}

// 检查注册表值内容
BOOL CheckRegistryValueContent(HKEY hRootKey, const wchar_t* subKeyPath, const wchar_t* valueName, const wchar_t* expectedContent) {
    wchar_t valueBuffer[512];
    if (GetRegistryStringValue(hRootKey, subKeyPath, valueName, valueBuffer, sizeof(valueBuffer) / sizeof(valueBuffer[0]))) {
        printf("注册表值 %ws: %ws\n", valueName, valueBuffer);
        
        // 检查是否包含期望的内容
        if (wcsstr(valueBuffer, expectedContent) != NULL) {
            printf("检测到虚拟机相关注册表值内容: %ws\n", expectedContent);
            return TRUE;
        }
    }
    
    return FALSE;
}

// 改进的注册表检测
BOOL ImprovedVMRegistryDetection() {
    printf("=== 改进版注册表检测 ===\n");
    
    BOOL vmDetected = FALSE;
    
    // 检查VMware相关注册表值
    if (CheckRegistryValueContent(HKEY_LOCAL_MACHINE, L"SOFTWARE\\VMware, Inc.\\VMware Tools\\", L"InstallPath", L"VMware")) {
        vmDetected = TRUE;
    }
    
    // 检查VirtualBox相关注册表值
    if (CheckRegistryValueContent(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Oracle\\VirtualBox\\", L"InstallDir", L"VirtualBox")) {
        vmDetected = TRUE;
    }
    
    // 检查Hyper-V相关注册表值
    wchar_t hyperVValue[512];
    if (GetRegistryStringValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Virtual Machine\\Guest\\", L"VirtualMachineName", hyperVValue, sizeof(hyperVValue) / sizeof(hyperVValue[0]))) {
        printf("检测到Hyper-V虚拟机名称: %ws\n", hyperVValue);
        vmDetected = TRUE;
    }
    
    return vmDetected;
}

4.3 高级注册表检测技术

// 枚举注册表子键
BOOL EnumerateRegistrySubKeys(HKEY hRootKey, const wchar_t* subKeyPath) {
    printf("=== 枚举注册表子键: %ws ===\n", subKeyPath);
    
    HKEY hKey;
    if (RegOpenKeyExW(hRootKey, subKeyPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
        return FALSE;
    }
    
    BOOL vmDetected = FALSE;
    
    // 枚举子键
    wchar_t subKeyName[256];
    DWORD subKeyNameSize = sizeof(subKeyName) / sizeof(subKeyName[0]);
    DWORD index = 0;
    
    while (RegEnumKeyExW(hKey, index, subKeyName, &subKeyNameSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
        printf("子键: %ws\n", subKeyName);
        
        // 检查子键名称是否包含虚拟机相关词汇
        wchar_t* vmKeywords[] = {
            L"vmware", L"virtualbox", L"vbox", L"hyper-v", L"hyperv",
            L"parallels", L"qemu", L"virtual"
        };
        
        for (int i = 0; i < sizeof(vmKeywords) / sizeof(vmKeywords[0]); i++) {
            if (wcsstr(subKeyName, vmKeywords[i]) != NULL) {
                printf("检测到虚拟机相关子键名称: %ws\n", vmKeywords[i]);
                vmDetected = TRUE;
            }
        }
        
        subKeyNameSize = sizeof(subKeyName) / sizeof(subKeyName[0]);
        index++;
    }
    
    RegCloseKey(hKey);
    return vmDetected;
}

// 检查注册表键值对
BOOL CheckRegistryKeyValuePairs(HKEY hRootKey, const wchar_t* subKeyPath) {
    printf("=== 检查注册表键值对: %ws ===\n", subKeyPath);
    
    HKEY hKey;
    if (RegOpenKeyExW(hRootKey, subKeyPath, 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
        return FALSE;
    }
    
    BOOL vmDetected = FALSE;
    
    // 枚举值
    wchar_t valueName[256];
    DWORD valueNameSize = sizeof(valueName) / sizeof(valueName[0]);
    DWORD index = 0;
    
    while (RegEnumValueW(hKey, index, valueName, &valueNameSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
        printf("值名称: %ws\n", valueName);
        
        // 检查值名称是否包含虚拟机相关词汇
        wchar_t* vmValueKeywords[] = {
            L"vmware", L"virtualbox", L"vbox", L"hyper-v", L"hyperv",
            L"parallels", L"qemu", L"virtual"
        };
        
        for (int i = 0; i < sizeof(vmValueKeywords) / sizeof(vmValueKeywords[0]); i++) {
            if (wcsstr(valueName, vmValueKeywords[i]) != NULL) {
                printf("检测到虚拟机相关值名称: %ws\n", vmValueKeywords[i]);
                vmDetected = TRUE;
            }
        }
        
        valueNameSize = sizeof(valueName) / sizeof(valueName[0]);
        index++;
    }
    
    RegCloseKey(hKey);
    return vmDetected;
}

// 检查注册表特征
BOOL CheckRegistryCharacteristics() {
    printf("=== 注册表特征检查 ===\n");
    
    BOOL vmDetected = FALSE;
    
    // 检查常见的软件安装路径
    const wchar_t* softwarePaths[] = {
        L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\",
        L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
    };
    
    for (int i = 0; i < sizeof(softwarePaths) / sizeof(softwarePaths[0]); i++) {
        if (EnumerateRegistrySubKeys(HKEY_LOCAL_MACHINE, softwarePaths[i])) {
            vmDetected = TRUE;
        }
    }
    
    // 检查系统信息键
    if (CheckRegistryKeyValuePairs(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\")) {
        vmDetected = TRUE;
    }
    
    // 检查硬件信息
    if (CheckRegistryKeyValuePairs(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\")) {
        vmDetected = TRUE;
    }
    
    return vmDetected;
}

// 综合注册表检测
BOOL ComprehensiveRegistryDetection() {
    printf("=== 综合注册表检测 ===\n");
    
    BOOL result1 = DetectVMViaRegistry();
    BOOL result2 = ImprovedVMRegistryDetection();
    BOOL result3 = CheckRegistryCharacteristics();
    
    return result1 || result2 || result3;
}

4.4 反虚拟机实现

// 简单的注册表反虚拟机检测
VOID SimpleRegistryAntiVM() {
    if (ComprehensiveRegistryDetection()) {
        printf("通过注册表信息检测到虚拟机环境!程序即将退出。\n");
        ExitProcess(1);
    }
}

// 多层次注册表检测
BOOL MultiLayerRegistryDetection() {
    // 第一层:基础检测
    if (DetectVMViaRegistry()) {
        return TRUE;
    }
    
    // 第二层:改进检测
    if (ImprovedVMRegistryDetection()) {
        return TRUE;
    }
    
    // 第三层:特征检查
    if (CheckRegistryCharacteristics()) {
        return TRUE;
    }
    
    return FALSE;
}

// 增强版反虚拟机检测
VOID EnhancedRegistryAntiVM() {
    // 多次检测
    for (int i = 0; i < 3; i++) {
        if (MultiLayerRegistryDetection()) {
            printf("第%d次注册表检测发现虚拟机环境!\n", i + 1);
            
            // 随机化响应
            int response = rand() % 4;
            switch (response) {
            case 0:
                ExitProcess(0);
            case 1:
                printf("发生未知错误。\n");
                Sleep(5000);
                exit(1);
            case 2:
                // 执行错误指令
                __debugbreak();
            case 3:
                // 进入无限循环
                while (1) {
                    Sleep(1000);
                }
            }
        }
        
        // 随机延迟
        Sleep(rand() % 100 + 50);
    }
    
    printf("注册表反虚拟机检测通过。\n");
}

4.5 绕过注册表检测的方法

// 注册表检测绕过技术
class RegistryObfuscator {
public:
    // 删除虚拟机相关注册表项
    static BOOL DeleteVMRegistryEntries() {
        printf("删除虚拟机相关注册表项...\n");
        
        // 实际应用中,这需要管理员权限并且可能被安全软件阻止
        // 这里仅作为概念演示
        
        return FALSE;
    }
    
    // 修改注册表值
    static BOOL ModifyRegistryValues() {
        printf("修改注册表值...\n");
        
        // 可以修改虚拟机相关注册表值来隐藏特征
        
        return FALSE;
    }
    
    // 创建虚假注册表项
    static BOOL CreateFakeRegistryEntries() {
        printf("创建虚假注册表项...\n");
        
        // 创建看起来像正常软件的注册表项来混淆检测
        
        return FALSE;
    }
};

// 综合绕过方法
VOID ComprehensiveRegistryBypass() {
    // 删除虚拟机相关注册表项
    RegistryObfuscator::DeleteVMRegistryEntries();
    
    // 修改注册表值
    RegistryObfuscator::ModifyRegistryValues();
    
    // 创建虚假注册表项
    RegistryObfuscator::CreateFakeRegistryEntries();
    
    printf("注册表检测绕过完成。\n");
}

4.6 完整测试程序

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// 前面实现的函数声明
BOOL DetectVMViaRegistry();
BOOL ImprovedVMRegistryDetection();
BOOL CheckRegistryCharacteristics();
BOOL MultiLayerRegistryDetection();

// 显示注册表检测信息
VOID DisplayRegistryDetectionInfo() {
    printf("=== 注册表检测信息 ===\n");
    
    // 显示当前用户信息
    wchar_t username[256];
    DWORD usernameSize = sizeof(username) / sizeof(username[0]);
    if (GetUserNameW(username, &usernameSize)) {
        printf("当前用户: %ws\n", username);
    }
    
    // 显示系统信息
    OSVERSIONINFO osvi;
    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    
    printf("\n");
}

// 性能测试
VOID PerformanceTest() {
    const int iterations = 5;
    
    printf("=== 性能测试 (%d次调用) ===\n", iterations);
    
    // 测试基础注册表检测
    DWORD start = GetTickCount();
    for (int i = 0; i < iterations; i++) {
        DetectVMViaRegistry();
        Sleep(100);
    }
    DWORD basicTime = GetTickCount() - start;
    
    // 测试改进版检测
    start = GetTickCount();
    for (int i = 0; i < iterations; i++) {
        ImprovedVMRegistryDetection();
        Sleep(100);
    }
    DWORD improvedTime = GetTickCount() - start;
    
    printf("基础注册表检测耗时: %lu ms\n", basicTime);
    printf("改进版注册表检测耗时: %lu ms\n", improvedTime);
    
    printf("\n");
}

// 主程序
int main() {
    srand((unsigned int)time(NULL));
    
    printf("通过注册表信息检测虚拟机演示程序\n");
    printf("===========================\n\n");
    
    // 显示注册表检测信息
    DisplayRegistryDetectionInfo();
    
    // 基础注册表检测
    DetectVMViaRegistry();
    
    // 改进版检测
    ImprovedVMRegistryDetection();
    
    // 特征检查
    CheckRegistryCharacteristics();
    
    // 性能测试
    PerformanceTest();
    
    // 实际应用示例
    printf("=== 反虚拟机检测 ===\n");
    if (MultiLayerRegistryDetection()) {
        printf("检测到虚拟机环境,执行反虚拟机措施。\n");
        
        // 这里可以执行各种反虚拟机措施
        // 为演示目的,我们只是显示信息而不真正退出
        printf("(演示模式:不实际退出程序)\n");
    } else {
        printf("未检测到虚拟机环境,程序正常运行。\n");
        MessageBoxW(NULL, L"注册表检测通过,程序正常运行", L"提示", MB_OK);
    }
    
    // 演示绕过方法
    printf("\n=== 绕过演示 ===\n");
    printf("执行注册表绕过...\n");
    // ComprehensiveRegistryBypass();  // 注释掉以避免实际修改系统
    
    printf("绕过完成后再次检测:\n");
    if (MultiLayerRegistryDetection()) {
        printf("仍然检测到虚拟机环境。\n");
    } else {
        printf("检测结果显示未发现注册表异常。\n");
    }
    
    return 0;
}

4.7 高级技巧和注意事项

// 抗干扰版本(防止简单的Hook)
BOOL AntiTamperRegistryDetection() {
    // 多次调用并验证
    BOOL results[3];
    
    for (int i = 0; i < 3; i++) {
        results[i] = MultiLayerRegistryDetection();
        Sleep(10);  // 简短延迟
    }
    
    // 检查结果一致性
    for (int i = 1; i < 3; i++) {
        if (results[i] != results[0]) {
            // 结果不一致,可能是被干扰了
            return TRUE;  // 假设存在虚拟机环境
        }
    }
    
    return results[0];
}

// 综合检测函数
BOOL ComprehensiveRegistryDetectionEnhanced() {
    // 抗干扰检测
    if (AntiTamperRegistryDetection()) {
        return TRUE;
    }
    
    // 多层检测
    if (MultiLayerRegistryDetection()) {
        return TRUE;
    }
    
    return FALSE;
}

// 动态获取注册表API地址(避免静态导入)
FARPROC GetDynamicRegistryAPIAddress(LPCSTR functionName) {
    // 动态加载advapi32.dll
    HMODULE hAdvapi32 = GetModuleHandle(L"advapi32.dll");
    if (hAdvapi32 == NULL) {
        return NULL;
    }
    
    // 获取函数地址
    FARPROC pfn = GetProcAddress(hAdvapi32, functionName);
    
    return pfn;
}

// 检查注册表API调用的完整性
BOOL ValidateRegistryAPICall() {
    // 可以通过检查相关函数代码的完整性来验证未被修改
    // 这需要更高级的技术,如代码校验和检查
    
    return TRUE;
}

// 多线程环境下的注册表检测
BOOL MultiThreadRegistryDetection() {
    printf("=== 多线程注册表检测 ===\n");
    
    // 在多线程环境中进行检测可以增加检测的可靠性
    
    return FALSE;
}

五、课后作业

  1. 基础练习

    • 在不同的虚拟机软件中测试注册表检测的准确性
    • 研究更多虚拟机软件的注册表特征
    • 实现对注册表信息的完整验证
  2. 进阶练习

    • 实现一个完整的注册表行为监控器
    • 研究如何通过API Hook绕过注册表检测
    • 设计一个多层检测机制,结合注册表信息和其他反虚拟机技术
  3. 思考题

    • 注册表检测方法有哪些明显的局限性?
    • 如何提高注册表检测的准确性和隐蔽性?
    • 现代虚拟机采用了哪些技术来对抗注册表检测?
  4. 扩展阅读

    • 研究Windows注册表内部结构
    • 了解注册表监控技术
    • 学习现代反虚拟机技术