From f6542aa248015336b3a1c655c6a78c12722dc730 Mon Sep 17 00:00:00 2001 From: Requiem Date: Mon, 20 Jan 2025 20:49:06 +0100 Subject: [PATCH 1/2] Hyper-X fix --- docs/documentation.md | 4 +- src/cli.cpp | 15 +- src/vmaware.hpp | 360 +++++++++++++--------------------- src/vmaware_MIT.hpp | 439 ++++++++++++++++-------------------------- 4 files changed, 304 insertions(+), 514 deletions(-) diff --git a/docs/documentation.md b/docs/documentation.md index f740e2d..e6572ca 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -370,7 +370,6 @@ VMAware provides a convenient way to not only check for VMs, but also have the f | `VM::RDTSC_VMEXIT` | check through alternative RDTSC technique with VMEXIT | | 25% | | | | Disabled by default | | `VM::QEMU_BRAND` | Match for QEMU CPU brands with "QEMU Virtual CPU" string | | 100% | | | | | | `VM::BOCHS_CPU` | Check for various Bochs-related emulation oversights through CPU checks | | 95% | | | | | -| `VM::VPC_BOARD` | Check through the motherboard and match for VirtualPC-specific string | Windows | 20% | | | | | | `VM::HYPERV_WMI` | Check WMI query for "Hyper-V RAW" string | Windows | 80% | | | | | | `VM::HYPERV_REG` | Check presence for Hyper-V specific string in registry | Windows | 80% | | | | | | `VM::BIOS_SERIAL` | Check if the BIOS serial is valid (null = VM) | Windows | 60% | | | | | @@ -388,7 +387,6 @@ VMAware provides a convenient way to not only check for VMs, but also have the f | `VM::OFFSEC_SIDT` | Check for Offensive Security SIDT method | Windows | 60% | | | 32-bit | | | `VM::OFFSEC_SGDT` | Check for Offensive Security SGDT method | Windows | 60% | | | 32-bit | | | `VM::OFFSEC_SLDT` | Check for Offensive Security SLDT method | Windows | 20% | | | 32-bit | | -| `VM::HYPERV_BOARD` | Check for Hyper-V specific string in motherboard | Windows | 45% | | | | | | `VM::VPC_SIDT` | Check for sidt method with VPC's 0xE8XXXXXX range | Windows | 15% | | | 32-bit | | | `VM::VMWARE_IOMEM` | Check for VMware string in /proc/iomem | Linux | 65% | | | | | | `VM::VMWARE_IOPORTS` | Check for VMware string in /proc/ioports | Linux | 70% | | | | | @@ -457,6 +455,8 @@ VMAware provides a convenient way to not only check for VMs, but also have the f | `VM::SYS_QEMU` | Check for existence of "qemu_fw_cfg" directories within /sys/module and /sys/firmware | Linux | 70% | | | | | | `VM::LSHW_QEMU` | Check for QEMU string instances with lshw command | Linux | 80% | | | | | | `VM::VIRTUAL_PROCESSORS` | Checks if the number of maximum virtual processors matches the maximum number of logical processors | Windows | 35% | | | | | +| `VM::MOTHERBOARD_PRODUCT` | Check if the motherboard product string matches "Virtual Machine" | Windows | 25% | | | | | +
diff --git a/src/cli.cpp b/src/cli.cpp index a4b3dc4..3991daf 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -409,7 +409,6 @@ bool is_unsupported(VM::enum_flags flag) { case VM::PARALLELS_VM: case VM::QEMU_BRAND: case VM::BOCHS_CPU: - case VM::VPC_BOARD: case VM::HYPERV_WMI: case VM::HYPERV_REG: case VM::BIOS_SERIAL: @@ -422,7 +421,6 @@ bool is_unsupported(VM::enum_flags flag) { case VM::OFFSEC_SIDT: case VM::OFFSEC_SGDT: case VM::OFFSEC_SLDT: - case VM::HYPERV_BOARD: case VM::VPC_SIDT: case VM::VMWARE_STR: case VM::VMWARE_BACKDOOR: @@ -466,6 +464,8 @@ bool is_unsupported(VM::enum_flags flag) { case VM::POWER_CAPABILITIES: case VM::SETUPAPI_DISK: case VM::VMWARE_HARDENER: + case VM::VIRTUAL_PROCESSORS: + case VM::MOTHERBOARD_PRODUCT: // ADD WINDOWS FLAG return false; default: return true; @@ -484,7 +484,6 @@ bool is_unsupported(VM::enum_flags flag) { case VM::VMID_0X4: case VM::QEMU_BRAND: case VM::BOCHS_CPU: - case VM::VPC_BOARD: case VM::MAC_MEMSIZE: case VM::MAC_IOKIT: case VM::IOREG_GREP: @@ -558,13 +557,13 @@ void replace(std::string &text, const std::string &original, const std::string & } } -bool is_vm_brand_multiple(const std::string_view vm_brand) { +bool is_vm_brand_multiple(const std::string& vm_brand) { return (vm_brand.find(" or ") != std::string::npos); } -std::string vm_description(const std::string_view vm_brand) { +std::string vm_description(const std::string& vm_brand) { // if there's multiple brands, return null if (is_vm_brand_multiple(vm_brand)) { @@ -634,8 +633,7 @@ std::string vm_description(const std::string_view vm_brand) { { VM::brands::NULL_BRAND, "" } }; - auto it = description_table.find(vm_brand.data()); - + std::map::const_iterator it = description_table.find(vm_brand); if (it != description_table.end()) { return it->second; } @@ -885,7 +883,6 @@ void general() { checker(VM::LOADED_DLLS, "loaded DLLs"); checker(VM::QEMU_BRAND, "QEMU CPU brand"); checker(VM::BOCHS_CPU, "BOCHS CPU techniques"); - checker(VM::VPC_BOARD, "VirtualPC motherboard"); checker(VM::BIOS_SERIAL, "BIOS serial number"); checker(VM::MSSMBIOS, "MSSMBIOS"); checker(VM::MAC_MEMSIZE, "MacOS hw.memsize"); @@ -905,7 +902,6 @@ void general() { checker(VM::OFFSEC_SGDT, "Offensive Security SGDT"); checker(VM::OFFSEC_SLDT, "Offensive Security SLDT"); checker(VM::VPC_SIDT, "VirtualPC SIDT"); - checker(VM::HYPERV_BOARD, "Hyper-V motherboard"); checker(VM::VMWARE_IOMEM, "/proc/iomem file"); checker(VM::VMWARE_IOPORTS, "/proc/ioports file"); checker(VM::VMWARE_SCSI, "/proc/scsi/scsi file"); @@ -971,6 +967,7 @@ void general() { checker(VM::SYS_QEMU, "QEMU in /sys"); checker(VM::LSHW_QEMU, "QEMU in lshw output"); checker(VM::VIRTUAL_PROCESSORS, "virtual processors"); + checker(VM::MOTHERBOARD_PRODUCT, "motherboard product"); // ADD NEW TECHNIQUE CHECKER HERE std::printf("\n"); diff --git a/src/vmaware.hpp b/src/vmaware.hpp index 688db54..4653a35 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -25,13 +25,13 @@ * * ================================ SECTIONS ================================== * - enums for publicly accessible techniques => line 327 - * - struct for internal cpu operations => line 601 - * - struct for internal memoization => line 1061 - * - struct for internal utility functions => line 1444 - * - struct for internal core components => line 9586 - * - start of internal VM detection techniques => line 3040 - * - start of public VM detection functions => line 9984 - * - start of externally defined variables => line 10854 + * - struct for internal cpu operations => line 499 + * - struct for internal memoization => line 1059 + * - struct for internal utility functions => line 1431 + * - struct for internal core components => line 9453 + * - start of internal VM detection techniques => line 2990 + * - start of public VM detection functions => line 9851 + * - start of externally defined variables => line 10720 * * * ================================ EXAMPLE ================================== @@ -364,7 +364,6 @@ struct VM { PARALLELS_VM, QEMU_BRAND, BOCHS_CPU, - VPC_BOARD, HYPERV_WMI, HYPERV_REG, BIOS_SERIAL, @@ -382,7 +381,6 @@ struct VM { OFFSEC_SIDT, OFFSEC_SGDT, OFFSEC_SLDT, - HYPERV_BOARD, VPC_SIDT, VMWARE_IOMEM, VMWARE_IOPORTS, @@ -446,6 +444,7 @@ struct VM { SYS_QEMU, LSHW_QEMU, VIRTUAL_PROCESSORS, + MOTHERBOARD_PRODUCT, // ADD NEW TECHNIQUE ENUM NAME HERE // start of settings technique flags (THE ORDERING IS VERY SPECIFIC HERE AND MIGHT BREAK SOMETHING IF RE-ORDERED) @@ -1268,7 +1267,6 @@ struct VM { return memo::wmi::fetch(); } - // this will clean up wmi when the program terminates std::atexit(wmi::cleanup); if (pSvc != nullptr) { @@ -1277,80 +1275,70 @@ struct VM { } HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); + bool shouldUninitialize = false; + if (FAILED(hres)) { - debug("wmi: Failed to initialize COM library. Error code = ", hres); - memo::wmi::store(false); - return false; + if (hres == RPC_E_CHANGED_MODE) { + debug("wmi: COM already initialized with a different mode, continuing..."); + } + else { + debug("wmi: Failed to initialize COM library. Error code = ", hres); + memo::wmi::store(false); + return false; + } + } + else { + shouldUninitialize = true; } hres = CoInitializeSecurity( - NULL, - -1, - NULL, - NULL, + NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, - NULL, - EOAC_NONE, - NULL + NULL, EOAC_NONE, NULL ); if (FAILED(hres)) { - CoUninitialize(); + if (shouldUninitialize) CoUninitialize(); debug("wmi: Failed to initialize security. Error code = ", hres); memo::wmi::store(false); return false; } hres = CoCreateInstance( - CLSID_WbemLocator, - 0, - CLSCTX_INPROC_SERVER, - IID_IWbemLocator, - (LPVOID*)&pLoc + CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID*)&pLoc ); if (FAILED(hres)) { - CoUninitialize(); + if (shouldUninitialize) CoUninitialize(); debug("wmi: Failed to create IWbemLocator object. Error code = ", hres); memo::wmi::store(false); return false; } hres = pLoc->ConnectServer( - _bstr_t(L"ROOT\\CIMV2"), - NULL, - NULL, - 0, - NULL, - 0, - 0, - &pSvc + _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc ); if (FAILED(hres)) { pLoc->Release(); - CoUninitialize(); + if (shouldUninitialize) CoUninitialize(); debug("wmi: Could not connect to WMI server. Error code = ", hres); memo::wmi::store(false); return false; } hres = CoSetProxyBlanket( - pSvc, - RPC_C_AUTHN_WINNT, - RPC_C_AUTHZ_NONE, - NULL, - RPC_C_AUTHN_LEVEL_CALL, - RPC_C_IMP_LEVEL_IMPERSONATE, - NULL, - EOAC_NONE + pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, + RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, EOAC_NONE ); if (FAILED(hres)) { pSvc->Release(); pLoc->Release(); - CoUninitialize(); + if (shouldUninitialize) CoUninitialize(); debug("wmi: Could not set proxy blanket. Error code = ", hres); memo::wmi::store(false); return false; @@ -2013,17 +2001,6 @@ struct VM { return result; }; - // motherboard check - auto is_motherboard_hyperv = []() -> bool { - const bool motherboard = motherboard_string("Microsoft Corporation"); - - if (motherboard) { - core_debug("HYPER_X: motherboard string match = ", motherboard); - } - - return motherboard; - }; - // event log check (slow, so in last place) auto is_event_log_hyperv = []() -> bool { @@ -2075,7 +2052,6 @@ struct VM { eax() == 11 || is_smbios_hyperv() || is_acpi_hyperv() || - is_motherboard_hyperv() || is_event_log_hyperv() ); @@ -2596,26 +2572,6 @@ struct VM { } - [[nodiscard]] static bool motherboard_string(const char* vm_string) { - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in motherboard_string"); - return false; - } - - wmi_result results = wmi::execute(L"SELECT * FROM Win32_BaseBoard", { L"Manufacturer" }); - - for (const auto& res : results) { - if (res.type == wmi::result_type::String) { - if (_stricmp(res.strValue.c_str(), vm_string) == 0) { - return true; - } - } - } - - return false; - } - - /** * @brief Retrieves the last error message from the Windows API. Useful for __VMAWARE_DEBUG__ * @author Requiem (https://github.com/NotRequiem) @@ -2940,11 +2896,6 @@ struct VM { }; auto GetThreadsUsingWMI = []() -> int { - if (!wmi::initialize()) { - std::cerr << "Failed to initialize WMI in GetThreadsUsingWMI.\n"; - return 1; - } - wmi_result results = wmi::execute(L"SELECT NumberOfLogicalProcessors FROM Win32_Processor", { L"NumberOfLogicalProcessors" }); for (const auto& res : results) { if (res.type == wmi::result_type::Integer) { @@ -2952,7 +2903,7 @@ struct VM { } } - return 1; + return 0; }; auto GetThreadsUsingGetSystemInfo = []() -> int { @@ -4190,74 +4141,86 @@ struct VM { /* GPL */ // @author CheckPointSW (InviZzzible project) /* GPL */ // @link https://github.com/CheckPointSW/InviZzzible/blob/master/SandboxEvasion/helper.cpp /* GPL */ // @copyright GPL-3.0 -/* GPL */ [[nodiscard]] static bool check_audio() { +/* GPL */ [[nodiscard]] static bool check_audio() { /* GPL */ #if (!WINDOWS) /* GPL */ return false; /* GPL */ #else /* GPL */ PCWSTR wszfilterName = L"audio_device_random_name"; -/* GPL */ -/* GPL */ if (FAILED(CoInitialize(NULL))) -/* GPL */ return false; -/* GPL */ +/* GPL */ +/* GPL */ HRESULT hres = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); +/* GPL */ bool shouldUninitialize = false; +/* GPL */ +/* GPL */ if (FAILED(hres)) { +/* GPL */ if (hres == RPC_E_CHANGED_MODE) { +/* GPL */ debug("check_audio: COM is already initialized with a different mode. Using existing COM context."); +/* GPL */ } +/* GPL */ else { +/* GPL */ return false; +/* GPL */ } +/* GPL */ } +/* GPL */ else { +/* GPL */ shouldUninitialize = true; +/* GPL */ } +/* GPL */ /* GPL */ IGraphBuilder* pGraph = nullptr; -/* GPL */ if (FAILED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph))) +/* GPL */ if (FAILED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph))) { +/* GPL */ if (shouldUninitialize) CoUninitialize(); /* GPL */ return false; -/* GPL */ -/* GPL */ // First anti-emulation check: If AddFilter is called with NULL as a first argument it should return the E_POINTER error code. -/* GPL */ // Some emulators may implement unknown COM interfaces in a generic way, so they will probably fail here. -/* GPL */ if (E_POINTER != pGraph->AddFilter(NULL, wszfilterName)) +/* GPL */ } +/* GPL */ +/* GPL */ if (E_POINTER != pGraph->AddFilter(NULL, wszfilterName)) { +/* GPL */ if (shouldUninitialize) CoUninitialize(); /* GPL */ return true; -/* GPL */ -/* GPL */ // Initializes a simple Audio Renderer, error code is not checked, -/* GPL */ // but pBaseFilter will be set to NULL upon failure and the code will eventually fail later. +/* GPL */ } +/* GPL */ /* GPL */ IBaseFilter* pBaseFilter = nullptr; -/* GPL */ /* GPL */ HRESULT hr = CoCreateInstance(CLSID_AudioRender, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pBaseFilter); /* GPL */ if (FAILED(hr)) { +/* GPL */ if (shouldUninitialize) CoUninitialize(); /* GPL */ return false; /* GPL */ } -/* GPL */ -/* GPL */ // Adds the previously created Audio Renderer to the Filter Graph, no error checks +/* GPL */ /* GPL */ pGraph->AddFilter(pBaseFilter, wszfilterName); -/* GPL */ -/* GPL */ // Tries to find the filter that was just added; in case of any previously not checked error (or wrong emulation) -/* GPL */ // this function won't find the filter and the sandbox/emulator will be successfully detected. +/* GPL */ /* GPL */ IBaseFilter* pBaseFilter2 = nullptr; /* GPL */ pGraph->FindFilterByName(wszfilterName, &pBaseFilter2); -/* GPL */ if (nullptr == pBaseFilter2) +/* GPL */ if (nullptr == pBaseFilter2) { +/* GPL */ if (shouldUninitialize) CoUninitialize(); /* GPL */ return true; -/* GPL */ -/* GPL */ // Checks if info.achName is equal to the previously added filterName, if not - poor API emulation +/* GPL */ } +/* GPL */ /* GPL */ FILTER_INFO info = { 0 }; /* GPL */ pBaseFilter2->QueryFilterInfo(&info); -/* GPL */ if (0 != wcscmp(info.achName, wszfilterName)) +/* GPL */ if (0 != wcscmp(info.achName, wszfilterName)) { +/* GPL */ if (shouldUninitialize) CoUninitialize(); /* GPL */ return false; -/* GPL */ -/* GPL */ // Checks if the API sets a proper IReferenceClock pointer +/* GPL */ } +/* GPL */ /* GPL */ IReferenceClock* pClock = nullptr; -/* GPL */ if (0 != pBaseFilter2->GetSyncSource(&pClock)) -/* GPL */ return false; -/* GPL */ if (0 != pClock) +/* GPL */ if (0 != pBaseFilter2->GetSyncSource(&pClock) || pClock != nullptr) { +/* GPL */ if (shouldUninitialize) CoUninitialize(); /* GPL */ return false; -/* GPL */ -/* GPL */ // Checks if CLSID is different from 0 +/* GPL */ } +/* GPL */ /* GPL */ CLSID clsID = { 0 }; /* GPL */ pBaseFilter2->GetClassID(&clsID); -/* GPL */ if (clsID.Data1 == 0) +/* GPL */ if (clsID.Data1 == 0) { +/* GPL */ if (shouldUninitialize) CoUninitialize(); /* GPL */ return true; -/* GPL */ -/* GPL */ if (nullptr == pBaseFilter2) -/* GPL */ return true; -/* GPL */ -/* GPL */ // Just checks if the call was successful +/* GPL */ } +/* GPL */ /* GPL */ IEnumPins* pEnum = nullptr; -/* GPL */ if (0 != pBaseFilter2->EnumPins(&pEnum)) +/* GPL */ if (0 != pBaseFilter2->EnumPins(&pEnum)) { +/* GPL */ if (shouldUninitialize) CoUninitialize(); /* GPL */ return true; -/* GPL */ -/* GPL */ // The reference count returned by AddRef has to be higher than 0 -/* GPL */ if (0 == pBaseFilter2->AddRef()) +/* GPL */ } +/* GPL */ +/* GPL */ if (0 == pBaseFilter2->AddRef()) { +/* GPL */ if (shouldUninitialize) CoUninitialize(); /* GPL */ return true; -/* GPL */ +/* GPL */ } +/* GPL */ +/* GPL */ if (shouldUninitialize) CoUninitialize(); /* GPL */ return false; /* GPL */ #endif /* GPL */ } @@ -4701,25 +4664,6 @@ struct VM { } - /** - * @brief Check through the motherboard and match for VirtualPC-specific string - * @category Windows - */ - [[nodiscard]] static bool vpc_board() { -#if (!WINDOWS) - return false; -#else - const bool is_vm = util::motherboard_string("Microsoft Corporation"); - - if (is_vm) { - return core::add(brands::VPC); - } - - return false; -#endif - } - - /** * @brief Check if the BIOS serial is valid (null = VM) * @category Windows @@ -5403,34 +5347,6 @@ struct VM { } - /** - * @brief Check for Hyper-V specific string in motherboard - * @category Windows - */ - [[nodiscard]] static bool hyperv_board() { -#if (!WINDOWS) - return false; -#else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in hyperv_board"); - return false; - } - - wmi_result results = wmi::execute(L"SELECT * FROM Win32_BaseBoard", { L"Manufacturer" }); - - for (const auto& res : results) { - if (res.type == wmi::result_type::String) { - if (_stricmp(res.strValue.c_str(), "Microsoft Corporation Virtual Machine") == 0) { - return core::add(brands::HYPERV); - } - } - } - - return false; // No match found -#endif - } - - /** * @brief Check for sidt method with VPC's 0xE8XXXXXX range * @category Windows, x86 @@ -8598,11 +8514,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in gpu_chiptype"); - return false; - } - wmi_result results = wmi::execute(L"SELECT * FROM Win32_VideoController", { L"VideoProcessor" }); std::string result = ""; @@ -8780,11 +8691,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in hdd_serial_number"); - return false; - } - const char* targetSerial = "VBbd5bbffd-59166c24"; wmi_result results = wmi::execute(L"SELECT SerialNumber FROM Win32_DiskDrive", { L"SerialNumber" }); @@ -8811,13 +8717,23 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in port_connectors"); - return false; - } + std::wstring query = L"SELECT Product FROM Win32_BaseBoard"; + std::vector properties = { L"Product" }; + wmi_result results = wmi::execute(query, properties); - wmi_result results = wmi::execute(L"SELECT * FROM Win32_PortConnector", { L"Caption" }); + for (const auto& res : results) { + if (res.type == wmi::result_type::String) { + std::string lowerStr = res.strValue; + std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(), ::tolower); + if (lowerStr.find("surface") != std::string::npos) { // This WMI query returns false for Surface Pro devices + return false; + } + } + } + + wmi_result portResults = wmi::execute(L"SELECT * FROM Win32_PortConnector", { L"Caption" }); + return results.empty(); #endif }; @@ -8831,11 +8747,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in vm_hdd"); - return false; - } - wmi_result results = wmi::execute(L"SELECT Model FROM Win32_DiskDrive", { L"Model" }); for (const auto& res : results) { @@ -9120,11 +9031,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in number_of_cores"); - return false; - } - std::wstring query = L"SELECT NumberOfCores FROM Win32_Processor"; std::vector properties = { L"NumberOfCores" }; @@ -9152,11 +9058,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in number_of_cores"); - return false; - } - std::wstring query = L"SELECT Model FROM Win32_ComputerSystem"; std::vector properties = { L"Model" }; wmi_result results = wmi::execute(query, properties); @@ -9182,11 +9083,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in wmi_manufacturer"); - return false; - } - std::wstring query = L"SELECT Manufacturer FROM Win32_ComputerSystem"; std::vector properties = { L"Manufacturer" }; wmi_result results = wmi::execute(query, properties); @@ -9212,11 +9108,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in wmi_temperature"); - return false; - } - std::wstring query = L"SELECT * FROM MSAcpi_ThermalZoneTemperature"; std::vector properties = { L"CurrentTemperature" }; @@ -9242,11 +9133,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in processor_id"); - return false; - } - std::wstring query = L"SELECT ProcessorId FROM Win32_Processor"; std::vector properties = { L"ProcessorId" }; wmi_result results = wmi::execute(query, properties); @@ -9272,11 +9158,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in cpu_fans"); - return false; - } - std::wstring query = L"SELECT * FROM Win32_Fan"; std::vector properties = { }; wmi_result results = wmi::execute(query, properties); @@ -9408,7 +9289,6 @@ static bool rdtsc() { /** * @brief Check for existence of qemu_fw_cfg directories within sys/module and /sys/firmware * @category Linux - * @note */ [[nodiscard]] static bool sys_qemu_dir() { #if (!LINUX) @@ -9449,7 +9329,6 @@ static bool rdtsc() { /** * @brief Check for QEMU string instances with lshw command * @category Linux - * @note */ [[nodiscard]] static bool lshw_qemu() { #if (!LINUX) @@ -9497,7 +9376,7 @@ static bool rdtsc() { * @note https://medium.com/@matterpreter/hypervisor-detection-with-systemhypervisordetailinformation-26e44a57f80e */ [[nodiscard]] static bool virtual_processors() { -#if (!WINDOWS || !x86_64) +#if (!WINDOWS) return false; #else struct Registers { @@ -9526,6 +9405,30 @@ static bool rdtsc() { #endif } + + /* + * @brief Detects if the motherboard product matches the signature of a virtual machine + * @category Windows + * @author Requiem + */ + [[nodiscard]] static bool motherboard_product() { +#if (!WINDOWS) + return false; +#else + std::wstring query = L"SELECT Product FROM Win32_BaseBoard"; + std::vector properties = { L"Product" }; + wmi_result results = wmi::execute(query, properties); + + for (const auto& res : results) { + if (res.type == wmi::result_type::String && res.strValue == "Virtual Machine") { + return true; + } + } + + return false; +#endif + } + // ADD NEW TECHNIQUE FUNCTION HERE @@ -10481,7 +10384,6 @@ static bool rdtsc() { case PARALLELS_VM: return "PARALLELS_VM"; case QEMU_BRAND: return "QEMU_BRAND"; case BOCHS_CPU: return "BOCHS_CPU"; - case VPC_BOARD: return "VPC_BOARD"; case HYPERV_WMI: return "HYPERV_WMI"; case HYPERV_REG: return "HYPERV_REG"; case BIOS_SERIAL: return "BIOS_SERIAL"; @@ -10499,7 +10401,6 @@ static bool rdtsc() { case OFFSEC_SIDT: return "OFFSEC_SIDT"; case OFFSEC_SGDT: return "OFFSEC_SGDT"; case OFFSEC_SLDT: return "OFFSEC_SLDT"; - case HYPERV_BOARD: return "HYPERV_BOARD"; case VPC_SIDT: return "VPC_SIDT"; case VMWARE_IOMEM: return "VMWARE_IOMEM"; case VMWARE_IOPORTS: return "VMWARE_IOPORTS"; @@ -10565,6 +10466,8 @@ static bool rdtsc() { case SYS_QEMU: return "SYS_QEMU"; case LSHW_QEMU: return "LSHW_QEMU"; case VIRTUAL_PROCESSORS: return "VIRTUAL_PROCESSORS"; + case MOTHERBOARD_PRODUCT: return "MOTHERBOARD_PRODUCT"; + // ADD NEW CASE HERE FOR NEW TECHNIQUE default: return "Unknown flag"; } @@ -11029,7 +10932,6 @@ std::pair VM::core::technique_list[] = { { VM::PARALLELS_VM, { 50, VM::parallels, false } }, { VM::QEMU_BRAND, { 100, VM::cpu_brand_qemu, false } }, { VM::BOCHS_CPU, { 100, VM::bochs_cpu, false } }, - { VM::VPC_BOARD, { 25, VM::vpc_board, false } }, { VM::BIOS_SERIAL, { 60, VM::bios_serial, false } }, { VM::MSSMBIOS, { 75, VM::mssmbios, false } }, { VM::MAC_MEMSIZE, { 15, VM::hw_memsize, true } }, @@ -11046,7 +10948,6 @@ std::pair VM::core::technique_list[] = { { VM::OFFSEC_SGDT, { 60, VM::offsec_sgdt, false } }, { VM::OFFSEC_SLDT, { 20, VM::offsec_sldt, false } }, { VM::VPC_SIDT, { 15, VM::vpc_sidt, false } }, - { VM::HYPERV_BOARD, { 100, VM::hyperv_board, false } }, { VM::VMWARE_IOMEM, { 65, VM::vmware_iomem, false } }, { VM::VMWARE_IOPORTS, { 70, VM::vmware_ioports, false } }, { VM::VMWARE_SCSI, { 40, VM::vmware_scsi, false } }, @@ -11091,7 +10992,7 @@ std::pair VM::core::technique_list[] = { { VM::DRIVER_NAMES, { 80, VM::driver_names, false } }, { VM::VM_SIDT, { 100, VM::vm_sidt, false } }, { VM::HDD_SERIAL, { 100, VM::hdd_serial_number, false } }, - { VM::PORT_CONNECTORS, { 15, VM::port_connectors, false } }, + { VM::PORT_CONNECTORS, { 10, VM::port_connectors, false } }, { VM::VM_HDD, { 90, VM::vm_hdd, false } }, { VM::ACPI_DETECT, { 85, VM::acpi_detect, false } }, { VM::GPU_NAME, { 100, VM::vm_gpu, false } }, @@ -11109,6 +11010,7 @@ std::pair VM::core::technique_list[] = { { VM::SYS_QEMU, { 70, VM::sys_qemu_dir, false } }, { VM::LSHW_QEMU, { 80, VM::lshw_qemu, false } }, { VM::VIRTUAL_PROCESSORS, { 35, VM::virtual_processors, false } }, + { VM::MOTHERBOARD_PRODUCT, { 25, VM::motherboard_product, false } }, // ADD NEW TECHNIQUE STRUCTURE HERE }; diff --git a/src/vmaware_MIT.hpp b/src/vmaware_MIT.hpp index f029cf0..c11a902 100644 --- a/src/vmaware_MIT.hpp +++ b/src/vmaware_MIT.hpp @@ -25,13 +25,13 @@ * * ================================ SECTIONS ================================== * - enums for publicly accessible techniques => line 327 - * - struct for internal cpu operations => line 592 - * - struct for internal memoization => line 1053 - * - struct for internal utility functions => line 1439 - * - struct for internal core components => line 9227 - * - start of internal VM detection techniques => line 3036 - * - start of public VM detection functions => line 9630 - * - start of externally defined variables => line 10501 + * - struct for internal cpu operations => line 499 + * - struct for internal memoization => line 1059 + * - struct for internal utility functions => line 1431 + * - struct for internal core components => line 9453 + * - start of internal VM detection techniques => line 2990 + * - start of public VM detection functions => line 9851 + * - start of externally defined variables => line 10720 * * * ================================ EXAMPLE ================================== @@ -355,7 +355,6 @@ struct VM { PARALLELS_VM, QEMU_BRAND, BOCHS_CPU, - VPC_BOARD, HYPERV_WMI, HYPERV_REG, BIOS_SERIAL, @@ -373,7 +372,6 @@ struct VM { OFFSEC_SIDT, OFFSEC_SGDT, OFFSEC_SLDT, - HYPERV_BOARD, VPC_SIDT, VMWARE_IOMEM, VMWARE_IOPORTS, @@ -434,10 +432,10 @@ struct VM { PROCESSOR_ID, CPU_FANS, VMWARE_HARDENER, - WMI_QUERIES, SYS_QEMU, LSHW_QEMU, VIRTUAL_PROCESSORS, + MOTHERBOARD_PRODUCT, // ADD NEW TECHNIQUE ENUM NAME HERE // start of settings technique flags (THE ORDERING IS VERY SPECIFIC HERE AND MIGHT BREAK SOMETHING IF RE-ORDERED) @@ -1264,7 +1262,6 @@ struct VM { return memo::wmi::fetch(); } - // this will clean up wmi when the program terminates std::atexit(wmi::cleanup); if (pSvc != nullptr) { @@ -1273,80 +1270,70 @@ struct VM { } HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); + bool shouldUninitialize = false; + if (FAILED(hres)) { - debug("wmi: Failed to initialize COM library. Error code = ", hres); - memo::wmi::store(false); - return false; + if (hres == RPC_E_CHANGED_MODE) { + debug("wmi: COM already initialized with a different mode, continuing..."); + } + else { + debug("wmi: Failed to initialize COM library. Error code = ", hres); + memo::wmi::store(false); + return false; + } + } + else { + shouldUninitialize = true; } hres = CoInitializeSecurity( - NULL, - -1, - NULL, - NULL, + NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, - NULL, - EOAC_NONE, - NULL + NULL, EOAC_NONE, NULL ); if (FAILED(hres)) { - CoUninitialize(); + if (shouldUninitialize) CoUninitialize(); debug("wmi: Failed to initialize security. Error code = ", hres); memo::wmi::store(false); return false; } hres = CoCreateInstance( - CLSID_WbemLocator, - 0, - CLSCTX_INPROC_SERVER, - IID_IWbemLocator, - (LPVOID*)&pLoc + CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID*)&pLoc ); if (FAILED(hres)) { - CoUninitialize(); + if (shouldUninitialize) CoUninitialize(); debug("wmi: Failed to create IWbemLocator object. Error code = ", hres); memo::wmi::store(false); return false; } hres = pLoc->ConnectServer( - _bstr_t(L"ROOT\\CIMV2"), - NULL, - NULL, - 0, - NULL, - 0, - 0, - &pSvc + _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc ); if (FAILED(hres)) { pLoc->Release(); - CoUninitialize(); + if (shouldUninitialize) CoUninitialize(); debug("wmi: Could not connect to WMI server. Error code = ", hres); memo::wmi::store(false); return false; } hres = CoSetProxyBlanket( - pSvc, - RPC_C_AUTHN_WINNT, - RPC_C_AUTHZ_NONE, - NULL, - RPC_C_AUTHN_LEVEL_CALL, - RPC_C_IMP_LEVEL_IMPERSONATE, - NULL, - EOAC_NONE + pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, + RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, + NULL, EOAC_NONE ); if (FAILED(hres)) { pSvc->Release(); pLoc->Release(); - CoUninitialize(); + if (shouldUninitialize) CoUninitialize(); debug("wmi: Could not set proxy blanket. Error code = ", hres); memo::wmi::store(false); return false; @@ -2010,17 +1997,6 @@ struct VM { return result; }; - // motherboard check - auto is_motherboard_hyperv = []() -> bool { - const bool motherboard = motherboard_string("Microsoft Corporation"); - - if (motherboard) { - core_debug("HYPER_X: motherboard string match = ", motherboard); - } - - return motherboard; - }; - // event log check (slow, so in last place) auto is_event_log_hyperv = []() -> bool { @@ -2072,7 +2048,6 @@ struct VM { eax() == 11 || is_smbios_hyperv() || is_acpi_hyperv() || - is_motherboard_hyperv() || is_event_log_hyperv() ); @@ -2593,26 +2568,6 @@ struct VM { } - [[nodiscard]] static bool motherboard_string(const char* vm_string) { - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in motherboard_string"); - return false; - } - - wmi_result results = wmi::execute(L"SELECT * FROM Win32_BaseBoard", { L"Manufacturer" }); - - for (const auto& res : results) { - if (res.type == wmi::result_type::String) { - if (_stricmp(res.strValue.c_str(), vm_string) == 0) { - return true; - } - } - } - - return false; - } - - /** * @brief Retrieves the last error message from the Windows API. Useful for __VMAWARE_DEBUG__ * @author Requiem (https://github.com/NotRequiem) @@ -2937,11 +2892,6 @@ struct VM { }; auto GetThreadsUsingWMI = []() -> int { - if (!wmi::initialize()) { - std::cerr << "Failed to initialize WMI in GetThreadsUsingWMI.\n"; - return 1; - } - wmi_result results = wmi::execute(L"SELECT NumberOfLogicalProcessors FROM Win32_Processor", { L"NumberOfLogicalProcessors" }); for (const auto& res : results) { if (res.type == wmi::result_type::Integer) { @@ -2949,7 +2899,7 @@ struct VM { } } - return 1; + return 0; }; auto GetThreadsUsingGetSystemInfo = []() -> int { @@ -4365,25 +4315,6 @@ struct VM { } - /** - * @brief Check through the motherboard and match for VirtualPC-specific string - * @category Windows - */ - [[nodiscard]] static bool vpc_board() { -#if (!WINDOWS) - return false; -#else - const bool is_vm = util::motherboard_string("Microsoft Corporation"); - - if (is_vm) { - return core::add(brands::VPC); - } - - return false; -#endif - } - - /** * @brief Check if the BIOS serial is valid (null = VM) * @category Windows @@ -5070,34 +5001,6 @@ struct VM { } - /** - * @brief Check for Hyper-V specific string in motherboard - * @category Windows - */ - [[nodiscard]] static bool hyperv_board() { -#if (!WINDOWS) - return false; -#else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in hyperv_board"); - return false; - } - - wmi_result results = wmi::execute(L"SELECT * FROM Win32_BaseBoard", { L"Manufacturer" }); - - for (const auto& res : results) { - if (res.type == wmi::result_type::String) { - if (_stricmp(res.strValue.c_str(), "Microsoft Corporation Virtual Machine") == 0) { - return core::add(brands::HYPERV); - } - } - } - - return false; // No match found -#endif - } - - /** * @brief Check for sidt method with VPC's 0xE8XXXXXX range * @category Windows, x86 @@ -8275,11 +8178,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in gpu_chiptype"); - return false; - } - wmi_result results = wmi::execute(L"SELECT * FROM Win32_VideoController", { L"VideoProcessor" }); std::string result = ""; @@ -8457,11 +8355,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in hdd_serial_number"); - return false; - } - const char* targetSerial = "VBbd5bbffd-59166c24"; wmi_result results = wmi::execute(L"SELECT SerialNumber FROM Win32_DiskDrive", { L"SerialNumber" }); @@ -8488,12 +8381,22 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in port_connectors"); - return false; + std::wstring query = L"SELECT Product FROM Win32_BaseBoard"; + std::vector properties = { L"Product" }; + wmi_result results = wmi::execute(query, properties); + + for (const auto& res : results) { + if (res.type == wmi::result_type::String) { + std::string lowerStr = res.strValue; + std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(), ::tolower); + + if (lowerStr.find("surface") != std::string::npos) { // This WMI query returns false for Surface Pro devices + return false; + } + } } - wmi_result results = wmi::execute(L"SELECT * FROM Win32_PortConnector", { L"Caption" }); + wmi_result portResults = wmi::execute(L"SELECT * FROM Win32_PortConnector", { L"Caption" }); return results.empty(); #endif @@ -8508,11 +8411,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in vm_hdd"); - return false; - } - wmi_result results = wmi::execute(L"SELECT Model FROM Win32_DiskDrive", { L"Model" }); for (const auto& res : results) { @@ -8797,11 +8695,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in number_of_cores"); - return false; - } - std::wstring query = L"SELECT NumberOfCores FROM Win32_Processor"; std::vector properties = { L"NumberOfCores" }; @@ -8829,11 +8722,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in number_of_cores"); - return false; - } - std::wstring query = L"SELECT Model FROM Win32_ComputerSystem"; std::vector properties = { L"Model" }; wmi_result results = wmi::execute(query, properties); @@ -8859,11 +8747,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in wmi_manufacturer"); - return false; - } - std::wstring query = L"SELECT Manufacturer FROM Win32_ComputerSystem"; std::vector properties = { L"Manufacturer" }; wmi_result results = wmi::execute(query, properties); @@ -8889,11 +8772,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in wmi_temperature"); - return false; - } - std::wstring query = L"SELECT * FROM MSAcpi_ThermalZoneTemperature"; std::vector properties = { L"CurrentTemperature" }; @@ -8919,11 +8797,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in processor_id"); - return false; - } - std::wstring query = L"SELECT ProcessorId FROM Win32_Processor"; std::vector properties = { L"ProcessorId" }; wmi_result results = wmi::execute(query, properties); @@ -8949,11 +8822,6 @@ struct VM { #if (!WINDOWS) return false; #else - if (!wmi::initialize()) { - core_debug("Failed to initialize WMI in cpu_fans"); - return false; - } - std::wstring query = L"SELECT * FROM Win32_Fan"; std::vector properties = { }; wmi_result results = wmi::execute(query, properties); @@ -9085,7 +8953,6 @@ struct VM { /** * @brief Check for existence of qemu_fw_cfg directories within sys/module and /sys/firmware * @category Linux - * @note */ [[nodiscard]] static bool sys_qemu_dir() { #if (!LINUX) @@ -9126,7 +8993,6 @@ struct VM { /** * @brief Check for QEMU string instances with lshw command * @category Linux - * @note */ [[nodiscard]] static bool lshw_qemu() { #if (!LINUX) @@ -9174,7 +9040,7 @@ struct VM { * @note https://medium.com/@matterpreter/hypervisor-detection-with-systemhypervisordetailinformation-26e44a57f80e */ [[nodiscard]] static bool virtual_processors() { -#if (!WINDOWS || !x86_64) +#if (!WINDOWS) return false; #else struct Registers { @@ -9203,6 +9069,30 @@ struct VM { #endif } + + /* + * @brief Detects if the motherboard product matches the signature of a virtual machine + * @category Windows + * @author Requiem + */ + [[nodiscard]] static bool motherboard_product() { +#if (!WINDOWS) + return false; +#else + std::wstring query = L"SELECT Product FROM Win32_BaseBoard"; + std::vector properties = { L"Product" }; + wmi_result results = wmi::execute(query, properties); + + for (const auto& res : results) { + if (res.type == wmi::result_type::String && res.strValue == "Virtual Machine") { + return true; + } + } + + return false; +#endif + } + // ADD NEW TECHNIQUE FUNCTION HERE @@ -10162,7 +10052,6 @@ struct VM { case PARALLELS_VM: return "PARALLELS_VM"; case QEMU_BRAND: return "QEMU_BRAND"; case BOCHS_CPU: return "BOCHS_CPU"; - case VPC_BOARD: return "VPC_BOARD"; case HYPERV_WMI: return "HYPERV_WMI"; case HYPERV_REG: return "HYPERV_REG"; case BIOS_SERIAL: return "BIOS_SERIAL"; @@ -10180,7 +10069,6 @@ struct VM { case OFFSEC_SIDT: return "OFFSEC_SIDT"; case OFFSEC_SGDT: return "OFFSEC_SGDT"; case OFFSEC_SLDT: return "OFFSEC_SLDT"; - case HYPERV_BOARD: return "HYPERV_BOARD"; case VPC_SIDT: return "VPC_SIDT"; case VMWARE_IOMEM: return "VMWARE_IOMEM"; case VMWARE_IOPORTS: return "VMWARE_IOPORTS"; @@ -10240,10 +10128,14 @@ struct VM { case WMI_TEMPERATURE: return "WMI_TEMPERATURE"; case PROCESSOR_ID: return "PROCESSOR_ID"; case CPU_FANS: return "CPU_FANS"; + case POWER_CAPABILITIES: return "POWER_CAPABILITIES"; + case SETUPAPI_DISK: return "SETUPAPI_DISK"; case VMWARE_HARDENER: return "VMWARE_HARDENER_LOADER"; case SYS_QEMU: return "SYS_QEMU"; case LSHW_QEMU: return "LSHW_QEMU"; case VIRTUAL_PROCESSORS: return "VIRTUAL_PROCESSORS"; + case MOTHERBOARD_PRODUCT: return "MOTHERBOARD_PRODUCT"; + // ADD NEW CASE HERE FOR NEW TECHNIQUE default: return "Unknown flag"; } @@ -10340,7 +10232,6 @@ struct VM { { brands::AZURE_HYPERV, "Hypervisor (type 1)" }, { brands::NANOVISOR, "Hypervisor (type 1)" }, { brands::KVM, "Hypervisor (type 1)" }, - { brands::BHYVE, "Hypervisor (type 1)" }, { brands::KVM_HYPERV, "Hypervisor (type 1)" }, { brands::QEMU_KVM_HYPERV, "Hypervisor (type 1)" }, { brands::QEMU_KVM, "Hypervisor (type 1)" }, @@ -10354,6 +10245,7 @@ struct VM { { brands::AWS_NITRO, "Hypervisor (type 1)" }, // type 2 + { brands::BHYVE, "Hypervisor (type 2)" }, { brands::VBOX, "Hypervisor (type 2)" }, { brands::VMWARE, "Hypervisor (type 2)" }, { brands::VMWARE_EXPRESS, "Hypervisor (type 2)" }, @@ -10694,94 +10586,93 @@ std::pair VM::core::technique_list[] = { { VM::DISK_SIZE, { 60, VM::disk_size, false } }, { VM::VBOX_DEFAULT, { 25, VM::vbox_default_specs, false } }, { VM::VBOX_NETWORK, { 100, VM::vbox_network_share, false } }, - { VM::VM_PROCESSES, { 15, VM::vm_processes, true } }, - { VM::LINUX_USER_HOST, { 10, VM::linux_user_host, true } }, - { VM::GAMARUE, { 10, VM::gamarue, true } }, - { VM::VMID_0X4, { 100, VM::vmid_0x4, false } }, - { VM::PARALLELS_VM, { 50, VM::parallels, false } }, - { VM::QEMU_BRAND, { 100, VM::cpu_brand_qemu, false } }, - { VM::BOCHS_CPU, { 100, VM::bochs_cpu, false } }, - { VM::VPC_BOARD, { 25, VM::vpc_board, false } }, - { VM::BIOS_SERIAL, { 60, VM::bios_serial, false } }, - { VM::MSSMBIOS, { 75, VM::mssmbios, false } }, - { VM::MAC_MEMSIZE, { 15, VM::hw_memsize, true } }, - { VM::MAC_IOKIT, { 40, VM::io_kit, true } }, - { VM::IOREG_GREP, { 30, VM::ioreg_grep, true } }, - { VM::MAC_SIP, { 40, VM::mac_sip, true } }, - { VM::HKLM_REGISTRIES, { 25, VM::hklm_registries, true } }, - { VM::QEMU_GA, { 10, VM::qemu_ga, true } }, - { VM::VPC_INVALID, { 75, VM::vpc_invalid, false } }, - { VM::SIDT, { 25, VM::sidt, false } }, - { VM::SGDT, { 30, VM::sgdt, false } }, - { VM::SLDT, { 15, VM::sldt, false } }, - { VM::OFFSEC_SIDT, { 60, VM::offsec_sidt, false } }, - { VM::OFFSEC_SGDT, { 60, VM::offsec_sgdt, false } }, - { VM::OFFSEC_SLDT, { 20, VM::offsec_sldt, false } }, - { VM::VPC_SIDT, { 15, VM::vpc_sidt, false } }, - { VM::HYPERV_BOARD, { 100, VM::hyperv_board, false } }, - { VM::VMWARE_IOMEM, { 65, VM::vmware_iomem, false } }, - { VM::VMWARE_IOPORTS, { 70, VM::vmware_ioports, false } }, - { VM::VMWARE_SCSI, { 40, VM::vmware_scsi, false } }, - { VM::VMWARE_DMESG, { 65, VM::vmware_dmesg, false } }, - { VM::VMWARE_STR, { 35, VM::vmware_str, false } }, - { VM::VMWARE_BACKDOOR, { 100, VM::vmware_backdoor, false } }, - { VM::VMWARE_PORT_MEM, { 85, VM::vmware_port_memory, false } }, - { VM::SMSW, { 30, VM::smsw, false } }, - { VM::MUTEX, { 85, VM::mutex, false } }, - { VM::ODD_CPU_THREADS, { 80, VM::odd_cpu_threads, false } }, - { VM::INTEL_THREAD_MISMATCH, { 50, VM::intel_thread_mismatch, false } }, - { VM::XEON_THREAD_MISMATCH, { 85, VM::xeon_thread_mismatch, false } }, - { VM::NETTITUDE_VM_MEMORY, { 100, VM::nettitude_vm_memory, false } }, - { VM::CPUID_BITSET, { 25, VM::cpuid_bitset, false } }, - { VM::CUCKOO_DIR, { 30, VM::cuckoo_dir, true } }, - { VM::CUCKOO_PIPE, { 30, VM::cuckoo_pipe, true } }, - { VM::HYPERV_HOSTNAME, { 30, VM::hyperv_hostname, true } }, - { VM::GENERAL_HOSTNAME, { 10, VM::general_hostname, true } }, - { VM::SCREEN_RESOLUTION, { 20, VM::screen_resolution, false } }, - { VM::DEVICE_STRING, { 25, VM::device_string, false } }, - { VM::BLUESTACKS_FOLDERS, { 5, VM::bluestacks, true } }, - { VM::CPUID_SIGNATURE, { 95, VM::cpuid_signature, false } }, - { VM::HYPERV_BITMASK, { 20, VM::hyperv_bitmask, false } }, - { VM::KVM_BITMASK, { 40, VM::kvm_bitmask, false } }, - { VM::KGT_SIGNATURE, { 80, VM::intel_kgt_signature, false } }, - { VM::VMWARE_DMI, { 40, VM::vmware_dmi, false } }, - { VM::VMWARE_EVENT_LOGS, { 25, VM::vmware_event_logs, false } }, - { VM::QEMU_VIRTUAL_DMI, { 40, VM::qemu_virtual_dmi, false } }, - { VM::QEMU_USB, { 20, VM::qemu_USB, false } }, - { VM::HYPERVISOR_DIR, { 20, VM::hypervisor_dir, false } }, - { VM::UML_CPU, { 80, VM::uml_cpu, false } }, - { VM::KMSG, { 5, VM::kmsg, true } }, - { VM::VM_PROCS, { 10, VM::vm_procs, true } }, - { VM::VBOX_MODULE, { 15, VM::vbox_module, false } }, - { VM::SYSINFO_PROC, { 15, VM::sysinfo_proc, false } }, - { VM::DEVICE_TREE, { 20, VM::device_tree, false } }, - { VM::DMI_SCAN, { 50, VM::dmi_scan, false } }, - { VM::SMBIOS_VM_BIT, { 50, VM::smbios_vm_bit, false } }, - { VM::PODMAN_FILE, { 5, VM::podman_file, true } }, - { VM::WSL_PROC, { 30, VM::wsl_proc_subdir, false } }, - { VM::GPU_CHIPTYPE, { 100, VM::gpu_chiptype, false } }, - { VM::DRIVER_NAMES, { 80, VM::driver_names, false } }, - { VM::VM_SIDT, { 100, VM::vm_sidt, false } }, - { VM::HDD_SERIAL, { 100, VM::hdd_serial_number, false } }, - { VM::PORT_CONNECTORS, { 15, VM::port_connectors, false } }, - { VM::VM_HDD, { 90, VM::vm_hdd, false } }, - { VM::ACPI_DETECT, { 85, VM::acpi_detect, false } }, - { VM::GPU_NAME, { 100, VM::vm_gpu, false } }, - { VM::VM_DEVICES, { 45, VM::vm_devices, true } }, - { VM::VMWARE_MEMORY, { 50, VM::vmware_memory, false } }, - { VM::IDT_GDT_MISMATCH, { 50, VM::idt_gdt_mismatch, false } }, - { VM::PROCESSOR_NUMBER, { 25, VM::processor_number, false } }, - { VM::NUMBER_OF_CORES, { 50, VM::number_of_cores, false } }, - { VM::WMI_MODEL, { 100, VM::wmi_model, false } }, - { VM::WMI_MANUFACTURER, { 100, VM::wmi_manufacturer, false } }, - { VM::WMI_TEMPERATURE, { 25, VM::wmi_temperature, false } }, - { VM::PROCESSOR_ID, { 25, VM::processor_id, false } }, - { VM::CPU_FANS, { 35, VM::cpu_fans, false } }, - { VM::VMWARE_HARDENER, { 60, VM::vmware_hardener, false } }, - { VM::SYS_QEMU, { 70, VM::sys_qemu_dir, false } }, - { VM::LSHW_QEMU, { 80, VM::lshw_qemu, false } }, - { VM::VIRTUAL_PROCESSORS, { 35, VM::virtual_processors, false } }, - // ADD NEW TECHNIQUE STRUCTURE HERE + { VM::VM_PROCESSES, { 15, VM::vm_processes, true } }, + { VM::LINUX_USER_HOST, { 10, VM::linux_user_host, true } }, + { VM::GAMARUE, { 10, VM::gamarue, true } }, + { VM::VMID_0X4, { 100, VM::vmid_0x4, false } }, + { VM::PARALLELS_VM, { 50, VM::parallels, false } }, + { VM::QEMU_BRAND, { 100, VM::cpu_brand_qemu, false } }, + { VM::BOCHS_CPU, { 100, VM::bochs_cpu, false } }, + { VM::BIOS_SERIAL, { 60, VM::bios_serial, false } }, + { VM::MSSMBIOS, { 75, VM::mssmbios, false } }, + { VM::MAC_MEMSIZE, { 15, VM::hw_memsize, true } }, + { VM::MAC_IOKIT, { 40, VM::io_kit, true } }, + { VM::IOREG_GREP, { 30, VM::ioreg_grep, true } }, + { VM::MAC_SIP, { 40, VM::mac_sip, true } }, + { VM::HKLM_REGISTRIES, { 25, VM::hklm_registries, true } }, + { VM::QEMU_GA, { 10, VM::qemu_ga, true } }, + { VM::VPC_INVALID, { 75, VM::vpc_invalid, false } }, + { VM::SIDT, { 25, VM::sidt, false } }, + { VM::SGDT, { 30, VM::sgdt, false } }, + { VM::SLDT, { 15, VM::sldt, false } }, + { VM::OFFSEC_SIDT, { 60, VM::offsec_sidt, false } }, + { VM::OFFSEC_SGDT, { 60, VM::offsec_sgdt, false } }, + { VM::OFFSEC_SLDT, { 20, VM::offsec_sldt, false } }, + { VM::VPC_SIDT, { 15, VM::vpc_sidt, false } }, + { VM::VMWARE_IOMEM, { 65, VM::vmware_iomem, false } }, + { VM::VMWARE_IOPORTS, { 70, VM::vmware_ioports, false } }, + { VM::VMWARE_SCSI, { 40, VM::vmware_scsi, false } }, + { VM::VMWARE_DMESG, { 65, VM::vmware_dmesg, false } }, + { VM::VMWARE_STR, { 35, VM::vmware_str, false } }, + { VM::VMWARE_BACKDOOR, { 100, VM::vmware_backdoor, false } }, + { VM::VMWARE_PORT_MEM, { 85, VM::vmware_port_memory, false } }, + { VM::SMSW, { 30, VM::smsw, false } }, + { VM::MUTEX, { 85, VM::mutex, false } }, + { VM::ODD_CPU_THREADS, { 80, VM::odd_cpu_threads, false } }, + { VM::INTEL_THREAD_MISMATCH, { 50, VM::intel_thread_mismatch, false } }, + { VM::XEON_THREAD_MISMATCH, { 85, VM::xeon_thread_mismatch, false } }, + { VM::NETTITUDE_VM_MEMORY, { 100, VM::nettitude_vm_memory, false } }, + { VM::CPUID_BITSET, { 25, VM::cpuid_bitset, false } }, + { VM::CUCKOO_DIR, { 30, VM::cuckoo_dir, true } }, + { VM::CUCKOO_PIPE, { 30, VM::cuckoo_pipe, true } }, + { VM::HYPERV_HOSTNAME, { 30, VM::hyperv_hostname, true } }, + { VM::GENERAL_HOSTNAME, { 10, VM::general_hostname, true } }, + { VM::SCREEN_RESOLUTION, { 20, VM::screen_resolution, false } }, + { VM::DEVICE_STRING, { 25, VM::device_string, false } }, + { VM::BLUESTACKS_FOLDERS, { 5, VM::bluestacks, true } }, + { VM::CPUID_SIGNATURE, { 95, VM::cpuid_signature, false } }, + { VM::HYPERV_BITMASK, { 20, VM::hyperv_bitmask, false } }, + { VM::KVM_BITMASK, { 40, VM::kvm_bitmask, false } }, + { VM::KGT_SIGNATURE, { 80, VM::intel_kgt_signature, false } }, + { VM::VMWARE_DMI, { 40, VM::vmware_dmi, false } }, + { VM::VMWARE_EVENT_LOGS, { 25, VM::vmware_event_logs, false } }, + { VM::QEMU_VIRTUAL_DMI, { 40, VM::qemu_virtual_dmi, false } }, + { VM::QEMU_USB, { 20, VM::qemu_USB, false } }, + { VM::HYPERVISOR_DIR, { 20, VM::hypervisor_dir, false } }, + { VM::UML_CPU, { 80, VM::uml_cpu, false } }, + { VM::KMSG, { 5, VM::kmsg, true } }, + { VM::VM_PROCS, { 10, VM::vm_procs, true } }, + { VM::VBOX_MODULE, { 15, VM::vbox_module, false } }, + { VM::SYSINFO_PROC, { 15, VM::sysinfo_proc, false } }, + { VM::DEVICE_TREE, { 20, VM::device_tree, false } }, + { VM::DMI_SCAN, { 50, VM::dmi_scan, false } }, + { VM::SMBIOS_VM_BIT, { 50, VM::smbios_vm_bit, false } }, + { VM::PODMAN_FILE, { 5, VM::podman_file, true } }, + { VM::WSL_PROC, { 30, VM::wsl_proc_subdir, false } }, + { VM::GPU_CHIPTYPE, { 100, VM::gpu_chiptype, false } }, + { VM::DRIVER_NAMES, { 80, VM::driver_names, false } }, + { VM::VM_SIDT, { 100, VM::vm_sidt, false } }, + { VM::HDD_SERIAL, { 100, VM::hdd_serial_number, false } }, + { VM::PORT_CONNECTORS, { 10, VM::port_connectors, false } }, + { VM::VM_HDD, { 90, VM::vm_hdd, false } }, + { VM::ACPI_DETECT, { 85, VM::acpi_detect, false } }, + { VM::GPU_NAME, { 100, VM::vm_gpu, false } }, + { VM::VM_DEVICES, { 45, VM::vm_devices, true } }, + { VM::VMWARE_MEMORY, { 50, VM::vmware_memory, false } }, + { VM::IDT_GDT_MISMATCH, { 50, VM::idt_gdt_mismatch, false } }, + { VM::PROCESSOR_NUMBER, { 25, VM::processor_number, false } }, + { VM::NUMBER_OF_CORES, { 50, VM::number_of_cores, false } }, + { VM::WMI_MODEL, { 100, VM::wmi_model, false } }, + { VM::WMI_MANUFACTURER, { 100, VM::wmi_manufacturer, false } }, + { VM::WMI_TEMPERATURE, { 25, VM::wmi_temperature, false } }, + { VM::PROCESSOR_ID, { 25, VM::processor_id, false } }, + { VM::CPU_FANS, { 35, VM::cpu_fans, false } }, + { VM::VMWARE_HARDENER, { 60, VM::vmware_hardener, false } }, + { VM::SYS_QEMU, { 70, VM::sys_qemu_dir, false } }, + { VM::LSHW_QEMU, { 80, VM::lshw_qemu, false } }, + { VM::VIRTUAL_PROCESSORS, { 35, VM::virtual_processors, false } }, + { VM::MOTHERBOARD_PRODUCT, { 25, VM::motherboard_product, false } }, + // ADD NEW TECHNIQUE STRUCTURE HERE }; From 06e1db33a3c65b7d322da2df81354f86e7f2a53d Mon Sep 17 00:00:00 2001 From: Requiem Date: Tue, 21 Jan 2025 22:49:48 +0100 Subject: [PATCH 2/2] Added HvlQueryDetailInfo technique --- docs/documentation.md | 5 +- src/cli.cpp | 2 + src/vmaware.hpp | 140 ++++++++++++++++++++++++++++++++---------- 3 files changed, 111 insertions(+), 36 deletions(-) diff --git a/docs/documentation.md b/docs/documentation.md index e6572ca..64b63f9 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -454,8 +454,9 @@ VMAware provides a convenient way to not only check for VMs, but also have the f | `VM::WMI_QUERIES` | Executes generic WMI queries that always return more than 0 entries in physical machines and checks if any query returns zero entries | Windows | 50% | | GPL | | | | `VM::SYS_QEMU` | Check for existence of "qemu_fw_cfg" directories within /sys/module and /sys/firmware | Linux | 70% | | | | | | `VM::LSHW_QEMU` | Check for QEMU string instances with lshw command | Linux | 80% | | | | | -| `VM::VIRTUAL_PROCESSORS` | Checks if the number of maximum virtual processors matches the maximum number of logical processors | Windows | 35% | | | | | -| `VM::MOTHERBOARD_PRODUCT` | Check if the motherboard product string matches "Virtual Machine" | Windows | 25% | | | | | +| `VM::VIRTUAL_PROCESSORS` | Checks if the number of maximum virtual processors matches the maximum number of logical processors | Windows | 50% | | | | | +| `VM::MOTHERBOARD_PRODUCT` | Check if the motherboard product string matches "Virtual Machine" | Windows | 50% | | | | | +| `VM::HVLQUERYDETAILINFO` | Checks if a call to NtQuerySystemInformation with the 0x9f leaf fills a _SYSTEM_HYPERVISOR_DETAIL_INFORMATION structure | Windows | 50% | | | | | diff --git a/src/cli.cpp b/src/cli.cpp index 3991daf..e5faa5b 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -466,6 +466,7 @@ bool is_unsupported(VM::enum_flags flag) { case VM::VMWARE_HARDENER: case VM::VIRTUAL_PROCESSORS: case VM::MOTHERBOARD_PRODUCT: + case VM::HVLQUERYDETAILINFO: // ADD WINDOWS FLAG return false; default: return true; @@ -968,6 +969,7 @@ void general() { checker(VM::LSHW_QEMU, "QEMU in lshw output"); checker(VM::VIRTUAL_PROCESSORS, "virtual processors"); checker(VM::MOTHERBOARD_PRODUCT, "motherboard product"); + checker(VM::HVLQUERYDETAILINFO, "HvlQueryDetailInfo"); // ADD NEW TECHNIQUE CHECKER HERE std::printf("\n"); diff --git a/src/vmaware.hpp b/src/vmaware.hpp index 4653a35..610b6a7 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -194,6 +194,7 @@ #include #include #include +#include #include #include #include @@ -445,6 +446,7 @@ struct VM { LSHW_QEMU, VIRTUAL_PROCESSORS, MOTHERBOARD_PRODUCT, + HVLQUERYDETAILINFO, // ADD NEW TECHNIQUE ENUM NAME HERE // start of settings technique flags (THE ORDERING IS VERY SPECIFIC HERE AND MIGHT BREAK SOMETHING IF RE-ORDERED) @@ -2004,9 +2006,6 @@ struct VM { // event log check (slow, so in last place) auto is_event_log_hyperv = []() -> bool { -#if (!x86_64) - return false; -#else std::wstring logName = L"Microsoft-Windows-Kernel-PnP/Configuration"; std::vector searchStrings = { L"Virtual_Machine", L"VMBUS" }; const bool result = (util::query_event_logs(logName, searchStrings)); @@ -2016,7 +2015,6 @@ struct VM { } return result; -#endif }; @@ -2574,7 +2572,6 @@ struct VM { /** * @brief Retrieves the last error message from the Windows API. Useful for __VMAWARE_DEBUG__ - * @author Requiem (https://github.com/NotRequiem) * @return A std::wstring containing the error message. */ [[nodiscard]] static std::wstring GetLastErrorString() { @@ -2609,9 +2606,6 @@ struct VM { DWORD flags = EvtQueryReverseDirection, DWORD timeout = INFINITE, const DWORD maxEvents = 1000) { -#if (!x86_64) - return false; -#else EVT_HANDLE hLog = EvtOpenLog(nullptr, logName.c_str(), EvtOpenChannelPath); if (!hLog) { @@ -2632,11 +2626,10 @@ struct VM { DWORD count = 0; WCHAR* pBuffer = nullptr; - // Iterate over events up to the maximum number specified for (DWORD eventCount = 0; eventCount < maxEvents; ++eventCount) { if (!EvtNext(hResults, 1, &hEvent, timeout, 0, &count)) { if (GetLastError() == ERROR_NO_MORE_ITEMS) { - break; // No more events to process + break; } std::wcerr << L"EvtNext failed. Error: " << GetLastErrorString() << "\n"; EvtClose(hResults); @@ -2695,7 +2688,6 @@ struct VM { EvtClose(hLog); return false; -#endif } @@ -2753,7 +2745,7 @@ struct VM { * * @return bool `true` if `searchString` is found in `buffer`, `false` otherwise. */ - static bool findSubstring(const wchar_t* buffer, size_t bufferSize, const std::wstring& searchString) { + static bool findSubstring(const wchar_t* buffer, const size_t bufferSize, const std::wstring& searchString) { size_t searchLength = searchString.length(); if (searchLength > bufferSize) return false; @@ -5004,27 +4996,41 @@ struct VM { #else u8 count = 0; - auto check_key = [&count](const char* p_brand, const char* subKey, const char* valueName, const char* comp_string) { + std::unordered_set failedKeys; + + auto check_key = [&failedKeys, &count](const char* p_brand, const char* subKey, const char* valueName, const char* comp_string) { + if (failedKeys.find(subKey) != failedKeys.end()) { + return; + } + HKEY hKey; - DWORD dwType = REG_SZ; - char buffer[1024]{}; + DWORD dwType; + char buffer[1024] = {}; DWORD bufferSize = sizeof(buffer); - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { - if (RegQueryValueExA(hKey, valueName, NULL, &dwType, reinterpret_cast(buffer), &bufferSize) == ERROR_SUCCESS) { - if (strstr(buffer, comp_string) != nullptr) { - core::add(p_brand); - count++; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS) { + if (RegQueryValueExA(hKey, valueName, nullptr, &dwType, reinterpret_cast(buffer), &bufferSize) == ERROR_SUCCESS) { + if (dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ) { + buffer[bufferSize - 1] = '\0'; + if (strstr(buffer, comp_string) != nullptr) { + core::add(p_brand); + count++; + } + } + else { + std::cerr << "[DEBUG] Value type is not a string for \"" << subKey << "\\" << valueName << "\"\n"; } - } else { - debug("Failed to query value for \"", subKey, "\""); } - + else { + std::cerr << "[DEBUG] Failed to query value for \"" << subKey << "\\" << valueName << "\". Error: " << GetLastError() << "\n"; + } RegCloseKey(hKey); - } else { - debug("Failed to open registry key for \"", subKey, "\""); } - }; + else { + std::cerr << "[DEBUG] Failed to open registry key \"" << subKey << "\". Error: " << GetLastError() << "\n"; + failedKeys.insert(subKey); + } + }; check_key(brands::BOCHS, "HARDWARE\\Description\\System", "SystemBiosVersion", "BOCHS"); check_key(brands::BOCHS, "HARDWARE\\Description\\System", "VideoBiosVersion", "BOCHS"); @@ -8032,7 +8038,7 @@ struct VM { * @author Requiem (https://github.com/NotRequiem) */ [[nodiscard]] static bool vmware_event_logs() { -#if (!WINDOWS || !x86_64) +#if (!WINDOWS) return false; #else std::vector logNames = { @@ -8876,7 +8882,7 @@ struct VM { const std::wstring searchString1 = L"_VMWARE_"; const std::wstring searchString2 = L"VMware, Inc."; - auto search_service_memory = [](const std::wstring& searchString, const std::string& serviceName) -> bool { + auto scan_service_memory = [](const std::wstring& searchString, const std::string& serviceName) -> bool { const DWORD pid = util::FindProcessIdByServiceName(serviceName); if (pid == 0) return false; // Process missing; potentially tampered @@ -8920,15 +8926,15 @@ struct VM { return false; }; - if (search_service_memory(searchString1, "PlugPlay")) { + if (scan_service_memory(searchString1, "PlugPlay")) { return core::add(brands::VMWARE); } - if (search_service_memory(searchString2, "Winmgmt")) { + if (scan_service_memory(searchString2, "Winmgmt")) { return core::add(brands::VMWARE); } - if (search_service_memory(searchString2, "CDPSvc")) { + if (scan_service_memory(searchString2, "CDPSvc")) { return core::add(brands::VMWARE); } @@ -9370,6 +9376,7 @@ static bool rdtsc() { #endif } + /** * @brief Check if the maximum number of virtual processors matches the maximum number of logical processors * @category Windows @@ -9429,6 +9436,70 @@ static bool rdtsc() { #endif } + + /* + * @brief Checks if a call to NtQuerySystemInformation with the 0x9f leaf fills a _SYSTEM_HYPERVISOR_DETAIL_INFORMATION structure + * @category Windows + */ + [[nodiscard]] static bool hvlquerydetailinfo() { +#if (!WINDOWS) + return false; +#else + if (util::hyper_x()) { + return false; + } + + typedef struct _HV_DETAILS { + ULONG Data[4]; + } HV_DETAILS, * PHV_DETAILS; + + typedef struct _SYSTEM_HYPERVISOR_DETAIL_INFORMATION { + HV_DETAILS HvVendorAndMaxFunction; + HV_DETAILS HypervisorInterface; + HV_DETAILS HypervisorVersion; + HV_DETAILS HvFeatures; + HV_DETAILS HwFeatures; + HV_DETAILS EnlightenmentInfo; + HV_DETAILS ImplementationLimits; + } SYSTEM_HYPERVISOR_DETAIL_INFORMATION, * PSYSTEM_HYPERVISOR_DETAIL_INFORMATION; + + typedef NTSTATUS(NTAPI* FN_NtQuerySystemInformation)( + SYSTEM_INFORMATION_CLASS SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength + ); + + const HMODULE hNtdll = GetModuleHandleA("ntdll.dll"); + if (!hNtdll) { + return false; + } + + const char* functionNames[] = { "NtQuerySystemInformation" }; + void* functions[1] = { nullptr }; + + if (!util::GetFunctionAddresses(hNtdll, functionNames, functions, 1)) { + return false; + } + + FN_NtQuerySystemInformation pNtQuerySystemInformation = reinterpret_cast(functions[0]); + if (pNtQuerySystemInformation) { + SYSTEM_HYPERVISOR_DETAIL_INFORMATION hvInfo = { 0 }; + const NTSTATUS status = pNtQuerySystemInformation(static_cast(0x9F), &hvInfo, sizeof(hvInfo), nullptr); + + if (status != 0) { + return false; + } + + if (hvInfo.HvVendorAndMaxFunction.Data[0] != 0) { + return true; + } + } + + return false; +#endif + } + // ADD NEW TECHNIQUE FUNCTION HERE @@ -10467,7 +10538,7 @@ static bool rdtsc() { case LSHW_QEMU: return "LSHW_QEMU"; case VIRTUAL_PROCESSORS: return "VIRTUAL_PROCESSORS"; case MOTHERBOARD_PRODUCT: return "MOTHERBOARD_PRODUCT"; - + case HVLQUERYDETAILINFO: return "HVLQUERYDETAILINFO"; // ADD NEW CASE HERE FOR NEW TECHNIQUE default: return "Unknown flag"; } @@ -11009,8 +11080,9 @@ std::pair VM::core::technique_list[] = { { VM::VMWARE_HARDENER, { 60, VM::vmware_hardener, false } }, { VM::SYS_QEMU, { 70, VM::sys_qemu_dir, false } }, { VM::LSHW_QEMU, { 80, VM::lshw_qemu, false } }, - { VM::VIRTUAL_PROCESSORS, { 35, VM::virtual_processors, false } }, - { VM::MOTHERBOARD_PRODUCT, { 25, VM::motherboard_product, false } }, + { VM::VIRTUAL_PROCESSORS, { 50, VM::virtual_processors, false } }, + { VM::MOTHERBOARD_PRODUCT, { 50, VM::motherboard_product, false } }, + { VM::HVLQUERYDETAILINFO, { 50, VM::hvlquerydetailinfo, false } }, // ADD NEW TECHNIQUE STRUCTURE HERE };