Выявление деятельности руткита — это многообещающее новое направление в области обнаружения rootkit. Идея — поймать операционную систему на «лжи».
Если вы найдете API-функции, которые возвращают неверные значения, то вы не только определите факт наличия руткита, но и узнаете, что он пытается скрыть.
Однако для того чтобы определить, что система «врёт», вам требуется получить истинное значение, не полагаясь на значение, возвращаемое проверяемой API-функцией.
Большинство из описанных в этой статье подходов ориентировано на выявление следов захвата и скрытых процессов. На тему обнаружения модификаций файловой системы и скрытых каналов связи написаны целые книги. Выявляя следы захвата, можно обнаружить большинство известных руткитов.
Не существует алгоритмов обнаружения, которые были бы избавлены от недостатков. Искусство обнаружения — это всего лишь искусство. Однако по мере появления новых методов нападения развиваются и методы обнаружения.
Один из недостатков подробного разбора методик создания руткита и его обнаружения заключается в том, что это помогает атакующему. Как только мы раскрываем атакующему методику обнаружения его руткитов, он изменяет свою методику скрытия. Однако то, что та или иная методика вторжения не описана в литературе, еще не делает кого-то более или менее защищенным.
Выявление скрытых файлов и ключей реестра.
Марк Руссинович (Mark Russinovich) и Брюс Когсвелл (Вгусе Cogswell) создали инструмент под названием RootkitRevealer, позволяющий находить скрытые файлы и ключи реестра.
Для того чтобы определить, что есть «истина», Root kitRevealer выполняет синтаксический разбор файлов, составляющих реестр, не обращаясь к API-функциям Win32, таким как RegOpenKeyEx и RegQueryValueEx.
К тому же он работает с файловой системой на очень низком уровне, избегая обычных для этого вызовов API-функций. Затем RootkitRevealer вызывает высокоуровневые API-функции и сравнивает результат с тем, который был получен «вручную», то есть с результатом, в верности которого сомневаться не приходится.
Если результаты не сходятся, определяется факт деятельности руткита (и, соответственно, выясняется, что он прячет). Это методика достаточно простая и очень мощная.
Выявление скрытых процессов.
Часто от скрытых процессов и файлов исходит основная угроза безопасности вашей машины. Скрытый процесс опаснее, поскольку он представляет собой не известный вам код, запущенный непонятно кем на вашей системе. Ниже мы поговорим о способах выявления процессов, которые атакующий пытается спрятать от вас.
Захват функции SwapContext.
Захват функций может быть полезен при обнаружении скрытых процессов. Функция SwapContext из модуля ntoskrnl.exe вызывается для того, чтобы переключить контекст текущего программного потока на контекст другого.
При вызове SwapContext значение, находящееся в регистре EDI, представляет собой указатель на поток, в контекст которого мы хотим переключиться, а значение, находящееся в регистре ESI, — указатель на текущий поток, то есть на поток, из которого мы переключаемся.
Описываемый метод выявления скрытых процессов предполагает замену первых 5 байт функции SwapContext инструкцией безусловного перехода в нашу функцию обхода. Функция обхода должна проверить, что указатель потока, в который происходит переключение (хранящийся в регистре EDI), ссылается на блок EPRОCESS, действительно находящийся в двусвязном списке блоков EPRОCESS.
Имея эту информацию, вы можете найти процесс, спрятанный путем непосредственного манипулирования объектами ядра. Данный подход работает, так как переключение процессов в ядре происходит на основе потоков, а все потоки связаны с их родительским процессом. Впервые эта методика была описана Джеймсом Батлером (James Butler).
Точно так же этот метод можно использовать, чтобы искать процессы, спрятанные путем захвата. Захватив функцию SwapContext, вы получаете реальный список процессов. Вы можете сравнить эти данные с данными, возвращаемыми API-функциями, такими как функция NtQuerySystemlinformation, захват которой мы обсуждали в разделе «Захват таблицы дескрипторов системных служб».
Различные источники списка процессов.
Существуют и другие способы получить список процессов в системе, помимо основанных на вызове ZwQuerySystemIinformation. Непосредственное манипулирование объектами ядра или трюки с захватом могут легко ввести эту API-функцию в заблуждение.
Однако простая альтернатива, например, перечисление портов с помощью утилиты netstat.exe, может выявить скрытый процесс, так как тот имеет открытый порт.
Процесс CSRSS.EXE — еще один источник поиска практически любых процессов в системе. Он имеет описатели всех процессов, за исключением четырех:
? процесс бездействия;
? системный процесс;
? процесс SMSS.EXE;
? процесс CSRSS.EXE.
Перебирая описатели в модуле CSRSS.EXE и сопоставляя их процессам, вы получаете информацию для сравнения со списком, возвращаемым API-функциями.
В блоке EPROCESS каждого процесса существует указатель на его структуру HANDLETABLE. Структура HANDLE TABLE наряду с прочей информацией содержит указатель на действительную таблицу описателей. Подробную информацию о том, как работать с таблицей описателей, можно найти в дополнительной литературе.
Есть еще один способ получения списка процессов без вызовов потенциально модифицированных API-функций. Из предыдущего обсуждения вы знаете, что блок EPRОCESS каждого процесса содержит указатель на таблицу описателей. Оказывается, что все такие структуры таблиц описателей связаны при помощи структуры LISTENTRY точно так же, как связаны процессы.
Если найти таблицу описателей любого процесса и пройтись по списку процессов, можно идентифицировать все процессы в системе. Именно эта техника используется антивирусной программой BlackLight производства компании F-Secure.
Для того чтобы перебрать все элементы списка таблиц описателей, вам требуется знать смещение структуры LISTENTRY внутри структуры HANDLETABLE (помимо этого вам, естественно, необходимо знать смещение указателя на структуру HANDLETABLE в блоке EPRОCESS).
Структура HANDLETABLE содержит еще и идентификатор процесса (PID), которому принадлежит данная таблица описателей. Положение этого идентификатора в памяти тоже зависит от версии Windows.
Когда вы перебираете процессы, используя значения LISTENTRY, вы можете найти PID владельца. Таким образом, вы получаете еще один набор данных для сравнения с результатами, возвращаемыми API-функциями Win32.
Следующая функция позволяет получить перечень всех процессов в системе путем перебора связанного списка таблиц описателей:
Это всего лишь еще один способ идентифицировать скрытый процесс, хотя и очень эффективный. Если руткит не модифицирует этот список в ядре, что может быть делом достаточно сложным, ваш способ поиска позволит найти все скрытые руткитом процессы. Существуют другие похожие структуры в ядре, которые могут использоваться с тем же результатом.