|
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") |
@@ -657,6 +660,7 @@ struct VM { |
657 | 660 | NSJAIL_PID, |
658 | 661 | TPM, |
659 | 662 | PCI_VM_DEVICE_ID, |
| 663 | + QEMU_PASSTHROUGH, |
660 | 664 | // ADD NEW TECHNIQUE ENUM NAME HERE |
661 | 665 |
|
662 | 666 | // special flags, different to settings |
@@ -1968,6 +1972,36 @@ struct VM { |
1968 | 1972 | return std::string(); |
1969 | 1973 | } |
1970 | 1974 |
|
| 1975 | + |
| 1976 | + [[nodiscard]] static bool is_running_under_translator() { |
| 1977 | + #if (WINDOWS) |
| 1978 | + u8 ver = get_windows_version(); |
| 1979 | + if (ver == 10 || ver == 11) { |
| 1980 | + USHORT procMachine = 0, nativeMachine = 0; |
| 1981 | + if (IsWow64Process2(GetCurrentProcess(), &procMachine, &nativeMachine)) { |
| 1982 | + if (nativeMachine == IMAGE_FILE_MACHINE_ARM64 && |
| 1983 | + (procMachine == IMAGE_FILE_MACHINE_AMD64 || |
| 1984 | + procMachine == IMAGE_FILE_MACHINE_I386)) |
| 1985 | + { |
| 1986 | + return true; |
| 1987 | + } |
| 1988 | + } |
| 1989 | + } |
| 1990 | +#endif |
| 1991 | + |
| 1992 | + if (cpu::is_leaf_supported(cpu::leaf::hypervisor)) { |
| 1993 | + std::string vendor = cpu::cpu_manufacturer(cpu::leaf::hypervisor); |
| 1994 | + if (vendor == "VirtualApple" || // Apple Rosetta |
| 1995 | + vendor == "PowerVM Lx86") // IBM PowerVM Lx86 |
| 1996 | + { |
| 1997 | + return true; |
| 1998 | + } |
| 1999 | + } |
| 2000 | + |
| 2001 | + return false; |
| 2002 | + } |
| 2003 | + |
| 2004 | + |
1971 | 2005 | /** |
1972 | 2006 | * @brief Checks whether the system is running in a Hyper-V virtual machine or if the host system has Hyper-V enabled |
1973 | 2007 | * @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. |
@@ -3650,11 +3684,6 @@ struct VM { |
3650 | 3684 | /* GPL */ SP_DEVINFO_DATA DeviceInfoData{}; |
3651 | 3685 | /* GPL */ DWORD i; |
3652 | 3686 | /* GPL */ |
3653 | | -/* GPL */ constexpr GUID GUID_DEVCLASS_DISKDRIVE = { |
3654 | | -/* GPL */ 0x4d36e967L, 0xe325, 0x11ce, |
3655 | | -/* GPL */ { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } |
3656 | | -/* GPL */ }; |
3657 | | -/* GPL */ |
3658 | 3687 | /* GPL */ hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_DISKDRIVE, |
3659 | 3688 | /* GPL */ 0, |
3660 | 3689 | /* GPL */ 0, |
@@ -7497,6 +7526,11 @@ struct VM { |
7497 | 7526 | return false; |
7498 | 7527 | } |
7499 | 7528 |
|
| 7529 | + if (util::is_running_under_translator()) { |
| 7530 | + debug("Running inside binary translation layer."); |
| 7531 | + return false; |
| 7532 | + } |
| 7533 | + |
7500 | 7534 | // to minimize context switching/scheduling |
7501 | 7535 | #if (WINDOWS) |
7502 | 7536 | const HANDLE hThread = GetCurrentThread(); |
@@ -7537,7 +7571,7 @@ struct VM { |
7537 | 7571 | // 1. TSC Synchronization Check Across Cores |
7538 | 7572 | // Try reading the invariant TSC on two different cores to attempt to detect vCPU timers being shared |
7539 | 7573 | constexpr u8 tscIterations = 10; |
7540 | | - constexpr u16 tscSyncDiffThreshold = 5000; |
| 7574 | + constexpr u16 tscSyncDiffThreshold = 500; |
7541 | 7575 |
|
7542 | 7576 | bool tscSyncDetected = false; |
7543 | 7577 | tscSyncDetected = [&]() noexcept -> bool { |
@@ -9947,6 +9981,69 @@ struct VM { |
9947 | 9981 | #endif |
9948 | 9982 | } |
9949 | 9983 |
|
| 9984 | + |
| 9985 | + /** |
| 9986 | + * @brief Check for QEMU's hot-plug signature |
| 9987 | + * @category Windows |
| 9988 | + * @author Requiem (https://github.com/NotRequiem) |
| 9989 | + * @implements VM::QEMU_PASSTHROUGH |
| 9990 | + */ |
| 9991 | + [[nodiscard]] static bool qemu_passthrough() |
| 9992 | + { |
| 9993 | +#if (!WINDOWS) |
| 9994 | + return false; |
| 9995 | +#else |
| 9996 | + // QEMU passthrough location paths |
| 9997 | + static const std::wregex busRegex(L"PCIROOT\\(0\\)#PCI\\(0202\\)"); |
| 9998 | + static const std::wregex acpiSlotRegex(L"#ACPI\\(S[0-9]{2}_\\)"); |
| 9999 | + |
| 10000 | + HDEVINFO hDevInfo = SetupDiGetClassDevsW( |
| 10001 | + &GUID_DEVCLASS_DISPLAY, |
| 10002 | + nullptr, |
| 10003 | + nullptr, |
| 10004 | + DIGCF_PRESENT); |
| 10005 | + if (hDevInfo == INVALID_HANDLE_VALUE) |
| 10006 | + return false; |
| 10007 | + |
| 10008 | + SP_DEVINFO_DATA devInfo = {}; |
| 10009 | + devInfo.cbSize = sizeof(devInfo); |
| 10010 | + const DEVPROPKEY key = DEVPKEY_Device_LocationPaths; |
| 10011 | + |
| 10012 | + for (DWORD idx = 0; SetupDiEnumDeviceInfo(hDevInfo, idx, &devInfo); ++idx) |
| 10013 | + { |
| 10014 | + DEVPROPTYPE propType = 0; |
| 10015 | + DWORD requiredSize = 0; |
| 10016 | + |
| 10017 | + SetupDiGetDevicePropertyW( |
| 10018 | + hDevInfo, &devInfo, &key, &propType, |
| 10019 | + nullptr, 0, &requiredSize, 0); |
| 10020 | + |
| 10021 | + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || requiredSize == 0) |
| 10022 | + continue; |
| 10023 | + |
| 10024 | + std::vector<BYTE> buffer(requiredSize); |
| 10025 | + if (!SetupDiGetDevicePropertyW( |
| 10026 | + hDevInfo, &devInfo, &key, &propType, |
| 10027 | + buffer.data(), requiredSize, &requiredSize, 0)) |
| 10028 | + continue; |
| 10029 | + |
| 10030 | + const wchar_t* ptr = reinterpret_cast<const wchar_t*>(buffer.data()); |
| 10031 | + while (*ptr) { |
| 10032 | + std::wstring path(ptr); |
| 10033 | + if (std::regex_search(path, busRegex) || |
| 10034 | + std::regex_search(path, acpiSlotRegex)) |
| 10035 | + { |
| 10036 | + SetupDiDestroyDeviceInfoList(hDevInfo); |
| 10037 | + return true; |
| 10038 | + } |
| 10039 | + ptr += path.size() + 1; |
| 10040 | + } |
| 10041 | + } |
| 10042 | + |
| 10043 | + SetupDiDestroyDeviceInfoList(hDevInfo); |
| 10044 | + return false; |
| 10045 | +#endif |
| 10046 | + } |
9950 | 10047 | // ADD NEW TECHNIQUE FUNCTION HERE |
9951 | 10048 |
|
9952 | 10049 |
|
@@ -11240,8 +11337,8 @@ struct VM { |
11240 | 11337 | case UNKNOWN_MANUFACTURER: return "UNKNOWN_MANUFACTURER"; |
11241 | 11338 | case NSJAIL_PID: return "NSJAIL_PID"; |
11242 | 11339 | case TPM: return "TPM"; |
11243 | | - |
11244 | 11340 | case PCI_VM_DEVICE_ID: return "PCI_VM_DEVICE_ID"; |
| 11341 | + case QEMU_PASSTHROUGH: return "QEMU_PASSTHROUGH"; |
11245 | 11342 | // ADD NEW CASE HERE FOR NEW TECHNIQUE |
11246 | 11343 | default: return "Unknown flag"; |
11247 | 11344 | } |
@@ -11809,6 +11906,8 @@ std::pair<VM::enum_flags, VM::core::technique> VM::core::technique_list[] = { |
11809 | 11906 | std::make_pair(VM::NSJAIL_PID, VM::core::technique(75, VM::nsjail_proc_id)), |
11810 | 11907 | std::make_pair(VM::TPM, VM::core::technique(50, VM::tpm)), |
11811 | 11908 | std::make_pair(VM::PCI_VM_DEVICE_ID, VM::core::technique(90, VM::pci_vm_device_id)), |
| 11909 | + std::make_pair(VM::QEMU_PASSTHROUGH, VM::core::technique(90, VM::qemu_passthrough)), |
| 11910 | + |
11812 | 11911 | // ADD NEW TECHNIQUE STRUCTURE HERE |
11813 | 11912 | }; |
11814 | 11913 |
|
|
0 commit comments