- Предисловие
- Тестовая нагрузка?
- Загрузка
- Функции обратного вызова
- А как же Patch Guard?
- Статистика
- Заключение
Предисловие
Количество буткитов неуклонно растет. Новые буткиты появляются разные — сложные и простые, служащие разным целям (это могут быть и руткиты, и троянцы-вымогатели). Не брезгуют вирусописатели и анализом вредоносного кода конкурентов.
Сегодня мало кого из экспертов можно удивить очередным буткитом — тема инфицирования загрузочной записи исследована довольно глубоко, и в интернете достаточно информации на этот счет. Однако на этот раз нам попался довольно интересный экземпляр: файловый инфектор Xpaj, дополненный функционалом буткита, работающего как под Windows x86, так и под Windows x64. Интересен он прежде всего тем, что под Windows x64 при работающем механизме защиты Patch Guard успешно функционирует с установленным сплайсингом в ядре, защищая инфицированную загрузочную запись от чтения и модификации.
В данной статье я рассмотрю работу руткита только под Windows 7 x64, работу руткита под Windows x86 рассматривать не имеет смысла, т.к. алгоритм работы руткита в обеих ОС примерно одинаковый.
Тестовая нагрузка?
По результатам анализа той же модификации Xpaj наших коллег из компании Symantec, можно сказать следующее:
- файловый инфектор Xpaj не заражает 64-битные исполняемые модули, в том числе и драйверы режима ядра, т.е. вирус заражает лишь 32-битные исполняемые файлы (.exe и .dll);
- зараженные файлы не содержат механизма саморепликации;
- код, внедряемый из режима ядра в 64-битное приложение, всего лишь выводит отладочное сообщение и не содержит ничего более.
На основании вышеперечисленных фактов и статистики заражений (см. ниже) можно предположить, что данный экземпляр вируса — всего лишь тестовая версия. Возможно, следующая модификация вредоносной программы будет полноценной, и, кто знает, может быть авторами будет реализован механизм заражения 64-битных исполняемых файлов, в том числе и драйверов режима ядра (с отключением механизма проверки подписей, конечно же).
Загрузка
Как обычно, все начинается с инфицированного MBR. Основной задачей зараженной загрузочной записи, как практически во всех предыдущих случаях, является считывание дополнительных секторов и передача на них управления.
В дополнительных секторах в конце диска содержатся модули, которые буткит подгружает по мере надобности. Все модули, кроме первого, сжаты APLib.
Алгоритм работы первого модуля такой:
- cчитать оригинальный MBR до заражения и записать его в память на место инфицированного;
- перехватить 13h прерывание, отвечающее за чтение и запись секторов диска;
- передать управление оригинальной загрузочной записи.
В результате передачи управления оригинальной MBR произойдет дальнейшая инициализация операционной системы. Во время инициализации ОС будет происходить считывание файла ядра с диска и необходимых компонентов. В перехватчике прерывания буткит ожидает чтения файла ядра, подсчитывая контрольную сумму от начала файла и проверяя некоторые поля заголовка.
Для продолжения инициализации буткита был выбран метод, похожий на тот, который использовался в TDL-4, только жертвой на этот раз стал файл ядра, а не KDCOM.DLL. При обнаружении считывания файла ядра буткит сохраняет первые 0x120 байт от начала файла и перезаписывает заголовок своим кодом.
Рисунок 1. Модифицированный заголовок файла ядра
Далее буткит находит экспортируемую функцию MmMapIoSpace и перехватывает ее методом сплайсинга. Перехватчик ведет в код, расположенный в заголовке файла ядра.
Рисунок 2. Перехват функции MmMapIoSpace
Прототип функции выглядит следующим образом:
IN PHYSICAL_ADDRESS PhysicalAddress,
IN SIZE_T NumberOfBytes,
IN MEMORY_CACHING_TYPE CacheType
);
Данная функция позволяет отобразить физический адрес на виртуальную память. Не забывайте, что первый модуль буткита все еще находится в физической памяти на момент первого вызова этой функции.
Дальнейшая инициализация буткита происходит после вызова перехваченной функции.
Рисунок 3. Стек вызовов MmMapIoSpace
При первом вызове код, расположенный в заголовке файла ядра, восстанавливает украденные байты функции MmMapIoSpace и вызывает оригинальную функцию, которая отображает физический адрес первого модуля буткита (см. рисунок 1 и рисунок 5) на виртуальную память. И передает управление отображенному коду.
Рисунок 4. Заголовок файла ядра
Рисунок 5. Вызов оригинальной MmMapIoSpace и содержание физической памяти
Инициализация буткита продолжается передачей управления на отображенную физическую память.
Рисунок 6. Отображенный код
Дальнейший алгоритм работы выглядит следующим образом:
- восстановить украденные 0x120 байт начала файла ядра;
- перехватить прерывание INT 0x01 (KiDebugTrapOrFault) для каждого процессора;
- найти экспортируемую функцию ZwLoadDriver по хешу;
- перехватить ZwLoadDriver методом сплайсинга;
- найти экспортируемую функцию NtReadFile по хешу;
- перехватить NtReadFile методом сплайсинга;
- найти экспортируемую функцию NtWriteFile по хешу;
- перехватить NtWriteFile методом сплайсинга;
- снять перехват прерывания INT 0x01 (KiDebugTrapOrFault) для каждого процессора;
- вызвать MmMapIoSpace с оригинальными параметрами, т.е. передать управление ядру для дальнейшей инициализации ОС.
Рисунок 7. Перехват KiDebugTrapOrFault
Рисунок 8. Первая стадия перехватов ZwLoadDriver, NtReadFile и NtWriteFile
Дальнейшая инициализация буткита ложится на перехватчик функции ZwLoadDriver, так как на первой стадии работы перехваты NtReadFile/NtWriteFile — это обычные заглушки, которые передают управление оригинальным функциям и не выполняют никакой другой работы.
Рисунок 9. Заглушка функции NtReadFile
Очевидно, что тут специально подготовлено место, куда позже будет записан рабочий код для перехватов NtReadFile/NtWriteFile.
При первом вызове функции ZwLoadDriver произойдет дальнейшая инициализация буткита.
Алгоритм работы перехватчика ZwLoadDriver следующий:
- открыть ссылку «\??\physicaldrive0»;
- считать секторы третьего модуля с диска;
- распаковать APLib;
- передать управление на точку входа третьего модуля;
- вызвать оригинальную ZwLoadDriver.
На этом работа первого модуля заканчивается, и управление передается третьему модулю, который завершает инициализацию буткита в системе.
Рисунок 10. Основная работа третьего модуля
Третий модуль выполняет следующие действия:
- загружает различные настройки;
- устанавливает функцию обратного вызова на создание процесса;
- устанавливает функцию обратного вызова на загрузку модуля в память;
- заменяет заглушки перехватчиков NtReadFile/NtWriteFile полноценными версиями.
Рисунок 11. Полноценный перехват NtReadFile
Сравните перехватчик функции NtReadFile на рисунке 11 с перехватчиком на рисунке 9.
Совершенно очевидно, что перехваты NtReadFile/NtWriteFile нужны для того, чтобы защищать критичные места буткита от чтения и модификации.
Функции обратного вызова
Во время инициализации буткит устанавливает две функции обратного вызова.
Первая функция завершает процессы антивирусных продуктов. При вызове функции во время создания любого процесса в системе, буткит подсчитывает контрольную сумму от имени процесса и сравнивает ее со своим внутренним списком контрольных сумм.
Рисунок 12. Контрольные суммы имен процессов
При совпадении контрольной суммы имени процесса с контрольной суммой из списка буткита в точку входа процесса буткит вставляет инструкцию RET и процесс завершается.
Рисунок 13. Функция завершения процесса
Вторая функция обратного вызова устанавливается буткитом на загрузку модуля. Она используется для того, чтобы внедрить код в различные процессы, в том числе и в популярные браузеры. Аналогично функции завершения процесса в данной функции используется алгоритм подсчета контрольной суммы от имени процесса и ее сравнение с внутренним списком контрольных сумм.
Рисунок 14. Функция внедрения кода
А как же Patch Guard?
Я уже упоминал про защитный механизм, встроенный в ядро 64-битной операционной системы Windows. Цель Patch Guard — предотвращение изменения ядра ОС и ее критичных структур, таких как различные сервисные таблицы (SSDT, IDT, GDT), объекты ядра и так далее. Механизм защиты активируется на ранней стадии инициализации ядра и через некоторые промежутки времени проверяет вышеуказанные структуры на наличие модификаций. В случае обнаружения модификаций происходит намеренный крах системы. В первую очередь данный механизм был придуман для того, чтобы защититься от руткитов режима ядра. Но есть и обратная сторона медали — многие антивирусные и защитные продукты использовали перехваты в ядре для различных нужд, в том числе и для модуля проактивной защиты.
Споры антивирусных компаний и компании Microsoft по этому поводу не утихают по сей день. Есть те, кто считает, что в ядре не должно быть недокументированных перехватов антивирусными компаниями, и противодействовать попаданию в ядро вредоносного кода нужно другими методами. Есть те, кто считает, что компания Microsoft не обеспечивает должного уровня защиты, и перехваты нужны для усиления безопасности операционной системы. Есть и те, кто считает, что в случае попадания вредоносного кода в ядро системе доверять нельзя, и излечивать такие системы бесполезно. Все по-своему правы, и я не хочу на этом заострять внимание.
Любая защита может быть взломана или обойдена тем или иным способом. Не избежал этой участи и Patch Guard. Данный механизм был довольно хорошо исследован как сторонними исследователями, так и злоумышленниками, в результате было придумано несколько способов его обхода. Например, TDL-4 использует концептуальный метод, который заключается в том, что место перехвата этого руткита просто не проверяется защитным механизмом. Есть также известные механизмы, основанные на модификации загрузчика и файла ядра операционной системы, призванные отключить инициализацию Patch Guard. Есть и способ, основанный на модификации уже инициализированного ядра, отключающий запуск проверочного механизма. Также Patch Guard не инициализируется в случае подключения ядерного отладчика в момент загрузки ОС (это сделано для того, чтобы разработчики могли использовать точки останова для отладки и тестирования своих драйверов).
Xpaj интересен именно тем, что в нем используется еще один концептуальный способ обхода Patch Guard. Дело в том, что инициализация Patch Guard происходит не на самом раннем этапе загрузки операционной системы. Так как Xpaj — буткит, то он может контролировать любой этап загрузки ОС и модифицировать ядро еще до начала инициализации защитного механизма. В момент инициализации ядро уже содержит все модификации и перехваты Xpaj, и вместо того, чтобы обнаруживать эти изменения, Patch Guard начинает их защищать!
Я провел небольшой эксперимент, чтобы убедиться в том, что Patch Guard действительно защищает перехваты ZwLoadDriver/NtReadFile/NtWriteFile. Я стартовал зараженную систему в режиме отладки, дождался ее загрузки, подключил ядерный отладчик и восстановил модифицированные байты одной из перехваченных функций. Через некоторое время произошел крах системы. То есть Patch Guard обнаружил изменение ядра в памяти и вызвал BSOD.
Как говорится — без комментариев!
Статистика
С помощью нашего облачного сервиса KSN я собрал статистику по обнаруженным инфицированным Xpaj загрузочным записям и по количеству задетектированых инсталляторов этой вредоносной программы. Из всей статистики интересна, прежде всего, география распространения буткита и, конечно же, версии зараженных операционных систем.
Рисунок 16. География инсталляторов
Рисунок 17. География инфицированного MBR
Рисунок 18. Статистика по инфицированным ОС
Заключение
В 2008 году мы зафиксировали возрождение старой технологии — инфицирование MBR. С тех пор прошло довольно много времени. Сегодня буткиты — это современный тренд «руткитостроения», и в ближайшее время этот механизм останется в арсенале злоумышленников.
Заражение загрузочной записи — это очень удобный способ инициализации вредоносного кода как можно раньше, плюс ко всему — это громадные возможности для контроля загрузки ОС.
Операционные системы семейства Windows x64 прочно вошли в жизнь пользователей и, конечно же, вирусописатели стараются сделать свои творения универсальными, чтобы поддерживать количество заражений на высоком уровне.
Для противостояния руткитам компания Microsoft ввела ряд ограничений и новых технологий для Windows x64, однако, как показала практика, ни требование валидных подписей у драйверов режима ядра, ни наличие механизма Patch Guard ситуацию в целом не исправили. Руткиты под 64-битные операционные системы были, есть и будут, и количество их продолжит расти.
XPAJ. Исследование буткита под Windows x64