Установка ловушек в Windows
|
Если вы хотите чаще встречаться с понравившейся девушкой установите ей Windows'95
|
Сегодня мы поговорим об установке 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, здесь правда не вся информация, но большая ее часть).
|