Перехват (программирование)

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

Перехват (англ. hooking) — технология, позволяющая изменить стандартное поведение тех или иных компонентов информационной системы.

Назначение технологии перехвата[править | править исходный текст]

Очень часто в системном программировании возникает задача изменения стандартного поведения системных функций. Например довольно интересным применением данной технологии является переопределение оконной процедуры у GUI приложений Windows (сабклассинг). Это нужно, если программист хочет организовать собственную обработку какого-либо оконного сообщения и только потом передать стандартной оконной процедуре. После сабклассинга цикл обработки сообщений будет выглядеть так:

  • ДО САБКЛАССИНГА:

Сообщение Windows->Окно (оконная процедура)

  • ПОСЛЕ:

Сообщение Windows->Наша оконная процедура->Окно (оконная процедура)

Например, в Уроках Iczelion’а[1] описан пример того, как сабклассинг может использоваться для организации контроля ввода в элементы управления. Технологии перехвата нужны не только в этом случае, но и, например, для предварительной обработки результатов системных функций поиска файлов FindFirst и FindNext, EnumProcess, которая перечисляет процессы в Windows и т. д. Причем в этих целях такие технологии применяют как антивирусные средства[2], так и различного рода вирусы, руткиты и прочие виды вредоносного программного обеспечения.

Очень часто перехват бывает важен для организации отладки программ и является одной из основных технологий, применяемых в отладчиках. В данном случае эта технология позволяет одной программе контролировать выполнение другой. Для этих целей предусмотрен системный вызов ptrace, который позволяет подключаться к процессам, отслеживать значения регистров у контекста отлаживаемого процесса и в том числе контролировать другие системные вызовы. Он является основой для реализации такой возможности отладчиков как точки останова. Данный системный вызов хорошо документирован и присутствует во всех главных *Nix системах: Linux, FreeBSD, Solaris.[3] Чаще всего используется совместно с системным вызовом fork, который и вызывает ptrace, указывая в параметрах вызова, что запускаемый процесс — дочерний. Microsoft Windows также предоставляет для схожих целей т. н. DebugAPI[4].

Виды перехвата системных функций[править | править исходный текст]

Основными методами перехвата являются:

  • Подмена адреса настоящей функции (модификация IAT таблиц, модификация SSDT/IDT таблиц)
  • Непосредственное изменение функции (сплайсинг, перехват в режиме ядра с модификацией тела функции)
  • Непосредственная подмена всего компонента приложения/системы (например библиотеки с целевой функцией)

Методы можно также разделить по критерию режима выполнения:

  • Пользовательские (ring3) методы: модификация IAT таблиц, сплайсинг. Их особенность в том, что невозможно что-либо изменить в поведении ядра операционной системы и его расширений.
  • Режима ядра: модификация SSDT/IDT таблиц, перехват в режиме ядра с модификацией тела функции. Позволяет модифицировать структуры данных и код любой части операционной системы и приложений.

Сплайсинг[править | править исходный текст]

Сплайсинг (от англ. splice — "сращивать или склеивать концы чего-либо") — метод перехвата API функций путем изменения кода целевой функции. Обычно изменяются первые 5 байт функции. Вместо них вставляется переход на функцию, которую определяет программист. Чтобы обеспечить корректность выполнения операции, приложение, которое перехватывает функцию, обязано дать возможность выполниться коду, который был изменен в результате сплайсинга. Для этого приложение сохраняет заменяемый участок памяти у себя, а после отработки функции перехвата восстанавливает измененный участок функции и дает полностью выполниться настоящей функции.[5]

Особенности технологии[править | править исходный текст]

Для того чтобы программа могла использовать данную технологию, она должна иметь встроенный дизассемблерный движок и специальный дизассемблер длин, который позволит находить нужную функцию и корректно её изменять. Эта технология крайне платформенно-зависима, а потому требует тщательного контроля и проверки системы на соответствие версий, а также проверки самой функции на соответствие целевой. Системные функции могут меняться при выходе патчей и обновлений Windows (особенно Service Pack для Windows), а также в результате модификаций со стороны других приложений. Ошибки при работе с данной технологией могут приводить к BSOD. В то же время эта технология позволяет осуществлять глобальный перехват API функций, влияя таким образом на все процессы в системе. Начиная с Windows XP SP2 для поддержки "горячего патча" Microsoft изменила стандартный пролог функций с трех байт до пяти (добавила mov edi, edi в стандартный пролог push ebp; mov ebp, esp), что позволяет не проводить анализ длин. Длины в пять байт хватает для замены пролога на опкоды дальнего перехода, а известный пролог позволяет корректно передать управление подменяемой функции.

Сферы применения сплайсинга и методы обнаружения[править | править исходный текст]

Он применяется:

  • В ПО, которому необходимо осуществлять функции мониторинга системы
  • Механизмом хуков в Windows
  • Различного рода вредоносными программами. Это основная технология сокрытия для руткитов пользовательского уровня

Основной метод обнаружения факта сплайсинга — это сравнение машинного кода функции, проверяемой на сплайсинг, и кода системной функции, полученного в заведомо чистой системе. Также в обнаружении сплайсинга функции может помочь контроль адресов перехода.

