From 4a3a446ba7b41cba45703ad676cb2ac539da045e Mon Sep 17 00:00:00 2001 From: Dmitry Borisov Date: Sat, 19 Apr 2025 11:07:05 +0600 Subject: [PATCH] [KMTESTS] Add the ability to detect a virtual machine This allows the tests to interact directly with hardware CORE-20078 --- modules/rostests/kmtests/CMakeLists.txt | 8 +++ modules/rostests/kmtests/include/kmt_test.h | 1 + .../kmtests/include/kmt_test_kernel.h | 1 + .../rostests/kmtests/kmtest_drv/kmtest_drv.c | 5 ++ .../rostests/kmtests/kmtest_drv/vm_detect.S | 53 ++++++++++++++++ .../rostests/kmtests/kmtest_drv/vm_detect.c | 61 +++++++++++++++++++ 6 files changed, 129 insertions(+) create mode 100644 modules/rostests/kmtests/kmtest_drv/vm_detect.S create mode 100644 modules/rostests/kmtests/kmtest_drv/vm_detect.c diff --git a/modules/rostests/kmtests/CMakeLists.txt b/modules/rostests/kmtests/CMakeLists.txt index 373ffb887c3..63d8bd469f7 100644 --- a/modules/rostests/kmtests/CMakeLists.txt +++ b/modules/rostests/kmtests/CMakeLists.txt @@ -44,6 +44,7 @@ list(APPEND KMTEST_DRV_SOURCE kmtest_drv/kmtest_drv.c kmtest_drv/structs.c kmtest_drv/testlist.c + kmtest_drv/vm_detect.c example/Example.c example/KernelType.c @@ -119,6 +120,13 @@ list(APPEND KMTEST_DRV_SOURCE kmtest_drv/kmtest_drv.rc) +if(ARCH STREQUAL "i386" OR ARCH STREQUAL "amd64") + add_asm_files(KMTEST_DRV_ASM + kmtest_drv/vm_detect.S) + list(APPEND KMTEST_DRV_SOURCE + ${KMTEST_DRV_ASM}) +endif() + add_library(kmtest_drv MODULE ${KMTEST_DRV_SOURCE}) set_module_type(kmtest_drv kernelmodedriver) target_link_libraries(kmtest_drv kmtest_printf chkstk memcmp ntoskrnl_vista ${PSEH_LIB}) diff --git a/modules/rostests/kmtests/include/kmt_test.h b/modules/rostests/kmtests/include/kmt_test.h index 1e265c9a05a..7722a051b10 100644 --- a/modules/rostests/kmtests/include/kmt_test.h +++ b/modules/rostests/kmtests/include/kmt_test.h @@ -156,6 +156,7 @@ typedef struct extern BOOLEAN KmtIsCheckedBuild; extern BOOLEAN KmtIsMultiProcessorBuild; +extern BOOLEAN KmtIsVirtualMachine; extern PCSTR KmtMajorFunctionNames[]; extern PDRIVER_OBJECT KmtDriverObject; diff --git a/modules/rostests/kmtests/include/kmt_test_kernel.h b/modules/rostests/kmtests/include/kmt_test_kernel.h index d5a20076f4e..db4510d929f 100644 --- a/modules/rostests/kmtests/include/kmt_test_kernel.h +++ b/modules/rostests/kmtests/include/kmt_test_kernel.h @@ -14,6 +14,7 @@ BOOLEAN KmtIsCheckedBuild; BOOLEAN KmtIsMultiProcessorBuild; +BOOLEAN KmtIsVirtualMachine; PCSTR KmtMajorFunctionNames[] = { "Create", diff --git a/modules/rostests/kmtests/kmtest_drv/kmtest_drv.c b/modules/rostests/kmtests/kmtest_drv/kmtest_drv.c index 6e4e0e8212b..4fb3bf97836 100644 --- a/modules/rostests/kmtests/kmtest_drv/kmtest_drv.c +++ b/modules/rostests/kmtests/kmtest_drv/kmtest_drv.c @@ -36,6 +36,10 @@ typedef struct _KMT_USER_WORK_LIST KEVENT NewWorkEvent; } KMT_USER_WORK_LIST, *PKMT_USER_WORK_LIST; +extern +BOOLEAN +KmtDetectVirtualMachine(VOID); + /* Prototypes */ DRIVER_INITIALIZE DriverEntry; static DRIVER_UNLOAD DriverUnload; @@ -88,6 +92,7 @@ DriverEntry( Prcb = KeGetCurrentPrcb(); KmtIsCheckedBuild = (Prcb->BuildType & PRCB_BUILD_DEBUG) != 0; KmtIsMultiProcessorBuild = (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) == 0; + KmtIsVirtualMachine = KmtDetectVirtualMachine(); KmtDriverObject = DriverObject; RtlInitUnicodeString(&DeviceName, KMTEST_DEVICE_DRIVER_PATH); diff --git a/modules/rostests/kmtests/kmtest_drv/vm_detect.S b/modules/rostests/kmtests/kmtest_drv/vm_detect.S new file mode 100644 index 00000000000..cea4a6023fc --- /dev/null +++ b/modules/rostests/kmtests/kmtest_drv/vm_detect.S @@ -0,0 +1,53 @@ +/* + * PROJECT: ReactOS Kernel-Mode Tests + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: ASM helper functions for VM detection + * COPYRIGHT: Copyright 2025 Dmitry Borisov + */ + +#include + +#define VMWARE_SIGNATURE HEX(564D5868) // 'VMXh' +#define VMWARE_PORT HEX(5658) // 'VX' + +.code + +/* + * BOOLEAN + * VmIsVMware(VOID); + */ +#ifdef _M_IX86 +PUBLIC _VmIsVMware +_VmIsVMware: + push ebx + push ecx + push edx +#else +PUBLIC VmIsVMware +VmIsVMware: + push rbx + push rcx + push rdx +#endif + + mov eax, VMWARE_SIGNATURE + mov ebx, 0 + mov ecx, 10 + mov edx, VMWARE_PORT + in eax, dx + cmp ebx, VMWARE_SIGNATURE + sete al + +#ifdef _M_IX86 + pop edx + pop ecx + pop ebx +#else + pop rdx + pop rcx + pop rbx +#endif + + ret + +END diff --git a/modules/rostests/kmtests/kmtest_drv/vm_detect.c b/modules/rostests/kmtests/kmtest_drv/vm_detect.c new file mode 100644 index 00000000000..c34641450c1 --- /dev/null +++ b/modules/rostests/kmtests/kmtest_drv/vm_detect.c @@ -0,0 +1,61 @@ +/* + * PROJECT: ReactOS Kernel-Mode Tests + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: VM detection code + * COPYRIGHT: Copyright 2025 Dmitry Borisov + */ + +/* INCLUDES *******************************************************************/ + +#include + +/* FUNCTIONS ******************************************************************/ + +#if defined(_M_IX86) || defined(_M_AMD64) +extern BOOLEAN VmIsVMware(VOID); + +static +BOOLEAN +VmIsHypervisorPresent(VOID) +{ + INT CpuInfo[4]; + + __cpuid(CpuInfo, 1); + + return !!(CpuInfo[2] & 0x80000000); +} + +static +BOOLEAN +VmIsVbox(VOID) +{ + ULONG PciId, BytesRead; + PCI_SLOT_NUMBER Slot; + + Slot.u.AsULONG = 0; + Slot.u.bits.DeviceNumber = 4; + Slot.u.bits.FunctionNumber = 0; + + BytesRead = HalGetBusDataByOffset(PCIConfiguration, + 0, + Slot.u.AsULONG, + &PciId, + FIELD_OFFSET(PCI_COMMON_HEADER, VendorID), + sizeof(PciId)); + return (BytesRead == sizeof(PciId)) && (PciId == 0xCAFE80EE); +} +#endif // defined(_M_IX86) || defined(_M_AMD64) + +/* + * NOTE: We make no attempt to support every software in existence. + * Only VMs used by Testman are checked. + */ +BOOLEAN +KmtDetectVirtualMachine(VOID) +{ +#if defined(_M_IX86) || defined(_M_AMD64) + return VmIsHypervisorPresent() || VmIsVbox() || VmIsVMware(); +#else + return FALSE; +#endif +}