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>
string BiosInfo { get; }
/// <summary>
/// The name of the CPU.
/// </summary>
string CpuName { get; }
/// <summary>
/// Reveals whether the computer system contains a battery.
/// </summary>

View file

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

View file

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

View file

@ -7,7 +7,6 @@
*/
using System.Linq;
using System.Management;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.SystemComponents.Contracts;
using SafeExamBrowser.SystemComponents.Contracts.Registry;
@ -16,6 +15,7 @@ namespace SafeExamBrowser.SystemComponents
{
public class VirtualMachineDetector : IVirtualMachineDetector
{
private const string MANIPULATED = "000000000000";
private const string QEMU_MAC_PREFIX = "525400";
private const string VIRTUALBOX_MAC_PREFIX = "080027";
@ -52,176 +52,161 @@ namespace SafeExamBrowser.SystemComponents
public bool IsVirtualMachine()
{
var biosInfo = systemInfo.BiosInfo;
var devices = systemInfo.PlugAndPlayDeviceIds;
var isVirtualMachine = false;
var macAddress = systemInfo.MacAddress;
var manufacturer = systemInfo.Manufacturer;
var model = systemInfo.Model;
isVirtualMachine |= HasVirtualDevice();
isVirtualMachine |= HasVirtualMacAddress();
isVirtualMachine |= IsVirtualCpu();
isVirtualMachine |= IsVirtualRegistry();
isVirtualMachine |= IsVirtualSystemInfo(biosInfo, manufacturer, model);
isVirtualMachine |= IsVirtualWmi();
if (macAddress != null && macAddress.Count() > 2)
{
isVirtualMachine |= macAddress.StartsWith(QEMU_MAC_PREFIX);
isVirtualMachine |= macAddress.StartsWith(VIRTUALBOX_MAC_PREFIX);
isVirtualMachine |= macAddress.StartsWith("000000000000");
}
foreach (var device in devices)
{
isVirtualMachine |= DeviceBlacklist.Any(d => device.ToLower().Contains(d.ToLower())) && DeviceWhitelist.All(d => !device.ToLower().Contains(d.ToLower()));
}
isVirtualMachine |= IsVirtualSystem(systemInfo.BiosInfo, systemInfo.Manufacturer, systemInfo.Model);
logger.Debug($"Computer '{systemInfo.Name}' appears {(isVirtualMachine ? "" : "not ")}to be a virtual machine.");
return isVirtualMachine;
}
private bool IsVirtualSystemInfo(string biosInfo, string manufacturer, string model)
private bool HasVirtualDevice()
{
var isVirtualMachine = false;
var hasVirtualDevice = false;
foreach (var device in systemInfo.PlugAndPlayDeviceIds)
{
hasVirtualDevice |= DeviceBlacklist.Any(d => device.ToLower().Contains(d.ToLower())) && DeviceWhitelist.All(d => !device.ToLower().Contains(d.ToLower()));
}
return hasVirtualDevice;
}
private bool HasVirtualMacAddress()
{
var hasVirtualMacAddress = false;
var macAddress = systemInfo.MacAddress;
if (macAddress != null && macAddress.Length > 2)
{
hasVirtualMacAddress |= macAddress.StartsWith(MANIPULATED);
hasVirtualMacAddress |= macAddress.StartsWith(QEMU_MAC_PREFIX);
hasVirtualMacAddress |= macAddress.StartsWith(VIRTUALBOX_MAC_PREFIX);
}
return hasVirtualMacAddress;
}
private bool IsVirtualCpu()
{
var isVirtualCpu = false;
isVirtualCpu |= systemInfo.CpuName.ToLower().Contains(" kvm ");
return isVirtualCpu;
}
private bool IsVirtualRegistry()
{
var isVirtualRegistry = false;
isVirtualRegistry |= HasHistoricVirtualMachineHardwareConfiguration();
isVirtualRegistry |= HasLocalVirtualMachineDeviceCache();
return isVirtualRegistry;
}
private bool IsVirtualSystem(string biosInfo, string manufacturer, string model)
{
var isVirtualSystem = false;
biosInfo = biosInfo.ToLower();
manufacturer = manufacturer.ToLower();
model = model.ToLower();
isVirtualMachine |= biosInfo.Contains("hyper-v");
isVirtualMachine |= biosInfo.Contains("virtualbox");
isVirtualMachine |= biosInfo.Contains("vmware");
isVirtualMachine |= biosInfo.Contains("ovmf");
isVirtualMachine |= biosInfo.Contains("edk ii unknown");
isVirtualMachine |= manufacturer.Contains("microsoft corporation") && !model.Contains("surface");
isVirtualMachine |= manufacturer.Contains("parallels software");
isVirtualMachine |= manufacturer.Contains("qemu");
isVirtualMachine |= manufacturer.Contains("vmware");
isVirtualMachine |= model.Contains("virtualbox");
isVirtualMachine |= model.Contains("Q35 +");
isVirtualSystem |= biosInfo.Contains("hyper-v");
isVirtualSystem |= biosInfo.Contains("virtualbox");
isVirtualSystem |= biosInfo.Contains("vmware");
isVirtualSystem |= biosInfo.Contains("ovmf");
isVirtualSystem |= biosInfo.Contains("edk ii unknown");
isVirtualSystem |= manufacturer.Contains("microsoft corporation") && !model.Contains("surface");
isVirtualSystem |= manufacturer.Contains("parallels software");
isVirtualSystem |= manufacturer.Contains("qemu");
isVirtualSystem |= manufacturer.Contains("vmware");
isVirtualSystem |= model.Contains("virtualbox");
isVirtualSystem |= model.Contains("Q35 +");
return isVirtualMachine;
}
private bool IsVirtualRegistry()
{
var isVirtualMachine = false;
isVirtualMachine |= HasHistoricVirtualMachineHardwareConfiguration();
isVirtualMachine |= HasLocalVirtualMachineDeviceCache();
return isVirtualMachine;
return isVirtualSystem;
}
private bool HasHistoricVirtualMachineHardwareConfiguration()
{
/**
* scanned registry format:
*
* HKLM\SYSTEM\HardwareConfig\{configId=uuid}
* - BIOSVendor
* - SystemManufacturer
* - ...
* \ComputerIds
* - {computerId=uuid}: {computerSummary=hardwareInfo}
*
*/
const string HARDWARE_ROOT_KEY = "HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig";
const string HARDWARE_ROOT_KEY = @"HKEY_LOCAL_MACHINE\SYSTEM\HardwareConfig";
var isVirtualMachine = false;
var hasHistoricConfiguration = false;
if (!registry.TryGetSubKeys(HARDWARE_ROOT_KEY, out var hardwareConfigSubkeys))
if (registry.TryGetSubKeys(HARDWARE_ROOT_KEY, out var hardwareConfigSubkeys))
{
return false;
}
foreach (var configId in hardwareConfigSubkeys)
{
var hardwareConfigKey = $"{HARDWARE_ROOT_KEY}\\{configId}";
var didReadKeys = true;
didReadKeys &= registry.TryRead(hardwareConfigKey, "BIOSVendor", out var biosVendor);
didReadKeys &= registry.TryRead(hardwareConfigKey, "BIOSVersion", out var biosVersion);
didReadKeys &= registry.TryRead(hardwareConfigKey, "SystemManufacturer", out var systemManufacturer);
didReadKeys &= registry.TryRead(hardwareConfigKey, "SystemProductName", out var systemProductName);
if (!didReadKeys)
foreach (var configId in hardwareConfigSubkeys)
{
continue;
}
var hardwareConfigKey = $"{HARDWARE_ROOT_KEY}\\{configId}";
var computerIdsKey = $"{hardwareConfigKey}\\ComputerIds";
var success = true;
var biosInfo = $"{(string) biosVendor} {(string) biosVersion}";
success &= registry.TryRead(hardwareConfigKey, "BIOSVendor", out var biosVendor);
success &= registry.TryRead(hardwareConfigKey, "BIOSVersion", out var biosVersion);
success &= registry.TryRead(hardwareConfigKey, "SystemManufacturer", out var systemManufacturer);
success &= registry.TryRead(hardwareConfigKey, "SystemProductName", out var systemProductName);
isVirtualMachine |= IsVirtualSystemInfo(biosInfo, (string) systemManufacturer, (string) systemProductName);
var computerIdsKey = $"{hardwareConfigKey}\\ComputerIds";
if (!registry.TryGetNames(computerIdsKey, out var computerIdNames))
{
continue;
}
foreach (var computerIdName in computerIdNames)
{
if (!registry.TryRead(computerIdsKey, computerIdName, out var computerSummary))
if (success)
{
continue;
}
var biosInfo = $"{(string) biosVendor} {(string) biosVersion}";
isVirtualMachine |= IsVirtualSystemInfo((string) computerSummary, (string) systemManufacturer, (string) systemProductName);
hasHistoricConfiguration |= IsVirtualSystem(biosInfo, (string) systemManufacturer, (string) systemProductName);
if (registry.TryGetNames(computerIdsKey, out var computerIdNames))
{
foreach (var computerIdName in computerIdNames)
{
if (registry.TryRead(computerIdsKey, computerIdName, out var computerSummary))
{
hasHistoricConfiguration |= IsVirtualSystem((string) computerSummary, (string) systemManufacturer, (string) systemProductName);
}
}
}
}
}
}
return isVirtualMachine;
return hasHistoricConfiguration;
}
private bool HasLocalVirtualMachineDeviceCache()
{
const string DEVICE_CACHE_PARENT_KEY = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\TaskFlow\\DeviceCache";
const string DEVICE_CACHE_PARENT_KEY = @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\TaskFlow\DeviceCache";
var isVirtualMachine = false;
var deviceName = System.Environment.GetEnvironmentVariable("COMPUTERNAME");
var hasDeviceCache = false;
var hasDeviceCacheKeys = registry.TryGetSubKeys(DEVICE_CACHE_PARENT_KEY, out var deviceCacheKeys);
if (deviceName != null && hasDeviceCacheKeys)
if (deviceName != default && hasDeviceCacheKeys)
{
foreach (var cacheId in deviceCacheKeys)
{
var cacheIdKey = $"{DEVICE_CACHE_PARENT_KEY}\\{cacheId}";
var cacheIdKey = $@"{DEVICE_CACHE_PARENT_KEY}\{cacheId}";
var didReadKeys = true;
didReadKeys &= registry.TryRead(cacheIdKey, "DeviceName", out var cacheDeviceName);
if (!didReadKeys || deviceName.ToLower() != ((string) cacheDeviceName).ToLower())
if (didReadKeys && deviceName.ToLower() == ((string) cacheDeviceName).ToLower())
{
continue;
didReadKeys &= registry.TryRead(cacheIdKey, "DeviceMake", out var cacheDeviceManufacturer);
didReadKeys &= registry.TryRead(cacheIdKey, "DeviceModel", out var cacheDeviceModel);
if (didReadKeys)
{
hasDeviceCache |= IsVirtualSystem("", (string) cacheDeviceManufacturer, (string) cacheDeviceModel);
}
}
didReadKeys &= registry.TryRead(cacheIdKey, "DeviceMake", out var cacheDeviceManufacturer);
didReadKeys &= registry.TryRead(cacheIdKey, "DeviceModel", out var cacheDeviceModel);
if (!didReadKeys)
{
continue;
}
isVirtualMachine |= IsVirtualSystemInfo("", (string) cacheDeviceManufacturer, (string) cacheDeviceModel);
}
}
return isVirtualMachine;
}
private bool IsVirtualWmi()
{
var isVirtualMachine = false;
var cpuObjSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor");
foreach (var cpuObj in cpuObjSearcher.Get())
{
isVirtualMachine |= ((string) cpuObj["Name"]).ToLower().Contains(" kvm ");
}
return isVirtualMachine;
return hasDeviceCache;
}
}
}