C++Builder: Защита от клавиатурных шпионов


Скачать готовый пример (№2) Подавляющее большинство клавиатурных шпионов использует для мониторинга нажатий клавиш hook-процедуру WH_KEYBOARD. Чтобы клавиатурное сообщение не попало в установленную ловушку, достаточно перехватить вызов этой hook-процедуры и отменить его. Это можно сделать, установив свой hook - WH_DEBUG. Процедура этого hook'а будет получать управление при вызове других hook-процедур (в том числе и WH_DEBUG, если такие уже имеются). Таким образом, мы устанавливаем hook для других hook'ов, получая, в результате, достаточно мощное средство.

Приступим к реализации. Создайте новый DLL-проект; VCL можно отключить.
Код процедуры в DLL:
extern "C" __export LRESULT CALLBACK
        DebugProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode == HC_ACTION)
  {
  if(wParam == WH_KEYBOARD)
    {
    if(MessageBox(NULL, "Do you want to pass keyboard message to WH_KEYBOARD hook-procedure?",
		"Confirmation",
		MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 | 
		MB_TOPMOST | MB_SYSTEMMODAL) == IDNO)
      return 1;
    }
  }

return CallNextHookEx(NULL, nCode, wParam, lParam);
}

Всё очень просто - мы проверяем тип вызываемой ловушки на соответствие WH_KEYBOARD, и, если равенство верное, запрашиваем подтверждение на вызов этой процедуры. Если в пропуске отказано, возвращаем ненулевое значение.

Теперь осталось написать приложение, ответственное за установку и снятие этой ловушки.
Код:
// Глобальные переменные:
HMODULE hDLL = NULL;
HHOOK hHook = NULL;

//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
if(hHook != NULL)
  {
  ShowMessage("The Hook has already been set.");
  return;
  }

hDLL = LoadLibrary("hook.dll");
if(hDLL == NULL)
  {
  ShowMessage("Can't load hook.dll. Reason:\n" + SysErrorMessage(GetLastError()));
  return;
  }

typedef LRESULT __import (CALLBACK *fnType)(int, WPARAM, LPARAM);
fnType DebugProc = (fnType)GetProcAddress(hDLL, "DebugProc");

if(DebugProc == NULL)
  {
  FreeLibrary(hDLL);
  hDLL = NULL;
  ShowMessage("Can't find \"DebugProc\" in hook.dll.");
  return;
  }

hHook = SetWindowsHookEx(WH_DEBUG, (HOOKPROC)DebugProc, hDLL, 0);
if(hHook == NULL)
  {
  FreeLibrary(hDLL);
  hDLL = NULL;
  ShowMessage("Can't set WH_DEBUG hook. Reason:\n" + SysErrorMessage(GetLastError()));
  return;
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
if(hDLL)
  FreeLibrary(hDLL);
if(hHook)
  {
  UnhookWindowsHookEx(hHook);
  hHook = NULL;
  }
}
Комментарии излишни. Разве что, не забудьте переименовать DLL (или изменить её имя в коде).

Недостатки примера:

  • К моменту запуска нашего приложения hook'и WH_KEYBOARD могут быть установлены другими программами, не являющимися шпионами. Поэтому, возможно, запрос из DLL будет появляться при любом нажатии клавиш, даже если не запущены никакие кейлоггеры.
  • При кратковременном нажатии на одну клавишу придётся отвечать на два сообщения (поскольку было два события - нажатие и отжатие). Конечно, сообщения можно убрать вообще, ведь они были нужны только для демонстрации.
  • Сам клавиатурный шпион может установить WH_DEBUG-hook и блокировать вызовы остальных DEBUG-процедур, но с этим я ещё не сталкивался.


    Hosted by uCoz