Сегодня мы поговорим об установке hook'ов (ловушек) в Windows. Hook - это
механизм перехвата сообщений, путем установки специальной функции на верх стека
hook-функций системы. Без установки таких ловушек практически невозможно
обойтись при написании различных средств удаленного администрирования, шпионов и
других программ в той или иной степени осуществляющих контроль за пользователем,
использующем ОС Windows. Hook'и бывают глобальные (на всю систему) и локальные
(на какой-либо поток).
Установить в систему hook можно при помощи функции SetWindowsHookEx(), со
следующим заголовком:
HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);
Если ты плохо воспринимаешь Си-шный код, на Delphi заголовок выглядит так:
SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HINST; dwThreadId: DWORD): HHOOK;
Функция SetWindowsHookEx() в случае установки hook'a возвращает его
дескриптор, в случае ошибки возвращает 0.
Разберем подробней все входящие параметры этой функции:
1. idHook - константа, определяет типа устанавливаемого hook'а. Может
принимать одно из ниже перечисленных значений:
WH_CALLWNDPROC - Следит за сообщениями до отправки в оконную функцию
и вызывается, когда процедуре окна посылается сообщение. Ловушка срабатывает при
каждом вызове функции SendMessage.
WH_CALLWNDPROCRET - Контролирует сообщения после их отправки в оконную
функцию.
WH_CBT - Вызывается перед обработкой большинства сообщений окон, мыши и
клавиатуры (созданием окон, активация окон, уничтожением окон, сменой размера
окон, перед установкой фокуса и.т.п.)
WH_DEBUG - Вызывается перед любой другой ловушкой. Полезно для отладки
hook'ов.
WH_GETMESSAGE - Вызывается, когда из очереди приложения считывается
сообщение.
WH_HARDWARE - Вызывается, когда из очереди приложения считывается сообщение
установленного на компьютере оборудования.
WH_JOURNALPLAYBACK - Вызывается, когда из очереди системы считывается
сообщение. Применяется для добавления в очередь системных событий.
WH_JOURNALRECORD - Вызывается, когда из очереди системы запрашивается
какое-нибудь событие. Применяется для регистрации системных событий.
WH_KEYBOARD - Вызывается, когда из очереди приложения считывается сообщения
WM_Keydown или WM_Keyup. Одна из самых распространенных ловушек -).
WH_MOUSE - Вызывается, когда из очереди приложения считывается сообщение
мыши.
WH_MSGFILTER - Вызывается, когда сообщение должно быть обработано диалоговым
окном приложения, меню или окном приложения.
WH_SHELL - Вызывается, когда создаются и разрушаются окна верхнего уровня или
когда приложению-оболочке требуется стать активным.
2. lpfn - указатель на саму hook функцию. Ее заголовок:
function HOOKFUNCTION(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
Значения входящих параметров зависят от типа hook'a. Если ставится глобальный
hook, эта функция должна обязательно находиться в dll.
3. hmod - принимает значение hInstance или дескриптор DLL (в глобальных
ловушках).
4. dwThreadId - идентифицирует поток, в который вставляется ловушка. В
глобальных hook'ах этот параметр должен быть равен 0.
Для удаления установленной ловушки существует функция UnhookWindowsHookEx().
В качестве параметра нужно использовать указатель (дескриптор) на hook функцию
(значение, которое возвращает функция SetWindowsHookEx()).
Ну вот и все, с основами мы ознакомлены. Теперь напишем маленькую шуточную
программу, ставящую hook на считывания сообщений мыши (WH_MOUSE). Сделаем так,
чтобы при нажатии на правую кнопку мыши скрывалась кнопка "Пуск", при нажатии на
левую - появлялась, среднею - изменялся заголовок активного окна. Сама hook
функция будет находиться в dll. Кроме того, в dll будут находиться две процедуры
- sethook() и removehook(), соответственно устанавливающие и удаляющие ловушку.
Привожу код dll библиотеки:
library lib;
uses windows,messages; var H : THandle;
{Hook-функция} function hook(c0de, wParam, lParam : integer): Lresult; stdcall; {Объявления переменных} var w : THandle; hw : hwnd; begin {Если c0de не меньше 0, все в порядке, продолжаем} if c0de >= 0 then begin { Если wParam = WM_RBUTTONUP, т.е. нажата правая кнопка мыши, получаем хендл (handle) кнопки "Пуск" и скрываем ее } case wParam of WM_RBUTTONUP : begin W:= FindWindow('Shell_TrayWnd', nil); W:= FindWindowEx(W, HWND(0),'Button', nil); ShowWindow(W, SW_hide); end; { Если wParam = WM_LBUTTONUP, т.е. нажата левая кнопка мыши, получаем хендл кнопки пуск и показываем ее } WM_LBUTTONUP: begin W:= FindWindow('Shell_TrayWnd', nil); W:= FindWindowEx(W, HWND(0),'Button', nil); ShowWindow(W, SW_SHOW); end; { Если wParam = WM_MBUTTONUP, т.е. нажата средняя кнопка мыши, получаем указатель на заголовок активного окна и изменяем его } WM_MBUTTONUP: begin hw:=GetForegroundWindow; SetWindowText(hw,'EXAMPLE OF WINDOWS HOOK (WH_MOUSE) - by Dark Lord <darklord@smtp.ru>'); end; end; end else {Если c0de меньше 0} begin {Вызываем следующую ловушку в цепочке ловушек Windows и выходим из процедуры} result := CallNextHookEx(H, c0de, wParam, lParam); exit; end; {Вызываем следующую ловушку в цепочке ловушек Windows} result := CallNextHookEx(H, c0de, wParam, lParam); End;
{ Процедура установки ловушки, если не удалось установить - выводим сообщение об ошибке } procedure sethook; begin H:= SetWindowsHookEx(WH_MOUSE, @hook, hInstance, 0); if H = 0 then messagebox(0,'hmmm..','ERROR',mb_iconhand); end;
{ Процедура удаления ловушки } procedure removehook; begin UnhookWindowsHookEx(H); end;
{ Экспорт процедур установки и удаления hook'a } exports sethook index 1 name 'sethook', removehook index 2 name 'removehook'; end.
|
В самой программе ловушка будет устанавливаться вызовом из dll процедуры
sethook, удаляться - вызовом процедуры removehook. Пример установки и удаления
hook'а и исходник dll библиотеки есть в прилагающемся исходнике. В данной статье
были рассмотрены только основы установки ловушек. Есть немалое количество
нюансов и возникающих проблем при установке нескольких hook'ов, установки
hook'ов в разных ОС (особенно это касается глобальных ловушек). Для получения
подробностей по этим вопросам рекомендую использовать Win32 API Reference или
MSDN (если нет диска с MSDN - прогуляйтесь на http://msdn.microsoft.com,
здесь правда не вся информация, но большая ее часть).
|