Чтение онлайн

ЖАНРЫ

Шрифт:
...

Листинг 10.19.

Обработка сообщения WM_SPY_NOTIFY

procedure TfrmMessages.WndProc(var Message: TMessage);

var

item: TListItem;

i: Integer;

begin

if (Message.Msg = WM_SPY_NOTIFY) and (hook_info <> nil) then

begin

//Обрабатываем уведомление о приходе сообщения в наблюдае-

мое окно

for i := mess_first to mess_last do

if (messages_list[i].value = hook_info^.mess) and

messages_list[i].used then

begin

//Сообщение выбрано в фильтре – добавим запись в список

item := lvwMessages.Items.Add;

item.Caption := messages_list[i].name;

item.SubItems.Add(IntToStr(hook_info^.wParam));

item.SubItems.Add(IntToStr(hook_info^.lParam));

end;

end

else

inherited WndProc(Message);

end;

Ловушка

Теперь

обратимся к реализации самой ловушки. По рассмотренным ранее причинам ловушка размещена в отдельной DLL (hook\hook.dll на прилагаемом к книге диске в папке с номером главы). На случай, если вы не знакомы с созданием DLL средствами Delphi, приведем краткие сведения.

Среда программирования Delphi замечательна тем, что позволяет просто делать довольно сложные вещи. Хотя и при использовании сред разработки, скрывающих меньшее количество сложных деталей, например Visual C++, создание DLL не является очень сложной задачей. Итак, для создания DLL в простейшем, то есть нашем, случае достаточно выполнить следующие действия.

1. Создать соответствующий проект (с помощью команды меню FiLe → New → Other, тип проекта – DLL Wizard) (рис. 10.6).

2. В DPR-файле получившегося проекта реализуем функции, которые предполагается экспортировать.

3. Объявляем, какие функции нужно экспортировать с помощью ключевого слова exports (листинг 10.20).

Рис. 10.6. Создание проекта DLL

Структура DLL ловушки, реализованной в нашем примере, приведена в листинге 10.20.

...

Листинг 10.20.

DLL ловушки без реализации функций

library hook;

uses

Windows,

HookData;

//****************************************************

//Экспортируемые функции

function InstallHook(wnd: HWND; spy: HWND): Boolean stdcall;

forward;

function RemoveHook: Boolean stdcall; forward;

exports

InstallHook,

RemoveHook;

//****************************************************

begin

hook_info := nil;

hFile := 0;

end.

Код после begin является кодом инициализации библиотеки (выполняется при загрузке DLL в память процесса). Правда, как показали многочисленные эксперименты, проведенные во время написания и отладки ловушки, код этот не выполняется при загрузке DLL ловушки в адресное пространство другого процесса.

Теперь обратимся к реализации экспортируемых функций InstallHook, а также RemoveHook. Как вы помните, только эти две функции вызываются из программы-шпиона. Начнем с функции установки ловушки (листинг 10.21).

...

Листинг 10.21.

Установка (создание) ловушки

function InstallHook(wnd: HWND; spy: HWND): Boolean stdcall;

begin

//Открываем проекцию файла (области файла подкачки)

if not GetFileMapping then

begin

//Не удалось спроецировать файл в память

InstallHook := False;

Exit;

end;

//Сохраняем данные, необходимые для работы ловушки

hook_info^.wnd := wnd;

hook_info^.spy_wnd := spy;

//Создаем ловушку

if (GetWindowThreadProcessId(wnd) <> 0)

then

hook_info^.hook_handle :=

SetWindowsHookEx(WH_CALLWNDPROC, WndProcHook,

hInstance, GetWindowThreadProcessId(wnd))

else

//Создание ловушки для потоков нашего приложения

//было бы фатальным

hook_info^.hook_handle := 0;

InstallHook := hook_info^.hook_handle <> 0;

//Освободим проекцию файла

ReleaseFileMapping;

end;

