From 71b722d21534dd345840546ddd8234ea9d5399cb Mon Sep 17 00:00:00 2001 From: user Date: Sat, 1 Apr 2023 16:25:56 +0200 Subject: [PATCH 01/20] added mac check, added WMI checks, and in progress registry check --- .../VirtualMachineDetector.cs | 75 ++++++++++++++++--- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 17d99b9b..cbce361f 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -6,9 +6,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; using System.Linq; +using System.Management; +using System.Runtime.InteropServices; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts; +using Microsoft.Win32; namespace SafeExamBrowser.SystemComponents { @@ -36,28 +40,80 @@ namespace SafeExamBrowser.SystemComponents this.logger = logger; this.systemInfo = systemInfo; } - - public bool IsVirtualMachine() + private bool IsVirtualSystemInfo(string biosInfo, string manufacturer, string model) { - var biosInfo = systemInfo.BiosInfo.ToLower(); - var isVirtualMachine = false; - var macAddress = systemInfo.MacAddress; - var manufacturer = systemInfo.Manufacturer.ToLower(); - var model = systemInfo.Model.ToLower(); - var devices = systemInfo.PlugAndPlayDeviceIds; + bool isVirtualMachine = 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"); // qemu 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 +"); + + return isVirtualMachine; + } + + private bool IsVirtualRegistry() + { + bool isVirtualMachine = false; + + RegistryKey hardwareConfig = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SYSTEM\\HardwareConfig"); + + foreach (string childKeyName in hardwareConfig.GetSubKeyNames()) + { + RegistryKey childKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($"SYSTEM\\HardwareConfig\\{childKeyName}"); + childKey.GetValue(""); + + } + + return isVirtualMachine; + } + + private bool IsVirtualWmi() + { + bool isVirtualMachine = false; + + ManagementObjectSearcher searcherCpu = new ManagementObjectSearcher("SELECT * FROM Win32_Processor"); + + // edge case where no CPU is detected? + foreach (ManagementObject obj in searcherCpu.Get()) + { + isVirtualMachine |= ((string) obj["Name"]).ToLower().Contains(" kvm "); // qemu + } + + return isVirtualMachine; + } + + public bool IsVirtualMachine() + { + var biosInfo = systemInfo.BiosInfo; + var isVirtualMachine = false; + var macAddress = systemInfo.MacAddress; + var manufacturer = systemInfo.Manufacturer; + var model = systemInfo.Model; + var devices = systemInfo.PlugAndPlayDeviceIds; + + isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); + isVirtualMachine |= IsVirtualWmi(); + isVirtualMachine |= IsVirtualRegistry(); + + // TODO: system version if (macAddress != null && macAddress.Count() > 2) { - isVirtualMachine |= macAddress.StartsWith(QEMU_MAC_PREFIX) || macAddress.StartsWith(VIRTUALBOX_MAC_PREFIX); + isVirtualMachine |= macAddress.StartsWith(QEMU_MAC_PREFIX); + isVirtualMachine |= macAddress.StartsWith(VIRTUALBOX_MAC_PREFIX); + isVirtualMachine |= macAddress.StartsWith("000000000000"); // indicates tampering } foreach (var device in devices) @@ -65,6 +121,7 @@ namespace SafeExamBrowser.SystemComponents isVirtualMachine |= DEVICE_BLACKLIST.Any(d => device.ToLower().Contains(d.ToLower())); } + logger.Debug($"Computer '{systemInfo.Name}' appears {(isVirtualMachine ? "" : "not ")}to be a virtual machine."); return isVirtualMachine; From c0f37b309ba420cc9983b2246f5735c40ba2eaae Mon Sep 17 00:00:00 2001 From: user Date: Sat, 1 Apr 2023 19:09:01 +0200 Subject: [PATCH 02/20] added registry check for the device cache --- .../VirtualMachineDetector.cs | 58 +++++++++++++++++-- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index cbce361f..3f59c935 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -42,6 +42,7 @@ namespace SafeExamBrowser.SystemComponents } private bool IsVirtualSystemInfo(string biosInfo, string manufacturer, string model) { + bool isVirtualMachine = false; biosInfo = biosInfo.ToLower(); @@ -60,6 +61,8 @@ namespace SafeExamBrowser.SystemComponents isVirtualMachine |= model.Contains("virtualbox"); isVirtualMachine |= model.Contains("Q35 +"); + Console.WriteLine($"biosInfo: {biosInfo}, manufacturer: {manufacturer}, model: {model}, isVirtualMachine: {isVirtualMachine}"); + return isVirtualMachine; } @@ -67,13 +70,58 @@ namespace SafeExamBrowser.SystemComponents { bool isVirtualMachine = false; + // check historic hardware profiles RegistryKey hardwareConfig = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SYSTEM\\HardwareConfig"); - foreach (string childKeyName in hardwareConfig.GetSubKeyNames()) + if (hardwareConfig != null) { - RegistryKey childKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($"SYSTEM\\HardwareConfig\\{childKeyName}"); - childKey.GetValue(""); + foreach (string configId in hardwareConfig.GetSubKeyNames()) + { + RegistryKey configKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($"SYSTEM\\HardwareConfig\\{configId}"); + if (configKey == null) + { + continue; + } + + // reconstruct the systemInfo.biosInfo string + string biosInfo = (string) configKey.GetValue("BIOSVendor") + " " + (string) configKey.GetValue("BIOSVersion"); + string manufacturer = (string) configKey.GetValue("SystemManufacturer"); + string model = (string) configKey.GetValue("SystemProductName"); + + isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); + + // TODO: check computerIds + } + } + + // check Windows timeline caches for current hardware config + RegistryKey deviceCache = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"); + + if (deviceCache != null) + { + foreach (string cacheId in deviceCache.GetSubKeyNames()) + { + RegistryKey cacheKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache\\{cacheId}"); + + if (cacheKey == null) + { + continue; + } + + string currHostname = Environment.GetEnvironmentVariable("COMPUTERNAME").ToLower(); + string cacheHostname = ((string) cacheKey.GetValue("DeviceName")).ToLower(); + + // windows timeline syncs with other hosts that a user has logged into, hence avoid false positives + if (cacheHostname == currHostname) + { + string biosInfo = ""; + string manufacturer = (string) cacheKey.GetValue("DeviceMake"); + string model = (string) cacheKey.GetValue("DeviceModel"); + + isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); + } + } } return isVirtualMachine; @@ -85,7 +133,7 @@ namespace SafeExamBrowser.SystemComponents ManagementObjectSearcher searcherCpu = new ManagementObjectSearcher("SELECT * FROM Win32_Processor"); - // edge case where no CPU is detected? + // TODO: how to handle no CPU? foreach (ManagementObject obj in searcherCpu.Get()) { isVirtualMachine |= ((string) obj["Name"]).ToLower().Contains(" kvm "); // qemu @@ -103,6 +151,7 @@ namespace SafeExamBrowser.SystemComponents var model = systemInfo.Model; var devices = systemInfo.PlugAndPlayDeviceIds; + // redundant: registry check (hardware config) isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); isVirtualMachine |= IsVirtualWmi(); isVirtualMachine |= IsVirtualRegistry(); @@ -121,7 +170,6 @@ namespace SafeExamBrowser.SystemComponents isVirtualMachine |= DEVICE_BLACKLIST.Any(d => device.ToLower().Contains(d.ToLower())); } - logger.Debug($"Computer '{systemInfo.Name}' appears {(isVirtualMachine ? "" : "not ")}to be a virtual machine."); return isVirtualMachine; From bd145e14b0386d003d6e960023ac0b69ed81ad4f Mon Sep 17 00:00:00 2001 From: user Date: Sat, 1 Apr 2023 19:54:38 +0200 Subject: [PATCH 03/20] chores --- SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 3f59c935..4c9ab014 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -6,13 +6,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -using System; using System.Linq; using System.Management; -using System.Runtime.InteropServices; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts; using Microsoft.Win32; +using System; namespace SafeExamBrowser.SystemComponents { @@ -61,8 +60,6 @@ namespace SafeExamBrowser.SystemComponents isVirtualMachine |= model.Contains("virtualbox"); isVirtualMachine |= model.Contains("Q35 +"); - Console.WriteLine($"biosInfo: {biosInfo}, manufacturer: {manufacturer}, model: {model}, isVirtualMachine: {isVirtualMachine}"); - return isVirtualMachine; } @@ -109,7 +106,7 @@ namespace SafeExamBrowser.SystemComponents continue; } - string currHostname = Environment.GetEnvironmentVariable("COMPUTERNAME").ToLower(); + string currHostname = System.Environment.GetEnvironmentVariable("COMPUTERNAME").ToLower(); string cacheHostname = ((string) cacheKey.GetValue("DeviceName")).ToLower(); // windows timeline syncs with other hosts that a user has logged into, hence avoid false positives From 1fec696909292b4dd4030282c46a0cbff0b1c427 Mon Sep 17 00:00:00 2001 From: user Date: Sat, 1 Apr 2023 20:14:24 +0200 Subject: [PATCH 04/20] added computerIds check --- .../VirtualMachineDetector.cs | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 4c9ab014..27116f63 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -11,7 +11,6 @@ using System.Management; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts; using Microsoft.Win32; -using System; namespace SafeExamBrowser.SystemComponents { @@ -58,7 +57,7 @@ namespace SafeExamBrowser.SystemComponents isVirtualMachine |= manufacturer.Contains("qemu"); isVirtualMachine |= manufacturer.Contains("vmware"); isVirtualMachine |= model.Contains("virtualbox"); - isVirtualMachine |= model.Contains("Q35 +"); + isVirtualMachine |= model.Contains("Q35 +"); // qemu return isVirtualMachine; } @@ -88,7 +87,20 @@ namespace SafeExamBrowser.SystemComponents isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); - // TODO: check computerIds + // hardware information of profile throughout installation etc. + RegistryKey computerIds = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($"SYSTEM\\HardwareConfig\\{configId}\\ComputerIds"); + + if (computerIds == null) + { + continue; + } + + foreach (string computerId in computerIds.GetSubKeyNames()) + { + // e.g. manufacturer&version&sku&... + string computer = (string)computerIds.GetValue(computerId); + isVirtualMachine |= IsVirtualSystemInfo(computer, computer, computer); + } } } @@ -121,6 +133,8 @@ namespace SafeExamBrowser.SystemComponents } } + // TODO: find a way to check BCD registries (to hunt for QEMU HARDDISK) without admin privs + return isVirtualMachine; } @@ -148,13 +162,11 @@ namespace SafeExamBrowser.SystemComponents var model = systemInfo.Model; var devices = systemInfo.PlugAndPlayDeviceIds; - // redundant: registry check (hardware config) + // redundant: registry check (hardware config) does this aswell isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); isVirtualMachine |= IsVirtualWmi(); isVirtualMachine |= IsVirtualRegistry(); - // TODO: system version - if (macAddress != null && macAddress.Count() > 2) { isVirtualMachine |= macAddress.StartsWith(QEMU_MAC_PREFIX); From 22ef7ef364e1c5cdf856594d7564726cc7e375f8 Mon Sep 17 00:00:00 2001 From: user Date: Sat, 8 Apr 2023 12:53:06 +0200 Subject: [PATCH 05/20] chores --- SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 27116f63..bd972c2f 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -38,9 +38,9 @@ namespace SafeExamBrowser.SystemComponents this.logger = logger; this.systemInfo = systemInfo; } + private bool IsVirtualSystemInfo(string biosInfo, string manufacturer, string model) { - bool isVirtualMachine = false; biosInfo = biosInfo.ToLower(); @@ -133,8 +133,6 @@ namespace SafeExamBrowser.SystemComponents } } - // TODO: find a way to check BCD registries (to hunt for QEMU HARDDISK) without admin privs - return isVirtualMachine; } @@ -144,7 +142,6 @@ namespace SafeExamBrowser.SystemComponents ManagementObjectSearcher searcherCpu = new ManagementObjectSearcher("SELECT * FROM Win32_Processor"); - // TODO: how to handle no CPU? foreach (ManagementObject obj in searcherCpu.Get()) { isVirtualMachine |= ((string) obj["Name"]).ToLower().Contains(" kvm "); // qemu @@ -162,7 +159,7 @@ namespace SafeExamBrowser.SystemComponents var model = systemInfo.Model; var devices = systemInfo.PlugAndPlayDeviceIds; - // redundant: registry check (hardware config) does this aswell + // redundancy: registry check does this aswell (systemInfo may be using different methods) isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); isVirtualMachine |= IsVirtualWmi(); isVirtualMachine |= IsVirtualRegistry(); From 538127661f65d5e8fdc86ffaf826e103d4247d95 Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Fri, 14 Apr 2023 19:56:22 +0200 Subject: [PATCH 06/20] chore: moved public functions above private functions --- .../VirtualMachineDetector.cs | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index bd972c2f..95ad7d42 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -39,6 +39,37 @@ namespace SafeExamBrowser.SystemComponents this.systemInfo = systemInfo; } + public bool IsVirtualMachine() + { + var biosInfo = systemInfo.BiosInfo; + var isVirtualMachine = false; + var macAddress = systemInfo.MacAddress; + var manufacturer = systemInfo.Manufacturer; + var model = systemInfo.Model; + var devices = systemInfo.PlugAndPlayDeviceIds; + + // redundancy: registry check does this aswell (systemInfo may be using different methods) + isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); + isVirtualMachine |= IsVirtualWmi(); + isVirtualMachine |= IsVirtualRegistry(); + + if (macAddress != null && macAddress.Count() > 2) + { + isVirtualMachine |= macAddress.StartsWith(QEMU_MAC_PREFIX); + isVirtualMachine |= macAddress.StartsWith(VIRTUALBOX_MAC_PREFIX); + isVirtualMachine |= macAddress.StartsWith("000000000000"); // indicates tampering + } + + foreach (var device in devices) + { + isVirtualMachine |= DEVICE_BLACKLIST.Any(d => device.ToLower().Contains(d.ToLower())); + } + + logger.Debug($"Computer '{systemInfo.Name}' appears {(isVirtualMachine ? "" : "not ")}to be a virtual machine."); + + return isVirtualMachine; + } + private bool IsVirtualSystemInfo(string biosInfo, string manufacturer, string model) { bool isVirtualMachine = false; @@ -98,7 +129,7 @@ namespace SafeExamBrowser.SystemComponents foreach (string computerId in computerIds.GetSubKeyNames()) { // e.g. manufacturer&version&sku&... - string computer = (string)computerIds.GetValue(computerId); + string computer = (string) computerIds.GetValue(computerId); isVirtualMachine |= IsVirtualSystemInfo(computer, computer, computer); } } @@ -106,7 +137,7 @@ namespace SafeExamBrowser.SystemComponents // check Windows timeline caches for current hardware config RegistryKey deviceCache = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"); - + if (deviceCache != null) { foreach (string cacheId in deviceCache.GetSubKeyNames()) @@ -121,7 +152,7 @@ namespace SafeExamBrowser.SystemComponents string currHostname = System.Environment.GetEnvironmentVariable("COMPUTERNAME").ToLower(); string cacheHostname = ((string) cacheKey.GetValue("DeviceName")).ToLower(); - // windows timeline syncs with other hosts that a user has logged into, hence avoid false positives + // windows timeline syncs with other hosts that a user has logged into: check hostname to only check this device if (cacheHostname == currHostname) { string biosInfo = ""; @@ -144,41 +175,10 @@ namespace SafeExamBrowser.SystemComponents foreach (ManagementObject obj in searcherCpu.Get()) { - isVirtualMachine |= ((string) obj["Name"]).ToLower().Contains(" kvm "); // qemu + isVirtualMachine |= ((string) obj["Name"]).ToLower().Contains(" kvm "); // qemu (KVM specifically) } return isVirtualMachine; } - - public bool IsVirtualMachine() - { - var biosInfo = systemInfo.BiosInfo; - var isVirtualMachine = false; - var macAddress = systemInfo.MacAddress; - var manufacturer = systemInfo.Manufacturer; - var model = systemInfo.Model; - var devices = systemInfo.PlugAndPlayDeviceIds; - - // redundancy: registry check does this aswell (systemInfo may be using different methods) - isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); - isVirtualMachine |= IsVirtualWmi(); - isVirtualMachine |= IsVirtualRegistry(); - - if (macAddress != null && macAddress.Count() > 2) - { - isVirtualMachine |= macAddress.StartsWith(QEMU_MAC_PREFIX); - isVirtualMachine |= macAddress.StartsWith(VIRTUALBOX_MAC_PREFIX); - isVirtualMachine |= macAddress.StartsWith("000000000000"); // indicates tampering - } - - foreach (var device in devices) - { - isVirtualMachine |= DEVICE_BLACKLIST.Any(d => device.ToLower().Contains(d.ToLower())); - } - - logger.Debug($"Computer '{systemInfo.Name}' appears {(isVirtualMachine ? "" : "not ")}to be a virtual machine."); - - return isVirtualMachine; - } } } From c201389af412c5f88309a5eeabbdd4e23ba92d48 Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Fri, 14 Apr 2023 20:13:29 +0200 Subject: [PATCH 07/20] chore: switches to using `var` instead of explicit typing --- .../VirtualMachineDetector.cs | 57 +++++++++---------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 95ad7d42..a157e95b 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -72,7 +72,7 @@ namespace SafeExamBrowser.SystemComponents private bool IsVirtualSystemInfo(string biosInfo, string manufacturer, string model) { - bool isVirtualMachine = false; + var isVirtualMachine = false; biosInfo = biosInfo.ToLower(); manufacturer = manufacturer.ToLower(); @@ -95,16 +95,15 @@ namespace SafeExamBrowser.SystemComponents private bool IsVirtualRegistry() { - bool isVirtualMachine = false; + var isVirtualMachine = false; // check historic hardware profiles - RegistryKey hardwareConfig = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SYSTEM\\HardwareConfig"); - - if (hardwareConfig != null) + var hardwareConfKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SYSTEM\\HardwareConfig"); + if (hardwareConfKey != null) { - foreach (string configId in hardwareConfig.GetSubKeyNames()) + foreach (string configId in hardwareConfKey.GetSubKeyNames()) { - RegistryKey configKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($"SYSTEM\\HardwareConfig\\{configId}"); + var configKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($"SYSTEM\\HardwareConfig\\{configId}"); if (configKey == null) { @@ -112,52 +111,51 @@ namespace SafeExamBrowser.SystemComponents } // reconstruct the systemInfo.biosInfo string - string biosInfo = (string) configKey.GetValue("BIOSVendor") + " " + (string) configKey.GetValue("BIOSVersion"); - string manufacturer = (string) configKey.GetValue("SystemManufacturer"); - string model = (string) configKey.GetValue("SystemProductName"); + var biosInfo = (string) configKey.GetValue("BIOSVendor") + " " + (string) configKey.GetValue("BIOSVersion"); + var manufacturer = (string) configKey.GetValue("SystemManufacturer"); + var model = (string) configKey.GetValue("SystemProductName"); isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); // hardware information of profile throughout installation etc. - RegistryKey computerIds = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($"SYSTEM\\HardwareConfig\\{configId}\\ComputerIds"); + var computerIdsKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($"SYSTEM\\HardwareConfig\\{configId}\\ComputerIds"); - if (computerIds == null) + if (computerIdsKey == null) { continue; } - foreach (string computerId in computerIds.GetSubKeyNames()) + foreach (var computerId in computerIdsKey.GetSubKeyNames()) { // e.g. manufacturer&version&sku&... - string computer = (string) computerIds.GetValue(computerId); - isVirtualMachine |= IsVirtualSystemInfo(computer, computer, computer); + var computerSummary = (string) computerIdsKey.GetValue(computerId); + isVirtualMachine |= IsVirtualSystemInfo(computerSummary, computerSummary, computerSummary); } } } // check Windows timeline caches for current hardware config - RegistryKey deviceCache = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"); - - if (deviceCache != null) + var deviceCacheKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"); + if (deviceCacheKey != null) { - foreach (string cacheId in deviceCache.GetSubKeyNames()) + foreach (var cacheId in deviceCacheKey.GetSubKeyNames()) { - RegistryKey cacheKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache\\{cacheId}"); + var cacheKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache\\{cacheId}"); if (cacheKey == null) { continue; } - string currHostname = System.Environment.GetEnvironmentVariable("COMPUTERNAME").ToLower(); - string cacheHostname = ((string) cacheKey.GetValue("DeviceName")).ToLower(); + var currHostname = System.Environment.GetEnvironmentVariable("COMPUTERNAME").ToLower(); + var cacheHostname = ((string) cacheKey.GetValue("DeviceName")).ToLower(); // windows timeline syncs with other hosts that a user has logged into: check hostname to only check this device if (cacheHostname == currHostname) { - string biosInfo = ""; - string manufacturer = (string) cacheKey.GetValue("DeviceMake"); - string model = (string) cacheKey.GetValue("DeviceModel"); + var biosInfo = ""; + var manufacturer = (string) cacheKey.GetValue("DeviceMake"); + var model = (string) cacheKey.GetValue("DeviceModel"); isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); } @@ -169,13 +167,12 @@ namespace SafeExamBrowser.SystemComponents private bool IsVirtualWmi() { - bool isVirtualMachine = false; + var isVirtualMachine = false; + var cpuObjSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor"); - ManagementObjectSearcher searcherCpu = new ManagementObjectSearcher("SELECT * FROM Win32_Processor"); - - foreach (ManagementObject obj in searcherCpu.Get()) + foreach (var cpuObj in cpuObjSearcher.Get()) { - isVirtualMachine |= ((string) obj["Name"]).ToLower().Contains(" kvm "); // qemu (KVM specifically) + isVirtualMachine |= ((string) cpuObj["Name"]).ToLower().Contains(" kvm "); // qemu (KVM specifically) } return isVirtualMachine; From efb3c8056a0ba69f831303dac2d82e53511704f5 Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Fri, 14 Apr 2023 21:18:08 +0200 Subject: [PATCH 08/20] fix: fixed crash when env var "computername" does not exist --- SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index a157e95b..5294d825 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -136,7 +136,9 @@ namespace SafeExamBrowser.SystemComponents // check Windows timeline caches for current hardware config var deviceCacheKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"); - if (deviceCacheKey != null) + var currHostname = System.Environment.GetEnvironmentVariable("COMPUTERNAME"); + + if (deviceCacheKey != null && currHostname != null) { foreach (var cacheId in deviceCacheKey.GetSubKeyNames()) { @@ -147,7 +149,6 @@ namespace SafeExamBrowser.SystemComponents continue; } - var currHostname = System.Environment.GetEnvironmentVariable("COMPUTERNAME").ToLower(); var cacheHostname = ((string) cacheKey.GetValue("DeviceName")).ToLower(); // windows timeline syncs with other hosts that a user has logged into: check hostname to only check this device From e4e0f7c16be471b24a1d68585e0eb2ed6fea2c02 Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Fri, 14 Apr 2023 21:22:53 +0200 Subject: [PATCH 09/20] fix: corrected lowercasing on `computercheck` name --- SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 5294d825..69a9e3fe 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -152,7 +152,7 @@ namespace SafeExamBrowser.SystemComponents var cacheHostname = ((string) cacheKey.GetValue("DeviceName")).ToLower(); // windows timeline syncs with other hosts that a user has logged into: check hostname to only check this device - if (cacheHostname == currHostname) + if (currHostname.ToLower() == cacheHostname) { var biosInfo = ""; var manufacturer = (string) cacheKey.GetValue("DeviceMake"); From 7fc31f6e90f9884160962c7cf001b772dd911a9b Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Mon, 17 Jul 2023 16:40:33 +0200 Subject: [PATCH 10/20] feat: extended IRegistry interface (no breaking changes). VM detection is broken regardless --- SafeExamBrowser.Runtime/CompositionRoot.cs | 2 +- .../Registry/IRegistry.cs | 11 ++ .../Registry/Registry.cs | 134 ++++++++++++++++++ .../VirtualMachineDetector.cs | 93 ++++++++---- 4 files changed, 208 insertions(+), 32 deletions(-) diff --git a/SafeExamBrowser.Runtime/CompositionRoot.cs b/SafeExamBrowser.Runtime/CompositionRoot.cs index 7b3ca5bc..97c3b564 100644 --- a/SafeExamBrowser.Runtime/CompositionRoot.cs +++ b/SafeExamBrowser.Runtime/CompositionRoot.cs @@ -83,7 +83,7 @@ namespace SafeExamBrowser.Runtime var serviceProxy = new ServiceProxy(appConfig.ServiceAddress, new ProxyObjectFactory(), ModuleLogger(nameof(ServiceProxy)), Interlocutor.Runtime); var sessionContext = new SessionContext(); var splashScreen = uiFactory.CreateSplashScreen(appConfig); - var vmDetector = new VirtualMachineDetector(ModuleLogger(nameof(VirtualMachineDetector)), systemInfo); + var vmDetector = new VirtualMachineDetector(ModuleLogger(nameof(VirtualMachineDetector)), registry, systemInfo); var bootstrapOperations = new Queue(); var sessionOperations = new Queue(); diff --git a/SafeExamBrowser.SystemComponents.Contracts/Registry/IRegistry.cs b/SafeExamBrowser.SystemComponents.Contracts/Registry/IRegistry.cs index 25db0c17..da6aabcd 100644 --- a/SafeExamBrowser.SystemComponents.Contracts/Registry/IRegistry.cs +++ b/SafeExamBrowser.SystemComponents.Contracts/Registry/IRegistry.cs @@ -7,6 +7,7 @@ */ using SafeExamBrowser.SystemComponents.Contracts.Registry.Events; +using System.Collections.Generic; namespace SafeExamBrowser.SystemComponents.Contracts.Registry { @@ -34,5 +35,15 @@ namespace SafeExamBrowser.SystemComponents.Contracts.Registry /// Attempts to read the value of the given name under the specified registry key. /// bool TryRead(string key, string name, out object value); + + /// + /// Attempts to read the value names of the given registry key. + /// + bool TryGetNames(string key, out IEnumerable names); + + /// + /// Attempts to read the subkey names of the given registry key. + /// + bool TryGetSubKeys(string key, out IEnumerable subKeys); } } diff --git a/SafeExamBrowser.SystemComponents/Registry/Registry.cs b/SafeExamBrowser.SystemComponents/Registry/Registry.cs index cbbf958b..68d2f886 100644 --- a/SafeExamBrowser.SystemComponents/Registry/Registry.cs +++ b/SafeExamBrowser.SystemComponents/Registry/Registry.cs @@ -8,7 +8,10 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Security.Cryptography; using System.Timers; +using Microsoft.Win32; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts.Registry; using SafeExamBrowser.SystemComponents.Contracts.Registry.Events; @@ -86,6 +89,38 @@ namespace SafeExamBrowser.SystemComponents.Registry return success; } + public bool TryGetNames(string key, out IEnumerable names) + { + names = null; + + RegistryKey keyObj; + if (!TryOpenKey(key, out keyObj)) + return false; + + using (keyObj) + { + names = keyObj.GetValueNames(); + } + + return true; + } + + public bool TryGetSubKeys(string key, out IEnumerable subKeys) + { + subKeys = null; + + RegistryKey keyObj; + if (!TryOpenKey(key, out keyObj)) + return false; + + using (keyObj) + { + subKeys = keyObj.GetSubKeyNames(); + } + + return true; + } + private void Timer_Elapsed(object sender, ElapsedEventArgs e) { foreach (var item in values) @@ -104,5 +139,104 @@ namespace SafeExamBrowser.SystemComponents.Registry } } } + + /// + /// Parses a keyName and returns the basekey for it. + /// It will also store the subkey name in the out parameter. + /// If the keyName is not valid, we will return false. + /// Does not raise Exceptions. + /// Supports shortcuts. + /// + // yoinked (and partially modified to follow SEB conventions) private Win32 function: https://stackoverflow.com/a/58547945 + private bool GetBaseKeyFromKeyName(string keyName, out RegistryKey hiveKey, out string subKeyName) + { + hiveKey = null; + subKeyName = null; + + string basekeyName; + int i = keyName.IndexOf('\\'); + if (i != -1) + { + basekeyName = keyName.Substring(0, i).ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + else + { + basekeyName = keyName.ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + + // add shortcuts as well to be implicit + switch (basekeyName) + { + case "HKEY_CURRENT_USER": + case "HKCU": + hiveKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); + break; + case "HKEY_LOCAL_MACHINE": + case "HKLM": + hiveKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); + break; + case "HKEY_CLASSES_ROOT": + case "HKCR": + hiveKey = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64); + break; + case "HKEY_USERS": + case "HKU": + hiveKey = RegistryKey.OpenBaseKey(RegistryHive.Users, RegistryView.Registry64); + break; + case "HKEY_PERFORMANCE_DATA": + case "HKPD": + hiveKey = RegistryKey.OpenBaseKey(RegistryHive.PerformanceData, RegistryView.Registry64); + break; + case "HKEY_CURRENT_CONFIG": + case "HKCC": + hiveKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentConfig, RegistryView.Registry64); + break; + case "HKEY_DYN_DATA": + case "HKDD": + hiveKey = RegistryKey.OpenBaseKey(RegistryHive.DynData, RegistryView.Registry64); + break; + default: + // output is already set to null at the start + return false; + } + + if (i == -1 || i == keyName.Length) + { + subKeyName = string.Empty; + } + else + { + subKeyName = keyName.Substring(i + 1, keyName.Length - i - 1); + } + + return true; + } + + /// + /// Tries to open a key and outputs a RegistryKey object. Does not raise Exceptions, but returns false/true. + /// + private bool TryOpenKey(string key, out RegistryKey keyObj) + { + keyObj = null; + + string subHiveKey; + try + { + RegistryKey hiveObj; + if (!GetBaseKeyFromKeyName(key, out hiveObj, out subHiveKey)) + return false; + + keyObj = hiveObj.OpenSubKey(subHiveKey); + if (keyObj == null) + return false; + } + catch (Exception e) + { + logger.Error($"Failed to open registry key '{key}'!", e); + return false; + } + + return true; + } } } diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 69a9e3fe..1cff1b81 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -10,7 +10,11 @@ using System.Linq; using System.Management; using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.SystemComponents.Contracts; +using SafeExamBrowser.SystemComponents.Contracts.Registry; using Microsoft.Win32; +using System.Collections; +using System.Collections.Generic; +using System; namespace SafeExamBrowser.SystemComponents { @@ -31,11 +35,13 @@ namespace SafeExamBrowser.SystemComponents private static readonly string VIRTUALBOX_MAC_PREFIX = "080027"; private readonly ILogger logger; + private readonly IRegistry registry; private readonly ISystemInfo systemInfo; - public VirtualMachineDetector(ILogger logger, ISystemInfo systemInfo) + public VirtualMachineDetector(ILogger logger, IRegistry registry, ISystemInfo systemInfo) { this.logger = logger; + this.registry = registry; this.systemInfo = systemInfo; } @@ -97,45 +103,70 @@ namespace SafeExamBrowser.SystemComponents { var isVirtualMachine = false; - // check historic hardware profiles - var hardwareConfKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SYSTEM\\HardwareConfig"); - if (hardwareConfKey != null) + /** + * check historic hardware profiles + * + * HKLM\SYSTEM\HardwareConfig\{configId=uuid}\ComputerIds + * - {computerId=uuid}: {computerSummary=hardwareInfo} + * + */ + IEnumerable hardwareConfigSubkeys; + if (!registry.TryGetSubKeys("HKLM\\SYSTEM\\HardwareConfig", out hardwareConfigSubkeys)) + return false; + + foreach (string configId in hardwareConfigSubkeys) { - foreach (string configId in hardwareConfKey.GetSubKeyNames()) + logger.Info($"scanning configId: {configId}"); + var configKey = $"HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig\\{configId}"; + + object biosVendor; + object biosVersion; + object systemManufacturer; + object systemProductName; + + bool success = true; + + success &= registry.TryRead(configKey, "BIOSVendor", out biosVendor); + success &= registry.TryRead(configKey, "BIOSVersion", out biosVersion); + success &= registry.TryRead(configKey, "SystemManufacturer", out systemManufacturer); + success &= registry.TryRead(configKey, "SystemProductName", out systemProductName); + + if (!success) + continue; + + // reconstruct the systemInfo.biosInfo string + string biosInfo = $"{(string) biosVendor} {(string) biosVersion}"; + + isVirtualMachine |= IsVirtualSystemInfo(biosInfo, (string) systemManufacturer, (string) systemProductName); + + // hardware information of profile throughout installation etc. + IEnumerable computerIds; + if (!registry.TryGetSubKeys($"HKLM\\SYSTEM\\HardwareConfig\\{configId}\\ComputerIds", out computerIds)) + return false; + + foreach (var computerId in computerIds) { - var configKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($"SYSTEM\\HardwareConfig\\{configId}"); + logger.Info($"computerId: {computerId}"); + // e.g. manufacturer&version&sku&... + object computerSummary; // = (string) computerIds.GetValue(computerId); - if (configKey == null) - { + if (!registry.TryRead($"HKLM\\SYSTEM\\HardwareConfig\\{configId}\\ComputerIds", computerId, out computerSummary)) continue; - } - // reconstruct the systemInfo.biosInfo string - var biosInfo = (string) configKey.GetValue("BIOSVendor") + " " + (string) configKey.GetValue("BIOSVersion"); - var manufacturer = (string) configKey.GetValue("SystemManufacturer"); - var model = (string) configKey.GetValue("SystemProductName"); - - isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); - - // hardware information of profile throughout installation etc. - var computerIdsKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($"SYSTEM\\HardwareConfig\\{configId}\\ComputerIds"); - - if (computerIdsKey == null) - { - continue; - } - - foreach (var computerId in computerIdsKey.GetSubKeyNames()) - { - // e.g. manufacturer&version&sku&... - var computerSummary = (string) computerIdsKey.GetValue(computerId); - isVirtualMachine |= IsVirtualSystemInfo(computerSummary, computerSummary, computerSummary); - } + isVirtualMachine |= IsVirtualSystemInfo((string) computerSummary, (string) systemManufacturer, (string) systemProductName); } } // check Windows timeline caches for current hardware config - var deviceCacheKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"); + /*IEnumerable deviceCacheSubkeys; + if (registry.TryGetSubKeys($"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache", out deviceCacheSubkeys) + { + foreach (string deviceCacheKey in deviceCacheSubkeys) + { + if (registry.TryRead($"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"))*/ + + + var deviceCacheKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"); var currHostname = System.Environment.GetEnvironmentVariable("COMPUTERNAME"); if (deviceCacheKey != null && currHostname != null) From e99bdabc51e393117ec2f3d6a11d8298eebc62ff Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Mon, 17 Jul 2023 16:57:14 +0200 Subject: [PATCH 11/20] fix: used default instead of null for better type safety --- .../Registry/Registry.cs | 42 +++++++++++++++---- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/Registry/Registry.cs b/SafeExamBrowser.SystemComponents/Registry/Registry.cs index 68d2f886..09f040f2 100644 --- a/SafeExamBrowser.SystemComponents/Registry/Registry.cs +++ b/SafeExamBrowser.SystemComponents/Registry/Registry.cs @@ -91,34 +91,55 @@ namespace SafeExamBrowser.SystemComponents.Registry public bool TryGetNames(string key, out IEnumerable names) { - names = null; + names = default; RegistryKey keyObj; if (!TryOpenKey(key, out keyObj)) return false; + bool success = true; using (keyObj) { - names = keyObj.GetValueNames(); + try + { + names = keyObj.GetValueNames(); + } + catch (Exception e) + { + logger.Error($"Failed to get registry value names '{key}'!", e); + success = false; + // persist keyObj dispose operation by finishing using() {} + } + } - return true; + return success; } public bool TryGetSubKeys(string key, out IEnumerable subKeys) { - subKeys = null; + subKeys = default; RegistryKey keyObj; if (!TryOpenKey(key, out keyObj)) return false; + bool success = true; using (keyObj) { - subKeys = keyObj.GetSubKeyNames(); + try + { + subKeys = keyObj.GetSubKeyNames(); + } + catch (Exception e) + { + logger.Error($"Failed to get registry value names '{key}'!", e); + success = false; + // persist keyObj dispose operation by finishing using() {} + } } - return true; + return success; } private void Timer_Elapsed(object sender, ElapsedEventArgs e) @@ -150,8 +171,8 @@ namespace SafeExamBrowser.SystemComponents.Registry // yoinked (and partially modified to follow SEB conventions) private Win32 function: https://stackoverflow.com/a/58547945 private bool GetBaseKeyFromKeyName(string keyName, out RegistryKey hiveKey, out string subKeyName) { - hiveKey = null; - subKeyName = null; + hiveKey = default; + subKeyName = default; string basekeyName; int i = keyName.IndexOf('\\'); @@ -217,7 +238,7 @@ namespace SafeExamBrowser.SystemComponents.Registry /// private bool TryOpenKey(string key, out RegistryKey keyObj) { - keyObj = null; + keyObj = default; string subHiveKey; try @@ -228,7 +249,10 @@ namespace SafeExamBrowser.SystemComponents.Registry keyObj = hiveObj.OpenSubKey(subHiveKey); if (keyObj == null) + { + keyObj = default; return false; + } } catch (Exception e) { From 3b8f552138f723f977a24f9ae055ce7f96a01658 Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Mon, 17 Jul 2023 17:06:46 +0200 Subject: [PATCH 12/20] fix: ported first part of IsVirtualRegistry to use IRegistry --- .../VirtualMachineDetector.cs | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 1cff1b81..48fadf81 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -111,14 +111,16 @@ namespace SafeExamBrowser.SystemComponents * */ IEnumerable hardwareConfigSubkeys; - if (!registry.TryGetSubKeys("HKLM\\SYSTEM\\HardwareConfig", out hardwareConfigSubkeys)) + const string hwConfigParentKey = "HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig"; + if (!registry.TryGetSubKeys(hwConfigParentKey, out hardwareConfigSubkeys)) return false; foreach (string configId in hardwareConfigSubkeys) { logger.Info($"scanning configId: {configId}"); - var configKey = $"HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig\\{configId}"; + var hwConfigKey = $"{hwConfigParentKey}\\{configId}"; + // collect system values for IsVirtualSystemInfo() object biosVendor; object biosVersion; object systemManufacturer; @@ -126,10 +128,10 @@ namespace SafeExamBrowser.SystemComponents bool success = true; - success &= registry.TryRead(configKey, "BIOSVendor", out biosVendor); - success &= registry.TryRead(configKey, "BIOSVersion", out biosVersion); - success &= registry.TryRead(configKey, "SystemManufacturer", out systemManufacturer); - success &= registry.TryRead(configKey, "SystemProductName", out systemProductName); + success &= registry.TryRead(hwConfigKey, "BIOSVendor", out biosVendor); + success &= registry.TryRead(hwConfigKey, "BIOSVersion", out biosVersion); + success &= registry.TryRead(hwConfigKey, "SystemManufacturer", out systemManufacturer); + success &= registry.TryRead(hwConfigKey, "SystemProductName", out systemProductName); if (!success) continue; @@ -139,18 +141,19 @@ namespace SafeExamBrowser.SystemComponents isVirtualMachine |= IsVirtualSystemInfo(biosInfo, (string) systemManufacturer, (string) systemProductName); - // hardware information of profile throughout installation etc. - IEnumerable computerIds; - if (!registry.TryGetSubKeys($"HKLM\\SYSTEM\\HardwareConfig\\{configId}\\ComputerIds", out computerIds)) - return false; + // check even more hardware information + IEnumerable computerIdNames; + var computerIdsKey = $"{hwConfigKey}\\ComputerIds"; + if (!registry.TryGetNames(computerIdsKey, out computerIdNames)) + continue; - foreach (var computerId in computerIds) + foreach (var computerIdName in computerIdNames) { - logger.Info($"computerId: {computerId}"); - // e.g. manufacturer&version&sku&... - object computerSummary; // = (string) computerIds.GetValue(computerId); - - if (!registry.TryRead($"HKLM\\SYSTEM\\HardwareConfig\\{configId}\\ComputerIds", computerId, out computerSummary)) + logger.Info($"computerId: {computerIdName}"); + + // collect computer hardware summary (e.g. manufacturer&version&sku&...) + object computerSummary; + if (!registry.TryRead(computerIdsKey, computerIdName, out computerSummary)) continue; isVirtualMachine |= IsVirtualSystemInfo((string) computerSummary, (string) systemManufacturer, (string) systemProductName); From 689e388e2344fbf78230628be0eb986aee258ec0 Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Mon, 17 Jul 2023 17:33:21 +0200 Subject: [PATCH 13/20] chore: split up functions and added docs --- .../VirtualMachineDetector.cs | 81 ++++++++++++------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 48fadf81..c7e37fa4 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -76,6 +76,9 @@ namespace SafeExamBrowser.SystemComponents return isVirtualMachine; } + /// + /// Scans parameters for disallowed strings (signatures) + /// private bool IsVirtualSystemInfo(string biosInfo, string manufacturer, string model) { var isVirtualMachine = false; @@ -103,8 +106,23 @@ namespace SafeExamBrowser.SystemComponents { var isVirtualMachine = false; + // the resulting IsVirtualRegistry() would be massive so split it + isVirtualMachine |= IsVirtualRegistryHardwareConfig(); + isVirtualMachine |= IsVirtualRegistryDeviceCache(); + + return isVirtualMachine; + } + + + /// + /// Scans (historic) hardware configurations in the registry. + /// + private bool IsVirtualRegistryHardwareConfig() + { + bool isVirtualMachine = false; + /** - * check historic hardware profiles + * scanned registry format: * * HKLM\SYSTEM\HardwareConfig\{configId=uuid}\ComputerIds * - {computerId=uuid}: {computerSummary=hardwareInfo} @@ -127,7 +145,6 @@ namespace SafeExamBrowser.SystemComponents object systemProductName; bool success = true; - success &= registry.TryRead(hwConfigKey, "BIOSVendor", out biosVendor); success &= registry.TryRead(hwConfigKey, "BIOSVersion", out biosVersion); success &= registry.TryRead(hwConfigKey, "SystemManufacturer", out systemManufacturer); @@ -150,7 +167,7 @@ namespace SafeExamBrowser.SystemComponents foreach (var computerIdName in computerIdNames) { logger.Info($"computerId: {computerIdName}"); - + // collect computer hardware summary (e.g. manufacturer&version&sku&...) object computerSummary; if (!registry.TryRead(computerIdsKey, computerIdName, out computerSummary)) @@ -160,40 +177,46 @@ namespace SafeExamBrowser.SystemComponents } } + return isVirtualMachine; + } + + /// + /// Scans (synced) device cache for hardware info of the current device. + /// + private bool IsVirtualRegistryDeviceCache() + { + bool isVirtualMachine = false; + + // device cache contains hardware about other devices logged into as well, so lock onto this device in case an innocent VM was logged into. + // in the future, try to improve this check somehow since DeviceCache only gives ComputerName + var deviceName = System.Environment.GetEnvironmentVariable("COMPUTERNAME"); + // check Windows timeline caches for current hardware config - /*IEnumerable deviceCacheSubkeys; - if (registry.TryGetSubKeys($"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache", out deviceCacheSubkeys) + const string deviceCacheParentKey = "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"; + IEnumerable deviceCacheKeys; + bool has_dc_keys = registry.TryGetSubKeys(deviceCacheParentKey, out deviceCacheKeys); + + if (deviceName != null && has_dc_keys) { - foreach (string deviceCacheKey in deviceCacheSubkeys) + foreach (string cacheId in deviceCacheKeys) { - if (registry.TryRead($"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"))*/ + var cacheIdKey = $"{deviceCacheParentKey}\\{cacheId}"; + object cacheDeviceName; + object cacheDeviceManufacturer; + object cacheDeviceModel; + bool success = true; + success &= registry.TryRead(cacheIdKey, "DeviceName", out cacheDeviceName); - var deviceCacheKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"); - var currHostname = System.Environment.GetEnvironmentVariable("COMPUTERNAME"); - - if (deviceCacheKey != null && currHostname != null) - { - foreach (var cacheId in deviceCacheKey.GetSubKeyNames()) - { - var cacheKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey($"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache\\{cacheId}"); - - if (cacheKey == null) - { + if (!success || deviceName.ToLower() != ((string) cacheDeviceName).ToLower()) continue; - } - var cacheHostname = ((string) cacheKey.GetValue("DeviceName")).ToLower(); + success &= registry.TryRead(cacheIdKey, "DeviceMake", out cacheDeviceManufacturer); + success &= registry.TryRead(cacheIdKey, "DeviceModel", out cacheDeviceModel); + if (!success) + continue; - // windows timeline syncs with other hosts that a user has logged into: check hostname to only check this device - if (currHostname.ToLower() == cacheHostname) - { - var biosInfo = ""; - var manufacturer = (string) cacheKey.GetValue("DeviceMake"); - var model = (string) cacheKey.GetValue("DeviceModel"); - - isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); - } + isVirtualMachine |= IsVirtualSystemInfo("", (string) cacheDeviceManufacturer, (string) cacheDeviceModel); } } From a21c9007abeb9f74b93222309ad023d6946746b9 Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Mon, 17 Jul 2023 17:40:21 +0200 Subject: [PATCH 14/20] fix: removed debug logging statements --- SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index c7e37fa4..9f2a8488 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -135,7 +135,6 @@ namespace SafeExamBrowser.SystemComponents foreach (string configId in hardwareConfigSubkeys) { - logger.Info($"scanning configId: {configId}"); var hwConfigKey = $"{hwConfigParentKey}\\{configId}"; // collect system values for IsVirtualSystemInfo() @@ -166,8 +165,6 @@ namespace SafeExamBrowser.SystemComponents foreach (var computerIdName in computerIdNames) { - logger.Info($"computerId: {computerIdName}"); - // collect computer hardware summary (e.g. manufacturer&version&sku&...) object computerSummary; if (!registry.TryRead(computerIdsKey, computerIdName, out computerSummary)) From bc30e56e3826b67f6eae22f836028b9e41d31c0b Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Tue, 18 Jul 2023 14:21:49 +0200 Subject: [PATCH 15/20] chore: fix style issue (out var x) --- .../Registry/Registry.cs | 12 +++---- .../VirtualMachineDetector.cs | 34 ++++++------------- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/Registry/Registry.cs b/SafeExamBrowser.SystemComponents/Registry/Registry.cs index 09f040f2..c1def091 100644 --- a/SafeExamBrowser.SystemComponents/Registry/Registry.cs +++ b/SafeExamBrowser.SystemComponents/Registry/Registry.cs @@ -93,8 +93,7 @@ namespace SafeExamBrowser.SystemComponents.Registry { names = default; - RegistryKey keyObj; - if (!TryOpenKey(key, out keyObj)) + if (!TryOpenKey(key, out var keyObj)) return false; bool success = true; @@ -119,9 +118,8 @@ namespace SafeExamBrowser.SystemComponents.Registry public bool TryGetSubKeys(string key, out IEnumerable subKeys) { subKeys = default; - - RegistryKey keyObj; - if (!TryOpenKey(key, out keyObj)) + + if (!TryOpenKey(key, out var keyObj)) return false; bool success = true; @@ -240,11 +238,9 @@ namespace SafeExamBrowser.SystemComponents.Registry { keyObj = default; - string subHiveKey; try { - RegistryKey hiveObj; - if (!GetBaseKeyFromKeyName(key, out hiveObj, out subHiveKey)) + if (!GetBaseKeyFromKeyName(key, out var hiveObj, out var subHiveKey)) return false; keyObj = hiveObj.OpenSubKey(subHiveKey); diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 9f2a8488..4b1943b3 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -128,9 +128,8 @@ namespace SafeExamBrowser.SystemComponents * - {computerId=uuid}: {computerSummary=hardwareInfo} * */ - IEnumerable hardwareConfigSubkeys; const string hwConfigParentKey = "HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig"; - if (!registry.TryGetSubKeys(hwConfigParentKey, out hardwareConfigSubkeys)) + if (!registry.TryGetSubKeys(hwConfigParentKey, out var hardwareConfigSubkeys)) return false; foreach (string configId in hardwareConfigSubkeys) @@ -138,16 +137,11 @@ namespace SafeExamBrowser.SystemComponents var hwConfigKey = $"{hwConfigParentKey}\\{configId}"; // collect system values for IsVirtualSystemInfo() - object biosVendor; - object biosVersion; - object systemManufacturer; - object systemProductName; - bool success = true; - success &= registry.TryRead(hwConfigKey, "BIOSVendor", out biosVendor); - success &= registry.TryRead(hwConfigKey, "BIOSVersion", out biosVersion); - success &= registry.TryRead(hwConfigKey, "SystemManufacturer", out systemManufacturer); - success &= registry.TryRead(hwConfigKey, "SystemProductName", out systemProductName); + success &= registry.TryRead(hwConfigKey, "BIOSVendor", out var biosVendor); + success &= registry.TryRead(hwConfigKey, "BIOSVersion", out var biosVersion); + success &= registry.TryRead(hwConfigKey, "SystemManufacturer", out var systemManufacturer); + success &= registry.TryRead(hwConfigKey, "SystemProductName", out var systemProductName); if (!success) continue; @@ -158,16 +152,14 @@ namespace SafeExamBrowser.SystemComponents isVirtualMachine |= IsVirtualSystemInfo(biosInfo, (string) systemManufacturer, (string) systemProductName); // check even more hardware information - IEnumerable computerIdNames; var computerIdsKey = $"{hwConfigKey}\\ComputerIds"; - if (!registry.TryGetNames(computerIdsKey, out computerIdNames)) + if (!registry.TryGetNames(computerIdsKey, out var computerIdNames)) continue; foreach (var computerIdName in computerIdNames) { // collect computer hardware summary (e.g. manufacturer&version&sku&...) - object computerSummary; - if (!registry.TryRead(computerIdsKey, computerIdName, out computerSummary)) + if (!registry.TryRead(computerIdsKey, computerIdName, out var computerSummary)) continue; isVirtualMachine |= IsVirtualSystemInfo((string) computerSummary, (string) systemManufacturer, (string) systemProductName); @@ -190,26 +182,22 @@ namespace SafeExamBrowser.SystemComponents // check Windows timeline caches for current hardware config const string deviceCacheParentKey = "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"; - IEnumerable deviceCacheKeys; - bool has_dc_keys = registry.TryGetSubKeys(deviceCacheParentKey, out deviceCacheKeys); + bool has_dc_keys = registry.TryGetSubKeys(deviceCacheParentKey, out var deviceCacheKeys); if (deviceName != null && has_dc_keys) { foreach (string cacheId in deviceCacheKeys) { var cacheIdKey = $"{deviceCacheParentKey}\\{cacheId}"; - object cacheDeviceName; - object cacheDeviceManufacturer; - object cacheDeviceModel; bool success = true; - success &= registry.TryRead(cacheIdKey, "DeviceName", out cacheDeviceName); + success &= registry.TryRead(cacheIdKey, "DeviceName", out var cacheDeviceName); if (!success || deviceName.ToLower() != ((string) cacheDeviceName).ToLower()) continue; - success &= registry.TryRead(cacheIdKey, "DeviceMake", out cacheDeviceManufacturer); - success &= registry.TryRead(cacheIdKey, "DeviceModel", out cacheDeviceModel); + success &= registry.TryRead(cacheIdKey, "DeviceMake", out var cacheDeviceManufacturer); + success &= registry.TryRead(cacheIdKey, "DeviceModel", out var cacheDeviceModel); if (!success) continue; From f2917f69a685879d76bdcef3abae2fd021a6ce2f Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Tue, 18 Jul 2023 14:32:54 +0200 Subject: [PATCH 16/20] chore: change varnames (and declarations), and fix registry bug --- .../Registry/Registry.cs | 34 ++++++++-------- .../VirtualMachineDetector.cs | 40 +++++++++---------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/Registry/Registry.cs b/SafeExamBrowser.SystemComponents/Registry/Registry.cs index c1def091..6eacccbe 100644 --- a/SafeExamBrowser.SystemComponents/Registry/Registry.cs +++ b/SafeExamBrowser.SystemComponents/Registry/Registry.cs @@ -89,23 +89,23 @@ namespace SafeExamBrowser.SystemComponents.Registry return success; } - public bool TryGetNames(string key, out IEnumerable names) + public bool TryGetNames(string keyName, out IEnumerable names) { names = default; - if (!TryOpenKey(key, out var keyObj)) + if (!TryOpenKey(keyName, out var key)) return false; bool success = true; - using (keyObj) + using (key) { try { - names = keyObj.GetValueNames(); + names = key.GetValueNames(); } catch (Exception e) { - logger.Error($"Failed to get registry value names '{key}'!", e); + logger.Error($"Failed to get registry value names '{keyName}'!", e); success = false; // persist keyObj dispose operation by finishing using() {} } @@ -115,23 +115,23 @@ namespace SafeExamBrowser.SystemComponents.Registry return success; } - public bool TryGetSubKeys(string key, out IEnumerable subKeys) + public bool TryGetSubKeys(string keyName, out IEnumerable subKeys) { subKeys = default; - if (!TryOpenKey(key, out var keyObj)) + if (!TryOpenKey(keyName, out var key)) return false; bool success = true; - using (keyObj) + using (key) { try { - subKeys = keyObj.GetSubKeyNames(); + subKeys = key.GetSubKeyNames(); } catch (Exception e) { - logger.Error($"Failed to get registry value names '{key}'!", e); + logger.Error($"Failed to get registry value names '{keyName}'!", e); success = false; // persist keyObj dispose operation by finishing using() {} } @@ -234,25 +234,25 @@ namespace SafeExamBrowser.SystemComponents.Registry /// /// Tries to open a key and outputs a RegistryKey object. Does not raise Exceptions, but returns false/true. /// - private bool TryOpenKey(string key, out RegistryKey keyObj) + private bool TryOpenKey(string keyName, out RegistryKey key) { - keyObj = default; + key = default; try { - if (!GetBaseKeyFromKeyName(key, out var hiveObj, out var subHiveKey)) + if (!GetBaseKeyFromKeyName(keyName, out var hiveObj, out var subHiveKey)) return false; - keyObj = hiveObj.OpenSubKey(subHiveKey); - if (keyObj == null) + key = hiveObj.OpenSubKey(subHiveKey); + if (key == null) { - keyObj = default; + key = default; return false; } } catch (Exception e) { - logger.Error($"Failed to open registry key '{key}'!", e); + logger.Error($"Failed to open registry key '{keyName}'!", e); return false; } diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index 4b1943b3..fc80450a 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -119,7 +119,7 @@ namespace SafeExamBrowser.SystemComponents /// private bool IsVirtualRegistryHardwareConfig() { - bool isVirtualMachine = false; + var isVirtualMachine = false; /** * scanned registry format: @@ -135,19 +135,18 @@ namespace SafeExamBrowser.SystemComponents foreach (string configId in hardwareConfigSubkeys) { var hwConfigKey = $"{hwConfigParentKey}\\{configId}"; + bool didReadKeys = true; // collect system values for IsVirtualSystemInfo() - bool success = true; - success &= registry.TryRead(hwConfigKey, "BIOSVendor", out var biosVendor); - success &= registry.TryRead(hwConfigKey, "BIOSVersion", out var biosVersion); - success &= registry.TryRead(hwConfigKey, "SystemManufacturer", out var systemManufacturer); - success &= registry.TryRead(hwConfigKey, "SystemProductName", out var systemProductName); - - if (!success) + didReadKeys &= registry.TryRead(hwConfigKey, "BIOSVendor", out var biosVendor); + didReadKeys &= registry.TryRead(hwConfigKey, "BIOSVersion", out var biosVersion); + didReadKeys &= registry.TryRead(hwConfigKey, "SystemManufacturer", out var systemManufacturer); + didReadKeys &= registry.TryRead(hwConfigKey, "SystemProductName", out var systemProductName); + if (!didReadKeys) continue; // reconstruct the systemInfo.biosInfo string - string biosInfo = $"{(string) biosVendor} {(string) biosVersion}"; + var biosInfo = $"{(string) biosVendor} {(string) biosVersion}"; isVirtualMachine |= IsVirtualSystemInfo(biosInfo, (string) systemManufacturer, (string) systemProductName); @@ -174,31 +173,30 @@ namespace SafeExamBrowser.SystemComponents /// private bool IsVirtualRegistryDeviceCache() { - bool isVirtualMachine = false; + var isVirtualMachine = false; // device cache contains hardware about other devices logged into as well, so lock onto this device in case an innocent VM was logged into. // in the future, try to improve this check somehow since DeviceCache only gives ComputerName var deviceName = System.Environment.GetEnvironmentVariable("COMPUTERNAME"); // check Windows timeline caches for current hardware config - const string deviceCacheParentKey = "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"; - bool has_dc_keys = registry.TryGetSubKeys(deviceCacheParentKey, out var deviceCacheKeys); + const string deviceCacheParentKey = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache"; + var hasDeviceCacheKeys = registry.TryGetSubKeys(deviceCacheParentKey, out var deviceCacheKeys); - if (deviceName != null && has_dc_keys) + if (deviceName != null && hasDeviceCacheKeys) { - foreach (string cacheId in deviceCacheKeys) + foreach (var cacheId in deviceCacheKeys) { var cacheIdKey = $"{deviceCacheParentKey}\\{cacheId}"; + var didReadKeys = true; - bool success = true; - success &= registry.TryRead(cacheIdKey, "DeviceName", out var cacheDeviceName); - - if (!success || deviceName.ToLower() != ((string) cacheDeviceName).ToLower()) + didReadKeys &= registry.TryRead(cacheIdKey, "DeviceName", out var cacheDeviceName); + if (!didReadKeys || deviceName.ToLower() != ((string) cacheDeviceName).ToLower()) continue; - success &= registry.TryRead(cacheIdKey, "DeviceMake", out var cacheDeviceManufacturer); - success &= registry.TryRead(cacheIdKey, "DeviceModel", out var cacheDeviceModel); - if (!success) + 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); From 210a0419cab6de48e25e053b0f1526d43c7c3c7f Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Tue, 18 Jul 2023 14:45:10 +0200 Subject: [PATCH 17/20] chore: removed unnecessary docs and changed var declarations --- .../Registry/Registry.cs | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/Registry/Registry.cs b/SafeExamBrowser.SystemComponents/Registry/Registry.cs index 6eacccbe..cca618db 100644 --- a/SafeExamBrowser.SystemComponents/Registry/Registry.cs +++ b/SafeExamBrowser.SystemComponents/Registry/Registry.cs @@ -96,7 +96,7 @@ namespace SafeExamBrowser.SystemComponents.Registry if (!TryOpenKey(keyName, out var key)) return false; - bool success = true; + var success = true; using (key) { try @@ -107,7 +107,6 @@ namespace SafeExamBrowser.SystemComponents.Registry { logger.Error($"Failed to get registry value names '{keyName}'!", e); success = false; - // persist keyObj dispose operation by finishing using() {} } } @@ -122,7 +121,7 @@ namespace SafeExamBrowser.SystemComponents.Registry if (!TryOpenKey(keyName, out var key)) return false; - bool success = true; + var success = true; using (key) { try @@ -133,7 +132,6 @@ namespace SafeExamBrowser.SystemComponents.Registry { logger.Error($"Failed to get registry value names '{keyName}'!", e); success = false; - // persist keyObj dispose operation by finishing using() {} } } @@ -167,16 +165,16 @@ namespace SafeExamBrowser.SystemComponents.Registry /// Supports shortcuts. /// // yoinked (and partially modified to follow SEB conventions) private Win32 function: https://stackoverflow.com/a/58547945 - private bool GetBaseKeyFromKeyName(string keyName, out RegistryKey hiveKey, out string subKeyName) + private bool TryGetBaseKeyFromKeyName(string keyName, out RegistryKey baseKey, out string subKeyName) { - hiveKey = default; + baseKey = default; subKeyName = default; string basekeyName; - int i = keyName.IndexOf('\\'); - if (i != -1) + var baseKeyLength = keyName.IndexOf('\\'); + if (baseKeyLength != -1) { - basekeyName = keyName.Substring(0, i).ToUpper(System.Globalization.CultureInfo.InvariantCulture); + basekeyName = keyName.Substring(0, baseKeyLength).ToUpper(System.Globalization.CultureInfo.InvariantCulture); } else { @@ -188,62 +186,58 @@ namespace SafeExamBrowser.SystemComponents.Registry { case "HKEY_CURRENT_USER": case "HKCU": - hiveKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); + baseKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); break; case "HKEY_LOCAL_MACHINE": case "HKLM": - hiveKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); + baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); break; case "HKEY_CLASSES_ROOT": case "HKCR": - hiveKey = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64); + baseKey = RegistryKey.OpenBaseKey(RegistryHive.ClassesRoot, RegistryView.Registry64); break; case "HKEY_USERS": case "HKU": - hiveKey = RegistryKey.OpenBaseKey(RegistryHive.Users, RegistryView.Registry64); + baseKey = RegistryKey.OpenBaseKey(RegistryHive.Users, RegistryView.Registry64); break; case "HKEY_PERFORMANCE_DATA": case "HKPD": - hiveKey = RegistryKey.OpenBaseKey(RegistryHive.PerformanceData, RegistryView.Registry64); + baseKey = RegistryKey.OpenBaseKey(RegistryHive.PerformanceData, RegistryView.Registry64); break; case "HKEY_CURRENT_CONFIG": case "HKCC": - hiveKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentConfig, RegistryView.Registry64); + baseKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentConfig, RegistryView.Registry64); break; case "HKEY_DYN_DATA": case "HKDD": - hiveKey = RegistryKey.OpenBaseKey(RegistryHive.DynData, RegistryView.Registry64); + baseKey = RegistryKey.OpenBaseKey(RegistryHive.DynData, RegistryView.Registry64); break; default: - // output is already set to null at the start return false; } - if (i == -1 || i == keyName.Length) + if (baseKeyLength == -1 || baseKeyLength == keyName.Length) { subKeyName = string.Empty; } else { - subKeyName = keyName.Substring(i + 1, keyName.Length - i - 1); + subKeyName = keyName.Substring(baseKeyLength + 1, keyName.Length - baseKeyLength - 1); } return true; } - /// - /// Tries to open a key and outputs a RegistryKey object. Does not raise Exceptions, but returns false/true. - /// private bool TryOpenKey(string keyName, out RegistryKey key) { key = default; try { - if (!GetBaseKeyFromKeyName(keyName, out var hiveObj, out var subHiveKey)) + if (!TryGetBaseKeyFromKeyName(keyName, out var baseKey, out var subKey)) return false; - key = hiveObj.OpenSubKey(subHiveKey); + key = baseKey.OpenSubKey(subKey); if (key == null) { key = default; From c1307624d9d99db105ed7b1221c221e444ac24a5 Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:02:02 +0200 Subject: [PATCH 18/20] chore: added function blocks and fixed if statement --- .../Registry/Registry.cs | 19 ++++++++++--------- .../VirtualMachineDetector.cs | 12 ++++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/Registry/Registry.cs b/SafeExamBrowser.SystemComponents/Registry/Registry.cs index cca618db..9e30aaa5 100644 --- a/SafeExamBrowser.SystemComponents/Registry/Registry.cs +++ b/SafeExamBrowser.SystemComponents/Registry/Registry.cs @@ -94,7 +94,9 @@ namespace SafeExamBrowser.SystemComponents.Registry names = default; if (!TryOpenKey(keyName, out var key)) + { return false; + } var success = true; using (key) @@ -117,9 +119,11 @@ namespace SafeExamBrowser.SystemComponents.Registry public bool TryGetSubKeys(string keyName, out IEnumerable subKeys) { subKeys = default; - + if (!TryOpenKey(keyName, out var key)) + { return false; + } var success = true; using (key) @@ -234,15 +238,12 @@ namespace SafeExamBrowser.SystemComponents.Registry try { - if (!TryGetBaseKeyFromKeyName(keyName, out var baseKey, out var subKey)) - return false; - - key = baseKey.OpenSubKey(subKey); - if (key == null) + logger.Info($"default(RegistryKey) == null: {key == null}"); + if (TryGetBaseKeyFromKeyName(keyName, out var baseKey, out var subKey)) { - key = default; - return false; + key = baseKey.OpenSubKey(subKey); } + } catch (Exception e) { @@ -250,7 +251,7 @@ namespace SafeExamBrowser.SystemComponents.Registry return false; } - return true; + return key != default; } } } diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index fc80450a..cab97671 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -130,7 +130,9 @@ namespace SafeExamBrowser.SystemComponents */ const string hwConfigParentKey = "HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig"; if (!registry.TryGetSubKeys(hwConfigParentKey, out var hardwareConfigSubkeys)) + { return false; + } foreach (string configId in hardwareConfigSubkeys) { @@ -143,7 +145,9 @@ namespace SafeExamBrowser.SystemComponents didReadKeys &= registry.TryRead(hwConfigKey, "SystemManufacturer", out var systemManufacturer); didReadKeys &= registry.TryRead(hwConfigKey, "SystemProductName", out var systemProductName); if (!didReadKeys) + { continue; + } // reconstruct the systemInfo.biosInfo string var biosInfo = $"{(string) biosVendor} {(string) biosVersion}"; @@ -153,13 +157,17 @@ namespace SafeExamBrowser.SystemComponents // check even more hardware information var computerIdsKey = $"{hwConfigKey}\\ComputerIds"; if (!registry.TryGetNames(computerIdsKey, out var computerIdNames)) + { continue; + } foreach (var computerIdName in computerIdNames) { // collect computer hardware summary (e.g. manufacturer&version&sku&...) if (!registry.TryRead(computerIdsKey, computerIdName, out var computerSummary)) + { continue; + } isVirtualMachine |= IsVirtualSystemInfo((string) computerSummary, (string) systemManufacturer, (string) systemProductName); } @@ -192,12 +200,16 @@ namespace SafeExamBrowser.SystemComponents didReadKeys &= registry.TryRead(cacheIdKey, "DeviceName", out var cacheDeviceName); 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) + { continue; + } isVirtualMachine |= IsVirtualSystemInfo("", (string) cacheDeviceManufacturer, (string) cacheDeviceModel); } From 5173bf3d6efb962b2b0aa905e8f71d3e5a520279 Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:11:44 +0200 Subject: [PATCH 19/20] chore: removed more unnecessary docs, and changed function names --- .../Registry/Registry.cs | 9 --------- .../VirtualMachineDetector.cs | 19 ++++++------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/Registry/Registry.cs b/SafeExamBrowser.SystemComponents/Registry/Registry.cs index 9e30aaa5..43b67ddd 100644 --- a/SafeExamBrowser.SystemComponents/Registry/Registry.cs +++ b/SafeExamBrowser.SystemComponents/Registry/Registry.cs @@ -161,14 +161,6 @@ namespace SafeExamBrowser.SystemComponents.Registry } } - /// - /// Parses a keyName and returns the basekey for it. - /// It will also store the subkey name in the out parameter. - /// If the keyName is not valid, we will return false. - /// Does not raise Exceptions. - /// Supports shortcuts. - /// - // yoinked (and partially modified to follow SEB conventions) private Win32 function: https://stackoverflow.com/a/58547945 private bool TryGetBaseKeyFromKeyName(string keyName, out RegistryKey baseKey, out string subKeyName) { baseKey = default; @@ -185,7 +177,6 @@ namespace SafeExamBrowser.SystemComponents.Registry basekeyName = keyName.ToUpper(System.Globalization.CultureInfo.InvariantCulture); } - // add shortcuts as well to be implicit switch (basekeyName) { case "HKEY_CURRENT_USER": diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index cab97671..d693fb9f 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -76,9 +76,6 @@ namespace SafeExamBrowser.SystemComponents return isVirtualMachine; } - /// - /// Scans parameters for disallowed strings (signatures) - /// private bool IsVirtualSystemInfo(string biosInfo, string manufacturer, string model) { var isVirtualMachine = false; @@ -107,17 +104,13 @@ namespace SafeExamBrowser.SystemComponents var isVirtualMachine = false; // the resulting IsVirtualRegistry() would be massive so split it - isVirtualMachine |= IsVirtualRegistryHardwareConfig(); - isVirtualMachine |= IsVirtualRegistryDeviceCache(); + isVirtualMachine |= HasHistoricVirtualMachineHardwareConfiguration(); + isVirtualMachine |= HasLocalVirtualMachineDeviceCache(); return isVirtualMachine; } - - /// - /// Scans (historic) hardware configurations in the registry. - /// - private bool IsVirtualRegistryHardwareConfig() + private bool HasHistoricVirtualMachineHardwareConfiguration() { var isVirtualMachine = false; @@ -134,10 +127,10 @@ namespace SafeExamBrowser.SystemComponents return false; } - foreach (string configId in hardwareConfigSubkeys) + foreach (var configId in hardwareConfigSubkeys) { var hwConfigKey = $"{hwConfigParentKey}\\{configId}"; - bool didReadKeys = true; + var didReadKeys = true; // collect system values for IsVirtualSystemInfo() didReadKeys &= registry.TryRead(hwConfigKey, "BIOSVendor", out var biosVendor); @@ -179,7 +172,7 @@ namespace SafeExamBrowser.SystemComponents /// /// Scans (synced) device cache for hardware info of the current device. /// - private bool IsVirtualRegistryDeviceCache() + private bool HasLocalVirtualMachineDeviceCache() { var isVirtualMachine = false; From 9b0bfa291e46efe3ff1f17b1367e13669d63c515 Mon Sep 17 00:00:00 2001 From: Notselwyn <68616630+Notselwyn@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:20:10 +0200 Subject: [PATCH 20/20] chore: fixed Hungarian notation and corrected scanned registry docs --- .../VirtualMachineDetector.cs | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs index d693fb9f..258a9786 100644 --- a/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs +++ b/SafeExamBrowser.SystemComponents/VirtualMachineDetector.cs @@ -47,8 +47,9 @@ namespace SafeExamBrowser.SystemComponents public bool IsVirtualMachine() { - var biosInfo = systemInfo.BiosInfo; var isVirtualMachine = false; + + var biosInfo = systemInfo.BiosInfo; var macAddress = systemInfo.MacAddress; var manufacturer = systemInfo.Manufacturer; var model = systemInfo.Model; @@ -117,26 +118,30 @@ namespace SafeExamBrowser.SystemComponents /** * scanned registry format: * - * HKLM\SYSTEM\HardwareConfig\{configId=uuid}\ComputerIds - * - {computerId=uuid}: {computerSummary=hardwareInfo} - * + * HKLM\SYSTEM\HardwareConfig\{configId=uuid} + * - BIOSVendor + * - SystemManufacturer + * - ... + * \ComputerIds + * - {computerId=uuid}: {computerSummary=hardwareInfo} + * */ - const string hwConfigParentKey = "HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig"; - if (!registry.TryGetSubKeys(hwConfigParentKey, out var hardwareConfigSubkeys)) + const string hardwareRootKey = "HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig"; + if (!registry.TryGetSubKeys(hardwareRootKey, out var hardwareConfigSubkeys)) { return false; } foreach (var configId in hardwareConfigSubkeys) { - var hwConfigKey = $"{hwConfigParentKey}\\{configId}"; + var hardwareConfigKey = $"{hardwareRootKey}\\{configId}"; var didReadKeys = true; // collect system values for IsVirtualSystemInfo() - didReadKeys &= registry.TryRead(hwConfigKey, "BIOSVendor", out var biosVendor); - didReadKeys &= registry.TryRead(hwConfigKey, "BIOSVersion", out var biosVersion); - didReadKeys &= registry.TryRead(hwConfigKey, "SystemManufacturer", out var systemManufacturer); - didReadKeys &= registry.TryRead(hwConfigKey, "SystemProductName", out var systemProductName); + 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) { continue; @@ -148,7 +153,7 @@ namespace SafeExamBrowser.SystemComponents isVirtualMachine |= IsVirtualSystemInfo(biosInfo, (string) systemManufacturer, (string) systemProductName); // check even more hardware information - var computerIdsKey = $"{hwConfigKey}\\ComputerIds"; + var computerIdsKey = $"{hardwareConfigKey}\\ComputerIds"; if (!registry.TryGetNames(computerIdsKey, out var computerIdNames)) { continue; @@ -169,9 +174,6 @@ namespace SafeExamBrowser.SystemComponents return isVirtualMachine; } - /// - /// Scans (synced) device cache for hardware info of the current device. - /// private bool HasLocalVirtualMachineDeviceCache() { var isVirtualMachine = false;