Шесть грехов malware-писателей

       

Грех5 — недокументированные возможности


Использование недокументированных возможностей оправдано тогда и _только_ тогда, когда без них обойтись _невозможно_ или же создатель малвари на 100% уверен, что на всех целевых операционных системах эти возможности реализованы одинаково, что вовсе не факт. Даже установка очередного пакета обновления приводит к значительным изменениям в поведении оси.

Вот только один пример. При запуске exe-файла, доступ к нему блокируется и если он вдруг захочет себя удалить, без посторонней помощи ему это ни за что не сделать, поскольку удаление становится возможным только после снятия блокировки, то есть после завершения процесса. Конечно, можно создать bat-файл, но только это некрасиво (хоть и надежно), а можно воспользоваться недокументированной особенностью Windows 9x/NT, позволяющей освобождать страничный образ файла, снимая тем самым с него блокировку. В 9x это делается функцией FreeLibrary, в NT и W2k – UnmapViewOfFile. Правда, выполнение кода в освобожденной секции становится невозможным и любая попытка обращения к принадлежащей ей памяти возбуждает исключение. А нам еще DeleteFile

и ExitProcess

выполнить надо! Как быть?! Приходится разрывая себе задницу напополам, "заряжать" стек.

Конкретная реализация показана ниже. Попробуйте разобраться как _это_ вообще работает и почему (ведь с первого взгляда не должно) и только потом обращайтесь к разгадке (только чур, не подглядывать!).

module = GetModuleHandle(0);

GetModuleFileName(module, buf, MAX_PATH);

if(0x80000000 & GetVersion())

{

       // для Win9x

       fnFreeOrUnmap = FreeLibrary;

}

       else



{

       // для WinNT

       fnFreeOrUnmap = UnmapViewOfFile;

       CloseHandle((HANDLE)4);

}

__asm

{

       lea    eax, buf

       push   0

       push   0

       push   eax

       push   ExitProcess

       push   module

       push   DeleteFile

       push   fnFreeOrUnmap

       ret

}

Листинг 2 код, удаляющий текущий процесс

Начнем раскрутить головоломку с конца.
Очевидно, что ret передает управление по адресу, который был занесен в стек перед ним, то есть вызывает функцию fnFreeOrUnmap, которой в зависимости от версии Windows оказывается либо FreeLibrary, либо UnmapViewOfFile. Получив управление, функция смотрит на стек и думает: ага, "DeleteFile" это адрес возврата, а вот "module" — это мой аргумент. Освободив страничный образ, она передает управление по адресу возврата (на месте которого лежит адрес DeleteFile) и увеличивает значение указателя стека на 4 (размер переданных ей аргументов).

Получив управление, DeleteFile

смотри на стек и думает: ага, ExitProcess – это адрес возврата, а вот "push eax" — мой аргумент с именем файла, которая я должна удалить! (и ведь удаляет, поскольку модуль к этому времени уже освобожден).

Следующей (и последней) управление получает функция ExitProcess, завершающая выполнение программы, которой уже нет.



Рисунок 9 файл, удаляющий себя сам

Элегантно, не правда ли?! Никаких тебе временных bat-файлов и прочей дисковой активности (которую, кстати, могут заметить всякие недружелюбно настроенные мониторы). Но! Разве кто-нибудь гарантировал нам (документация или лично Билл Гейтс), что UnmapViewOfFile

позволяет освобождать образ exe-файла? На NT и W2K это работало лишь потому, что ядро хранило ссылку на обработчик объекта-секции (не путать с секциями PE-файла) и UnmapViewOfFile послушно его освобождало. Начиная с XP ядро обращается к обработчику секции через указатель, обламывая вызов UnmapViewOfFile, а вместе с ним весь наш кайф.

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


Содержание раздела