Rootkit (руткит, от англ. root kit, то есть «набор root'а») — программа или набор программ для скрытия следов присутствия злоумышленника или вредоносной программы в системе.
Термин Rootkit исторически пришёл из мира UNIX, и под этим термином понимается набор утилит или специальный модуль ядра, которые взломщик устанавливает на взломанной им компьютерной системе сразу после получения прав суперпользователя. Этот набор, как правило, включает в себя разнообразные утилиты для «заметания следов» вторжения в систему, снифферы, сканеры, кейлоггеры, троянские программы, замещающие основные утилиты UNIX (в случае неядерного руткита). Rootkit позволяет взломщику закрепиться во взломанной системе и скрыть следы своей деятельности путём сокрытия файлов, процессов, а также самого присутствия руткита в системе.
Говоря о руткитах, непременно упоминают этимологию термина rootkit: “root” – привилегированный администратор UNIX-системы, “kit” – набор инструментов, rootkit – набор утилит для обеспечения «привилегированного» доступа злоумышленника к системе незаметно для настоящего администратора. Такие утилиты для UNIX появились в начале 90-х гг. и существуют до сих пор, но практически не развиваются.
У Windows-руткитов был более близкий по функционалу предшественник, чем UNIX-руткиты – а именно, стелс-вирусы для DOS. Стелс-вирусы появились около 1990 года. В отличие от UNIX-руткитов, основная задача которых – впустить злоумышленника в систему и маскировать его действия, стелс-вирусы DOS, заражая файлы, просто скрывали себя от пользователя и антивирусных программ.
Windows-руткиты появились десятью годами позже стелс-вирусов, и то, что их назвали именно руткитами, а не стелс-вирусами, заслуга исключительно Грега Хогланда (Greg Hoglund). Он был одним из первых, кто реализовал технику обхода системных механизмов защиты Windows в форме утилиты, нацеленной на сокрытие информации в системе. Результаты его работы были опубликованы в электронном журнале PHRACK. Утилита, названная автором NT Rootkit, впоследствии была применена во многих вредоносных программах и по сей день вдохновляет исследователей и руткитостроителей.
Статья Хогланда датирована 1999 годом. В ней он опирается на исследования ядра Windows, опубликованные годом раньше в форумах Usenet программистом из Шри-Ланки. Еще раньше, начиная с 1995 года, Джефри Рихтер (Jeffrey Richter) в своей книге «Advanced Windows» и четвертом ее издании «Programming Applications for Microsoft Windows» раскрывает технологии перехвата системных вызовов на уровне пользователя, которые будут впоследствии использованы во многих руткитах с точностью до приведенного в книге исходного кода.
Техники перехвата системных вызовов на уровне ядра общедоступно раскрыты в двух других классических книгах по программированию: С. Шрайбер «Недокументированные возможности Windows 2000», 2001 г. (Sven Schreiber Undocumented Windows 2000 secrets) и П. Дабак и др. «Недокументированные возможности Windows NT», 1999 г. (P. Dabak et al Undocumented Windows NT). Исследования системных механизмов защиты Windows продолжились, и вслед за NT Rootkit было выпущено еще несколько утилит, позволяющих скрывать объекты в операционной системе.
В 2000 году появился he4hook - проект русского программиста. Утилита не несла в себе вредоносного функционала, но являлась инструментом для сокрытия файлов и работала в режиме ядра. Помимо этого, утилита самим автором не обозначалась как руткит.
В 2002 году на свет появился Hacker Defender (HacDef). Это также лишь инструмент, но уже более мощный – при помощи него можно скрыть любой файл, процесс или ключ реестра, параметры гибко настраиваются в файле конфигурации. Работает преимущественно в режиме пользователя.
В 2003 году появились Vanquish и Haxdoor (он же A-311 Death и в модифицированном варианте Nuclear Grabber). Vanquish - инструмент, работающий в режиме пользователя и позволяющий скрывать файлы, директории, а также ключи реестра. Кроме того, в нем уже предусмотрена вредоносная функция – логгирование паролей. Haxdoor - это уже полноценный бэкдор, работающий в режиме ядра и использующий руткит-технологии для самомаскировки.
В 2004 году выпущена FU – утилита для скрытия процессов, которая реализовала принципиально новую технологию, основанную на изменении самих системных структур, а не путей доступа к ним.
Все перечисленные руткиты являются ключевыми в истории Windows-руткитов. Особенно стоит отметить HacDef, Haxdoor и FU, широко распространявшихся "в диком виде" в связке с вредоносными программами. Руткиты этого периода (2000-2004) четко вписываются в общепринятую, но устаревшую классификацию: руткит может функционировать на уровне пользователя (user level) или на уровне ядра (kernel level), на основе модификации цепочки системных вызовов (Execution Path Modification) или на основе прямого изменения системных данных (Direct Kernel Objects Manipulation). В середине 2000-х порядка 80% всех руткитов приходилось на HacDef и Haxdoor. Первыми среди уже существовавших вредоносных программ, куда начали встраиваться руткит-технологии, были многофункциональные бэкдоры Rbot и SdBot.
Немного позже – около 2006 г. – руткит-технологии начали встраивать в популярные e-mail-черви (Bagle) и троянцы-шпионы (Goldun), еще позже появился Mailbot (Rustock), оказавшийся серьезным вызовом для антивирусных продуктов.
После длительного затишья в начале 2008 года появилась новая вредоносная программа, заражающая загрузочный сектор диска. В антивирусных базах разных производителей она именуется Sinowal, Mebroot, StealthMBR. Этот руткит, больше известный как «буткит» в силу своей «загрузочной» специфики, основан на коде концептуальной разработки eEye Bootroot (немного измененном) и представляет собой не столько самостоятельную вредоносную программу, сколько инструмент для сокрытия любого троянца.
По уровню привилегий
Уровня пользователя (user-mode)
Уровня ядра (kernel-mode)
По принципу действия
изменяющие алгоритмы выполнения системных функций (Modify execution path)
изменяющие системные структуры данных (Direct kernel object manupulation)
Рис. 1. Классификация руткитов
4 Методы перехвата API функций в режиме пользователя (user mode)
Описания методик перехвата функций снабжены схемами их работы, при этом красная пунктирная стрелка показывает вмешательство RootKit в процесс работы программы, красные стрелки показывают отклонения в логике работы, вызванные вмешательством RootKit.
Перехват функций позволяет RootKit модифицировать результаты их работы – например, перехват функции поиска файла на диске позволяет исключить из результатов поиска маскируемые файлы, а перехват функций типа ntdll.ZwQuerySystemInformation позволяет замаскировать запущенные процессы и загруженные библиотеки.
4.1 Принцип вызова API функции
Перед рассмотрением принципов работы RootKit пользовательского режима необходимо кратко и упрощенно рассмотреть принцип вызова функций, размещенных в DLL.
Известно два базовых способа:
1.Раннее связывание (статически импортируемые функции).
Этот метод основан на том, компилятору известен перечень импортируемых программой функций. Опираясь на эту информацию, компилятор формирует так называемую таблицу импорта EXE файла. Таблица импорта – это особая структура (ее местоположение и размер описываются в заголовке EXE файла), которая содержит список используемых программой библиотек и список импортируемых из каждой библиотеки функций. Для каждой функции в таблице имеется поле для хранения адреса, но на стадии компиляции адрес не известен. В процессе загрузки EXE файла система анализирует его таблицу импорта, загружает все перечисленные в ней DLL и производит занесение в таблицу импорта реальных адресов функций этих DLL. У раннего связывания есть существенный плюс – на момент запуска программы все необходимые DLL оказываются загруженными, таблица импорта заполнена – и все это делается системой, без участия программы. Но отсутствие в процессе загрузки указанной в его таблице импорта DLL (или отсутствие в DLL требуемой функции) приведет к ошибке загрузки программы. Кроме того, очень часто нет необходимости загружать все используемые программой DLL в момент запуска программы. На рисунке показан процесс раннего связывания – в момент загрузки происходит заполнение адресов в таблице импорта (шаг 1), в момент вызова функции из таблицы импорта берется адрес функции (шаг 2) и происходит собственно вызов функции (шаг 3);
Рис.2 Раннее связывание
2.Позднее связывание.
Отличается от раннего связывания тем, что загрузка DLL производится динамически при помощи функции API LoadLibrary. Эта функция находится в kernel32.dll, поэтому если не прибегать к хакерским приемам, то kernel32.dll придется загружать статически. При помощи LoadLibrary программа может загрузить интересующую ее библиотеку в любой момент времени. Соответственно для получения адреса функции применяется функция kernel32.dll GetProcAddress. На рисунке шаг 4 соответствует загрузке библиотеки при помощи LoadLibrary и определению адресов при помощи GetProcAddress. Далее можно вызывать функции DLL (шаг 5), но естественно при этом таблица импорта не нужна. Чтобы не вызывать GetProcAddress перед каждым вызова функции из DLL программист может однократно определить адреса интересующих его функций и сохранить их в массиве или некоторых переменных.
Независимо от метода связывания системе необходимо знать, какие функции экспортирует DLL. Для этого у каждой DLL имеется таблица экспорта – таблица, в которой перечислены экспортируемые DLL функции, их номера (ординалы) и относительные адреса функций (RVA).
4.2 Модификация машинного кода прикладной программы.
В этом случае модифицируется машинный код, отвечающий в прикладной программе за вызов той или иной функции API. Это методика сложна в реализации, т.к. существует множество языков программирования, версий компиляторов и программист может реализовать вызов API функций различными методиками. Но теоретически подобное возможно при условии, что внедрение будет идти в заранее заданную программу известной версии. В этом случае можно проанализировать ее машинный код и разработать перехватчик.