Умри, но сейчас КРИС КАСПЕРСКИ АКА МЫЩЪХ Спецвыпуск: Хакер, номер #070, стр. 070-076-4 ЛИСТИНГ код, удаляющий текущий процесс 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 } Проще раскрутить головоломку с конца. Очевидно, что ret передает управление по адресу, который был занесен в стек перед ним, то есть вызывает функцию fnFreeOrUnmap, которой, в зависимости от версии Windows, оказывается либо FreeLibrary, либо UnmapViewOfFile. Получив управление, функция смотрит на стек и думает: ага, «DeleteFile» — это адрес возврата, а вот «module» — это мой аргумент. Освободив страничный образ, она передает управление по адресу возврата (на месте которого лежит адрес DeleteFile) и увеличивает значение указателя стека на 4 (размер переданных ей аргументов). Получив управление, DeleteFile смотрит на стек и думает: ага, «ExitProcess» – это адрес возврата, а вот «push eax» — мой аргумент с именем файла, который нужно удалить! И ведь удаляет, поскольку модуль к этому времени уже освобожден. Следующей (и последней) управление получает функция ExitProcess, завершающая выполнение программы, которой уже нет. Элегантно! Никаких тебе временных bat-файлов и прочей дисковой активности (которую, кстати, могут заметить всякие недружелюбно настроенные мониторы). Но разве кто-нибудь гарантировал (документация или лично Билл Гейтс), что UnmapViewOfFile позволяет освобождать образ exe-файла? На NT и W2K это работало лишь потому, что ядро хранило ссылку на обработчик объекта-секции (не путать с секциями PE-файла) и UnmapViewOfFile послушно его освобождало. Начиная с XP, ядро обращается к обработчику секции через указатель, обламывая вызов UnmapViewOfFile, а вместе с ним весь кайф. Отсюда вывод — решение, построенное на недокументированных возможностях, может рухнуть в любой момент. Поэтому, используя его, необходимо как минимум предусмотреть обходной путь на тот случай, если оно не сработает. [6 незаконнорожденные потоки] Чтобы не порождать отдельный процесс, некоторая малварь внедряется в один из уже существующих, порождая в нем свой поток, причем делает это настолько неумело, что сразу же обращает на себя внимание и легко обнаруживается утилитой «Process Explorer» Марка Руссиновича или любым отладчиком (OlyDbg, soft-ice). А все потому, что память, в которой малварь размещает свой код, в 99% случаях выделяется через VirtualAlloc/VirtualAllocEx, то есть берется из динамической памяти, в то время как нормальные потоки вращаются в пределах образов исполняемых файлов или DLL. |