Функция InstallHook использует глобальную переменную-указатель hook_inf о, которая объявлена в модуле HookData. Функция GetFileMapping, также используемая в листинге 10.21, связывает указатель hookinf о с областью памяти, на которую проецируется файл. Соответственно, процедура ReleaseFileMapping

отменяет проецирование файла в память (после этого использовать указатель hookinf о нельзя).

API-функция GetWindowThreadProcessId используется для определения идентификатора потока, создавшего наблюдаемое окно. Проверка неравенства значения, возвращенного этой функцией, нулю используется для того, чтобы в случае закрытия интересующего нас окна до запуска ловушки мы не начали следить за окнами приложения-шпиона.

Работу с проецируемым файлом в ловушке рассмотрим чуть позже. Сейчас же обратимся к функции удаления ловушки, реализация которой приводится в листинге 10.22.

...

Листинг 10.22.

Удаление ловушки

function RemoveHook: Boolean stdcall;

begin

if GetFileMapping then

begin

if hook_info^.hook_handle <> 0 then

//Удаляем ловушку

UnhookWindowsHookEx(hook_info^.hook_handle);

//Закрываем проекцию файла

ReleaseFileMapping;

RemoveHook := True;

end

else

RemoveHook := False;

end;

Тут все просто и не требует подробного пояснения. Теперь же рассмотрим так часто используемые функцию и процедуру, работающие с проекцией файла в память. Функция GetFileMapping, приведенная в листинге 10.23, открывает проекцию файла в память и связывает указатель hookinf о с областью памяти, отведенной для проекции файла.

...

Листинг 10.23.

Открытие проекции файла

function GetFileMapping: Boolean;

begin

//Пытаемся открыть проекцию файла

hFile := OpenFileMapping(FILE_MAP_WRITE, False, PAnsiChar(strFileMapName));

//Получаем адрес разделяемой памяти

hook_info := MapViewOfFile(hFile, FILE_MAP_WRITE, 0, 0, SizeOf(THookInfo));

GetFileMapping := hook_info <> nil;

end;

Процедура ReleaseFileMapping, симметричная по своему назначению функции GetFileMapping, реализована так, как показано в листинге 10.24.

...

Листинг 10.24.

Освобождение проекции файла

procedure ReleaseFileMapping;

begin

UnmapViewOfFile(hook_info);

hook_info := nil;

CloseHandle(hFile);

hFile := 0;

end;

Функция GetFileMapping и процедура ReleaseFileMapping используют дополнительно глобальную переменную hFile (тип THandle), объявленную в модуле HookData.

Наконец пришла очередь функции-ловушки. Ее реализация приведена в листинге 10.25.

...

Листинг 10.25.

Функция-ловушка

function WndProcHook(code: Integer; wparam: WPARAM;

lparam: LPARAM): LRESULT stdcall;

var

hook_data: ^TCWPStruct;

begin

//Получим доступ к проекции файла

if not GetFileMapping then

begin

//Не удалось получить доступ к проекции файла. Ценой потери

//сообщений не дадим возникнуть ошибкам доступа к памяти

WndProcHook := 0;

Exit;

end;

if code < 0 then

begin

WndProcHook := CallNextHookEx(hook_info^.hook_handle, code,

wParam, lParam);

//Освободим проекцию файла

ReleaseFileMapping;

Exit;

end;

//Можно обрабатывать сообщение

hook_data := Pointer(lParam);

//Обрабатываем только сообщения нужного окна

if hook_data^.hwnd = hook_info^.wnd then

begin

//Заполняем поля структуры в общей области памяти и посылаем

//сообщение окну-шпиону

hook_info^.mess := hook_data^.message;

hook_info^.wParam := hook_data^.wParam;

hook_info^.lParam := hook_data^.lParam;

PostMessage(hook_info^.spy_wnd, WM_SPY_NOTIFY, 0, 0);

end;

//Передаем сообщение для дальнейшей обработки

WndProcHook := CallNextHookEx(hook_info^.hook_handle, code,

wParam, lParam);

//Освободим проекцию файла

ReleaseFileMapping;

end;

Поделиться с друзьями: