SEBWIN-717: Merged changes & minor code cleanup.

This commit is contained in:
Damian Büchel 2023-07-31 10:52:40 +02:00
commit b36df9ad5a
4 changed files with 144 additions and 125 deletions

View file

@ -18,6 +18,11 @@ namespace SafeExamBrowser.SystemComponents.Contracts
/// </summary> /// </summary>
string BiosInfo { get; } string BiosInfo { get; }
/// <summary>
/// The name of the CPU.
/// </summary>
string CpuName { get; }
/// <summary> /// <summary>
/// Reveals whether the computer system contains a battery. /// Reveals whether the computer system contains a battery.
/// </summary> /// </summary>

View file

@ -229,7 +229,6 @@ namespace SafeExamBrowser.SystemComponents.Registry
try try
{ {
logger.Info($"default(RegistryKey) == null: {key == null}");
if (TryGetBaseKeyFromKeyName(keyName, out var baseKey, out var subKey)) if (TryGetBaseKeyFromKeyName(keyName, out var baseKey, out var subKey))
{ {
key = baseKey.OpenSubKey(subKey); key = baseKey.OpenSubKey(subKey);

View file

@ -20,6 +20,7 @@ namespace SafeExamBrowser.SystemComponents
public class SystemInfo : ISystemInfo public class SystemInfo : ISystemInfo
{ {
public string BiosInfo { get; private set; } public string BiosInfo { get; private set; }
public string CpuName { get; private set; }
public bool HasBattery { get; private set; } public bool HasBattery { get; private set; }
public string MacAddress { get; private set; } public string MacAddress { get; private set; }
public string Manufacturer { get; private set; } public string Manufacturer { get; private set; }
@ -33,6 +34,7 @@ namespace SafeExamBrowser.SystemComponents
{ {
InitializeBattery(); InitializeBattery();
InitializeBiosInfo(); InitializeBiosInfo();
InitializeCpuName();
InitializeMacAddress(); InitializeMacAddress();
InitializeMachineInfo(); InitializeMachineInfo();
InitializeOperatingSystem(); 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() private void InitializeMachineInfo()
{ {
var model = default(string); 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 searcher = new ManagementObjectSearcher("SELECT MACAddress FROM Win32_NetworkAdapterConfiguration WHERE DNSDomain IS NOT NULL"))
using (var results = searcher.Get()) using (var results = searcher.Get())
{ {
if (results != null && results.Count > 0) if (results != default && results.Count > 0)
{ {
using (var networkAdapter = results.Cast<ManagementObject>().First()) using (var networkAdapter = results.Cast<ManagementObject>().First())
{ {
@ -226,11 +256,11 @@ namespace SafeExamBrowser.SystemComponents
using (var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT DeviceID FROM Win32_PnPEntity")) using (var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT DeviceID FROM Win32_PnPEntity"))
using (var results = searcher.Get()) using (var results = searcher.Get())
{ {
foreach (ManagementObject queryObj in results) foreach (var device in results.Cast<ManagementObject>())
{ {
using (queryObj) using (device)
{ {
foreach (var property in queryObj.Properties) foreach (var property in device.Properties)
{ {
if (property.Name.Equals("DeviceID")) if (property.Name.Equals("DeviceID"))
{ {

View file

@ -7,7 +7,6 @@
*/ */
using System.Linq; using System.Linq;
using System.Management;
using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.SystemComponents.Contracts; using SafeExamBrowser.SystemComponents.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.Registry; using SafeExamBrowser.SystemComponents.Contracts.Registry;
@ -16,6 +15,7 @@ namespace SafeExamBrowser.SystemComponents
{ {
public class VirtualMachineDetector : IVirtualMachineDetector public class VirtualMachineDetector : IVirtualMachineDetector
{ {
private const string MANIPULATED = "000000000000";
private const string QEMU_MAC_PREFIX = "525400"; private const string QEMU_MAC_PREFIX = "525400";
private const string VIRTUALBOX_MAC_PREFIX = "080027"; private const string VIRTUALBOX_MAC_PREFIX = "080027";
@ -52,176 +52,161 @@ namespace SafeExamBrowser.SystemComponents
public bool IsVirtualMachine() public bool IsVirtualMachine()
{ {
var biosInfo = systemInfo.BiosInfo;
var devices = systemInfo.PlugAndPlayDeviceIds;
var isVirtualMachine = false; var isVirtualMachine = false;
var macAddress = systemInfo.MacAddress;
var manufacturer = systemInfo.Manufacturer;
var model = systemInfo.Model;
isVirtualMachine |= HasVirtualDevice();
isVirtualMachine |= HasVirtualMacAddress();
isVirtualMachine |= IsVirtualCpu();
isVirtualMachine |= IsVirtualRegistry(); isVirtualMachine |= IsVirtualRegistry();
isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model); isVirtualMachine |= IsVirtualSystem(systemInfo.BiosInfo, systemInfo.Manufacturer, systemInfo.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()));
}
logger.Debug($"Computer '{systemInfo.Name}' appears {(isVirtualMachine ? "" : "not ")}to be a virtual machine."); logger.Debug($"Computer '{systemInfo.Name}' appears {(isVirtualMachine ? "" : "not ")}to be a virtual machine.");
return isVirtualMachine; 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(); biosInfo = biosInfo.ToLower();
manufacturer = manufacturer.ToLower(); manufacturer = manufacturer.ToLower();
model = model.ToLower(); model = model.ToLower();
isVirtualMachine |= biosInfo.Contains("hyper-v"); isVirtualSystem |= biosInfo.Contains("hyper-v");
isVirtualMachine |= biosInfo.Contains("virtualbox"); isVirtualSystem |= biosInfo.Contains("virtualbox");
isVirtualMachine |= biosInfo.Contains("vmware"); isVirtualSystem |= biosInfo.Contains("vmware");
isVirtualMachine |= biosInfo.Contains("ovmf"); isVirtualSystem |= biosInfo.Contains("ovmf");
isVirtualMachine |= biosInfo.Contains("edk ii unknown"); isVirtualSystem |= biosInfo.Contains("edk ii unknown");
isVirtualMachine |= manufacturer.Contains("microsoft corporation") && !model.Contains("surface"); isVirtualSystem |= manufacturer.Contains("microsoft corporation") && !model.Contains("surface");
isVirtualMachine |= manufacturer.Contains("parallels software"); isVirtualSystem |= manufacturer.Contains("parallels software");
isVirtualMachine |= manufacturer.Contains("qemu"); isVirtualSystem |= manufacturer.Contains("qemu");
isVirtualMachine |= manufacturer.Contains("vmware"); isVirtualSystem |= manufacturer.Contains("vmware");
isVirtualMachine |= model.Contains("virtualbox"); isVirtualSystem |= model.Contains("virtualbox");
isVirtualMachine |= model.Contains("Q35 +"); isVirtualSystem |= model.Contains("Q35 +");
return isVirtualMachine; return isVirtualSystem;
}
private bool IsVirtualRegistry()
{
var isVirtualMachine = false;
isVirtualMachine |= HasHistoricVirtualMachineHardwareConfiguration();
isVirtualMachine |= HasLocalVirtualMachineDeviceCache();
return isVirtualMachine;
} }
private bool HasHistoricVirtualMachineHardwareConfiguration() private bool HasHistoricVirtualMachineHardwareConfiguration()
{ {
/** const string HARDWARE_ROOT_KEY = @"HKEY_LOCAL_MACHINE\SYSTEM\HardwareConfig";
* 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";
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)
}
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)
{ {
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); if (success)
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))
{ {
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() 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 deviceName = System.Environment.GetEnvironmentVariable("COMPUTERNAME");
var hasDeviceCache = false;
var hasDeviceCacheKeys = registry.TryGetSubKeys(DEVICE_CACHE_PARENT_KEY, out var deviceCacheKeys); var hasDeviceCacheKeys = registry.TryGetSubKeys(DEVICE_CACHE_PARENT_KEY, out var deviceCacheKeys);
if (deviceName != null && hasDeviceCacheKeys) if (deviceName != default && hasDeviceCacheKeys)
{ {
foreach (var cacheId in deviceCacheKeys) foreach (var cacheId in deviceCacheKeys)
{ {
var cacheIdKey = $"{DEVICE_CACHE_PARENT_KEY}\\{cacheId}"; var cacheIdKey = $@"{DEVICE_CACHE_PARENT_KEY}\{cacheId}";
var didReadKeys = true; var didReadKeys = true;
didReadKeys &= registry.TryRead(cacheIdKey, "DeviceName", out var cacheDeviceName); 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; return hasDeviceCache;
}
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;
} }
} }
} }