Виртуальный шпион Tony (porco@argentina.com) Спецвыпуск: Хакер, номер #060, стр. 060-058-3 Хук справа, хук слева После того, как мы с тобой запустили шпиона и спрятали его от посторонних глаз, пришло время решать задачи с его помощью. Запротоколировать нажатия кнопок клавиатуры, с одной стороны, проще пареной репы, а с другой - не так тривиально. Простота заключается в малом количестве строк кода, а сложность - в содержимом этих строк. Для решения подобных задач используют хуки – механизмы перехвата системных сообщений Windows. Функция SetWindowsHookEx() позволяет установить свой обработчик сообщений, посылаемых окнам (фильтрующую функцию); посылаемое сообщение можно обработать, передав его получателю, либо модифицировать или проигнорировать. Функция UnhookWindowsHookEx() убирает установленный хук. Есть небольшая разница в использовании локальных хуков (отлавливаются сообщения в своем процессе) и глобальных хуков (отлавливаются все системные сообщения). Поскольку нас интересуют сообщения от клавиатуры, которые могут посылаться любому приложению, наш случай - это случай глобального хука. Фильтрующая функция глобального хука может быть создана только в динамической библиотеке, поскольку она будет вызываться из адресного пространства каждого процесса. Как ты помнишь, DLL загружается в адресное пространство процесса, который использует ее, соответственно, используемые адреса являются адресами виртуальной памяти для процесса, а в другом процессе адресное пространство будет иным. Следовательно, чтобы фильтрующая функция могла передать твоему приложению событие перехвата (сообщение), дескриптор твоего окна необходимо создать в разделяемой (shared) секции DLL. Таким образом, экземпляры фильтрующей функции в каждом процессе, подгрузившем эту библиотеку, будут обращаться к одному и тому же физическому адресу памяти за дескриптором окна, которое будет получать перехваченные сообщения. Сейчас я все разжую подробнее с помощью примера. Открываем проект SpyHook из каталога примеров - динамическую библиотеку, в которой реализуется перехват сообщений типа WM_CHAR. //Объявляем разделяемую секцию #pragma data_seg(".Shared") HWND gParentWnd = NULL; //Дескриптор управляющего приложения #pragma data_seg( ) //Создаем разделяемую секцию библиотеки с атрибутами RWS |