diff --git a/SafeExamBrowser.SystemComponents.Contracts/ISystemInfo.cs b/SafeExamBrowser.SystemComponents.Contracts/ISystemInfo.cs index 194bb969..c328f921 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/ISystemInfo.cs +++ b/SafeExamBrowser.SystemComponents.Contracts/ISystemInfo.cs @@ -18,6 +18,11 @@ namespace SafeExamBrowser.SystemComponents.Contracts /// string BiosInfo { get; } + /// + /// The name of the CPU. + /// + string CpuName { get; } + /// /// Reveals whether the computer system contains a battery. /// diff --git a/SafeExamBrowser.SystemComponents/Registry/Registry.cs b/SafeExamBrowser.SystemComponents/Registry/Registry.cs index 43b67ddd..f70185a6 100644 --- a/SafeExamBrowser.SystemComponents/Registry/Registry.cs +++ b/SafeExamBrowser.SystemComponents/Registry/Registry.cs @@ -229,7 +229,6 @@ namespace SafeExamBrowser.SystemComponents.Registry try { - logger.Info($"default(RegistryKey) == null: {key == null}"); if (TryGetBaseKeyFromKeyName(keyName, out var baseKey, out var subKey)) { key = baseKey.OpenSubKey(subKey); diff --git a/SafeExamBrowser.SystemComponents/SystemInfo.cs b/SafeExamBrowser.SystemComponents/SystemInfo.cs index 207a2fab..476c45d3 100644 --- a/SafeExamBrowser.SystemComponents/SystemInfo.cs +++ b/SafeExamBrowser.SystemComponents/SystemInfo.cs @@ -20,6 +20,7 @@ namespace SafeExamBrowser.SystemComponents public class SystemInfo : ISystemInfo { public string BiosInfo { get; private set; } + public string CpuName { get; private set; } public bool HasBattery { get; private set; } public string MacAddress { get; private set; } public string Manufacturer { get; private set; } @@ -33,6 +34,7 @@ namespace SafeExamBrowser.SystemComponents { InitializeBattery(); InitializeBiosInfo(); + InitializeCpuName(); InitializeMacAddress(); InitializeMachineInfo(); InitializeOperatingSystem(); @@ -79,6 +81,34 @@ namespace SafeExamBrowser.SystemComponents } } + private void InitializeCpuName() + { + try + { + using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor")) + using (var results = searcher.Get()) + { + foreach (var cpu in results) + { + using (cpu) + { + foreach (var property in cpu.Properties) + { + if (property.Name.Equals("Name")) + { + CpuName = Convert.ToString(property.Value); + } + } + } + } + } + } + catch (Exception) + { + CpuName = ""; + } + } + private void InitializeMachineInfo() { var model = default(string); @@ -192,7 +222,7 @@ namespace SafeExamBrowser.SystemComponents using (var searcher = new ManagementObjectSearcher("SELECT MACAddress FROM Win32_NetworkAdapterConfiguration WHERE DNSDomain IS NOT NULL")) using (var results = searcher.Get()) { - if (results != null && results.Count > 0) + if (results != default && results.Count > 0) { using (var networkAdapter = results.Cast().First()) { @@ -226,11 +256,11 @@ namespace SafeExamBrowser.SystemComponents using (var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT DeviceID FROM Win32_PnPEntity")) using (var results = searcher.Get()) { - foreach (ManagementObject queryObj in results) + foreach (var device in results.Cast()) { - using (queryObj) + using (device) { - foreach (var property in queryObj.Properties) + foreach (var property in device.Properties) { if (property.Name.Equals("DeviceID")) { diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 94306633..7e49711c 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -7,7 +7,6 @@ */ using System.Linq; -using System.Management; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts; using SafeExamBrowser.SystemComponents.Contracts.Registry; @@ -16,6 +15,7 @@ namespace SafeExamBrowser.SystemComponents { public class VirtualMachineDetector : IVirtualMachineDetector { + private const string MANIPULATED = "000000000000"; private const string QEMU_MAC_PREFIX = "525400"; private const string VIRTUALBOX_MAC_PREFIX = "080027"; @@ -52,176 +52,161 @@ namespace SafeExamBrowser.SystemComponents public bool IsVirtualMachine() { - var biosInfo = systemInfo.BiosInfo; - var devices = systemInfo.PlugAndPlayDeviceIds; var isVirtualMachine = false; - var macAddress = systemInfo.MacAddress; - var manufacturer = systemInfo.Manufacturer; - var model = systemInfo.Model; + isVirtualMachine |= HasVirtualDevice(); + isVirtualMachine |= HasVirtualMacAddress(); + isVirtualMachine |= IsVirtualCpu(); isVirtualMachine |= IsVirtualRegistry(); - isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); - isVirtualMachine |= IsVirtualWmi(); - - if (macAddress != null && macAddress.Count() > 2) - { - isVirtualMachine |= macAddress.StartsWith(QEMU_MAC_PREFIX); - isVirtualMachine |= macAddress.StartsWith(VIRTUALBOX_MAC_PREFIX); - isVirtualMachine |= macAddress.StartsWith("000000000000"); - } - - foreach (var device in devices) - { - isVirtualMachine |= DeviceBlacklist.Any(d => device.ToLower().Contains(d.ToLower())) && DeviceWhitelist.All(d => !device.ToLower().Contains(d.ToLower())); - } + isVirtualMachine |= IsVirtualSystem(systemInfo.BiosInfo, systemInfo.Manufacturer, systemInfo.Model); logger.Debug($"Computer '{systemInfo.Name}' appears {(isVirtualMachine ? "" : "not ")}to be a virtual machine."); return isVirtualMachine; } - private bool IsVirtualSystemInfo(string biosInfo, string manufacturer, string model) + private bool HasVirtualDevice() { - var isVirtualMachine = false; + var hasVirtualDevice = false; + + foreach (var device in systemInfo.PlugAndPlayDeviceIds) + { + hasVirtualDevice |= DeviceBlacklist.Any(d => device.ToLower().Contains(d.ToLower())) && DeviceWhitelist.All(d => !device.ToLower().Contains(d.ToLower())); + } + + return hasVirtualDevice; + } + + private bool HasVirtualMacAddress() + { + var hasVirtualMacAddress = false; + var macAddress = systemInfo.MacAddress; + + if (macAddress != null && macAddress.Length > 2) + { + hasVirtualMacAddress |= macAddress.StartsWith(MANIPULATED); + hasVirtualMacAddress |= macAddress.StartsWith(QEMU_MAC_PREFIX); + hasVirtualMacAddress |= macAddress.StartsWith(VIRTUALBOX_MAC_PREFIX); + } + + return hasVirtualMacAddress; + } + + private bool IsVirtualCpu() + { + var isVirtualCpu = false; + + isVirtualCpu |= systemInfo.CpuName.ToLower().Contains(" kvm "); + + return isVirtualCpu; + } + + private bool IsVirtualRegistry() + { + var isVirtualRegistry = false; + + isVirtualRegistry |= HasHistoricVirtualMachineHardwareConfiguration(); + isVirtualRegistry |= HasLocalVirtualMachineDeviceCache(); + + return isVirtualRegistry; + } + + private bool IsVirtualSystem(string biosInfo, string manufacturer, string model) + { + var isVirtualSystem = false; biosInfo = biosInfo.ToLower(); manufacturer = manufacturer.ToLower(); model = model.ToLower(); - isVirtualMachine |= biosInfo.Contains("hyper-v"); - isVirtualMachine |= biosInfo.Contains("virtualbox"); - isVirtualMachine |= biosInfo.Contains("vmware"); - isVirtualMachine |= biosInfo.Contains("ovmf"); - isVirtualMachine |= biosInfo.Contains("edk ii unknown"); - isVirtualMachine |= manufacturer.Contains("microsoft corporation") && !model.Contains("surface"); - isVirtualMachine |= manufacturer.Contains("parallels software"); - isVirtualMachine |= manufacturer.Contains("qemu"); - isVirtualMachine |= manufacturer.Contains("vmware"); - isVirtualMachine |= model.Contains("virtualbox"); - isVirtualMachine |= model.Contains("Q35 +"); + isVirtualSystem |= biosInfo.Contains("hyper-v"); + isVirtualSystem |= biosInfo.Contains("virtualbox"); + isVirtualSystem |= biosInfo.Contains("vmware"); + isVirtualSystem |= biosInfo.Contains("ovmf"); + isVirtualSystem |= biosInfo.Contains("edk ii unknown"); + isVirtualSystem |= manufacturer.Contains("microsoft corporation") && !model.Contains("surface"); + isVirtualSystem |= manufacturer.Contains("parallels software"); + isVirtualSystem |= manufacturer.Contains("qemu"); + isVirtualSystem |= manufacturer.Contains("vmware"); + isVirtualSystem |= model.Contains("virtualbox"); + isVirtualSystem |= model.Contains("Q35 +"); - return isVirtualMachine; - } - - private bool IsVirtualRegistry() - { - var isVirtualMachine = false; - - isVirtualMachine |= HasHistoricVirtualMachineHardwareConfiguration(); - isVirtualMachine |= HasLocalVirtualMachineDeviceCache(); - - return isVirtualMachine; + return isVirtualSystem; } private bool HasHistoricVirtualMachineHardwareConfiguration() { - /** - * scanned registry format: - * - * HKLM\SYSTEM\HardwareConfig\{configId=uuid} - * - BIOSVendor - * - SystemManufacturer - * - ... - * \ComputerIds - * - {computerId=uuid}: {computerSummary=hardwareInfo} - * - */ - const string HARDWARE_ROOT_KEY = "HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig"; + const string HARDWARE_ROOT_KEY = @"HKEY_LOCAL_MACHINE\SYSTEM\HardwareConfig"; - var isVirtualMachine = false; + var hasHistoricConfiguration = false; - if (!registry.TryGetSubKeys(HARDWARE_ROOT_KEY, out var hardwareConfigSubkeys)) + if (registry.TryGetSubKeys(HARDWARE_ROOT_KEY, out var hardwareConfigSubkeys)) { - return false; - } - - foreach (var configId in hardwareConfigSubkeys) - { - var hardwareConfigKey = $"{HARDWARE_ROOT_KEY}\\{configId}"; - var didReadKeys = true; - - didReadKeys &= registry.TryRead(hardwareConfigKey, "BIOSVendor", out var biosVendor); - didReadKeys &= registry.TryRead(hardwareConfigKey, "BIOSVersion", out var biosVersion); - didReadKeys &= registry.TryRead(hardwareConfigKey, "SystemManufacturer", out var systemManufacturer); - didReadKeys &= registry.TryRead(hardwareConfigKey, "SystemProductName", out var systemProductName); - - if (!didReadKeys) + foreach (var configId in hardwareConfigSubkeys) { - continue; - } + var hardwareConfigKey = $"{HARDWARE_ROOT_KEY}\\{configId}"; + var computerIdsKey = $"{hardwareConfigKey}\\ComputerIds"; + var success = true; - var biosInfo = $"{(string) biosVendor} {(string) biosVersion}"; + success &= registry.TryRead(hardwareConfigKey, "BIOSVendor", out var biosVendor); + success &= registry.TryRead(hardwareConfigKey, "BIOSVersion", out var biosVersion); + success &= registry.TryRead(hardwareConfigKey, "SystemManufacturer", out var systemManufacturer); + success &= registry.TryRead(hardwareConfigKey, "SystemProductName", out var systemProductName); - isVirtualMachine |= IsVirtualSystemInfo(biosInfo, (string) systemManufacturer, (string) systemProductName); - - var computerIdsKey = $"{hardwareConfigKey}\\ComputerIds"; - if (!registry.TryGetNames(computerIdsKey, out var computerIdNames)) - { - continue; - } - - foreach (var computerIdName in computerIdNames) - { - if (!registry.TryRead(computerIdsKey, computerIdName, out var computerSummary)) + if (success) { - continue; - } + var biosInfo = $"{(string) biosVendor} {(string) biosVersion}"; - isVirtualMachine |= IsVirtualSystemInfo((string) computerSummary, (string) systemManufacturer, (string) systemProductName); + hasHistoricConfiguration |= IsVirtualSystem(biosInfo, (string) systemManufacturer, (string) systemProductName); + + if (registry.TryGetNames(computerIdsKey, out var computerIdNames)) + { + foreach (var computerIdName in computerIdNames) + { + if (registry.TryRead(computerIdsKey, computerIdName, out var computerSummary)) + { + hasHistoricConfiguration |= IsVirtualSystem((string) computerSummary, (string) systemManufacturer, (string) systemProductName); + } + } + } + } } } - return isVirtualMachine; + return hasHistoricConfiguration; } private bool HasLocalVirtualMachineDeviceCache() { - const string DEVICE_CACHE_PARENT_KEY = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"; + const string DEVICE_CACHE_PARENT_KEY = @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\TaskFlow\DeviceCache"; - var isVirtualMachine = false; var deviceName = System.Environment.GetEnvironmentVariable("COMPUTERNAME"); + var hasDeviceCache = false; var hasDeviceCacheKeys = registry.TryGetSubKeys(DEVICE_CACHE_PARENT_KEY, out var deviceCacheKeys); - if (deviceName != null && hasDeviceCacheKeys) + if (deviceName != default && hasDeviceCacheKeys) { foreach (var cacheId in deviceCacheKeys) { - var cacheIdKey = $"{DEVICE_CACHE_PARENT_KEY}\\{cacheId}"; + var cacheIdKey = $@"{DEVICE_CACHE_PARENT_KEY}\{cacheId}"; var didReadKeys = true; didReadKeys &= registry.TryRead(cacheIdKey, "DeviceName", out var cacheDeviceName); - if (!didReadKeys || deviceName.ToLower() != ((string) cacheDeviceName).ToLower()) + if (didReadKeys && deviceName.ToLower() == ((string) cacheDeviceName).ToLower()) { - continue; + didReadKeys &= registry.TryRead(cacheIdKey, "DeviceMake", out var cacheDeviceManufacturer); + didReadKeys &= registry.TryRead(cacheIdKey, "DeviceModel", out var cacheDeviceModel); + + if (didReadKeys) + { + hasDeviceCache |= IsVirtualSystem("", (string) cacheDeviceManufacturer, (string) cacheDeviceModel); + } } - - didReadKeys &= registry.TryRead(cacheIdKey, "DeviceMake", out var cacheDeviceManufacturer); - didReadKeys &= registry.TryRead(cacheIdKey, "DeviceModel", out var cacheDeviceModel); - - if (!didReadKeys) - { - continue; - } - - isVirtualMachine |= IsVirtualSystemInfo("", (string) cacheDeviceManufacturer, (string) cacheDeviceModel); } } - return isVirtualMachine; - } - - private bool IsVirtualWmi() - { - var isVirtualMachine = false; - var cpuObjSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor"); - - foreach (var cpuObj in cpuObjSearcher.Get()) - { - isVirtualMachine |= ((string) cpuObj["Name"]).ToLower().Contains(" kvm "); - } - - return isVirtualMachine; + return hasDeviceCache; } } }