|
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 |
@@ -2410,6 +2414,34 @@ struct VM { |
2410 | 2414 | } |
2411 | 2415 | } |
2412 | 2416 | } |
| 2417 | + |
| 2418 | + [[nodiscard]] static bool is_running_under_emulator() { |
| 2419 | +#if (WINDOWS) |
| 2420 | + u8 ver = get_windows_version(); |
| 2421 | + if (ver == 10 || ver == 11) { |
| 2422 | + USHORT procMachine = 0, nativeMachine = 0; |
| 2423 | + if (IsWow64Process2(GetCurrentProcess(), &procMachine, &nativeMachine)) { |
| 2424 | + if (nativeMachine == IMAGE_FILE_MACHINE_ARM64 && |
| 2425 | + (procMachine == IMAGE_FILE_MACHINE_AMD64 || |
| 2426 | + procMachine == IMAGE_FILE_MACHINE_I386)) |
| 2427 | + { |
| 2428 | + return true; |
| 2429 | + } |
| 2430 | + } |
| 2431 | + } |
| 2432 | +#endif |
| 2433 | + |
| 2434 | + if (cpu::is_leaf_supported(cpu::leaf::hypervisor)) { |
| 2435 | + std::string vendor = cpu::cpu_manufacturer(cpu::leaf::hypervisor); |
| 2436 | + if (vendor == "VirtualApple" || // Apple Rosetta |
| 2437 | + vendor == "PowerVM Lx86") // IBM PowerVM Lx86 |
| 2438 | + { |
| 2439 | + return true; |
| 2440 | + } |
| 2441 | + } |
| 2442 | + |
| 2443 | + return false; |
| 2444 | + } |
2413 | 2445 | #endif |
2414 | 2446 | }; |
2415 | 2447 |
|
@@ -3653,11 +3685,6 @@ struct VM { |
3653 | 3685 | /* GPL */ SP_DEVINFO_DATA DeviceInfoData{}; |
3654 | 3686 | /* GPL */ DWORD i; |
3655 | 3687 | /* GPL */ |
3656 | | -/* GPL */ constexpr GUID GUID_DEVCLASS_DISKDRIVE = { |
3657 | | -/* GPL */ 0x4d36e967L, 0xe325, 0x11ce, |
3658 | | -/* GPL */ { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } |
3659 | | -/* GPL */ }; |
3660 | | -/* GPL */ |
3661 | 3688 | /* GPL */ hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_DISKDRIVE, |
3662 | 3689 | /* GPL */ 0, |
3663 | 3690 | /* GPL */ 0, |
@@ -7500,6 +7527,11 @@ struct VM { |
7500 | 7527 | return false; |
7501 | 7528 | } |
7502 | 7529 |
|
| 7530 | + if (util::is_running_under_emulator()) { |
| 7531 | + debug("Running inside binary translation layer."); |
| 7532 | + return false; |
| 7533 | + } |
| 7534 | + |
7503 | 7535 | // to minimize context switching/scheduling |
7504 | 7536 | #if (WINDOWS) |
7505 | 7537 | const HANDLE hThread = GetCurrentThread(); |
@@ -7540,7 +7572,7 @@ struct VM { |
7540 | 7572 | // 1. TSC Synchronization Check Across Cores |
7541 | 7573 | // Try reading the invariant TSC on two different cores to attempt to detect vCPU timers being shared |
7542 | 7574 | constexpr u8 tscIterations = 10; |
7543 | | - constexpr u16 tscSyncDiffThreshold = 5000; |
| 7575 | + constexpr u16 tscSyncDiffThreshold = 500; |
7544 | 7576 |
|
7545 | 7577 | bool tscSyncDetected = false; |
7546 | 7578 | tscSyncDetected = [&]() noexcept -> bool { |
@@ -9985,6 +10017,69 @@ struct VM { |
9985 | 10017 | #endif |
9986 | 10018 | } |
9987 | 10019 |
|
| 10020 | + |
| 10021 | + /** |
| 10022 | + * @brief Check for QEMU's hot-plug signature |
| 10023 | + * @category Windows |
| 10024 | + * @author Requiem (https://github.com/NotRequiem) |
| 10025 | + * @implements VM::QEMU_PASSTHROUGH |
| 10026 | + */ |
| 10027 | + [[nodiscard]] static bool qemu_passthrough() |
| 10028 | + { |
| 10029 | +#if (!WINDOWS) |
| 10030 | + return false; |
| 10031 | +#else |
| 10032 | + // QEMU passthrough location paths |
| 10033 | + static const std::wregex busRegex(L"PCIROOT\\(0\\)#PCI\\(0202\\)"); |
| 10034 | + static const std::wregex acpiSlotRegex(L"#ACPI\\(S[0-9]{2}_\\)"); |
| 10035 | + |
| 10036 | + HDEVINFO hDevInfo = SetupDiGetClassDevsW( |
| 10037 | + &GUID_DEVCLASS_DISPLAY, |
| 10038 | + nullptr, |
| 10039 | + nullptr, |
| 10040 | + DIGCF_PRESENT); |
| 10041 | + if (hDevInfo == INVALID_HANDLE_VALUE) |
| 10042 | + return false; |
| 10043 | + |
| 10044 | + SP_DEVINFO_DATA devInfo = {}; |
| 10045 | + devInfo.cbSize = sizeof(devInfo); |
| 10046 | + const DEVPROPKEY key = DEVPKEY_Device_LocationPaths; |
| 10047 | + |
| 10048 | + for (DWORD idx = 0; SetupDiEnumDeviceInfo(hDevInfo, idx, &devInfo); ++idx) |
| 10049 | + { |
| 10050 | + DEVPROPTYPE propType = 0; |
| 10051 | + DWORD requiredSize = 0; |
| 10052 | + |
| 10053 | + SetupDiGetDevicePropertyW( |
| 10054 | + hDevInfo, &devInfo, &key, &propType, |
| 10055 | + nullptr, 0, &requiredSize, 0); |
| 10056 | + |
| 10057 | + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER || requiredSize == 0) |
| 10058 | + continue; |
| 10059 | + |
| 10060 | + std::vector<BYTE> buffer(requiredSize); |
| 10061 | + if (!SetupDiGetDevicePropertyW( |
| 10062 | + hDevInfo, &devInfo, &key, &propType, |
| 10063 | + buffer.data(), requiredSize, &requiredSize, 0)) |
| 10064 | + continue; |
| 10065 | + |
| 10066 | + const wchar_t* ptr = reinterpret_cast<const wchar_t*>(buffer.data()); |
| 10067 | + while (*ptr) { |
| 10068 | + std::wstring path(ptr); |
| 10069 | + if (std::regex_search(path, busRegex) || |
| 10070 | + std::regex_search(path, acpiSlotRegex)) |
| 10071 | + { |
| 10072 | + SetupDiDestroyDeviceInfoList(hDevInfo); |
| 10073 | + return true; |
| 10074 | + } |
| 10075 | + ptr += path.size() + 1; |
| 10076 | + } |
| 10077 | + } |
| 10078 | + |
| 10079 | + SetupDiDestroyDeviceInfoList(hDevInfo); |
| 10080 | + return false; |
| 10081 | +#endif |
| 10082 | + } |
9988 | 10083 | // ADD NEW TECHNIQUE FUNCTION HERE |
9989 | 10084 |
|
9990 | 10085 |
|
@@ -11280,8 +11375,8 @@ struct VM { |
11280 | 11375 | case NSJAIL_PID: return "NSJAIL_PID"; |
11281 | 11376 | case PCI_VM: return "PCI_VM"; |
11282 | 11377 | case TPM: return "TPM"; |
11283 | | - |
11284 | 11378 | case PCI_VM_DEVICE_ID: return "PCI_VM_DEVICE_ID"; |
| 11379 | + case QEMU_PASSTHROUGH: return "QEMU_PASSTHROUGH"; |
11285 | 11380 | // ADD NEW CASE HERE FOR NEW TECHNIQUE |
11286 | 11381 | default: return "Unknown flag"; |
11287 | 11382 | } |
@@ -11846,6 +11941,8 @@ std::pair<VM::enum_flags, VM::core::technique> VM::core::technique_list[] = { |
11846 | 11941 | std::make_pair(VM::PCI_VM, VM::core::technique(100, VM::lspci)), |
11847 | 11942 | std::make_pair(VM::TPM, VM::core::technique(50, VM::tpm)), |
11848 | 11943 | std::make_pair(VM::PCI_VM_DEVICE_ID, VM::core::technique(90, VM::pci_vm_device_id)), |
| 11944 | + std::make_pair(VM::QEMU_PASSTHROUGH, VM::core::technique(90, VM::qemu_passthrough)), |
| 11945 | + |
11849 | 11946 | // ADD NEW TECHNIQUE STRUCTURE HERE |
11850 | 11947 | }; |
11851 | 11948 |
|
|
0 commit comments