Сравнение с другими технологиями[править | править исходный текст]

  • Изменение IAT таблиц процесса[6]. Данная технология не позволяет изменить поведение самой системной функции, а лишь дает возможность «обмануть» выбранное приложение, заставив его использовать вашу функцию. IAT таблица — таблица адресов функций, импортируемых процессом. Технология носит лишь локальный характер, хотя может быть применена сразу к группе приложений. Может быть довольно быстро обнаружена из-за необходимости загрузки DLL[7] в адресное пространство целевого процесса. Сплайсинг же не требует DLL и внедрения в чужой процесс, обладает возможностью глобального захвата функции. У сплайсинга есть ещё одно преимущество: не все системные функции импортируются процессом через IAT. Например, функция может быть загружена вызовом GetProcAddress. Использование же непосредственной модификации кода функции снимает подобное ограничение.
  • Перехват в режиме ядра. Позволяет перехватывать любые функции, в том числе и экспортируемые ядром. Наиболее труден для обнаружения в случае успеха, так как позволяет фальсифицировать любые данные, предоставляемые операционной системой. Требует написания специального компонента для взаимодействия с ядром драйвера. Может привести к BSOD при неправильном программировании в режиме ядра. Может быть обнаружен на фазе загрузки драйвера в ядро или при проверке активных драйверов, а также при проверке ядра на изменения[8]. Более трудный в программировании метод, чем сплайсинг, но более гибкий, так как позволяет перехватить функции самого ядра, а не только WinAPI функции, которые служат лишь посредником между ядром и программой, которая что-либо запрашивает у операционной системы.
  • Замена самой библиотеки с функцией. Весьма радикальное решение проблемы, обладающее рядом существенных недостатков:
  1. Требует замены файла на диске, что может быть запрещено и пресечено самой системой. Например, замену системных файлов Windows не позволит выполнить защита файлов Windows (WFP), хотя её можно и отключить. Такое действие может быть также обнаружено при статическом анализе системы ревизорами.
  2. Требуется полная эмуляция всех возможностей заменяемой DLL или иного компонента, что весьма трудоемко даже в случае открытости и осложняется необходимостью дизассемблирования в случае закрытости целевой программы.

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

Перехват в режиме ядра[править | править исходный текст]

Он основан на модификации структур данных ядра и функций. Главными мишенями воздействия являются таблицы

  • IDT Таблица диспетчеризации прерываний. Довольно важным для перехвата является прерывание, обрабатывающее обращение к таблице служб SSDT (0x2E)[9].
  • SSDT (System Service Dispatch Table) Таблица диспетчеризации системных сервисов. Обращаясь к ней, система по номеру запрещенного сервиса может получить адрес соответствующего сервиса ядра и вызвать его. А таблица SSPT содержит общий размер параметров, передаваемых системному сервису.
  • psActiveprocess Структура ядра, хранящая список процессов в системе.
  • IRP Таблица драйвера, которая хранит указатели на функции обработки IRP-пакетов.
  • EPROCESS Структура ядра, хранящая большое количество информации о процессе, включая, например, PID (идентификатор процесса).

Такого рода руткиты называются DKOM-руткитами, то есть руткитами, основанными на непосредственной модификации объектов ядра. В руткитах для систем Windows Server 2003 и XP эта технология была модернизирована, так как в этих ОС появилась защита от записи некоторых областей памяти ядра[9]. Windows Vista и 7 получили дополнительную защиту ядра PatchGuard, однако все эти технологии были преодолены руткитописателями[10]. В то же время перехват системных функций в режиме ядра — основа проактивных систем защиты и гипервизоров.

Иные формы перехвата[править | править исходный текст]

Можно выделить и другие формы перехвата:

  • Перехват сетевых соединений и пакетов.[11]
  • Перехват паролей. Например, при помощи шпионажа за клавиатурным вводом при помощи кейлоггера.
  • Перехват обращений браузера к сайтам при помощи HTTP Proxy или расширений браузера. Позволяет проанализировать и/или подменить данные, которыми обмениваются браузер и сервер.

Здесь описана лишь часть применений данной технологии.

Примеры программ, использующих перехват[править | править исходный текст]

Примеры кода[править | править исходный текст]

См. также[править | править исходный текст]

Примечания[править | править исходный текст]

  1. Уроки Iczelion’а. Win32 API. Урок 20. Сабклассинг окна
  2. К примеру: невозможно получить доступ к процессу Kaspersky Internet Security штатными средствами Windows API, так как соответствующие функции перехвачены антивирусом.
  3. Страница из man Linux Ubuntu: man страница о вызове ptrace и русскоязычная версия: Русский перевод на OpenNET
  4. Официальное описание: The Debugging Application Programming Interface, а также примеры использования: Win32 API. Урок 28. Win32 Debug API I
  5. Цикл статей по перехвату WindowsAPI функций от Ms Rem
  6. Методы доступа и модификации IAT таблицы довольно подробно описаны у Хоглунд Г., Батлер Дж. — Руткиты: внедрение в ядро Windows. Гл 4 Древнее искусство захвата
  7. Методы внедрения DLL в чужой процесс описаны довольно подробно у Дж. Рихтера Кристофера Назара Windows via C/C++. Программирование на языке Visual C++. Некоторые методы внедрения впервые документировал сам Дж. Рихтер
  8. Например, один из первых руткит-детектеров KLISTNER
  9. 1 2 Г. Хоглунд Дж. Батлер Руткиты внедрение в ядро Windows. Глава 4 Древнее искусство захвата
  10. убийство часового КРИС КАСПЕРСКИ, АКА МЫЩЪХ Спецвыпуск: Хакер, номер #072, стр. 072-072-5
  11. Например, этим занимаются сниферы. Одной из бесплатных реализаций захвата сетевых пакетов является сетевой драйвер уровня NDIS WinPCAP

Литература[править | править исходный текст]

Ссылки[править | править исходный текст]