SEBWIN-732: Implemented random desktop functionality.
This commit is contained in:
parent
3711555f70
commit
026d1fbfd8
11 changed files with 116 additions and 38 deletions
|
@ -54,6 +54,7 @@ using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
using SafeExamBrowser.UserInterface.Shared.Activators;
|
using SafeExamBrowser.UserInterface.Shared.Activators;
|
||||||
using SafeExamBrowser.WindowsApi;
|
using SafeExamBrowser.WindowsApi;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
|
using SafeExamBrowser.WindowsApi.Processes;
|
||||||
using Desktop = SafeExamBrowser.UserInterface.Desktop;
|
using Desktop = SafeExamBrowser.UserInterface.Desktop;
|
||||||
using Mobile = SafeExamBrowser.UserInterface.Mobile;
|
using Mobile = SafeExamBrowser.UserInterface.Mobile;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ using SafeExamBrowser.SystemComponents.Contracts;
|
||||||
using SafeExamBrowser.SystemComponents.Registry;
|
using SafeExamBrowser.SystemComponents.Registry;
|
||||||
using SafeExamBrowser.UserInterface.Desktop;
|
using SafeExamBrowser.UserInterface.Desktop;
|
||||||
using SafeExamBrowser.WindowsApi;
|
using SafeExamBrowser.WindowsApi;
|
||||||
|
using SafeExamBrowser.WindowsApi.Desktops;
|
||||||
|
using SafeExamBrowser.WindowsApi.Processes;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime
|
namespace SafeExamBrowser.Runtime
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,14 +17,15 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
{
|
{
|
||||||
internal class KioskModeOperation : SessionOperation
|
internal class KioskModeOperation : SessionOperation
|
||||||
{
|
{
|
||||||
private IDesktop newDesktop;
|
private readonly IDesktopFactory desktopFactory;
|
||||||
private IDesktop originalDesktop;
|
private readonly IDesktopMonitor desktopMonitor;
|
||||||
private IDesktopFactory desktopFactory;
|
private readonly IExplorerShell explorerShell;
|
||||||
private IDesktopMonitor desktopMonitor;
|
private readonly ILogger logger;
|
||||||
private IExplorerShell explorerShell;
|
private readonly IProcessFactory processFactory;
|
||||||
|
|
||||||
private KioskMode? activeMode;
|
private KioskMode? activeMode;
|
||||||
private ILogger logger;
|
private IDesktop customDesktop;
|
||||||
private IProcessFactory processFactory;
|
private IDesktop originalDesktop;
|
||||||
|
|
||||||
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||||
public override event StatusChangedEventHandler StatusChanged;
|
public override event StatusChangedEventHandler StatusChanged;
|
||||||
|
@ -54,7 +55,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
switch (Context.Next.Settings.Security.KioskMode)
|
switch (Context.Next.Settings.Security.KioskMode)
|
||||||
{
|
{
|
||||||
case KioskMode.CreateNewDesktop:
|
case KioskMode.CreateNewDesktop:
|
||||||
CreateNewDesktop();
|
CreateCustomDesktop();
|
||||||
break;
|
break;
|
||||||
case KioskMode.DisableExplorerShell:
|
case KioskMode.DisableExplorerShell:
|
||||||
TerminateExplorerShell();
|
TerminateExplorerShell();
|
||||||
|
@ -80,7 +81,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
switch (activeMode)
|
switch (activeMode)
|
||||||
{
|
{
|
||||||
case KioskMode.CreateNewDesktop:
|
case KioskMode.CreateNewDesktop:
|
||||||
CloseNewDesktop();
|
CloseCustomDesktop();
|
||||||
break;
|
break;
|
||||||
case KioskMode.DisableExplorerShell:
|
case KioskMode.DisableExplorerShell:
|
||||||
RestartExplorerShell();
|
RestartExplorerShell();
|
||||||
|
@ -92,7 +93,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
switch (newMode)
|
switch (newMode)
|
||||||
{
|
{
|
||||||
case KioskMode.CreateNewDesktop:
|
case KioskMode.CreateNewDesktop:
|
||||||
CreateNewDesktop();
|
CreateCustomDesktop();
|
||||||
break;
|
break;
|
||||||
case KioskMode.DisableExplorerShell:
|
case KioskMode.DisableExplorerShell:
|
||||||
TerminateExplorerShell();
|
TerminateExplorerShell();
|
||||||
|
@ -111,7 +112,7 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
switch (activeMode)
|
switch (activeMode)
|
||||||
{
|
{
|
||||||
case KioskMode.CreateNewDesktop:
|
case KioskMode.CreateNewDesktop:
|
||||||
CloseNewDesktop();
|
CloseCustomDesktop();
|
||||||
break;
|
break;
|
||||||
case KioskMode.DisableExplorerShell:
|
case KioskMode.DisableExplorerShell:
|
||||||
RestartExplorerShell();
|
RestartExplorerShell();
|
||||||
|
@ -121,26 +122,26 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
return OperationResult.Success;
|
return OperationResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateNewDesktop()
|
private void CreateCustomDesktop()
|
||||||
{
|
{
|
||||||
originalDesktop = desktopFactory.GetCurrent();
|
originalDesktop = desktopFactory.GetCurrent();
|
||||||
logger.Info($"Current desktop is {originalDesktop}.");
|
logger.Info($"Current desktop is {originalDesktop}.");
|
||||||
|
|
||||||
newDesktop = desktopFactory.CreateNew(nameof(SafeExamBrowser));
|
customDesktop = desktopFactory.CreateRandom();
|
||||||
logger.Info($"Created new desktop {newDesktop}.");
|
logger.Info($"Created custom desktop {customDesktop}.");
|
||||||
|
|
||||||
newDesktop.Activate();
|
customDesktop.Activate();
|
||||||
processFactory.StartupDesktop = newDesktop;
|
processFactory.StartupDesktop = customDesktop;
|
||||||
logger.Info("Successfully activated new desktop.");
|
logger.Info("Successfully activated custom desktop.");
|
||||||
|
|
||||||
desktopMonitor.Start(newDesktop);
|
desktopMonitor.Start(customDesktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CloseNewDesktop()
|
private void CloseCustomDesktop()
|
||||||
{
|
{
|
||||||
desktopMonitor.Stop();
|
desktopMonitor.Stop();
|
||||||
|
|
||||||
if (originalDesktop != null)
|
if (originalDesktop != default)
|
||||||
{
|
{
|
||||||
originalDesktop.Activate();
|
originalDesktop.Activate();
|
||||||
processFactory.StartupDesktop = originalDesktop;
|
processFactory.StartupDesktop = originalDesktop;
|
||||||
|
@ -151,14 +152,14 @@ namespace SafeExamBrowser.Runtime.Operations
|
||||||
logger.Warn($"No original desktop found to activate!");
|
logger.Warn($"No original desktop found to activate!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newDesktop != null)
|
if (customDesktop != default)
|
||||||
{
|
{
|
||||||
newDesktop.Close();
|
customDesktop.Close();
|
||||||
logger.Info($"Closed new desktop {newDesktop}.");
|
logger.Info($"Closed custom desktop {customDesktop}.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.Warn($"No new desktop found to close!");
|
logger.Warn($"No custom desktop found to close!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,12 @@ namespace SafeExamBrowser.WindowsApi.Contracts
|
||||||
/// <exception cref="System.ComponentModel.Win32Exception">If the desktop could not be created.</exception>
|
/// <exception cref="System.ComponentModel.Win32Exception">If the desktop could not be created.</exception>
|
||||||
IDesktop CreateNew(string name);
|
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>
|
/// <summary>
|
||||||
/// Retrieves the currently active desktop.
|
/// Retrieves the currently active desktop.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -11,9 +11,9 @@ using System.ComponentModel;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
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 IntPtr Handle { get; private set; }
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
|
@ -10,18 +10,20 @@ using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
|
||||||
using SafeExamBrowser.WindowsApi.Constants;
|
using SafeExamBrowser.WindowsApi.Constants;
|
||||||
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
|
|
||||||
namespace SafeExamBrowser.WindowsApi
|
namespace SafeExamBrowser.WindowsApi.Desktops
|
||||||
{
|
{
|
||||||
public class DesktopFactory : IDesktopFactory
|
public class DesktopFactory : IDesktopFactory
|
||||||
{
|
{
|
||||||
private ILogger logger;
|
private readonly ILogger logger;
|
||||||
|
private readonly Random random;
|
||||||
|
|
||||||
public DesktopFactory(ILogger logger)
|
public DesktopFactory(ILogger logger)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
|
this.random = new Random();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDesktop CreateNew(string name)
|
public IDesktop CreateNew(string name)
|
||||||
|
@ -44,11 +46,34 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
return desktop;
|
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()
|
public IDesktop GetCurrent()
|
||||||
{
|
{
|
||||||
var threadId = Kernel32.GetCurrentThreadId();
|
var threadId = Kernel32.GetCurrentThreadId();
|
||||||
var handle = User32.GetThreadDesktop(threadId);
|
var handle = User32.GetThreadDesktop(threadId);
|
||||||
var name = String.Empty;
|
var name = string.Empty;
|
||||||
var nameLength = 0;
|
var nameLength = 0;
|
||||||
|
|
||||||
if (handle == IntPtr.Zero)
|
if (handle == IntPtr.Zero)
|
||||||
|
@ -81,5 +106,18 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
|
|
||||||
return desktop;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@ using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.WindowsApi.Constants;
|
using SafeExamBrowser.WindowsApi.Constants;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
|
|
||||||
namespace SafeExamBrowser.WindowsApi
|
namespace SafeExamBrowser.WindowsApi.Desktops
|
||||||
{
|
{
|
||||||
public class DesktopMonitor : IDesktopMonitor
|
public class DesktopMonitor : IDesktopMonitor
|
||||||
{
|
{
|
29
SafeExamBrowser.WindowsApi/Desktops/ObfuscatedDesktop.cs
Normal file
29
SafeExamBrowser.WindowsApi/Desktops/ObfuscatedDesktop.cs
Normal 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}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
|
using SafeExamBrowser.WindowsApi.Contracts.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.WindowsApi
|
namespace SafeExamBrowser.WindowsApi.Processes
|
||||||
{
|
{
|
||||||
internal class Process : IProcess
|
internal class Process : IProcess
|
||||||
{
|
{
|
|
@ -20,7 +20,7 @@ using SafeExamBrowser.WindowsApi.Constants;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
using SafeExamBrowser.WindowsApi.Types;
|
using SafeExamBrowser.WindowsApi.Types;
|
||||||
|
|
||||||
namespace SafeExamBrowser.WindowsApi
|
namespace SafeExamBrowser.WindowsApi.Processes
|
||||||
{
|
{
|
||||||
public class ProcessFactory : IProcessFactory
|
public class ProcessFactory : IProcessFactory
|
||||||
{
|
{
|
|
@ -63,14 +63,15 @@
|
||||||
<Compile Include="Delegates\EnumWindowsDelegate.cs" />
|
<Compile Include="Delegates\EnumWindowsDelegate.cs" />
|
||||||
<Compile Include="Delegates\EventDelegate.cs" />
|
<Compile Include="Delegates\EventDelegate.cs" />
|
||||||
<Compile Include="Delegates\HookDelegate.cs" />
|
<Compile Include="Delegates\HookDelegate.cs" />
|
||||||
<Compile Include="Desktop.cs" />
|
<Compile Include="Desktops\Desktop.cs" />
|
||||||
<Compile Include="DesktopFactory.cs" />
|
<Compile Include="Desktops\DesktopFactory.cs" />
|
||||||
<Compile Include="DesktopMonitor.cs" />
|
<Compile Include="Desktops\DesktopMonitor.cs" />
|
||||||
|
<Compile Include="Desktops\ObfuscatedDesktop.cs" />
|
||||||
<Compile Include="ExplorerShell.cs" />
|
<Compile Include="ExplorerShell.cs" />
|
||||||
<Compile Include="Hooks\MouseHook.cs" />
|
<Compile Include="Hooks\MouseHook.cs" />
|
||||||
<Compile Include="Hooks\SystemHook.cs" />
|
<Compile Include="Hooks\SystemHook.cs" />
|
||||||
<Compile Include="Process.cs" />
|
<Compile Include="Processes\Process.cs" />
|
||||||
<Compile Include="ProcessFactory.cs" />
|
<Compile Include="Processes\ProcessFactory.cs" />
|
||||||
<Compile Include="Constants\AccessMask.cs" />
|
<Compile Include="Constants\AccessMask.cs" />
|
||||||
<Compile Include="Types\Bounds.cs" />
|
<Compile Include="Types\Bounds.cs" />
|
||||||
<Compile Include="Types\EXECUTION_STATE.cs" />
|
<Compile Include="Types\EXECUTION_STATE.cs" />
|
||||||
|
|
Loading…
Add table
Reference in a new issue