Development Tip

애플리케이션에서 가상화 된 OS를 감지 하시겠습니까?

yourdevel 2020. 11. 19. 22:08
반응형

애플리케이션에서 가상화 된 OS를 감지 하시겠습니까?


내 애플리케이션이 가상화 된 OS 인스턴스 내에서 실행 중인지 여부를 감지해야합니다.

주제에 대한 유용한 정보 가 담긴 기사찾았습니다 . 동일한 기사가 여러 곳에 표시되지만 원본 출처가 확실하지 않습니다. VMware 는 자신에 대한 정보를 반환하기 위해 특정 유효하지 않은 x86 명령어를 구현하는 반면 VirtualPC 는 IN 명령어와 함께 매직 번호 및 I / O 포트를 사용합니다.

이것은 실행 가능하지만 두 경우 모두 문서화되지 않은 동작으로 보입니다. VMWare 또는 VirtualPC의 향후 릴리스가 메커니즘을 변경할 수 있다고 생각합니다. 더 좋은 방법이 있습니까? 두 제품에 대해 지원되는 메커니즘이 있습니까?

마찬가지로 Xen 또는 VirtualBox 를 감지하는 방법이 있습니까?

나는 플랫폼이 의도적으로 스스로를 숨기려고하는 경우에 대해 걱정하지 않습니다. 예를 들어 허니팟은 가상화를 사용하지만 때로는 맬웨어가이를 탐지하는 데 사용하는 메커니즘을 모호하게 만듭니다. 내 앱이 이러한 허니팟에서 가상화되지 않았다고 생각하는 것은 신경 쓰지 않고 "최선의"솔루션을 찾고 있습니다.

이 특정 기능에 대해 네이티브 코드와 JNI를 사용할 것으로 예상되지만 애플리케이션은 대부분 Java입니다. Windows XP / Vista 지원이 가장 중요하지만, 참조 문서에 설명 된 메커니즘은 x86의 일반적인 기능이며 특정 OS 기능에 의존하지 않습니다.


파란 알약, 빨간 알약 에 대해 들어 보셨습니까 ? . 가상 머신 내부에서 실행 중인지 여부를 확인하는 데 사용되는 기술입니다. 이 용어의 기원은 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을 반환합니다.


Linux에서는 dmidecode 명령을 사용했습니다 (CentOS와 Ubuntu에 모두 있습니다).

남자에게서 :

dmidecode는 컴퓨터의 DMI (SMBIOS라고도 함) 테이블 내용을 사람이 읽을 수있는 형식으로 덤프하는 도구입니다.

그래서 출력을 검색 한 결과 아마도 Microsoft 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 등을 반환하면 아마도 가상 서버 일 것입니다.


아니오. 이것은 완전한 정확도로 감지 할 수 없습니다. QEMU 와 같은 일부 가상화 시스템 은 전체 시스템을 하드웨어 레지스터까지 에뮬레이션합니다. 이것을 돌려 보자 : 당신이하려는 것이 무엇인가? 도움이 될 수도 있습니다.


VMware에는 일부 소스 코드가 있는 VMware 가상 머신 기술 자료 문서 에서 소프트웨어가 실행 중인지 확인 하는 메커니즘이 있습니다.

Microsoft에는 "하이퍼 바이저가 설치되었는지 확인"에 대한 페이지도 있습니다 . MS는 "서버 가상화 검증 테스트" 문서 의 IsVM TEST "섹션에서 하이퍼 바이저의이 요구 사항을 설명합니다.

VMware 및 MS 문서는 모두 CPUID 명령을 사용하여 하이퍼 바이저 존재 비트 (레지스터 ECX의 비트 31)를 확인한다고 언급합니다.

RHEL 버그 추적기 에는 Xen 커널에서 레지스터 ECX의 비트 31을 설정하기 위해 "CPUID 리프 0x00000001에 대해 ISVM 비트 (ECX : 31)를 설정해야 함"에 대한 하나가 있습니다.

