Restore SEBPatch
This commit is contained in:
128
SafeExamBrowser.WindowsApi/Hooks/KeyboardHook.cs
Normal file
128
SafeExamBrowser.WindowsApi/Hooks/KeyboardHook.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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;
|
||||
using System.Runtime.InteropServices;
|
||||
using SafeExamBrowser.WindowsApi.Constants;
|
||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
|
||||
using SafeExamBrowser.WindowsApi.Delegates;
|
||||
using SafeExamBrowser.WindowsApi.Types;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi.Hooks
|
||||
{
|
||||
internal class KeyboardHook
|
||||
{
|
||||
private bool altPressed, ctrlPressed;
|
||||
private KeyboardHookCallback callback;
|
||||
private IntPtr handle;
|
||||
private HookDelegate hookDelegate;
|
||||
|
||||
internal Guid Id { get; private set; }
|
||||
|
||||
internal KeyboardHook(KeyboardHookCallback callback)
|
||||
{
|
||||
this.callback = callback;
|
||||
this.Id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
internal void Attach()
|
||||
{
|
||||
var process = System.Diagnostics.Process.GetCurrentProcess();
|
||||
var module = process.MainModule;
|
||||
var moduleHandle = Kernel32.GetModuleHandle(module.ModuleName);
|
||||
|
||||
// IMPORTANT:
|
||||
// Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code.
|
||||
// Not doing so will result in a <c>CallbackOnCollectedDelegate</c> error and subsequent application crash!
|
||||
hookDelegate = new HookDelegate(LowLevelKeyboardProc);
|
||||
handle = User32.SetWindowsHookEx(HookType.WH_KEYBOARD_LL, hookDelegate, moduleHandle, 0);
|
||||
}
|
||||
|
||||
internal bool Detach()
|
||||
{
|
||||
return User32.UnhookWindowsHookEx(handle);
|
||||
}
|
||||
|
||||
private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
if (nCode >= 0)
|
||||
{
|
||||
var keyData = (KBDLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
|
||||
var modifier = GetModifiers(keyData, wParam.ToInt32());
|
||||
var state = GetState(wParam.ToInt32());
|
||||
|
||||
if (callback((int) keyData.KeyCode, modifier, state))
|
||||
{
|
||||
return (IntPtr) 1;
|
||||
}
|
||||
}
|
||||
|
||||
return User32.CallNextHookEx(handle, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
private KeyState GetState(int wParam)
|
||||
{
|
||||
switch (wParam)
|
||||
{
|
||||
case Constant.WM_KEYDOWN:
|
||||
case Constant.WM_SYSKEYDOWN:
|
||||
return KeyState.Pressed;
|
||||
case Constant.WM_KEYUP:
|
||||
case Constant.WM_SYSKEYUP:
|
||||
return KeyState.Released;
|
||||
default:
|
||||
return KeyState.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
private KeyModifier GetModifiers(KBDLLHOOKSTRUCT keyData, int wParam)
|
||||
{
|
||||
var modifier = KeyModifier.None;
|
||||
|
||||
TrackCtrlAndAlt(keyData, wParam);
|
||||
|
||||
if (altPressed || keyData.Flags.HasFlag(KBDLLHOOKSTRUCTFlags.LLKHF_ALTDOWN))
|
||||
{
|
||||
modifier |= KeyModifier.Alt;
|
||||
}
|
||||
|
||||
if (ctrlPressed)
|
||||
{
|
||||
modifier |= KeyModifier.Ctrl;
|
||||
}
|
||||
|
||||
return modifier;
|
||||
}
|
||||
|
||||
private void TrackCtrlAndAlt(KBDLLHOOKSTRUCT keyData, int wParam)
|
||||
{
|
||||
var keyCode = keyData.KeyCode;
|
||||
|
||||
if (keyCode == (uint) VirtualKeyCode.LeftControl || keyCode == (uint) VirtualKeyCode.RightControl)
|
||||
{
|
||||
ctrlPressed = IsPressed(wParam);
|
||||
}
|
||||
else if (keyCode == (uint) VirtualKeyCode.LeftAlt || keyCode == (uint) VirtualKeyCode.RightAlt)
|
||||
{
|
||||
altPressed = IsPressed(wParam);
|
||||
}
|
||||
|
||||
if (ctrlPressed && altPressed && keyCode == (uint) VirtualKeyCode.Delete)
|
||||
{
|
||||
// When the Secure Attention Sequence is pressed, the WM_KEYUP / WM_SYSKEYUP messages for CTRL and ALT get lost...
|
||||
ctrlPressed = false;
|
||||
altPressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsPressed(int wParam)
|
||||
{
|
||||
return wParam == Constant.WM_KEYDOWN || wParam == Constant.WM_SYSKEYDOWN;
|
||||
}
|
||||
}
|
||||
}
|
126
SafeExamBrowser.WindowsApi/Hooks/MouseHook.cs
Normal file
126
SafeExamBrowser.WindowsApi/Hooks/MouseHook.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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;
|
||||
using System.Runtime.InteropServices;
|
||||
using SafeExamBrowser.WindowsApi.Constants;
|
||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
|
||||
using SafeExamBrowser.WindowsApi.Delegates;
|
||||
using SafeExamBrowser.WindowsApi.Types;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi.Hooks
|
||||
{
|
||||
internal class MouseHook
|
||||
{
|
||||
private MouseHookCallback callback;
|
||||
private IntPtr handle;
|
||||
private HookDelegate hookDelegate;
|
||||
|
||||
internal Guid Id { get; private set; }
|
||||
|
||||
internal MouseHook(MouseHookCallback callback)
|
||||
{
|
||||
this.callback = callback;
|
||||
this.Id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
internal void Attach()
|
||||
{
|
||||
var process = System.Diagnostics.Process.GetCurrentProcess();
|
||||
var module = process.MainModule;
|
||||
var moduleHandle = Kernel32.GetModuleHandle(module.ModuleName);
|
||||
|
||||
// IMPORTANT:
|
||||
// Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code.
|
||||
// Not doing so will result in a <c>CallbackOnCollectedDelegate</c> error and subsequent application crash!
|
||||
hookDelegate = new HookDelegate(LowLevelMouseProc);
|
||||
handle = User32.SetWindowsHookEx(HookType.WH_MOUSE_LL, hookDelegate, moduleHandle, 0);
|
||||
}
|
||||
|
||||
internal bool Detach()
|
||||
{
|
||||
return User32.UnhookWindowsHookEx(handle);
|
||||
}
|
||||
|
||||
private IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
if (nCode >= 0 && !Ignore(wParam.ToInt32()))
|
||||
{
|
||||
var mouseData = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
|
||||
var button = GetButton(wParam.ToInt32());
|
||||
var state = GetState(wParam.ToInt32());
|
||||
var info = GetInfo(mouseData);
|
||||
|
||||
if (callback(button, state, info))
|
||||
{
|
||||
return (IntPtr) 1;
|
||||
}
|
||||
}
|
||||
|
||||
return User32.CallNextHookEx(handle, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
private bool Ignore(int wParam)
|
||||
{
|
||||
// For performance reasons, ignore mouse movement and wheel rotation...
|
||||
return wParam == Constant.WM_MOUSEMOVE || wParam == Constant.WM_MOUSEWHEEL;
|
||||
}
|
||||
|
||||
private MouseButton GetButton(int wParam)
|
||||
{
|
||||
switch (wParam)
|
||||
{
|
||||
case Constant.WM_LBUTTONDOWN:
|
||||
case Constant.WM_LBUTTONUP:
|
||||
return MouseButton.Left;
|
||||
case Constant.WM_MBUTTONDOWN:
|
||||
case Constant.WM_MBUTTONUP:
|
||||
return MouseButton.Middle;
|
||||
case Constant.WM_RBUTTONDOWN:
|
||||
case Constant.WM_RBUTTONUP:
|
||||
return MouseButton.Right;
|
||||
case Constant.WM_XBUTTONDOWN:
|
||||
case Constant.WM_XBUTTONUP:
|
||||
return MouseButton.Auxiliary;
|
||||
default:
|
||||
return MouseButton.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
private MouseInformation GetInfo(MSLLHOOKSTRUCT mouseData)
|
||||
{
|
||||
var info = new MouseInformation();
|
||||
var extraInfo = mouseData.DwExtraInfo.ToUInt32();
|
||||
|
||||
info.IsTouch = (extraInfo & Constant.MOUSEEVENTF_MASK) == Constant.MOUSEEVENTF_FROMTOUCH;
|
||||
info.X = mouseData.Point.X;
|
||||
info.Y = mouseData.Point.Y;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private MouseButtonState GetState(int wParam)
|
||||
{
|
||||
switch (wParam)
|
||||
{
|
||||
case Constant.WM_LBUTTONDOWN:
|
||||
case Constant.WM_MBUTTONDOWN:
|
||||
case Constant.WM_RBUTTONDOWN:
|
||||
case Constant.WM_XBUTTONDOWN:
|
||||
return MouseButtonState.Pressed;
|
||||
case Constant.WM_LBUTTONUP:
|
||||
case Constant.WM_MBUTTONUP:
|
||||
case Constant.WM_RBUTTONUP:
|
||||
case Constant.WM_XBUTTONUP:
|
||||
return MouseButtonState.Released;
|
||||
default:
|
||||
return MouseButtonState.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
SafeExamBrowser.WindowsApi/Hooks/SystemHook.cs
Normal file
66
SafeExamBrowser.WindowsApi/Hooks/SystemHook.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2024 ETH Zürich, IT Services
|
||||
*
|
||||
* 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;
|
||||
using System.Threading;
|
||||
using SafeExamBrowser.WindowsApi.Constants;
|
||||
using SafeExamBrowser.WindowsApi.Contracts.Events;
|
||||
using SafeExamBrowser.WindowsApi.Delegates;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi.Hooks
|
||||
{
|
||||
internal class SystemHook
|
||||
{
|
||||
private SystemEventCallback callback;
|
||||
private AutoResetEvent detachEvent, detachResultAvailableEvent;
|
||||
private bool detachSuccess;
|
||||
private EventDelegate eventDelegate;
|
||||
private uint eventId;
|
||||
private IntPtr handle;
|
||||
|
||||
internal Guid Id { get; private set; }
|
||||
|
||||
public SystemHook(SystemEventCallback callback, uint eventId)
|
||||
{
|
||||
this.callback = callback;
|
||||
this.detachEvent = new AutoResetEvent(false);
|
||||
this.detachResultAvailableEvent = new AutoResetEvent(false);
|
||||
this.eventId = eventId;
|
||||
this.Id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
internal void Attach()
|
||||
{
|
||||
// IMPORTANT:
|
||||
// Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code.
|
||||
// Not doing so will result in a <c>CallbackOnCollectedDelegate</c> error and subsequent application crash!
|
||||
eventDelegate = new EventDelegate(LowLevelSystemProc);
|
||||
handle = User32.SetWinEventHook(eventId, eventId, IntPtr.Zero, eventDelegate, 0, 0, Constant.WINEVENT_OUTOFCONTEXT);
|
||||
}
|
||||
|
||||
internal void AwaitDetach()
|
||||
{
|
||||
detachEvent.WaitOne();
|
||||
detachSuccess = User32.UnhookWinEvent(handle);
|
||||
detachResultAvailableEvent.Set();
|
||||
}
|
||||
|
||||
internal bool Detach()
|
||||
{
|
||||
detachEvent.Set();
|
||||
detachResultAvailableEvent.WaitOne();
|
||||
|
||||
return detachSuccess;
|
||||
}
|
||||
|
||||
private void LowLevelSystemProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||
{
|
||||
callback(hwnd);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user