SEBWIN-732: Implemented random desktop functionality.

This commit is contained in:
Damian Büchel 2023-10-04 14:48:08 +02:00
parent 3711555f70
commit 026d1fbfd8
11 changed files with 116 additions and 38 deletions

View file

@ -54,6 +54,7 @@ using SafeExamBrowser.UserInterface.Contracts.Shell;
using SafeExamBrowser.UserInterface.Shared.Activators;
using SafeExamBrowser.WindowsApi;
using SafeExamBrowser.WindowsApi.Contracts;
using SafeExamBrowser.WindowsApi.Processes;
using Desktop = SafeExamBrowser.UserInterface.Desktop;
using Mobile = SafeExamBrowser.UserInterface.Mobile;

View file

@ -35,6 +35,8 @@ using SafeExamBrowser.SystemComponents.Contracts;
using SafeExamBrowser.SystemComponents.Registry;
using SafeExamBrowser.UserInterface.Desktop;
using SafeExamBrowser.WindowsApi;
using SafeExamBrowser.WindowsApi.Desktops;
using SafeExamBrowser.WindowsApi.Processes;
namespace SafeExamBrowser.Runtime
{

View file

@ -17,14 +17,15 @@ namespace SafeExamBrowser.Runtime.Operations
{
internal class KioskModeOperation : SessionOperation
{
private IDesktop newDesktop;
private IDesktop originalDesktop;
private IDesktopFactory desktopFactory;
private IDesktopMonitor desktopMonitor;
private IExplorerShell explorerShell;
private readonly IDesktopFactory desktopFactory;
private readonly IDesktopMonitor desktopMonitor;
private readonly IExplorerShell explorerShell;
private readonly ILogger logger;
private readonly IProcessFactory processFactory;
private KioskMode? activeMode;
private ILogger logger;
private IProcessFactory processFactory;
private IDesktop customDesktop;
private IDesktop originalDesktop;
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
public override event StatusChangedEventHandler StatusChanged;
@ -54,7 +55,7 @@ namespace SafeExamBrowser.Runtime.Operations
switch (Context.Next.Settings.Security.KioskMode)
{
case KioskMode.CreateNewDesktop:
CreateNewDesktop();
CreateCustomDesktop();
break;
case KioskMode.DisableExplorerShell:
TerminateExplorerShell();
@ -80,7 +81,7 @@ namespace SafeExamBrowser.Runtime.Operations
switch (activeMode)
{
case KioskMode.CreateNewDesktop:
CloseNewDesktop();
CloseCustomDesktop();
break;
case KioskMode.DisableExplorerShell:
RestartExplorerShell();
@ -92,7 +93,7 @@ namespace SafeExamBrowser.Runtime.Operations
switch (newMode)
{
case KioskMode.CreateNewDesktop:
CreateNewDesktop();
CreateCustomDesktop();
break;
case KioskMode.DisableExplorerShell:
TerminateExplorerShell();
@ -111,7 +112,7 @@ namespace SafeExamBrowser.Runtime.Operations
switch (activeMode)
{
case KioskMode.CreateNewDesktop:
CloseNewDesktop();
CloseCustomDesktop();
break;
case KioskMode.DisableExplorerShell:
RestartExplorerShell();
@ -121,26 +122,26 @@ namespace SafeExamBrowser.Runtime.Operations
return OperationResult.Success;
}
private void CreateNewDesktop()
private void CreateCustomDesktop()
{
originalDesktop = desktopFactory.GetCurrent();
logger.Info($"Current desktop is {originalDesktop}.");
newDesktop = desktopFactory.CreateNew(nameof(SafeExamBrowser));
logger.Info($"Created new desktop {newDesktop}.");
customDesktop = desktopFactory.CreateRandom();
logger.Info($"Created custom desktop {customDesktop}.");
newDesktop.Activate();
processFactory.StartupDesktop = newDesktop;
logger.Info("Successfully activated new desktop.");
customDesktop.Activate();
processFactory.StartupDesktop = customDesktop;
logger.Info("Successfully activated custom desktop.");
desktopMonitor.Start(newDesktop);
desktopMonitor.Start(customDesktop);
}
private void CloseNewDesktop()
private void CloseCustomDesktop()
{
desktopMonitor.Stop();
if (originalDesktop != null)
if (originalDesktop != default)
{
originalDesktop.Activate();
processFactory.StartupDesktop = originalDesktop;
@ -151,14 +152,14 @@ namespace SafeExamBrowser.Runtime.Operations
logger.Warn($"No original desktop found to activate!");
}
if (newDesktop != null)
if (customDesktop != default)
{
newDesktop.Close();
logger.Info($"Closed new desktop {newDesktop}.");
customDesktop.Close();
logger.Info($"Closed custom desktop {customDesktop}.");
}
else
{
logger.Warn($"No new desktop found to close!");
logger.Warn($"No custom desktop found to close!");
}
}

View file

@ -19,6 +19,12 @@ namespace SafeExamBrowser.WindowsApi.Contracts
/// <exception cref="System.ComponentModel.Win32Exception">If the desktop could not be created.</exception>
IDesktop CreateNew(string name);
/// <summary>
/// Creates a new desktop with a random name.
/// </summary>
/// <exception cref="System.ComponentModel.Win32Exception">If the desktop could not be created.</exception>
IDesktop CreateRandom();
/// <summary>
/// Retrieves the currently active desktop.
/// </summary>

View file

@ -11,9 +11,9 @@ using System.ComponentModel;
using System.Runtime.InteropServices;
using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.WindowsApi
namespace SafeExamBrowser.WindowsApi.Desktops
{
public class Desktop : IDesktop
internal class Desktop : IDesktop
{
public IntPtr Handle { get; private set; }
public string Name { get; private set; }

View file

@ -10,18 +10,20 @@ using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.WindowsApi.Contracts;
using SafeExamBrowser.WindowsApi.Constants;
using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.WindowsApi
namespace SafeExamBrowser.WindowsApi.Desktops
{
public class DesktopFactory : IDesktopFactory
{
private ILogger logger;
private readonly ILogger logger;
private readonly Random random;
public DesktopFactory(ILogger logger)
{
this.logger = logger;
this.random = new Random();
}
public IDesktop CreateNew(string name)
@ -44,11 +46,34 @@ namespace SafeExamBrowser.WindowsApi
return desktop;
}
public IDesktop CreateRandom()
{
logger.Debug($"Attempting to create random desktop...");
var name = GenerateRandomDesktopName();
var handle = User32.CreateDesktop(name, IntPtr.Zero, IntPtr.Zero, 0, (uint) AccessMask.GENERIC_ALL, IntPtr.Zero);
if (handle == IntPtr.Zero)
{
logger.Error($"Failed to create random desktop '{name}'!");
throw new Win32Exception(Marshal.GetLastWin32Error());
}
var obfuscatedHandle = new IntPtr(random.Next(100, 10000));
var obfuscatedName = GenerateRandomDesktopName();
var desktop = new ObfuscatedDesktop(handle, name, obfuscatedHandle, obfuscatedName);
logger.Debug($"Successfully created random desktop {desktop}.");
return desktop;
}
public IDesktop GetCurrent()
{
var threadId = Kernel32.GetCurrentThreadId();
var handle = User32.GetThreadDesktop(threadId);
var name = String.Empty;
var name = string.Empty;
var nameLength = 0;
if (handle == IntPtr.Zero)
@ -81,5 +106,18 @@ namespace SafeExamBrowser.WindowsApi
return desktop;
}
private string GenerateRandomDesktopName()
{
var length = random.Next(5, 20);
var name = new char[length];
for (var letter = 0; letter < length; letter++)
{
name[letter] = (char) (random.Next(2) == 0 && letter != 0 ? random.Next('a', 'z' + 1) : random.Next('A', 'Z' + 1));
}
return new string(name);
}
}
}

View file

@ -13,7 +13,7 @@ using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.WindowsApi.Constants;
using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.WindowsApi
namespace SafeExamBrowser.WindowsApi.Desktops
{
public class DesktopMonitor : IDesktopMonitor
{

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2023 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using System;
namespace SafeExamBrowser.WindowsApi.Desktops
{
internal class ObfuscatedDesktop : Desktop
{
private readonly IntPtr? obfuscatedHandle;
private readonly string obfuscatedName;
public ObfuscatedDesktop(IntPtr handle, string name, IntPtr? obfuscatedHandle, string obfuscatedName) : base(handle, name)
{
this.obfuscatedHandle = obfuscatedHandle;
this.obfuscatedName = obfuscatedName;
}
public override string ToString()
{
return $"'{obfuscatedName}' [{obfuscatedHandle}]";
}
}
}

View file

@ -12,7 +12,7 @@ using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.WindowsApi.Contracts;
using SafeExamBrowser.WindowsApi.Contracts.Events;
namespace SafeExamBrowser.WindowsApi
namespace SafeExamBrowser.WindowsApi.Processes
{
internal class Process : IProcess
{

View file

@ -20,7 +20,7 @@ using SafeExamBrowser.WindowsApi.Constants;
using SafeExamBrowser.WindowsApi.Contracts;
using SafeExamBrowser.WindowsApi.Types;
namespace SafeExamBrowser.WindowsApi
namespace SafeExamBrowser.WindowsApi.Processes
{
public class ProcessFactory : IProcessFactory
{

View file

@ -63,14 +63,15 @@
<Compile Include="Delegates\EnumWindowsDelegate.cs" />
<Compile Include="Delegates\EventDelegate.cs" />
<Compile Include="Delegates\HookDelegate.cs" />
<Compile Include="Desktop.cs" />
<Compile Include="DesktopFactory.cs" />
<Compile Include="DesktopMonitor.cs" />
<Compile Include="Desktops\Desktop.cs" />
<Compile Include="Desktops\DesktopFactory.cs" />
<Compile Include="Desktops\DesktopMonitor.cs" />
<Compile Include="Desktops\ObfuscatedDesktop.cs" />
<Compile Include="ExplorerShell.cs" />
<Compile Include="Hooks\MouseHook.cs" />
<Compile Include="Hooks\SystemHook.cs" />
<Compile Include="Process.cs" />
<Compile Include="ProcessFactory.cs" />
<Compile Include="Processes\Process.cs" />
<Compile Include="Processes\ProcessFactory.cs" />
<Compile Include="Constants\AccessMask.cs" />
<Compile Include="Types\Bounds.cs" />
<Compile Include="Types\EXECUTION_STATE.cs" />