←предыдущая следующая→
1 2 3 4 5
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.
3.2. Защита вновь создаваемых программ
Ключевую информацию (будем для краткости называть ее ключ) о незараженной программе можно хранить в отдельном файле, но в этом случае существует опасность потерять дополнительный файл при копировании про¬граммы или ошибочно уничтожить его. Гораздо надежнее хранить ключ в теле самого защищаемого файла. К сожалению, его нельзя подобно вирусу при-стыковать в конец файла, т.к. в случае заражения вирус изменит поля PartPag и PageCnt и мы никогда не сможем определить то место в файле, где он рас¬полагается. Вспомним, что все константы (в том числе и типизированные) создаются на этапе компиляции программы, таким образом в файле обяза¬тельно имеется область данных, содержащая значения этих констант. Эта область в Турбо Паскалевых программах располагается в самом конце за¬гружаемой части файла (см.рис.6.2).
Следовательно, мы должны объявить в программе типизированную кон¬стант, предназначенную для хранения ключа, а затем в область файла, отве¬денную для ее размещения, поместить нужную информацию.
Каким образом отыскать в ЕХЕ-файле место, занимаемое ключом? Ко¬нечно, можно перед ним в программе разместить какую-либо типизиро¬ванную константу с характерным значением (например, заранее обуслов¬ленную текстовую строку) и затем отыскивать ее в файле. Однако такое ре¬шение вряд ли можно признать удовлетворительным: во-первых, всегда существует вероятность того, что какой-то фрагмент кодов программы со¬держит ту же цепочку байт, что и заголовок ключа; во-вторых, придется просматривать подчас большой по объему ЕХЕ—файл в поисках нужной константы. Значительно изящнее выглядит решение, основанное на точном вычислении смещения от начала файла до ключа.
Для этого нужно определить начало области данных в файле. В заголовке файла не предусмотрено никакой информации о начальном значении регистра DS, в котором хранится сегмент данных. Перед передачей управления про¬грамме загрузчик устанавливает значение этого регистра так, чтобы он ука¬зывал на начало так называемого префикса программного сегмента {PSP), а запущенная программа уже сама должна установить его надлежащим образом.
Префикс программного сегмента имеет длину 256 байт (16 параграфов) и размещается загрузчиком в оперативной памяти непосредственно перед за¬груженной программой. В PSP содержится различная служебная информация, которая может быть достаточно важной для ДОС и работающей программы (в PSP, например, хранятся параметры обращения к программе), но в нем нет указаний на содержимое регистра DS. Таким образом, найти начало области данных в файле достаточно трудно. Однако это нетрудно сделать в работающей программе-для этого предусмотрена стандартная функция DSeg, возвра¬щающая сегмент данных. Если бы программа могла получить также инфор¬мацию о сегменте PSP, с которого начинается загруженная программа, можно было бы вычислить смещение в файле от его начала до начала области данных. Такая возможность есть-функция MS-DOS с номером $62 возвращает в регистре ВХ значение сегмента PSP. Следовательно, программа должна полу¬чить значения обоих сегментов, вычислить их разницу и таким образом оп¬ределить место в файле, с которого начинается область данных.
Остается последняя проблема-как найти нужную константу. Турбо Паскаль размещает константы в области данных по мере их объявления в программе. Зная размер каждой константы и порядок их объявления, можно вычислить место размещения нужной нам типизированной константы. Однако этот метод не годится для универсальной программы защиты, так как порядок объявления констант может меняться от программы к программе. К счастью, мы можем использовать операцию получения адреса @. Результатом приме¬нения этой операции к адресу константы, выбранной в качестве ключа, яв¬ляется указатель (четырехбайтный адрес); смещение адреса, который он со¬держит, и является нужным нам смещением начала ключа относительно начала области данных.
3.3. Модуль F_Anti
В этом параграфе описывается модуль F_Anti, в котором осуществляются все необходимые действия по установке ключа во вновь создаваемый ЕХЕ-файл и последующей проверке этого ключа при каждой загрузке программы. Полный текст модуля см. прил.П7.
В качестве ключа для контроля факта заражения ЕХЕ-файла в модуле F_Anti используется типизированная константа Head, соответствующая такой структуре данных:
Type
НТуре = record
НЕ : HeadExeType; {Эталонный заголовок файла}
←предыдущая следующая→
1 2 3 4 5
|
|