|
27 | 27 | * |
28 | 28 | * |
29 | 29 | * ============================== SECTIONS ================================== |
30 | | - * - enums for publicly accessible techniques => line 555 |
31 | | - * - struct for internal cpu operations => line 741 |
32 | | - * - struct for internal memoization => line 1212 |
33 | | - * - struct for internal utility functions => line 1340 |
34 | | - * - struct for internal core components => line 10291 |
35 | | - * - start of VM detection technique list => line 2427 |
36 | | - * - start of public VM detection functions => line 10948 |
37 | | - * - start of externally defined variables => line 11892 |
| 30 | + * - enums for publicly accessible techniques => line 557 |
| 31 | + * - struct for internal cpu operations => line 743 |
| 32 | + * - struct for internal memoization => line 1209 |
| 33 | + * - struct for internal utility functions => line 1337 |
| 34 | + * - struct for internal core components => line 10102 |
| 35 | + * - start of VM detection technique list => line 2450 |
| 36 | + * - start of public VM detection functions => line 10759 |
| 37 | + * - start of externally defined variables => line 11710 |
38 | 38 | * |
39 | 39 | * |
40 | 40 | * ============================== EXAMPLE =================================== |
|
366 | 366 | #include <wrl/client.h> |
367 | 367 | #include <tbs.h> |
368 | 368 | #include <mutex> |
| 369 | +#include <initguid.h> |
| 370 | +#include <devpkey.h> |
| 371 | +#include <devguid.h> |
369 | 372 |
|
370 | 373 | #pragma comment(lib, "winmm.lib") |
371 | 374 | #pragma comment(lib, "setupapi.lib") |
@@ -658,6 +661,7 @@ struct VM { |
658 | 661 | PCI_VM, |
659 | 662 | TPM, |
660 | 663 | PCI_VM_DEVICE_ID, |
| 664 | + QEMU_PASSTHROUGH, |
661 | 665 | // ADD NEW TECHNIQUE ENUM NAME HERE |
662 | 666 |
|
663 | 667 | // special flags, different to settings |
@@ -1970,6 +1974,36 @@ struct VM { |
1970 | 1974 | return std::string(); |
1971 | 1975 | } |
1972 | 1976 |
|
| 1977 | + |
| 1978 | + [[nodiscard]] static bool is_running_under_translator() { |
| 1979 | + #if (WINDOWS) |
| 1980 | + u8 ver = get_windows_version(); |
| 1981 | + if (ver == 10 || ver == 11) { |
| 1982 | + USHORT procMachine = 0, nativeMachine = 0; |
| 1983 | + if (IsWow64Process2(GetCurrentProcess(), &procMachine, &nativeMachine)) { |
| 1984 | + if (nativeMachine == IMAGE_FILE_MACHINE_ARM64 && |
| 1985 | + (procMachine == IMAGE_FILE_MACHINE_AMD64 || |
| 1986 | + procMachine == IMAGE_FILE_MACHINE_I386)) |
| 1987 | + { |
| 1988 | + return true; |
| 1989 | + } |
| 1990 | + } |
| 1991 | + } |
| 1992 | +#endif |
| 1993 | + |
| 1994 | + if (cpu::is_leaf_supported(cpu::leaf::hypervisor)) { |
| 1995 | + std::string vendor = cpu::cpu_manufacturer(cpu::leaf::hypervisor); |
| 1996 | + if (vendor == "VirtualApple" || // Apple Rosetta |
| 1997 | + vendor == "PowerVM Lx86") // IBM PowerVM Lx86 |
| 1998 | + { |
| 1999 | + return true; |
| 2000 | + } |
| 2001 | + } |
| 2002 | + |
| 2003 | + return false; |
| 2004 | + } |
| 2005 | + |
| 2006 | + |
1973 | 2007 | /** |
1974 | 2008 | * @brief Checks whether the system is running in a Hyper-V virtual machine or if the host system has Hyper-V enabled |
1975 | 2009 | * @note Hyper-V's presence on a host system can set certain hypervisor-related CPU flags that may appear similar to those in a virtualized environment, which can make it challenging to differentiate between an actual Hyper-V virtual machine (VM) and a host system with Hyper-V enabled. |
@@ -3652,11 +3686,6 @@ struct VM { |
3652 | 3686 | /* GPL */ SP_DEVINFO_DATA DeviceInfoData{}; |
3653 | 3687 | /* GPL */ DWORD i; |
3654 | 3688 | /* GPL */ |
3655 | | -/* GPL */ constexpr GUID GUID_DEVCLASS_DISKDRIVE = { |
3656 | | -/* GPL */ 0x4d36e967L, 0xe325, 0x11ce, |
3657 | | -/* GPL */ { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } |
3658 | | -/* GPL */ }; |
3659 | | -/* GPL */ |
3660 | 3689 | /* GPL */ hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_DISKDRIVE, |
3661 | 3690 | /* GPL */ 0, |
3662 | 3691 | /* GPL */ 0, |
@@ -7499,6 +7528,11 @@ struct VM { |
7499 | 7528 | return false; |
7500 | 7529 | } |
7501 | 7530 |
|
| 7531 | + if (util::is_running_under_translator()) { |
| 7532 | + debug("Running inside binary translation layer."); |
| 7533 | + return false; |
| 7534 | + } |
| 7535 | + |
7502 | 7536 | // to minimize context switching/scheduling |
7503 | 7537 | #if (WINDOWS) |
7504 | 7538 | const HANDLE hThread = GetCurrentThread(); |
@@ -7539,7 +7573,7 @@ struct VM { |
7539 | 7573 | // 1. TSC Synchronization Check Across Cores |
7540 | 7574 | // Try reading the invariant TSC on two different cores to attempt to detect vCPU timers being shared |
7541 | 7575 | constexpr u8 tscIterations = 10; |
7542 | | - constexpr u16 tscSyncDiffThreshold = 5000; |
| 7576 | + constexpr u16 tscSyncDiffThreshold = 500; |
7543 | 7577 |
|
7544 | 7578 | bool tscSyncDetected = false; |
7545 | 7579 | tscSyncDetected = [&]() noexcept -> bool { |
@@ -9984,6 +10018,69 @@ struct VM { |
9984 | 10018 | #endif |
9985 | 10019 | } |
9986 | 10020 |
|
| 10021 | + |
| 10022 | + /** |
| 10023 | + * @brief Check for QEMU's hot-plug signature |
| 10024 | + * @category Windows |
| 10025 | + * @author Requiem (https://github.com/NotRequiem) |
| 10026 | + * @implements VM::QEMU_PASSTHROUGH |
| 10027 | + */ |
| 10028 | + [[nodiscard]] static bool qemu_passthrough() |
| 10029 | + { |
| 10030 | +#if (!WINDOWS) |
| 10031 | + return false; |
| 10032 | +#else |
| 10033 | + // QEMU passthrough location paths |
| 10034 | + static const std::wregex busRegex(L"PCIROOT\\(0\\)#PCI\\(0202\\)"); |
| 10035 | + static const std::wregex acpiSlotRegex(L"#ACPI\\(S[0-9]{2}_\\)"); |
| 10036 | + |
| 10037 | + HDEVINFO hDevInfo = SetupDiGetClassDevsW( |
| 10038 | + &GUID_DEVCLASS_DISPLAY, |
| 10039 | + nullptr, |
| 10040 | + nullptr, |
| 10041 | + DIGCF_PRESENT); |
| 10042 | + if (hDevInfo == INVALID_HANDLE_VALUE) |
| 10043 | + return false; |
| 10044 | + |
| 10045 | + SP_DEVINFO_DATA devInfo = {}; |
| 10046 | + devInfo.cbSize = sizeof(devInfo); |
| 10047 | + const DEVPROPKEY key = DEVPKEY_Device_LocationPaths; |
| 10048 | + |
| 10049 | + for (DWORD idx = 0; SetupDiEnumDeviceInfo(hDevInfo, idx, &devInfo); ++idx) |
| 10050 | + { |
| 10051 | + DEVPROPTYPE propType = 0; |
| 10052 | + DWORD requiredSize = 0; |
| 10053 | + |
| 10054 | + SetupDiGetDevicePropertyW( |
| 10055 | + hDevInfo, &devInfo, &key, &propType, |
| 10056 | + nullptr, 0, &requiredSize, 0); |
| 10057 | + |
| 10058 | + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || requiredSize == 0) |
| 10059 | + continue; |
| 10060 | + |
| 10061 | + std::vector<BYTE> buffer(requiredSize); |
| 10062 | + if (!SetupDiGetDevicePropertyW( |
| 10063 | + hDevInfo, &devInfo, &key, &propType, |
| 10064 | + buffer.data(), requiredSize, &requiredSize, 0)) |
| 10065 | + continue; |
| 10066 | + |
| 10067 | + const wchar_t* ptr = reinterpret_cast<const wchar_t*>(buffer.data()); |
| 10068 | + while (*ptr) { |
| 10069 | + std::wstring path(ptr); |
| 10070 | + if (std::regex_search(path, busRegex) || |
| 10071 | + std::regex_search(path, acpiSlotRegex)) |
| 10072 | + { |
| 10073 | + SetupDiDestroyDeviceInfoList(hDevInfo); |
| 10074 | + return true; |
| 10075 | + } |
| 10076 | + ptr += path.size() + 1; |
| 10077 | + } |
| 10078 | + } |
| 10079 | + |
| 10080 | + SetupDiDestroyDeviceInfoList(hDevInfo); |
| 10081 | + return false; |
| 10082 | +#endif |
| 10083 | + } |
9987 | 10084 | // ADD NEW TECHNIQUE FUNCTION HERE |
9988 | 10085 |
|
9989 | 10086 |
|
@@ -11279,8 +11376,8 @@ struct VM { |
11279 | 11376 | case NSJAIL_PID: return "NSJAIL_PID"; |
11280 | 11377 | case PCI_VM: return "PCI_VM"; |
11281 | 11378 | case TPM: return "TPM"; |
11282 | | - |
11283 | 11379 | case PCI_VM_DEVICE_ID: return "PCI_VM_DEVICE_ID"; |
| 11380 | + case QEMU_PASSTHROUGH: return "QEMU_PASSTHROUGH"; |
11284 | 11381 | // ADD NEW CASE HERE FOR NEW TECHNIQUE |
11285 | 11382 | default: return "Unknown flag"; |
11286 | 11383 | } |
@@ -11849,6 +11946,8 @@ std::pair<VM::enum_flags, VM::core::technique> VM::core::technique_list[] = { |
11849 | 11946 | std::make_pair(VM::PCI_VM, VM::core::technique(100, VM::lspci)), |
11850 | 11947 | std::make_pair(VM::TPM, VM::core::technique(50, VM::tpm)), |
11851 | 11948 | std::make_pair(VM::PCI_VM_DEVICE_ID, VM::core::technique(90, VM::pci_vm_device_id)), |
| 11949 | + std::make_pair(VM::QEMU_PASSTHROUGH, VM::core::technique(90, VM::qemu_passthrough)), |
| 11950 | + |
11852 | 11951 | // ADD NEW TECHNIQUE STRUCTURE HERE |
11853 | 11952 | }; |
11854 | 11953 |
|
|
0 commit comments