You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过编程判断程序是否运行在虚拟机?跨架构跨系统方案咨询

跨架构跨操作系统判断虚拟机运行环境的方案

以下是不依赖虚拟机厂商信息、适配x86/ARM架构及Windows/Linux/macOS的检测方案,按优先级排序:

一、架构原生指令/系统API检测(最通用)

1. x86/x86_64 架构

利用Intel/AMD统一支持的CPUID指令Hypervisor位,跨所有操作系统通用:

  • 调用CPUID并设置eax=1,检查ecx寄存器第31位(最高位)是否为1,为1则说明运行在虚拟机中。
  • 代码实现:
    // GCC/Clang
    #include <cpuid.h>
    int is_virtualized_x86() {
        unsigned int eax, ebx, ecx, edx;
        __get_cpuid(1, &eax, &ebx, &ecx, &edx);
        return (ecx & (1U << 31)) != 0;
    }
    
    // MSVC
    #include <intrin.h>
    int is_virtualized_x86() {
        int info[4];
        __cpuid(info, 1);
        return (info[2] & (1U << 31)) != 0;
    }
    

2. ARM/AArch64 架构

Windows ARM64

直接使用系统API,Windows 10 1607及以上版本支持:

#include <windows.h>
int is_virtualized_arm64_windows() {
    // SM_VIRTUAL_MACHINE = 194
    return GetSystemMetrics(194) != 0;
}

Linux ARM/AArch64

通过系统文件和CPU特性判断:

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>

int is_virtualized_arm_linux() {
    // 检查hypervisor专属设备文件
    struct stat st;
    if (stat("/sys/devices/virtual/misc/hypervisor/version", &st) == 0) {
        return 1;
    }
    // 解析CPU特性,判断是否存在虚拟化扩展并处于guest模式
    FILE* fp = fopen("/proc/cpuinfo", "r");
    if (!fp) return 0;
    char line[256];
    int has_hyp = 0;
    while (fgets(line, sizeof(line), fp)) {
        if (strstr(line, "Features") && strstr(line, "hyp")) {
            has_hyp = 1;
            break;
        }
    }
    fclose(fp);
    // 存在虚拟化扩展时,结合其他标志或尝试访问hypervisor资源判断
    return has_hyp && stat("/sys/class/misc/hypervisor", &st) == 0;
}

macOS Apple Silicon(AArch64)

通过系统查询接口获取虚拟化状态:

#include <sys/sysctl.h>

int is_virtualized_macos_arm() {
    int virt_supported = 0;
    size_t len = sizeof(virt_supported);
    // 先检查CPU是否支持虚拟化
    if (sysctlbyname("machdep.cpu.virtualization", &virt_supported, &len, NULL, 0) != 0 || !virt_supported) {
        return 0;
    }
    // 检查是否运行在虚拟机中(宿主系统也支持虚拟化,需区分guest)
    char hv_vendor[64];
    len = sizeof(hv_vendor);
    return sysctlbyname("kern.hv_vendor", hv_vendor, &len, NULL, 0) == 0 && len > 0;
}

二、操作系统通用检测方法

Windows 系统

  • 跨版本兼容方案:使用NtQuerySystemInformation查询hypervisor信息(Windows 8及以上支持):
    #include <windows.h>
    typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)(
        ULONG SystemInformationClass,
        PVOID SystemInformation,
        ULONG SystemInformationLength,
        PULONG ReturnLength
    );
    
    int is_virtualized_windows_legacy() {
        HMODULE ntdll = LoadLibraryA("ntdll.dll");
        if (!ntdll) return 0;
        PNtQuerySystemInformation NtQuerySystemInfo = (PNtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation");
        if (!NtQuerySystemInfo) return 0;
        
        ULONG returnLen = 0;
        // SystemHypervisorInformation = 112
        NTSTATUS status = NtQuerySystemInfo(112, NULL, 0, &returnLen);
        if (status != STATUS_INFO_LENGTH_MISMATCH) return 0;
        
        PVOID info = malloc(returnLen);
        status = NtQuerySystemInfo(112, info, returnLen, NULL);
        free(info);
        FreeLibrary(ntdll);
        
        return status == STATUS_SUCCESS;
    }
    

Linux 系统

除了ARM的方法,x86架构可直接复用CPUID方案,通用补充方案:

#include <sys/stat.h>

int is_virtualized_linux() {
    // 检查hypervisor设备文件
    struct stat st;
    if (stat("/sys/devices/virtual/misc/hypervisor/version", &st) == 0) {
        return 1;
    }
    // x86架构 fallback 到CPUID
    #ifdef __x86_64__
    unsigned int eax, ebx, ecx, edx;
    __get_cpuid(1, &eax, &ebx, &ecx, &edx);
    return (ecx & (1U << 31)) != 0;
    #endif
    return 0;
}

macOS 系统

x86架构复用CPUID方案,通用方案:

#include <sys/sysctl.h>

int is_virtualized_macos() {
    // 检查hypervisor厂商信息
    char hv_vendor[64];
    size_t len = sizeof(hv_vendor);
    if (sysctlbyname("kern.hv_vendor", hv_vendor, &len, NULL, 0) == 0 && len > 0) {
        return 1;
    }
    // x86架构 fallback 到CPUID
    #ifdef __x86_64__
    unsigned int eax, ebx, ecx, edx;
    __get_cpuid(1, &eax, &ebx, &ecx, &edx);
    return (ecx & (1U << 31)) != 0;
    #endif
    return 0;
}

三、选型建议

  1. 优先架构原生方案:跨系统兼容性最好,不依赖厂商信息,性能最优。
  2. 操作系统API作为补充:当原生指令受权限限制时(如部分沙箱环境),使用系统提供的标准接口。
  3. 避免厂商名称匹配:该方法需持续维护厂商列表,可移植性差,仅作为最终 fallback。

内容的提问来源于stack exchange,提问作者Zamah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 23:01:04