Skip to content

Commit 6a88ebf

Browse files
committed
updated VM::PCI_VM_DEVICE_ID and removed VM::PCI_VM
2 parents 2f9cd11 + ab708ac commit 6a88ebf

4 files changed

Lines changed: 825 additions & 907 deletions

File tree

docs/documentation.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
441441
| `VM::CPU_BRAND` | Check if CPU brand model contains any VM-specific string snippets | 🐧🪟🍏 | 50% | | | | | [link](https://github.com/kernelwernel/VMAware/blob/8cb2491b1c7d2cb7300d1d698b7c64c953b4ae75/src/vmaware.hpp#L2545) |
442442
| `VM::HYPERVISOR_BIT` | Check if hypervisor feature bit in CPUID eax bit 31 is enabled (always false for physical CPUs) | 🐧🪟🍏 | 100% | | | | | [link](https://github.com/kernelwernel/VMAware/blob/8cb2491b1c7d2cb7300d1d698b7c64c953b4ae75/src/vmaware.hpp#L2601) |
443443
| `VM::HYPERVISOR_STR` | Check for hypervisor brand string length (would be around 2 characters in a host machine) | 🐧🪟🍏 | 75% | | | | | [link](https://github.com/kernelwernel/VMAware/blob/8cb2491b1c7d2cb7300d1d698b7c64c953b4ae75/src/vmaware.hpp#L2622) |
444-
| `VM::TIMER` | Check for timing anomalies in the system | 🐧🪟🍏 | 45% | | | | Unsafe to run under binary emulators | [link](https://github.com/kernelwernel/VMAware/blob/8cb2491b1c7d2cb7300d1d698b7c64c953b4ae75/src/vmaware.hpp#L8169 ) |
444+
| `VM::TIMER` | Check for timing anomalies in the system | 🐧🪟🍏 | 45% | | | | | [link](https://github.com/kernelwernel/VMAware/blob/8cb2491b1c7d2cb7300d1d698b7c64c953b4ae75/src/vmaware.hpp#L8169 ) |
445445
| `VM::THREADCOUNT` | Check if there are only 1 or 2 threads, which is a common pattern in VMs with default settings (nowadays physical CPUs should have at least 4 threads for modern CPUs) | 🐧🪟🍏 | 35% | | | | | [link](https://github.com/kernelwernel/VMAware/blob/8cb2491b1c7d2cb7300d1d698b7c64c953b4ae75/src/vmaware.hpp#L2649) |
446446
| `VM::MAC` | Check if mac address starts with certain VM designated values | 🐧🪟 | 20% | | | | | [link](https://github.com/kernelwernel/VMAware/blob/8cb2491b1c7d2cb7300d1d698b7c64c953b4ae75/src/vmaware.hpp#L2671) |
447447
| `VM::TEMPERATURE` | Check if thermal directory in linux is present, might not be present in VMs | 🐧 | 15% | | | | | [link](https://github.com/kernelwernel/VMAware/blob/8cb2491b1c7d2cb7300d1d698b7c64c953b4ae75/src/vmaware.hpp#L2804) |
@@ -544,6 +544,8 @@ VMAware provides a convenient way to not only check for VMs, but also have the f
544544
| `VM::PCI_VM` | Check for PCIe bridge names for known VM keywords and brands | 🐧 | 100% | | | | Disabled by default | [link](https://github.com/kernelwernel/VMAware/blob/8cb2491b1c7d2cb7300d1d698b7c64c953b4ae75/src/vmaware.hpp#L10142) |
545545
| `VM::TPM` | Check if the system has a physical TPM by matching the TPM manufacturer against known physical TPM chip vendors | 🪟 | 50% | | | | | [link](https://github.com/kernelwernel/VMAware/blob/fb66db9fdd7894edebe5eeade4b0148a08bd5514/src/vmaware.hpp#L10011)|
546546
| `VM::PCI_VM_DEVICE_ID` | Check for PCI vendor and device IDs that are VM-specific | 🐧 | 90% | | | | | |
547+
| `VM::QEMU_PASSTHROUGH` | Check for QEMU's hot-plug signature | 🪟 | 100% | | | | | |
548+
547549
<!-- ADD TECHNIQUE DETAILS HERE -->
548550

549551
<br>

src/cli.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ bool is_unsupported(VM::enum_flags flag) {
468468
case VM::FIRMWARE:
469469
case VM::UNKNOWN_MANUFACTURER:
470470
case VM::TPM:
471+
case VM::QEMU_PASSTHROUGH:
471472
// ADD WINDOWS FLAG
472473
return false;
473474
default: return true;
@@ -974,6 +975,8 @@ void general() {
974975
checker(VM::NSJAIL_PID, "nsjail PID");
975976
checker(VM::TPM, "TPM manufacturer");
976977
checker(VM::PCI_VM_DEVICE_ID, "PCI vendor/device ID");
978+
checker(VM::QEMU_PASSTHROUGH, "QEMU passthrough");
979+
977980
// ADD NEW TECHNIQUE CHECKER HERE
978981

979982
std::printf("\n");

src/vmaware.hpp

Lines changed: 114 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@
2727
*
2828
*
2929
* ============================== 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
3838
*
3939
*
4040
* ============================== EXAMPLE ===================================
@@ -366,6 +366,9 @@
366366
#include <wrl/client.h>
367367
#include <tbs.h>
368368
#include <mutex>
369+
#include <initguid.h>
370+
#include <devpkey.h>
371+
#include <devguid.h>
369372

370373
#pragma comment(lib, "winmm.lib")
371374
#pragma comment(lib, "setupapi.lib")
@@ -657,6 +660,7 @@ struct VM {
657660
NSJAIL_PID,
658661
TPM,
659662
PCI_VM_DEVICE_ID,
663+
QEMU_PASSTHROUGH,
660664
// ADD NEW TECHNIQUE ENUM NAME HERE
661665

662666
// special flags, different to settings
@@ -1968,6 +1972,36 @@ struct VM {
19681972
return std::string();
19691973
}
19701974

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+
19712005
/**
19722006
* @brief Checks whether the system is running in a Hyper-V virtual machine or if the host system has Hyper-V enabled
19732007
* @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 {
36503684
/* GPL */ SP_DEVINFO_DATA DeviceInfoData{};
36513685
/* GPL */ DWORD i;
36523686
/* 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 */
36583687
/* GPL */ hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_DISKDRIVE,
36593688
/* GPL */ 0,
36603689
/* GPL */ 0,
@@ -7497,6 +7526,11 @@ struct VM {
74977526
return false;
74987527
}
74997528

7529+
if (util::is_running_under_translator()) {
7530+
debug("Running inside binary translation layer.");
7531+
return false;
7532+
}
7533+
75007534
// to minimize context switching/scheduling
75017535
#if (WINDOWS)
75027536
const HANDLE hThread = GetCurrentThread();
@@ -7537,7 +7571,7 @@ struct VM {
75377571
// 1. TSC Synchronization Check Across Cores
75387572
// Try reading the invariant TSC on two different cores to attempt to detect vCPU timers being shared
75397573
constexpr u8 tscIterations = 10;
7540-
constexpr u16 tscSyncDiffThreshold = 5000;
7574+
constexpr u16 tscSyncDiffThreshold = 500;
75417575

75427576
bool tscSyncDetected = false;
75437577
tscSyncDetected = [&]() noexcept -> bool {
@@ -9947,6 +9981,69 @@ struct VM {
99479981
#endif
99489982
}
99499983

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+
}
995010047
// ADD NEW TECHNIQUE FUNCTION HERE
995110048

995210049

@@ -11240,8 +11337,8 @@ struct VM {
1124011337
case UNKNOWN_MANUFACTURER: return "UNKNOWN_MANUFACTURER";
1124111338
case NSJAIL_PID: return "NSJAIL_PID";
1124211339
case TPM: return "TPM";
11243-
1124411340
case PCI_VM_DEVICE_ID: return "PCI_VM_DEVICE_ID";
11341+
case QEMU_PASSTHROUGH: return "QEMU_PASSTHROUGH";
1124511342
// ADD NEW CASE HERE FOR NEW TECHNIQUE
1124611343
default: return "Unknown flag";
1124711344
}
@@ -11809,6 +11906,8 @@ std::pair<VM::enum_flags, VM::core::technique> VM::core::technique_list[] = {
1180911906
std::make_pair(VM::NSJAIL_PID, VM::core::technique(75, VM::nsjail_proc_id)),
1181011907
std::make_pair(VM::TPM, VM::core::technique(50, VM::tpm)),
1181111908
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+
1181211911
// ADD NEW TECHNIQUE STRUCTURE HERE
1181311912
};
1181411913

0 commit comments

Comments
 (0)