стр. 2
Вверх
2
3
4

«ВАКЦИНАЦИЯ» ПРОГРАММ

      Что же следует сделать, чтобы эта безрадостная картина не стала реаль­ностью? Один ответ очевиден - периодически (и по возможности чаще) со­хранять жизненно важные для Вас результаты работы на дискетах. Нет ничего проще, чем дать этот совет, гораздо сложнее заставить себя следовать ему: я сам, честно говоря, далеко не каждый день трачу время на архивирование. Второй ответ менее очевиден. С его простой идеей я впервые познакомился в прекрасной статье Ф.Н.Шерстюка.

      Вот эта идея: нужно произвести «вакцинацию» исполняемых программ, т.е. придать им свойство самодиагностики, позволяющее произвести контроль собственного файла и выяснить, заражен он или нет. Если факт заражения установлен, программа может попытаться восстановить свой исходный вид, т.е. удалить прицепившийся к ее файлу вирус. Если эту идею последовательно воплощать в жизнь, то большинство Ваших программ приобретет стойкий «иммунитет» к вирусам, во всяком случае, они смогут достаточно быстро со­общить Вам о факте заражения.

      Преимущества этой идеи очевидны: в отличие от разработчиков много­численных антивирусных программ, которые борются с конкретными разно­видностями вирусов, Вы можете сохранить в файле программы некоторую ключевую информацию о ее незараженном виде, и поэтому факт заражения любым видом вируса может быть легко установлен в момент запуска Вашей программы.

3.1. Заголовок исполняемых файлов

      Какую именно информацию о незараженном файле следует сохранять? Для ответа на этот вопрос необходимо знать соглашение ДОС о формате испол­няемых файлов. Как известно, существуют два формата: СОМ и ЕХЕ. Любая программа, обрабатываемая системой Турбо Паскаль версии 4.0 и выше, может быть оттранслирована только в ЕХЕ-файл, поэтому все дальнейшие рассуж­дения относятся именно к этому формату.

      В начале ЕХЕ-файла располагается заголовок, в котором содержится вся информация, необходимая для преобразования дискового файла в готовую к работе программу. Первые 28 байт заголовка соответствуют следующей структуре данных:

 

Type

  HeadExeType = record

  Sign: Word; {Признак ЕХЕ-файла}

  PartPag: Word; {Часть неполного сектора в конце файла}

  PageCnt: Word; {Количество секторов, включая неполный}

  ReloCnt: Word; {Количество элементов в таблице перемещения}

  HdrSize: Word; {Длина заголовка в параграфах}

  MinMem: Word; {Минимальный размер кучи (в параграфах)}

  МахМет: Word; {Максимальный размер кучи (в параграфах)}

  ReloSS: Word; {Начальное значение сегмента стека SS}

  ExeSP: Word; {Начальное значение указателя стека SP}

  ChkSum: Word; {Контрольная сумма всех слов файла}

  ExelP: Word; {Смещение точки запуска программы}

  ReloCS: Word; {Начальное значение сегмента кода CS};

  TabiOff: Word; {Смещение первого элемента таблицы перемещения}

  Overlay: Word; {Номер оверлея или 0 для основной программы}

end; {HeadExe}

 

      Остальные элементы заголовка содержат так называемую таблицу пере­мещения, предназначенную для настройки адресов загруженной программы. Таблица начинается с байта TabiOff от начала файла и содержит ReloCnt четырехбайтных элементов следующего вида:

 

Type

        ReloTablltem = record

        ItemSeg: Word; {Сегмент перемещаемого адреса}

        IternOfs: Word; {Смещение перемещаемого адреса}

end;

 

      Признак ЕХЕ-файла хранится в поле Sign в виде символов «MZ» (код $5A4D) - с этого признака должен начинаться любой ЕХЕ-файл. Поле HdrSize содержит длину всего заголовка в параграфах (участках памяти длиной по 16 байт каждый). Поля PartPag и PageCnt определяют общую длину загружаемой в память части ЕХЕ-файла по следующей формуле:

L = (PageCnt-l)*512 + PartPag - HdrSize*16

      Остальная часть файла (длина ЕХЕ-файла может быть больше L+HdrSize*16) при загрузке программы не учитывается. Обычно в остатке файла, созданного системой Турбо Паскаль, (если, разумеется, есть остаток) содержится информация, используемая встроенным отладчиком, или оверлеи.

      Подавляющее большинство ЕХЕ-вирусов пристыковывает свою программу в конец файла, а для того чтобы эта программа была загружена в память и ей было передано управление, изменяет поля PartPag, PageCnt, ReloCS, ExelP (адрес точки, куда передается управление после окончания загрузки) и, воз­можно, некоторые другие поля. При таком способе внедрения общая длина загружаемой в память части файла должна составлять

ExeSize = FileSize + VirusSize,

где FileSize-полная длина ЕХЕ-файла, а VirusSize-длина программы ви­руса. Так как в остатке фала могут храниться оверлеи (или архив для саморазгружающихся архивных программ), длина ExeSize может оказаться чрез-мерно большой, так что программа не сможет загрузиться в память или не сможет работать нормальным образом. Некоторые безграмотно написанные вирусы не учитывают это обстоятельство и быстро выдают себя, т.к. зара­женные программы перестают работать.

Другой способ внедрения вируса-пристыковка кода вируса до начала загружаемой части программы и сразу за заголовком файла. L - загружаемая в память часть файла.

      Такой способ внедрения позволяет не загружать в память весь ЕХЕ-файл, а длина загруженной программы увеличивается только на длину кода вируса. Несмотря на кажущееся преимущество такого способа, он используется дос­таточно редко. Его реализация значительно сложнее, так как перед передачей управления основной программе вирус должен перенести 256 байт префикса программного сегмента {PSP) в конец собственного кода так, чтобы они не­посредственно предшествовали телу программы-в противном случае будет нарушена важная связь программы с PSP или относительная адресация в самой программе.

      Кроме того, в процессе заражения он должен увеличить на вели­чину VirusSize поле IternOfs каждого элемента таблицы перемещения и абсо­лютного адреса, указываемого этим элементом. В отличие от стандартного за­грузчика ДОС вирусу приходится корректировать не загруженную программу, а ее файловый образ. Так как в ЕХЕ-программе средней сложности может быть несколько сотен элементов таблицы перемещения, процесс настройки таблицы вирусом приводит к заметному увеличению времени запуска про­граммы, что может обнаружиться пользователем. На этапе размножения ви­русы стремятся по возможности скрыть от пользователя результат своей деятельности, поэтому ЕХЕ-файлы редко поражаются вирусами, пристыкованными в начало файла.

      Разумеется, существует возможность внедрения вируса непосредственно в тело исполняемой программы. Однако на практике это почти всегда означает разрушение логики работы программы, поэтому такой вирус немедленно об­наруживается.

      Анализ сказанного позволяет сделать важный вывод: практически любой существующий вирус (или вирус, который еще только будет создан!), рассчитанный на поражение ЕХЕ-файла, пристыковывает свой код в конец файла и изменяет его заголовок. Следовательно, для контроля факта заражения программы и ликвидации вируса необходимо где-то сохранить заголовок файла и его эталонную длину и периодически сопоставлять действительный заголовок и длину с эталонными значениями. При этом следует учитывать то обстоя­тельство, что некоторые вирусы контролируют любое обращение к дисковым секторам, в которых расположена их программа, и «подсовывают» незараженные копии этих секторов. Такие вирусы (их называют вирусы—невидимки) вряд ли удастся обнаружить с помощью стандартного обращения к функциям ДОС. Для борьбы с ними используют прямое обращение к BIOS-прерыванию $13.

 

Защита вновь создаваемых программ

      Ключевую информацию (будем для краткости называть ее ключ) о незараженной программе можно хранить в отдельном файле, но в этом случае существует опасность потерять дополнительный файл при копировании про­граммы или ошибочно уничтожить его. Гораздо надежнее хранить ключ в теле самого защищаемого файла. К сожалению, его нельзя подобно вирусу при-стыковать в конец файла, т.к. в случае заражения вирус изменит поля PartPag и PageCnt и мы никогда не сможем определить то место в файле, где он рас­полагается. Вспомним, что все константы (в том числе и типизированные) создаются на этапе компиляции программы, таким образом в файле обяза­тельно имеется область данных, содержащая значения этих констант. Эта область в Турбо Паскалевых программах располагается в самом конце за­гружаемой части файла (см.рис.6.2).

      Следовательно, мы должны объявить в программе типизированную кон­стант, предназначенную для хранения ключа, а затем в область файла, отве­денную для ее размещения, поместить нужную информацию.

      Каким образом отыскать в ЕХЕ-файле место, занимаемое ключом? Ко­нечно, можно перед ним в программе разместить какую-либо типизиро­ванную константу с характерным значением (например, заранее обуслов­ленную текстовую строку) и затем отыскивать ее в файле. Однако такое ре­шение вряд ли можно признать удовлетворительным: во-первых, всегда существует вероятность того, что какой-то фрагмент кодов программы со­держит ту же цепочку байт, что и заголовок ключа; во-вторых, придется просматривать подчас большой по объему ЕХЕ—файл в поисках нужной константы. Значительно изящнее выглядит решение, основанное на точном вычислении смещения от начала файла до ключа.

      Для этого нужно определить начало области данных в файле. В заголовке файла не предусмотрено никакой информации о начальном значении регистра DS, в котором хранится сегмент данных. Перед передачей управления про­грамме загрузчик устанавливает значение этого регистра так, чтобы он ука­зывал на начало так называемого префикса программного сегмента {PSP), а запущенная программа уже сама должна установить его надлежащим образом.

      Префикс программного сегмента имеет длину 256 байт (16 параграфов) и размещается загрузчиком в оперативной памяти непосредственно перед за­груженной программой. В PSP содержится различная служебная информация, которая может быть достаточно важной для ДОС и работающей программы (в PSP, например, хранятся параметры обращения к программе), но в нем нет указаний на содержимое регистра DS. Таким образом, найти начало области данных в файле достаточно трудно. Однако это нетрудно сделать в работающей программе - для этого предусмотрена стандартная функция DSeg, возвра­щающая сегмент данных. Если бы программа могла получить также инфор­мацию о сегменте PSP, с которого начинается загруженная программа, можно было бы вычислить смещение в файле от его начала до начала области данных. Такая возможность есть - функция MS-DOS с номером $62 возвращает в регистре ВХ значение сегмента PSP. Следовательно, программа должна полу­чить значения обоих сегментов, вычислить их разницу и таким образом оп­ределить место в файле, с которого начинается область данных.

      Остается последняя проблема - как найти нужную константу. Турбо Паскаль размещает константы в области данных по мере их объявления в программе. Зная размер каждой константы и порядок их объявления, можно вычислить место размещения нужной нам типизированной константы. Однако этот метод не годится для универсальной программы защиты, так как порядок объявления констант может меняться от программы к программе. К счастью, мы можем использовать операцию получения адреса @. Результатом приме­нения этой операции к адресу константы, выбранной в качестве ключа, яв­ляется указатель (четырехбайтный адрес); смещение адреса, который он со­держит, и является нужным нам смещением начала ключа относительно начала области данных.

 

2 3 4

Используются технологии uCoz