Вопрос, который стоит перед разработчиками настольных приложений на Windows, заключается в возможности определения, происходят ли события клавиатуры и мыши от аппаратных устройств или же они генерируются программным обеспечением, например, через TeamViewer, Steam или другие программы удаленного доступа. Цель не в том, чтобы предотвратить действия ботов, а в предотвращении удаленного доступа к приложению.
Похоже, что API RawInput позволяет обнаружить поддельные события, отправленные с помощью SendInput API. Это верно?
Описание решения
Для решения данной задачи можно использовать низкоуровневые хуки для клавиатуры и мыши, предоставляемые функцией SetWindowsHookEx(). Эти хуки могут сообщать, было ли вводное событие сгенерировано реальными устройствами или введено кодом приложения.
Для хука клавиатуры структурой, передаваемой хуку, является KBDLLHOOKSTRUCT, имеющий член flags, который содержит флаг LLKHF_INJECTED для обозначения поддельного ввода.
Для хука мыши используется структура MSLLHOOKSTRUCT, которая также имеет член flags с флагами LLMHF_INJECTED или LLMHF_LOWER_IL_INJECTED для обозначения поддельного ввода.
Оба хука могут возвращать ненулевое значение для блокировки ввода, чтобы он не был передан дальше по цепочке хуков и, соответственно, целевому окну.
Что касается Raw Input API, то согласно устаревшей версии документации для функции GetRawInputDeviceInfo(), hDevice может быть NULL, если приложение вводит данные, например, используя SendInput. Однако, блокировать ввод с помощью Raw Input API невозможно, для этого все равно необходим низкоуровневый хук.
Пример кода на Object Pascal (Delphi)
uses
Winapi.Windows,
Winapi.Messages,
Winapi.RawInput;
type
TKeyboardHookProc = function(Code: Integer; wParam, lParam: LongInt): LongInt; stdcall;
var
KeyboardHook: THookProc;
PreviousHook: TKeyboardHookProc;
function KeyboardHookProc(Code: Integer; wParam, lParam: LongInt): LongInt;
begin
if (wParam = WM_KEYDOWN) or (wParam = WM_KEYUP) then
begin
var KeyBoardLLHookStruct: PKBDLLHOOKSTRUCT read lParam;
if (KeyBoardLLHookStruct^.flags and LLKHF_INJECTED) <> 0 then
// Событие эмулировано
Result := 1
else
// Событие от аппаратного устройства
Result := CallNextHookEx(KeyboardHook, Code, wParam, lParam);
end
else
Result := CallNextHookEx(KeyboardHook, Code, wParam, lParam);
end;
procedure SetUpKeyboardHook;
var
HHKL: HHOOK;
begin
PreviousHook := SetWindowsHookEx($13, @KeyboardHookProc, Application.Handle, 0);
if PreviousHook = 0 then
RaiseLastOSError;
HHKL := PreviousHook;
end;
// Функция для установки хука мыши аналогична
Важно отметить, что использование хуков может привести к сложностям в отладке и взаимодействии с другими приложениями, поэтому необходимо тщательно планировать их использование в приложении.
Заключение
Используя SetWindowsHookEx(), разработчики могут определить, являются ли события клавиатуры и мыши аппаратными или эмулированными. Это позволяет создавать более защищенные настольные приложения, которые могут предотвратить нежелательный удаленный доступ.
Разработчики настольных приложений на Windows столкнулись с задачей различения аппаратных и эмулированных событий мыши и клавиатуры для предотвращения удаленного доступа к приложению, что возможно с использованием низкоуровневых хуков и анализа
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS