Добавлен: 29.10.2018
Просмотров: 48123
Скачиваний: 190
736
Глава 9. Безопасность
Во-вторых, процедура infect может проверить файл на зараженность, чтобы не тратить
зря время на повторное заражение одного и того же файла. В-третьих, можно принять
меры к сохранению прежнего времени последней модификации файла и его размера,
чтобы скрыть его зараженность. Для программ, размер которых превышает размер
вируса, будет оставлен прежний размер, но программы, чей размер был меньше вируса,
теперь станут больше. Поскольку большинство вирусов меньше большинства про-
грамм, эта проблема слишком остро не стоит.
Хотя эта программа не такая уж большая (вся программа на С, умещающаяся на од-
ной страничке, и текстовый сегмент после компиляции занимают меньше 2 Кбайт),
ассемблерная версия может быть еще короче. Людвиг привел пример программы на
ассемблере для MS-DOS, которая заражала все файлы в своем каталоге и занимала
после ассемблирования всего 44 байта (Ludwig, 1998).
Далее в этой главе будут рассмотрены антивирусные программы, выслеживающие
и удаляющие вирусы. Здесь интересно отметить, что логика, приведенная в листин-
ге 9.2, которую вирус мог использовать для поиска и заражения всех исполняемых
файлов, может быть применена также в антивирусной программе для отслеживания
всех зараженных программ с целью удаления вируса. Технологии заражения и лече-
ния идут рука об руку, поэтому чтобы эффективно бороться с вирусами, необходимо
детально разбираться в их работе.
С точки зрения Вирджила, недостатком перезаписывающего вируса является легкость
его обнаружения. В конечном итоге, при выполнении зараженной программы она
может распространять вирус дальше, но не может работать по своему прежнему пред-
назначению, что тут же заметит пользователь. Поэтому многие вирусы самостоятельно
присоединяются к программе и делают свою черную работу, но после этого дают про-
грамме возможность нормально работать. Это так называемые паразитические вирусы
(parasitic viruses).
Эти вирусы могут прикрепляться к началу или концу программы или встраиваться
в нее. Если вирус прикрепляется к началу, то сначала он должен скопировать програм-
му в оперативную память, поместить себя в ее начало, а затем скопировать программу,
следующую прямо за ним, из оперативной памяти (рис. 9.24, б). К сожалению, про-
грамма не будет запускаться по своему новому виртуальному адресу, поэтому вирусу
приходится перемещать программу либо на размер ее смещения, либо на виртуальный
адрес 0 после завершения своего собственного выполнения.
Чтобы избежать сложностей, связанных с загрузкой вируса в начало программы,
большинство вирусов являются вирусами с «задней» загрузкой. Они прикрепляют
себя к концу, а не к началу выполняемой программы, изменяя в заголовке содержимое
поля со стартовым адресом, чтобы оно указывало на начало вируса (рис. 9.24, в). Теперь
вирус будет выполняться с разных виртуальных адресов (в зависимости от того, на
какой зараженной программе он запущен), но все это означает, что Вирджилу нужно
обеспечить свой вирус позиционной независимостью, используя относительные, а не
абсолютные адреса. Для опытного программиста это не составит труда, а некоторые
компиляторы могут делать это по запросу.
Сложные форматы исполняемых программ, такие как файлы с расширением
.exe
в Windows и практически все современные двоичные форматы в UNIX, позволяют
программе иметь несколько сегментов текста и данных. Загрузчик собирает их в па-
мяти и совершает перемещение. В некоторых системах (например, в Windows) размер
9.9. Вредоносные программы
737
Рис. 9.24. а — исполняемая программа; б — с вирусом в начале; в — с вирусом в конце; г —
с вирусом, распределенным по свободным местам программы
всех сегментов (секций) кратен 512 байтам. Если сегменты не заполнены, компоновщик
заполняет их нулями. Разбирающиеся в этом вирусы могут попытаться спрятаться
в этих пустотах. Если вирус помещается в них целиком (рис. 9.24, г), размер файла
остается прежним, что будет несомненным плюсом, поскольку счастлив тот вирус,
которому удалось спрятаться. Вирусы, использующие этот принцип, называются
пустотными
, или заполняющими, вирусами (cavity viruses). Конечно, если загрузчик
не загружает пустующие области в память, вирусу потребуется иной способ запуска.
Резидентные вирусы
До сих пор мы считали, что при выполнении зараженной программы вирус запускается,
передает управление настоящей программе, а затем завершает свою работу. В отличие
от этого резидентные вирусы (memory-resident virus) остаются в оперативной памяти
на все время работы машины, либо спрятавшись в самых верхних адресах памяти, либо,
возможно, «прячась в траве», среди векторов прерываний в нескольких сотнях байтов,
остающихся, как правило, незадействованными. Самые изощренные вирусы могут
даже изменить карту памяти операционной системы, заставив ее считать память, куда
загрузился вирус, занятой, чтобы устранить угрозу ее перезаписи.
Типичный резидентный вирус перехватывает один из векторов системного или обычно-
го прерывания за счет копирования содержимого в рабочую переменную и помещения
в вектор собственного адреса, направляя это прерывание на себя. Лучше всего перехва-
тить системное прерывание. В таком случае вирус получает возможность запускаться
в режиме ядра при каждом системном вызове. Когда он завершает свою работу, он про-
сто осуществляет настоящий системный вызов, передавая управление по сохраненному
адресу системного прерывания.
А зачем вирусу запускаться при каждом системном вызове? Естественно, для того,
чтобы заражать программы. Вирус может просто выжидать, пока не поступит систем-
ный вызов exec, а затем, зная, что файл, имеющийся у него в распоряжении, является
исполняемым двоичным (и, наверное, вполне для этого подходящим) файлом, заражает
его. Для этого процесса не требуется такой большой активности диска, как при исполь-
зовании кода, представленного в листинге 9.2, поэтому он меньше бросается в глаза.
Перехват всех системных прерываний также дает вирусу огромные возможности для
шпионского сбора информации и нанесения различного вреда.
738
Глава 9. Безопасность
Вирусы, поражающие загрузочный сектор
В главе 5 говорилось о том, что при включении большинства компьютеров программа
BIOS считывает главную загрузочную запись с начала загрузочного диска в память
и выполняет имеющуюся в ней программу. Эта программа определяет, какой из разде-
лов активен, считывает первый загрузочный сектор из этого раздела и выполняет имею-
щуюся на нем программу. Эта программа затем либо загружает операционную систему,
либо активизирует загрузчик операционной системы. К сожалению, много лет назад
одного из соратников Вирджила осенила идея создать вирус, способный переписать
главную загрузочную запись или загрузочный сектор. Такие вирусы, называющиеся
вирусами загрузочного сектора
(boot sector viruses), встречаются еще довольно часто.
Как правило, вирус загрузочного сектора (а в это понятие включены и вирусы главной
загрузочной записи) сначала копирует настоящий загрузочный сектор в безопасное
место на диске, чтобы иметь возможность загрузить операционную систему по окон-
чании своей работы. Разработанная Microsoft программа форматирования диска fdisk
пропускает первую дорожку, поэтому она является неплохим укромным местечком
на Windows-машинах. Еще можно выбрать любой свободный сектор на диске, а затем
обновить список сбойных секторов, чтобы пометить убежище как сбойный сектор.
Вообще-то если вирус большой, то он может всего себя замаскировать под сбойные
сектора. По-настоящему агрессивный вирус может даже выделить себе обычное дис-
ковое пространство под настоящий загрузочный сектор и себя самого и соответству-
ющим образом обновить дисковый битовый массив или список свободных блоков.
Такие действия требуют глубоких знаний структур внутренних данных операционной
системы, но у Вирджила был хороший преподаватель по курсу операционных систем,
и он сам прилежно учился.
При загрузке компьютера вирус копирует самого себя в оперативную память — либо
в верхнюю ее часть, либо в нижнюю, среди неиспользуемых векторов прерываний.
В этот момент машина находится в режиме ядра с выключенным блоком управления
памятью, незагруженной операционной системой и незапущенными антивирусными
программами. И вирусам здесь сплошное раздолье. Когда все готово, вирус загружает
операционную систему, оставаясь обычно в памяти в качестве резидента и наблюдая
за всем происходящим.
Есть все же одна проблема, заключающаяся в последующем получении управления.
Обычно для этого используются специфические сведения о том, как операционная
система управляет векторами прерываний. К примеру, Windows не переписывает разом
все векторы прерываний. Вместо этого она по одному загружает драйверы устройств,
и каждый из них захватывает необходимый ему вектор прерывания. Этот процесс за-
нимает около минуты.
Это дает вирусу необходимые ему управляющие возможности. Он начинает с пере-
хвата всех векторов прерываний (рис. 9.25, а). По мере загрузки драйверов некоторые
из векторов переписываются, но если только драйвер часов не загрузится первым, то
позже будет вполне достаточно прерываний от часов, которые запустят вирус. Потеря
вирусом принтерного прерывания показана на рис. 9.25, б. Как только вирус увидит,
что один из контролируемых им векторов прерываний переписан, он может переписать
этот вектор опять, зная, что теперь это безопасно (на самом деле некоторые векторы
прерываний в процессе запуска системы переписываются по нескольку раз, но все идет
по вполне определенной схеме, и Вирджил это твердо усвоил). Перезахват принтера
9.9. Вредоносные программы
739
показан на рис. 9.25, в. Когда все будет уже загружено, вирус восстановит все векторы
прерываний, а себе оставит только вектор прерываний, используемый системными
вызовами. Теперь мы имеем дело с резидентным вирусом, контролирующим систем-
ные вызовы. Вообще-то именно так большинство резидентных вирусов обретают свое
существование.
Рис. 9.25. Ситуация: а — после захвата вирусом всех векторов обычных и системных
прерываний; б — после того, как операционная система отобрала вектор прерывания принтера;
в — после того, как вирус заметил потерю вектора прерывания принтера и захватил его повторно
Вирусы драйверов устройств
Подобное проникновение в память немного напоминает спелеологию (изучение пе-
щер) — вам нужно пройти по извилистому маршруту, опасаясь, что что-то упадет вам
на голову. Было бы намного проще, если бы операционная система оказала любезность
и загрузила вирус вполне официально. Приложив немного усилий, можно добиться
желаемого результата. Фокус в том, что нужно заразить драйвер устройства, что на-
талкивает на мысль о вирусе драйвера устройства (device driver virus). В Windows
и некоторых UNIX-системах драйверы устройств представляют собой обычные ис-
полняемые программы, которые находятся на диске и загружаются в процессе запуска
системы. Если один из них может быть заражен, то вирус всегда будет загружаться
вполне официально во время запуска системы. Что еще лучше, драйверы работают
в режиме ядра, и после того как драйвер загружен, он будет вызван, давая вирусу шанс
захватить вектор прерываний, используемый системными вызовами. Только один этот
факт уже является сильным аргументом в пользу запуска драйверов устройств в виде
программ, работающих в пользовательском режиме (как это делается в MINIX 3), —
если они будут заражены, то они не смогут нанести такого же ущерба, как зараженные
драйверы, работающие в режиме ядра.
Макровирусы
Многие программы, например Word и Excel, позволяют пользователям создавать
макросы для объединения нескольких команд, которые позже можно выполнить
740
Глава 9. Безопасность
одним нажатием клавиши. Макросы могут быть также подключены к пунктам меню
и выполняться при выборе одного из таких пунктов. В Microsoft Office макросы могут
содержать целые программы на полноценном языке программирования Visual Basic.
Макросы не компилируются, а интерпретируются, но это влияет только на скорость
выполнения, а не на их функциональность. Поскольку макросы могут иметь отноше-
ние к определенному документу, Office хранит макросы для каждого документа вместе
с документом.
А теперь рассмотрим суть проблемы. Вирджил создал документ в программе Word и ма-
крос, подключенный к функции OPEN FILE (открыть файл). В этом макросе содержится
макровирус
(macro virus). Затем он посылает документ по электронной почте своей
жертве, которая, естественно, его открывает (если предположить, что почтовая програм-
ма не сделала это за нее). Открытие документа приводит к выполнению макроса OPEN
FILE. Поскольку макрос может содержать любую программу, он может делать что угодно:
например, заражать другие документы Word, удалять файлы и делать многое другое.
Следует честно признать, что Microsoft ввела в Word предупреждение, появляющееся,
когда открывается файл с макросом, но большинство пользователей не понимают, что
это означает, и все равно продолжают открытие файла. Кроме того, вполне законные
документы тоже могут содержать макросы. Существуют программы, не выдающие даже
такого предупреждения, что еще более затрудняет обнаружение вируса.
С ростом количества почтовых вложений отправка документов с вирусами, встроен-
ными в макросы, упростилась. Намного проще создавать такие вирусы, чем скрывать
настоящий загрузочный сектор где-нибудь в списке сбойных блоков, прятать вирусы
среди векторов прерываний и захватывать вектор прерываний, используемый систем-
ными вызовами. Это означает, что теперь создание вирусов становится по силам куда
менее образованным людям, чем прежде, снижающим общее качество продукта и при-
носящим создателям вирусов дурную славу.
Вирусы, заражающие исходные тексты программ
Паразитические вирусы и вирусы загрузочного сектора слишком зависимы от при-
меняемой платформы; у вирусов, скрывающихся в документах, эта зависимость вы-
ражена несколько меньше (Word запускается на Windows и на Macintosh, но не на
UNIX). Самыми переносимыми из всех существующих являются вирусы исходного
кода
(source code viruses). Представьте себе вирус из листинга 9.2, но с модификацией,
заставляющей искать не двоичные исполняемые файлы, а программы на языке C, для
чего нужно изменить всего одну строчку (вызов процедуры access).
Процедура infect должна быть изменена для вставки строки
#include <virus.h>
в верхнюю часть каждого исходного текста программы на языке C. Для активации
вируса нужна еще одна вставка — это строка
run virus( );
Для того чтобы решить, куда поместить эту строку, нужно провести синтаксический
разбор кода на языке C, поскольку это должно быть место, которое позволяет осуще-
ствить вызов процедуры. Не будет работать строка, помещенная в середину коммен-
тария. Не лучшим выбором будет и помещение строки внутрь цикла. Если предпо-