Delphi 6. Hooks
Каждый пользователь хоть раз нажимал на кнопки клавиатуры:-). 99.(9)% пользователей делали это неоднократно. Некоторые используют клавиатуру чаще, чем мышь. Неудивительно, что иногда клавиатура приходит в негодность. В одних случаях проблема решается мытьем данного девайса, в других — покупкой нового.
Итак, на сегодня идея следующая: написать хук (что это такое, узнаешь после прочтения), который будет отслеживать нажатие пробела, а после некоторого количества нажатий блокировать сообщение клавиатуры в систему о данном факте.
Возникает вопрос: каким образом отследить нажатие клавиши? Ведь отслеживать нажатие следует даже если наше приложение неактивно. Я предлагаю реализовать это при помощи ловушек (hooks). Ловушка — это набор процедур и функций, которые реагируют на определенные события в среде Windows. Хук должен постоянно находиться в памяти, поэтому его нужно реализовывать в Dll'ке (Dynamic-Link Libraries). DLL — это модуль, состоящий из процедур\функций, иногда DLL содержит ресурсы. Использование DLL продиктовано такими факторами, как, например, экономия физической памяти: если какую-нибудь DLL используют несколько программ, то физически она будет загружена только один раз. В DLL можно хранить ресурсы: всевозможные картинки и данные, можно даже помещать окна программ. Обычно плагины также реализуют средствами DLL. В отличие от Unit'ов, DLL могут быть написаны на любом языке. Для создания DLL в Delphi 6 следует выполнить следующие действия: File — New — Other — DLL Wizard.
Текст библиотеки приведен ниже:
Структура библиотеки схожа со структурой модуля. Я объявил две переменные: Count_ для счетчика и My-HookHandle — дескриптор для ловушки. В разделе Var осуществлена инициализация этих переменных. Далее следуют пользовательские процедуры и функции. stdCall; после имени означает, что будет осуществляться стандартный вызов, а Export; — что данная процедура (функция) экспортируется из библиотеки (также их следует объявить и в разделе Exports). Только экспортируемая процедура (функция) будет доступна приложению, которое использует библиотеку. А это значит, что приложение может вызывать только процедуры SetHook и UnHook.
Функция SetWindowsHookEx устанавливает определенную программистом процедуру (MyCoolHook) в цепочку обработчиков ловушек, что позволяет производить мониторинг системы для некоторых типов событий. Отслеживать события можно в различных потоках или во всех потоках в системе.
HHOOK SetWindowsHookEx (
Int idHook, // определяет тип ловушки
HOOKPROC lpfn, // адрес процедуры обработки
HINSTANCE hMod, // дескриптор приложения, которое содержит процедуру обработки хука
DWORD dwThreadId //поток, с которым связан хук. Если 0, то хук связан со всеми потоками );
Если вызов функции успешен, то возвращаемое значение — дескриптор ловушки, иначе — null.
Функция CallNextHookEx вызывает следующую ловушку.
LRESULT CallNextHookEx (
HHOOK hhk, // дескриптор ловушки
Int nCode, // тип произошедшего события
WPARAM wParam, // информация о событии
LPARAM lParam // дополнительная информация о событии
);
Функция UnhookWindowsHookEx снимает ловушку. Если вызов функции успешен, то возвращаемое значение ненулевое, иначе — ноль.
Следует скомпилировать библиотеку: Ctrl+F9. С созданием библиотеки покончено. Теперь нужно создать приложение, которое зарегистрирует библиотеку SpyKey в системе. На форме следует разместить две кнопки:
Ниже приведен исходный код этого приложения:
Теперь библиотека SpyKey будет грузиться при каждом запуске explorer.exe, который загружается при каждой загрузке системы. Следует заметить, что {AC940172-49A3-4C32-ACD2-90CB0E483D4C} — MAC-адрес, чтобы его получить, следует нажать Ctrl+Shift+G в среде Delphi, поэтому в твоей программе MAC будет другой. Если запускать программу на другой машине, то необходимо его получать при помощи функции CreateGUID. В раздел var добавить
а получать в программе:
Если так получать MAC-адрес, то необходимо сохранять его, например, в файле, чтобы была возможна операция удаления из реестра данных о библиотеке.
Вот и все на сегодня. После перезагрузки можно посмотреть на свое творение. У тебя мог возникнуть вопрос: а зачем экспортировать функции SetHook и UnHook? Дело в том, что следовало тестировать библиотеку. Ведь не перезагружать же машину по сто раз в день! Для этого мной создавалось приложение для проверки библиотеки. Вот часть кода этого приложения:
Теперь ты сам можешь написать клавиатурный шпион и заработать кучу денег:-). Удачи в программировании.
Margo
Итак, на сегодня идея следующая: написать хук (что это такое, узнаешь после прочтения), который будет отслеживать нажатие пробела, а после некоторого количества нажатий блокировать сообщение клавиатуры в систему о данном факте.
Возникает вопрос: каким образом отследить нажатие клавиши? Ведь отслеживать нажатие следует даже если наше приложение неактивно. Я предлагаю реализовать это при помощи ловушек (hooks). Ловушка — это набор процедур и функций, которые реагируют на определенные события в среде Windows. Хук должен постоянно находиться в памяти, поэтому его нужно реализовывать в Dll'ке (Dynamic-Link Libraries). DLL — это модуль, состоящий из процедур\функций, иногда DLL содержит ресурсы. Использование DLL продиктовано такими факторами, как, например, экономия физической памяти: если какую-нибудь DLL используют несколько программ, то физически она будет загружена только один раз. В DLL можно хранить ресурсы: всевозможные картинки и данные, можно даже помещать окна программ. Обычно плагины также реализуют средствами DLL. В отличие от Unit'ов, DLL могут быть написаны на любом языке. Для создания DLL в Delphi 6 следует выполнить следующие действия: File — New — Other — DLL Wizard.
Текст библиотеки приведен ниже:
library SpyKey;// имя библиотеки uses Windows; var MyHookHandle :HHook = 0; Count_:integer = 0; function MyCoolHook(Code: in-teger; wParam: word; lP aram: Longint):LongInt;stdCall; begin if code<0 then Result := Call Next HookEx(MyHookHandle,Code, wParam, lParam) else//проверка, какая кнопка нажатаbegin result:=0; if wParam = VK_Space then begin Inc(Count_);//увеличиваю на 1 значение переменно й Count_ if Count_>50 then //Если Count_ больше некоторой константы, то… Result := 1;//для того, чтобы windows не обрабатывал это сообщение end; CallNextHookEx(MyHookHandle,Code, wParam, lParam)//вызыва ю следующую ловушку end;{if} end; {===========================}< r> procedure SetHook;stdCall;Ex-port; begin MyHookHandle := SetWindowsHookEx(W H_Keyboard, @MyCoolHook, hInstance, 0);//устанавливаю хук end; {===================== ======} procedure UnHook;stdCall;Export; begin UnhookWindowsHookEx(MyHookHa ndle);//снимаю хук end; {===========================} exports//экспортирую функц ии SetHook, Unhook; Begin SetHook;//устанавливаю ловушку en d.
Структура библиотеки схожа со структурой модуля. Я объявил две переменные: Count_ для счетчика и My-HookHandle — дескриптор для ловушки. В разделе Var осуществлена инициализация этих переменных. Далее следуют пользовательские процедуры и функции. stdCall; после имени означает, что будет осуществляться стандартный вызов, а Export; — что данная процедура (функция) экспортируется из библиотеки (также их следует объявить и в разделе Exports). Только экспортируемая процедура (функция) будет доступна приложению, которое использует библиотеку. А это значит, что приложение может вызывать только процедуры SetHook и UnHook.
Функция SetWindowsHookEx устанавливает определенную программистом процедуру (MyCoolHook) в цепочку обработчиков ловушек, что позволяет производить мониторинг системы для некоторых типов событий. Отслеживать события можно в различных потоках или во всех потоках в системе.
HHOOK SetWindowsHookEx (
Int idHook, // определяет тип ловушки
HOOKPROC lpfn, // адрес процедуры обработки
HINSTANCE hMod, // дескриптор приложения, которое содержит процедуру обработки хука
DWORD dwThreadId //поток, с которым связан хук. Если 0, то хук связан со всеми потоками );
Если вызов функции успешен, то возвращаемое значение — дескриптор ловушки, иначе — null.
Функция CallNextHookEx вызывает следующую ловушку.
LRESULT CallNextHookEx (
HHOOK hhk, // дескриптор ловушки
Int nCode, // тип произошедшего события
WPARAM wParam, // информация о событии
LPARAM lParam // дополнительная информация о событии
);
Функция UnhookWindowsHookEx снимает ловушку. Если вызов функции успешен, то возвращаемое значение ненулевое, иначе — ноль.
Следует скомпилировать библиотеку: Ctrl+F9. С созданием библиотеки покончено. Теперь нужно создать приложение, которое зарегистрирует библиотеку SpyKey в системе. На форме следует разместить две кнопки:
Ниже приведен исходный код этого приложения:
unit Registrayion; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,Registry; type TForm1 = c lass(TForm) Button1: TButton; Button2: TButton; procedu re Button1Click(Sen-der: TObject); procedure Button2Click(Sen-der: TObject);private { Private declarations } public { Public declarati ons } end; var Form1: TForm1; implementation {$ R *.dfm} procedure TForm1.Button1Click (Sender: TObject); var Reg:TRegistry; begin Reg := TRegistry.Create; reg.rootkey:=HKEY_CLASSES_ROOT; if reg.openkey ('CL SID\{AC940172- 49A3-4C32-ACD2-90CB0E483D4C} \InProcServer32', true) then// если создали идентификато р класса begin reg.writestring('','C:\Spy Key.dll'); //Пусть к библиотеке < tab>reg.closekey; reg.rootkey:=HKEY_LOCAL_ MACHINE; reg.openkey('Software\Micro-soft\ Windows\CurrentVersion\ ShellServiceObjectDelayLoad', true); reg.writestring('MyDllLoad', '{AC940172-49A3-4C32-ACD2-90CB0E483D4C}'); reg.closekey; end; Reg.Fre e; end; procedure TForm1.Button2Click (Sender: TObject); var Reg:TRegistry ; begin Reg := TRegistry.Create; reg.rootkey:=HKEY_CLASSES_ROOT; if reg.openkey ('CLSID\ {AC940172-49A3-4C32-ACD2-90CB0E483D4C}\InProcServer32', true) then begin reg.writestring('','C:\Spy Key.dll'); reg.closekey; reg.rootkey:=HKEY_LOCAL_ M ACHINE; reg.Deletekey('Software\Micro-soft\Windows\CurrentVersion\Shell ServiceObjectDelayLoad' ); reg.closekey; end; Reg.Free; end; end.
Теперь библиотека SpyKey будет грузиться при каждом запуске explorer.exe, который загружается при каждой загрузке системы. Следует заметить, что {AC940172-49A3-4C32-ACD2-90CB0E483D4C} — MAC-адрес, чтобы его получить, следует нажать Ctrl+Shift+G в среде Delphi, поэтому в твоей программе MAC будет другой. Если запускать программу на другой машине, то необходимо его получать при помощи функции CreateGUID. В раздел var добавить
TEmp:TGUID; S:String;
а получать в программе:
CreateGUID(Temp); s := GUIDToString(Temp);
Если так получать MAC-адрес, то необходимо сохранять его, например, в файле, чтобы была возможна операция удаления из реестра данных о библиотеке.
Вот и все на сегодня. После перезагрузки можно посмотреть на свое творение. У тебя мог возникнуть вопрос: а зачем экспортировать функции SetHook и UnHook? Дело в том, что следовало тестировать библиотеку. Ведь не перезагружать же машину по сто раз в день! Для этого мной создавалось приложение для проверки библиотеки. Вот часть кода этого приложения:
implementation procedure SetHook;stdCall; external 'SpyKey.Dll';// external 'SpyKey.Dll' — дире ктива, указывающая, из какой DLL будет импортирована функция procedure UnHook;stdCall; external 'SpyKey.Dll'; procedure TForm1.Button1Click (Sender: TObject); begin SetHook;< r> end; procedure TForm1.Button2Click (Sender: TObject); begin Unhook; e nd;
Теперь ты сам можешь написать клавиатурный шпион и заработать кучу денег:-). Удачи в программировании.
Margo
Компьютерная газета. Статья была опубликована в номере 26 за 2003 год в рубрике программирование :: delphi