CodeNet / Языки программирования / Ассемблер / "Вирусы", "Черви", "Драконы" и резиденты на службе прогресса.
"Вирусы", "Черви", "Драконы" и резиденты на службе прогресса.
гл.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-----------------------------------------------------------
исходный ЕХЕ-файл зараженный ЕХЕ-файл
(при этом он стал СОМ-файлом)
адрес
--¬ ¦ --¬ ¦Х¦ 40 -¬ ¦
¦ ¦ +пустое ¦Х¦ +код ви- ¦
¦ ¦ ¦место ¦Х¦ ¦руса ¦
¦ ¦ 1FF - ¦Х¦ 1FF - ¦
+-+ +-+ и
¦ 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-а
этого не произошло!
Ну вот мы и еще кое-что узнали.
Конец главе.
