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-а этого не произошло! Ну вот мы и еще кое-что узнали. Конец главе.