따라서 공급 업체 세부 정보를 얻지 않고도 CPUID 검사를 사용하여 가상으로 실행 중인지 여부를 알 수 있습니다.


앞으로는 하드웨어가 이상하고 지저분한 x86 아키텍처가 남긴 모든 구멍을 막기 때문에 깨진 SIDT 가상화와 같은 트릭에 의존하는 것이 실제로 도움이되지 않을 것이라고 생각합니다. 가장 좋은 방법은 최소한 사용자가 명시 적으로 허용 한 경우 VM에 있음을 알리는 표준 방법으로 Vm 공급자에게 로비하는 것입니다. 하지만 명시 적으로 VM 감지를 허용한다고 가정하면 가시적 마커를 거기에 배치 할 수 있습니다. 예를 들어 파일 시스템의 루트에있는 작은 텍스트 파일 인 VM에 있음을 알려주는 파일로 VM의 디스크를 업데이트하는 것이 좋습니다. 또는 ETH0의 MAC을 검사하고 지정된 알려진 문자열로 설정합니다.


virtualbox에서 VM 게스트를 제어 할 수 있고 dmidecode가 있다고 가정하면 다음 명령을 사용할 수 있습니다.

dmidecode -s bios-version

그리고 그것은 돌아올 것입니다

VirtualBox

Usenix HotOS '07, Comptibility is Not Transparency : VMM Detection Myths and Realities 에 게시 된 논문을 추천하고 싶습니다.이 논문은 애플리케이션이 가상화 된 환경에서 실행 중인지 여부를 알려주는 몇 가지 기술을 마무리합니다.

예를 들어, redpill처럼 sidt 명령어를 사용하거나 (이 명령어는 동적 변환을 통해 투명하게 만들 수도 있음) cpuid의 런타임을 가상화되지 않은 다른 명령어와 비교합니다.


Linux에서는 / proc / cpuinfo에 대해보고 할 수 있습니다. VMware에있는 경우 일반적으로 베어 메탈에있는 경우와 다르게 표시되지만 항상 그런 것은 아닙니다. Virtuozzo는 기본 하드웨어에 대한 패스 스루를 보여줍니다.


SMBIOS 구조, 특히 BIOS 정보 가있는 구조 를 읽어보십시오 .

Linux에서는 dmidecode 유틸리티를 사용 하여 정보를 찾아 볼 수 있습니다.


newes Ubuntu를 설치하는 동안 imvirt라는 패키지를 발견했습니다. http://micky.ibh.net/~liske/imvirt.html 에서 살펴보십시오 .


이 C 기능은 VM 게스트 OS를 감지합니다.

(Windows에서 테스트되었으며 Visual Studio로 컴파일 됨)

#include <intrin.h>

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

도구 virt-what을 확인하십시오 . 이전에 언급 한 dmidecode를 사용하여 가상화 된 호스트에 있는지 여부와 유형을 확인합니다.


Linux에서 systemd는 시스템이 가상 머신으로 실행 중인지 여부를 감지하는 명령을 제공합니다.

명령:
$ systemd-detect-virt

시스템이 가상화 된 경우 가상화 소프트웨어 / 기술의 이름을 출력합니다. 그렇지 않은 경우 출력none

예를 들어 시스템이 KVM을 실행하는 경우 :

$ systemd-detect-virt
kvm

sudo로 실행할 필요가 없습니다.


C#클래스를 사용 하여 게스트 OS가 가상 환경 내에서 실행 중인지 감지합니다 ( windows 만 해당 ).

sysInfo.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");
        }

친구가 제안한 다른 접근 방식을 시도했습니다 VMWARE에서 실행되는 가상 머신에는 CPU TEMPERATURE 속성이 없습니다. 즉 그들은 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.

}

VM웨어 머신에서 출력 여기에 이미지 설명 입력

실제 CPU에서 출력 여기에 이미지 설명 입력

참고 URL : https://stackoverflow.com/questions/154163/detect-virtualized-os-from-an-application

반응형