从应用程序中检测虚拟化操作系统?

wsewodh2  于 2021-07-03  发布在  Java
关注(0)|答案(15)|浏览(434)

我需要检测我的应用程序是否在虚拟操作系统示例中运行。
我找到一篇文章,里面有一些关于这个主题的有用信息。同一篇文章出现在多个地方,我不确定原始来源。vmware实现了一个特定的无效x86指令来返回关于它自己的信息,而virtualpc使用了一个幻数和带有in指令的i/o端口。
这是可行的,但在这两种情况下似乎都是非法行为。我想vmware或virtualpc的未来版本可能会改变这种机制。有更好的办法吗?两种产品都有支持的机制吗?
类似地,有没有办法检测xen或virtualbox?
我不关心平台故意隐藏自己的情况。例如,蜜罐使用虚拟化,但有时会掩盖恶意软件用来检测它的机制。我不在乎我的应用程序会认为它不是在这些蜜罐虚拟化,我只是在寻找一个“尽力而为”的解决方案。
应用程序主要是java,不过我希望使用本机代码和jni来实现这个特定的函数。windowsxp/vista支持是最重要的,尽管参考文章中描述的机制是x86的通用特性,不依赖于任何特定的操作系统功能。

zpqajqem

zpqajqem1#

此c函数将检测vm访客操作系统:
(在windows上测试,用visual studio编译)


# include <intrin.h>

    bool isGuestOSVM()
    {
        unsigned int cpuInfo[4];
        __cpuid((int*)cpuInfo,1);
        return ((cpuInfo[2] >> 31) & 1) == 1;
    }
fcipmucu

fcipmucu2#

在linux下,您可以在/proc/cpuinfo上报告。如果是在vmware中,它的表现通常与在裸机上不同,但并不总是如此。virtuozzo展示了底层硬件的传递。

vpfxa7rd

vpfxa7rd3#

在安装newes ubuntu时,我发现了一个名为imvirt的包。看一看http://micky.ibh.net/~liske/imvirt.html

0ve6wy6x

0ve6wy6x4#

我想推荐一篇发表在usenix hotos'07上的文章,compatibility is not transparency:vmm detection myths and realities,其中总结了几种判断应用程序是否在虚拟化环境中运行的技术。
例如,像redpill那样使用sidt指令(但也可以通过动态转换使此指令透明),或者将cpuid的运行时与其他非虚拟化指令进行比较。

bpsygsoo

bpsygsoo5#

我尝试了朋友建议的另一种方法。在vmware上运行的虚拟机没有cpu温度属性。i、 它们不显示cpu的温度。我使用cpu温度计应用程序来检查cpu温度。
(在vmware中运行的windows)

(在真正的cpu上运行的windows)

所以我编写了一个小的c程序来检测温度传感器


# include "stdafx.h"

# define _WIN32_DCOM

# include <iostream>

using namespace std;

# include <comdef.h>

# include <Wbemidl.h>

# pragma comment(lib, "wbemuuid.lib")

