Фильтры (HOOKS)
Фильтры (HOOKS).
Мы рассмотрим весьма действенное средство, чаще всего используемое для отладки программ. Средство это называют фильтрами или ловушками52. Смысл его заключается в том, что Вы при желании можете отслеживать сообщения как в рамках одного приложения, так и в рамках целой системы. В этой связи фильтры делят на глобальные (в рамках всей системы) и локальные (в рамках данного процесса). Работая с фильтрами, надо иметь в виду, что они могут существенным образом затормозить работу всей системы. Особенно это касается глобальных фильтров. С точки зрения программирования мы просто определяем функцию, которая вызывается системой при возникновении некоторого события. Можно также говорить о сообщении, приходящем на функцию фильтра.
Рассмотрим некоторые средства для работы с фильтрами. Ниже перечислены основные типы фильтров или сообщения.
Фильтр устанавливается при помощи функции SetWindowsHookEx. Рассмотрим параметры этой функции.
Функция фильтра получает три параметра. Первый параметр определяет произошедшее событие в зависимости от типа фильтра. Два последующих параметра расшифровывают это событие. Поскольку для каждого типа фильтра может быть несколько событий, я не буду их перечислять. Их можно найти в справочном руководстве.
По окончании работы фильтр обязательно должен быть закрыт с помощью функции UnhookWindowsHookEx, единственным параметром которой является дескриптор фильтра.
Фильтр, вообще говоря, есть лишь некоторое звено в вызываемой системой цепочке, поэтому следует из своей процедуры фильтра вызвать функцию CallNextHookEx, которая передаст нужную информацию по цепочке. Параметры этой функции:
Ниже на Рисунок 3.6.5 приводится пример простого фильтра, который отлавливает все произошедшие в системе нажатия клавиши "пробел". Обратите внимание, что поскольку устанавливаемый нами фильтр является глобальным, мы помещаем процедуру фильтра в динамическую библиотеку.
// файл dial.rc для программы DLLEX.ASM // определение констант
#define WS_SYSMENU 0x00080000L #define WS_MINIMIZEBOX 0x00020000L #define WS_MAXIMIZEBOX 0x00010000L
// определение диалогового окна DIAL1 DIALOG 0, 0, 240, 120 STYLE WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX CAPTION "Пример программы с фильтром" FONT 8, "Arial" { }
; основной модуль DLLEX.ASM, ; устанавливающий фильтр в динамической библиотеке .386P ; плоская модель .MODEL FLAT, stdcall ; константы ; сообщение приходит при закрытии окна WM_CLOSE equ 10h WM_INITDIALOG equ 110h WH_KEYBOARD equ 2
; структура сообщения MSGSTRUCT STRUC MSHWND DD ? MSMESSAGE DD ? MSWPARAM DD ? MSLPARAM DD ? MSTIME DD ? MSPT DD ? MSGSTRUCT ENDS
; прототипы внешних процедур IFDEF MASM ; MASM EXTERN UnhookWindowsHookEx@4:NEAR EXTERN SetWindowsHookExA@16:NEAR EXTERN EndDialog@8:NEAR EXTERN DialogBoxParamA@20:NEAR EXTERN GetProcAddress@8:NEAR EXTERN LoadLibraryA@4:NEAR EXTERN FreeLibrary@4:NEAR EXTERN ExitProcess@4:NEAR EXTERN MessageBoxA@16:NEAR ; директивы компоновщику для подключения библиотек includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE EXTERN UnhookWindowsHookEx:NEAR EXTERN SetWindowsHookExA:NEAER EXTERN EndDialog:NEAR EXTERN DialogBoxParamA:NEAR EXTERN GetProcAddress:NEAR EXTERN LoadLibraryA:NEAR EXTERN FreeLibrary:NEAR EXTERN ExitProcess:NEAR EXTERN MessageBoxA:NEAR
UnhookWindowsHookEx@4 = UnhookWindowsHookEx SetWindowsHookExA@16 = SetWindowsHookExA EndDialog@8 = EndDialog DialogBoxParamA@20 = DialogBoxParamA GetProcAddress@8 = GetProcAddress LoadLibraryA@4 = LoadLibraryA FreeLibrary@4 = FreeLibrary ExitProcess@4 = ExitProcess MessageBoxA@16 = MessageBoxA ; директивы компоновщику для подключения библиотек includelib c:\tasm32\lib\import32.lib ENDIF
; сегмент данных _DATA SEGMENT DWORD PUBLIC USE32 'DATA' MSG MSGSTRUCT <?> HINST DD 0 ; дескриптор приложения PA DB "DIAL1",0 LIBR DB 'DLL2.DLL',0 HLIB DD ? APROC DD ? HH DD ? ATOH DD ? IFDEF MASM NAMEPROC DB '_HOOK@0',0 NAMEPROC1 DB '_TOH@0',0 ELSE NAMEPROC1 DB '_TOH',0 NAMEPROC DB 'HOOK',0 ENDIF _DATA ENDS
; сегмент кода
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE' START: ; загрузить библиотеку PUSH OFFSET LIBR CALL LoadLibraryA@4 CMP EAX,0 JE _EXIT MOV HLIB,EAX ; получить адрес процедуры-фильтра PUSH OFFSET NAMEPROC PUSH HLIB CALL GetProcAddress@8 CMP EAX,0 JE _EXIT MOV APROC,EAX ; получить адрес вспомогательной процедуры PUSH OFFSET NAMEPROC1 PUSH HLIB CALL GetProcAddress@8 CMP EAX,0 JE _EXIT MOV ATOH,EAX ; здесь установить HOOK PUSH 0 PUSH HLIB PUSH APROC PUSH WH_KEYBOARD CALL SetWindowsHookExA@16 MOV HH,EAX ; запомним и передадим в библиотеку MOV EAX,ATOH PUSH HH CALL ATOH ; открыть диалоговое окно PUSH 0 PUSH OFFSET WNDPROC PUSH 0 PUSH OFFSET PA PUSH [HINST] CALL DialogBoxParamA@20 ; удалить HOOK PUSH HH CALL UnhookWindowsHookEx@4 ; закрыть библиотеку ; библиотека автоматически закрывается также ; при выходе из программы PUSH OFFSET NAMEPROC PUSH HLIB CALL FreeLibrary@4 ; выход _EXIT: PUSH 0 CALL ExitProcess@4
; процедура окна ; расположение параметров в стеке ; [EBP+014Н] ; LPARAM ; [EBP+10Н] ; WAPARAM ; [EBP+0CH] ; MES ; [EBP+8] ; HWND WNDPROC PROC PUSH EBP MOV EBP,ESP PUSH EBX PUSH ESI PUSH EDI ;------------------ CMP DWORD PTR [EBP+0CH],WM_CLOSE JNE L1 PUSH 0 PUSH DWORD PTR [EBP+08H] CALL EndDialog@8 JMP FINISH L1: CMP DWORD PTR [EBP+0CH],WM_INITDIALOG JNE FINISH FINISH: POP EDI POP ESI POP EBX POP EBP MOV EAX,0 RET 16 WNDPROC ENDP _TEXT ENDS END START
; динамическая библиотека DLL2.ASM ; содержащая процедуру-фильтр .386P ; плоская модель IFDEF MASM .MODEL FLAT, stdcall ELSE .MODEL FLAT ENDIF
PUBLIC HOOK, TOH
; константы ; сообщения, приходящие при открытии ; динамической библиотеки
DLL_PROCESS_DETACH equ 0 DLL_PROCESS_ATTACH equ 1 DLL_THREAD_ATTACH equ 2 DLL_THREAD_DETACH equ 3
IFDEF MASM ; MASM ; прототипы внешних процедур EXTERN CallNextHookEx@16:NEAR EXTERN MessageBoxA@16:NEAR ; директивы компоновщику для подключения библиотек includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE ; TASM EXTERN CallNextHookEx:NEAR EXTERN MessageBoxA:NEAR CallNextHookEx@16 = CallNextHookEx MessageBoxA@16 = MessageBoxA includelib c:\tasm32\lib\import32.lib ENDIF
;-------------------------------------------------- ; сегмент данных _DATA SEGMENT DWORD PUBLIC USE32 'DATA' HDL DD ? HHOOK DD ? CAP DB "Сообщение фильтра",0 MES DB "Нажат пробел",0 _DATA ENDS
; сегмент кода _TEXT SEGMENT DWORD PUBLIC USE32 'CODE' ; [EBP+10H] ; резервный параметр ; [EBP+0CH] ; причина вызова ; [EBP+8] ; идентификатор DLL-модуля DLLENTRY: MOV EAX,DWORD PTR [EBP+0CH] CMP EAX,0 JNE D1 ; закрытие библиотеки JMP _ЕХIТ D1: CMP EAX,1 JNE _EXIT ; открытие библиотеки ; запомнить идентификатор динамической библиотеки MOV EDX,DWORD PTR [EBP+08H] MOV HDL,EDX _ЕХIТ: MOV EAX,1 RET 12 ;---------------- TOH PROC EXPORT PUSH EBP MOV EBP,ESP MOV EAX,DWORD PTR [EBP+08H] MOV HHOOK,EAX POP EBP RET TOH ENDP
; процедура фильтра HOOK PROC EXPORT PUSH EBP MOV EBP,ESP ; отправить сообщение по цепочке PUSH DWORD PTR [EBP+010H] PUSH DWORD PTR [EBP+0CH] PUSH DWORD PTR [EBP+08H] PUSH HHOOK CALL CallNextHookEx@16 ; проверить, не нажат ли пробел CMP DWORD PTR [EBP+0CH],32 JNE _EX ; нажат - выводим сообщение PUSH 0 ; МВ_ОК PUSH OFFSET CAP PUSH OFFSET MES PUSH 0 ; в окне экрана CALL MessageBoxA@16 _EX: POP EBP RET HOOK ENDP _TEXT ENDS END DLLENTRY