Шрифт:
Листинг 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;