int main(int argc, char**argv)
{
    HRESULT hres;

    // Step 1: --------------------------------------------------
    // Initialize COM. ------------------------------------------

    hres = CoInitializeEx(0, COINIT_MULTITHREADED);
    if (FAILED(hres))
    {
        cout << "Failed to initialize COM library. Error code = 0x"
            << hex << hres << endl;
        return 1;                  // Program has failed.
    }

    // Step 2: --------------------------------------------------
    // Set general COM security levels --------------------------

    hres = CoInitializeSecurity(
        NULL,
        -1,                          // COM authentication
        NULL,                        // Authentication services
        NULL,                        // Reserved
        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 
        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  
        NULL,                        // Authentication info
        EOAC_NONE,                   // Additional capabilities 
        NULL                         // Reserved
        );

    if (FAILED(hres))
    {
        cout << "Failed to initialize security. Error code = 0x"
            << hex << hres << endl;
        CoUninitialize();
        return 1;                    // Program has failed.
    }

    // Step 3: ---------------------------------------------------
    // Obtain the initial locator to WMI -------------------------

    IWbemLocator *pLoc = NULL;

    hres = CoCreateInstance(
        CLSID_WbemLocator,
        0,
        CLSCTX_INPROC_SERVER,
        IID_IWbemLocator, (LPVOID *)&pLoc);

    if (FAILED(hres))
    {
        cout << "Failed to create IWbemLocator object."
            << " Err code = 0x"
            << hex << hres << endl;
        CoUninitialize();
        return 1;                 // Program has failed.
    }

    // Step 4: -----------------------------------------------------
    // Connect to WMI through the IWbemLocator::ConnectServer method

    IWbemServices *pSvc = NULL;

    // Connect to the root\cimv2 namespace with
    // the current user and obtain pointer pSvc
    // to make IWbemServices calls.
    hres = pLoc->ConnectServer(
        _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
        NULL,                    // User name. NULL = current user
        NULL,                    // User password. NULL = current
        0,                       // Locale. NULL indicates current
        NULL,                    // Security flags.
        0,                       // Authority (for example, Kerberos)
        0,                       // Context object 
        &pSvc                    // pointer to IWbemServices proxy
        );

    if (FAILED(hres))
    {
        cout << "Could not connect. Error code = 0x"
            << hex << hres << endl;
        pLoc->Release();
        CoUninitialize();
        return 1;                // Program has failed.
    }

    cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;

    // Step 5: --------------------------------------------------
    // Set security levels on the proxy -------------------------

    hres = CoSetProxyBlanket(
        pSvc,                        // Indicates the proxy to set
        RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx
        RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx
        NULL,                        // Server principal name 
        RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 
        RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
        NULL,                        // client identity
        EOAC_NONE                    // proxy capabilities 
        );

    if (FAILED(hres))
    {
        cout << "Could not set proxy blanket. Error code = 0x"
            << hex << hres << endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // Step 6: --------------------------------------------------
    // Use the IWbemServices pointer to make requests of WMI ----

    // For example, get the name of the operating system
    IEnumWbemClassObject* pEnumerator = NULL;
    hres = pSvc->ExecQuery(
        bstr_t("WQL"),
        bstr_t(L"SELECT * FROM Win32_TemperatureProbe"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
        NULL,
        &pEnumerator);

    if (FAILED(hres))
    {
        cout << "Query for operating system name failed."
            << " Error code = 0x"
            << hex << hres << endl;
        pSvc->Release();
        pLoc->Release();
        CoUninitialize();
        return 1;               // Program has failed.
    }

    // Step 7: -------------------------------------------------
    // Get the data from the query in step 6 -------------------

    IWbemClassObject *pclsObj = NULL;
    ULONG uReturn = 0;

    while (pEnumerator)
    {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
            &pclsObj, &uReturn);

        if (0 == uReturn)
        {
            break;
        }

        VARIANT vtProp;

        // Get the value of the Name property
        hr = pclsObj->Get(L"SystemName", 0, &vtProp, 0, 0);
        wcout << " OS Name : " << vtProp.bstrVal << endl;
        VariantClear(&vtProp);
        VARIANT vtProp1;
        VariantInit(&vtProp1);
        pclsObj->Get(L"Caption", 0, &vtProp1, 0, 0);
        wcout << "Caption: " << vtProp1.bstrVal << endl;
        VariantClear(&vtProp1);

        pclsObj->Release();
    }

    // Cleanup
    // ========

    pSvc->Release();
    pLoc->Release();
    pEnumerator->Release();
    CoUninitialize();

    return 0;   // Program successfully completed.

}

vmware机器上的输出

实际cpu上的输出

jtw3ybtb

jtw3ybtb6#

在linux上,systemd提供一个命令来检测系统是否作为虚拟机运行。
命令: $ systemd-detect-virt 如果系统是虚拟化的,它会输出虚拟化软件/技术的名称。如果没有,则输出 none 例如,如果系统正在运行kvm,则:

$ systemd-detect-virt
kvm

你不需要像sudo那样运行它。

9cbw7uwe

9cbw7uwe7#

检查一下工具。它使用前面提到的dmidecode来确定您是否在虚拟化主机上以及类型。

nfs0ujit

nfs0ujit8#

尝试读取smbios结构,尤其是包含bios信息的结构。
在linux中,您可以使用dmidecode实用程序来浏览信息。

pokxtpni

pokxtpni9#

vmware有一种机制来确定软件是否在vmware虚拟机知识库文章中运行,该文章包含一些源代码。
微软还有一个关于“确定是否安装了hypervisor”的页面。ms在其“服务器虚拟化验证测试”文档的“isvm测试”部分详细说明了hypervisor的这一需求
vmware和ms文档都提到使用cpuid指令检查hypervisor当前位(register ecx的位31)
rhel bugtracker有一个用于“应该设置isvm位”(ecx:31)为cpuid leaf 0x00000001“设置xen内核下寄存器ecx的位31。
因此,在不涉及供应商细节的情况下,您似乎可以使用cpuid检查来了解您是否在虚拟运行。

sf6xfgos

sf6xfgos10#

我用这个 C# 类以检测访客操作系统是否在虚拟环境中运行(仅限windows):
系统信息.cs

using System;
using System.Management;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    public class sysInfo
    {
            public static Boolean isVM()
            {
                bool foundMatch = false;
                ManagementObjectSearcher search1 = new ManagementObjectSearcher("select * from Win32_BIOS");
                var enu = search1.Get().GetEnumerator();
                if (!enu.MoveNext()) throw new Exception("Unexpected WMI query failure");
                string biosVersion = enu.Current["version"].ToString();
                string biosSerialNumber = enu.Current["SerialNumber"].ToString();

                try
                {
                    foundMatch = Regex.IsMatch(biosVersion + " " + biosSerialNumber, "VMware|VIRTUAL|A M I|Xen", RegexOptions.IgnoreCase);
                }
                catch (ArgumentException ex)
                {
                    // Syntax error in the regular expression
                }

                ManagementObjectSearcher search2 = new ManagementObjectSearcher("select * from Win32_ComputerSystem");
                var enu2 = search2.Get().GetEnumerator();
                if (!enu2.MoveNext()) throw new Exception("Unexpected WMI query failure");
                string manufacturer = enu2.Current["manufacturer"].ToString();
                string model = enu2.Current["model"].ToString();

                try
                {
                    foundMatch = Regex.IsMatch(manufacturer + " " + model, "Microsoft|VMWare|Virtual", RegexOptions.IgnoreCase);
                }
                catch (ArgumentException ex)
                {
                    // Syntax error in the regular expression
                }

                    return foundMatch;
            }
        }

}

用法:

if (sysInfo.isVM()) { 
            Console.WriteLine("VM FOUND");
        }
pod7payv

pod7payv11#

在virtualbox上,假设您控制了vm访客,并且拥有dmidecode,则可以使用以下命令:

dmidecode -s bios-version

它会回来的

VirtualBox
niknxzdl

niknxzdl12#

我认为,在未来,依靠像sidt虚拟化这样的技巧并不能真正起到帮助作用,因为硬件填补了x86体系结构所留下的所有漏洞。最好的办法是游说虚拟机提供商提供一种标准的方式来判断您是否在虚拟机上——至少在用户明确允许的情况下是这样。但是如果我们假设我们显式地允许vm被检测到,我们也可以在其中放置可见的标记,对吗?我建议用一个文件来更新虚拟机上的磁盘,告诉您您在虚拟机上——例如,文件系统根目录中的一个小文本文件。或者检查eth0的mac,并将其设置为给定的已知字符串。

dvtswwa3

dvtswwa313#

不,这是不可能完全准确地探测到的。一些虚拟化系统,比如qemu,模拟整个机器直到硬件寄存器。让我们扭转这个局面:你想做什么?也许我们能帮上忙。

koaltpgm

koaltpgm14#

在linux下,我使用了命令:dmidecode(我在centos和ubuntu上都有这个命令)
从男人那里:
dmidecode是一种以可读格式转储计算机dmi(有人说是smbios)表内容的工具。
所以我搜索了输出,发现它可能是微软的hyper-v

Handle 0x0001, DMI type 1, 25 bytes
System Information
    Manufacturer: Microsoft Corporation
    Product Name: Virtual Machine
    Version: 5.0
    Serial Number: some-strings
    UUID: some-strings
    Wake-up Type: Power Switch

Handle 0x0002, DMI type 2, 8 bytes
Base Board Information
    Manufacturer: Microsoft Corporation
    Product Name: Virtual Machine
    Version: 5.0
    Serial Number: some-strings

另一种方法是搜索eth0的mac地址与哪个制造商相关:http://www.coffer.com/mac_find/
如果它返回microsoft、vmware等。。那么它可能是一个虚拟服务器。

a6b3iqyw

a6b3iqyw15#

你听说过蓝色药丸,红色药丸吗?。这是一种用于查看是否在虚拟机中运行的技术。这个词的起源源于《黑客帝国》的电影,在电影中,neo得到了一颗蓝色或红色的药丸(待在黑客帝国内=蓝色,或进入“真实”世界=红色)。
以下代码将检测您是否在“矩阵”中运行:
(从这个网站上借用的代码也包含了一些关于当前主题的好信息):

int swallow_redpill () {
   unsigned char m[2+4], rpill[] = "\x0f\x01\x0d\x00\x00\x00\x00\xc3";
   *((unsigned*)&rpill[3]) = (unsigned)m;
   ((void(*)())&rpill)();
   return (m[5]>0xd0) ? 1 : 0;
 }

在虚拟机内运行时,函数将返回1,否则返回0。

相关问题