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. Текст библиотеки приведен ниже:
library SpyKey;// имя библиотеки
uses
Windows;
var
MyHookHandle:HHook = 0;
Count_:integer = 0;
function MyCoolHook(Code: in-teger; wParam: word; lParam: Longint):LongInt;stdCall;
begin
if code<0 then Result := Call NextHookEx(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;
{===========================}
procedure SetHook;stdCall;Ex-port;
begin
MyHookHandle := SetWindowsHookEx(WH_Keyboard, @MyCoolHook, hInstance, 0);
//устанавливаю хук
end;
{===========================}
procedure UnHook;stdCall;Export;
begin
UnhookWindowsHookEx(MyHookHandle);//снимаю хук
end;
{===========================}
exports//экспортирую функции
SetHook,
Unhook;
Begin
SetHook;//устанавливаю ловушку
end.
Структура библиотеки схожа со структурой модуля. Я объявил две
переменные: 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 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sen-der: TObject);
procedure Button2Click(Sen-der: TObject);
private
{ Private declarations }
public
{ Public declarations }
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 ('CLSID\{AC940172- 49A3-4C32-ACD2-90CB0E483D4C} \InProcServer32', true) then
// если создали идентификатор класса
begin
reg.writestring('','C:\Spy Key.dll'); //Пусть к библиотеке
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.Free;
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_ MACHINE;
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;
end;
procedure TForm1.Button2Click (Sender: TObject);
begin
Unhook;
end;
Теперь ты сам можешь написать клавиатурный шпион и заработать кучу
денег:-). Удачи в программировании.
Автор: Margo
Источник: www.infocity.kiev.ua
|