Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #70, СЕНТЯБРЬ 2006 г.

Умри, но сейчас

КРИС КАСПЕРСКИ АКА МЫЩЪХ

Спецвыпуск: Хакер, номер #070, стр. 070-076-5


Чтобы хоть как-то замаскировать торчащий из норы хвост, малварь должна поместить свое тело в DLL, закинуть его в системный каталог Windows (или куда-нибудь в другой место) и загрузить внутрь атакуемого процесса через LoadLibrary. Естественно, делать это следует из контекста атакуемого процесса, поскольку ни сама LoadLibrary, ни ее расширенная версия LoadLibraryEx не принимают обработчик процесса в качестве одного из своих аргументов. То есть, прежде чем загружать DLL, в процесс необходимо как-то внедриться. Проще всего это сделать через уже упомянутую VirtualAllocEx. Выделить блок в атакуемом процессе, скопировать туда код загрузчика и вызвать CreateRemoteThread, либо скорректировать контекст активного потока, передав загрузчику управление путем вызова функции GetThreadContext и коррекции регистра EIP.

Получив управление, загрузчик должен вызвать LoadLibrary для загрузки своей DLL, вызвать CreateThread, указав в качестве стартового адреса одну из функции динамической библиотеки, после чего «замести следы» — освободить блок памяти, выделенный VirtualAllocEx, завершить поток, порожденный CreateRemoteThread (или вернуть EIP на место). Поскольку после освобождения региона памяти исполнение оставшегося в нем кода становится невозможным, мы не сможем вызвать TerminateThread, не схлопотав исключение, если только... не воспользоваться приемом из кода, удаляющего текущий процесс (смотри листинги). На этот раз он не использует никаких недокументированных возможностей и полностью законен, сохраняя работоспособность даже на машинах с включенным механизмом DEP, препятствующим выполнению кода в стеке. Однако никакого кода в стеке у нас нет! Одни лишь адреса возврата вместе с аргументами вызываемых функций. Правда, на 64-битных версиях Windows это уже не сработает, поскольку там API-функции принимают аргументы через регистры и стек отдыхает (разумеется, сказанное относится только к 64-битным приложениям, старые 32-битные приложения будут работать, как обычно).

Кстати, о DEP. Выделяя блок памяти с помощью VirtualAllocEx, присвой ему атрибуты PAGE_READWRITE, а перед передачей управления смени на PAGE_EXECUTE через VirtualProtectEx. На машинах без DEP атрибуты PAGE_READ и PAGE_EXECUTE взаимно эквивалентны, поскольку процессоры старого поколения поддерживали только два атрибута страниц: ACCESS (страница доступна для чтения/исполнения или недоступна) и write (страница доступна/недоступна для записи). Атрибут EXECUTE был прерогативой таблиц селекторов, то есть сегментов. Во времена разработки 80386 никому и в голову не могло прийти, что массовая операционная система сведет все три сегмента (кода, стека и данных) в линейную память общего адресного пространства. Фактически, атрибут PAGE_EXECUTE был высосан разработчиками win32 из пальца и не соответствовал реальному положению вещей, но сейчас все изменилось. И хотя по умолчанию DEP включен только для системных процессов (да и то не для всех), привыкать к атрибуту PAGE_EXECUTE следует уже сейчас. А почему мы не установили сразу все три атрибута на страницу PAGE_EXECUTE_READWRITE? Ведь VirtualProtectEx это позволяет, да и процессор не против. Сейчас — да, никто не против и не возражает, но в Microsoft уже вынашивает планы по совершенствованию защиты своей оси, и попытка присвоения всех трех атрибутов будет либо вызывать исключение, либо требовать специальных привилегий.

Назад на стр. 070-076-4  Содержание  Вперед на стр. 070-076-6