Касперски Крис
Шрифт:
Сжатие части оригинального файла
Древние считали, что истина в вине. Они явно ошибались. Истина в том, что день ото дня программы становятся все жирнее и жирнее, а вирусы все изощреннее и изощреннее. Какой бы уродливый код ни выбрасывала на рынок фирма Microsoft, он все же лучше некоторых UNIX-подделок. Например, файл cat, входящий в FreeBSD 4.5, занимает более 64 Кбайт. Не слишком ли много для простенькой утилиты?!
Просмотр файла под hex-редактором обнаруживает большое количество регулярных последовательностей (в большинстве своем – цепочек нулей), которые либо вообще никак не используются, либо поддаются эффективному сжатию. Вирус, соблазнившись наличием свободного места, может скопировать туда свое тело, пускай – ему и придется «рассыпаться» на несколько десятков пятен. Если же свободное место отсутствует – не беда! Практически каждый исполняемый файл содержит большое количество текстовых строк, а текстовые строки легко поддаются сжатию. На первый взгляд, такой алгоритм заражения кажется чрезвычайно сложным, но, поверьте, реализовать простейший упаковщик Хаффмана намного проще того шаманства с раздвижками секций, что приходится делать вирусу для внедрения в середину файла. К тому же при таком способе заражения длина файла остается неизменной, что частично скрывает факт наличия вируса.
Рассмотрим, как происходит внедрение вируса в кодовый сегмент. В простейшем случае вирус сканирует файл на предмет поиска более или менее длинной последовательности команд NOP, использующихся для выравнивания программного кода по кратным адресам, записывает в них кусочек своего тела и добавляет команду перехода на следующий фрагмент. Так продолжается до тех пор, пока вирус полностью не окажется в файле. На завершающем этапе заражения вирус записывает адреса «захваченных» им фрагментов, после чего передает управление файлу-носителю (если этого не сделать, вирус не сможет скопировать свое тело в следующий заражаемый файл, правда, пара особо изощренных вирусов содержит встроенный трассировщик, автоматически собирающий тело вируса на лету, но это чисто лабораторные вирусы и на свободе им не гулять).
Различные программы содержат различное количество свободного места, расходующегося на выравнивание. В частности, программы, входящие в базовый комплект поставки Free BSD 4.5, преимущественно откомпилированы с выравниванием на величину 4-х байт. Учитывая, что команда безусловного перехода в х86-системах занимает по меньшей мере два байта, втиснуться в этот скромный объем вирусу просто нереально. С операционной системой Red Hat 5.0 дела обстоят иначе. Кратность выравнивания, установленная на величину от 08h до 10h байт, с легкостью вмещает в себя вирус средних размеров.
Ниже в качестве примера приведен фрагмент дизассемблерного листинга утилиты PING, зараженной вирусом UNIX.NuxBe.quilt(модификация известного вируса NuxBee, опубликованного в электронном журнале, выпускаемом группой #29А) (листинг 2.7).
Даже начинающий исследователь легко обнаружит присутствие вируса в теле программы. Характерная цепочка jmp'oB, протянувшаяся через весь сегмент данных, не может не броситься в глаза. В «честных» программах такого практически никогда не бывает (хитрые конвертные защиты и упаковщики исполняемых файлов, построенные на полиморфных движках, мы оставим в стороне).
Листинг 2.7. Фрагмент файла, зараженного вирусом UNIX.NuxBe.quilt, «оазмазываюшим» себя по кодовой секции
Отметим, что фрагменты вируса не обязательно должны следовать линейно. Напротив, вирус (если только его создатель не даун) предпримет все усилия, чтобы замаскировать факт своего существования. Вы должны быть готовы к тому, что jmp'bi будут блохой скакать по всему файлу, используя «левые» эпилоги и прологи для слияния с окружающими функциями. Но этот обман легко разоблачить по перекрестным ссылкам, автоматически генерируемым дизассемблером IDA Pro. На подложные прологи/эпилоги перекрестные ссылки отсутствуют!
Кстати говоря, рассмотренный нами алгоритм не совсем корректен. Цепочка NOP'ob может встретиться в любом месте программы (например, внутри функции), и тогда зараженный файл перестанет работать. Чтобы этого не произошло, некоторые вирусы выполняют ряд дополнительных проверок, в частности убеждаются, что NOP'bi расположены между двумя функциями, опознавая их по командам пролога/эпилога.
Внедрение в секцию данных осуществляется еще проще. Вирус ищет длинную цепочку нулей, разделенную «читабельными» (точнее – printable) ASCII-символами, и, найдя таковую, полагает, что он находится на ничейной территории, образовавшейся в результате выравнивая текстовых строк. Поскольку текстовые строки все чаще располагают в секции. rodata, доступной лишь для чтения, вирус должен быть готов сохранять все модифицируемые им ячейки на стеке и/или динамической памяти.
Забавно, но вирусы этого типа достаточно трудно обнаружить. Действительно, наличие «нечитабельных» ASCII-символов между текстовыми строками – явление вполне нормальное. Может быть, это смещения или еще какие-то структуры данных, на худой конец – мусор, оставленный линкером (рис. 2.5)!
Рис. 2.5. Так выглядел файл cat до (вверху) и после (внизу) его заражения. Согласитесь, что факт зараженности файла вовсе не так очевиден
Исследователи, имеющие некоторый опыт работы с IDA, здесь, возможно, возразят: мол, какие проблемы? Подогнал курсор к первому символу, следующему за концом ASCIIZ-строки, нажал на С и… дизассемблер мгновенно распахнул код вируса, живописно вплетенный в текстовые строки (листинг 2.8). На самом деле так случается только в теории. Среди «нечитабельных» символов вируса присутствуют и «читабельные» тоже. Эвристический анализатор IDA, ошибочно приняв последние за «настоящие» текстовые строки, просто не позволит их дизассемблировать. Ну, во всяком случае, до тех пор, пока они явно не будут «обезличены» нажатием клавиши U. К тому же вирус может вставлять в начало каждого своего фрагмента специальный символ, являющийся частью той или иной машинной команды и сбивающий дизассемблер с толку. В результате IDA дизассемблирует всего лишь один-единственный фрагмент вируса (да и тот некорректно), после чего заткнется, подталкивая нас к индуктивному выводу, что мы имеем дело с легальной структурной данных, и зловредный машинный код здесь отродясь не ночевал.
Листинг 2.8. Фрагмент файла, зараженного вирусом UNIX.NuxBe.jullet, «размазывающим» себя по секции данных
Увы! Какой бы могучей IDA ни была – она все-таки не всесильна, и над всяким полученным листингом вам еще предстоит поработать. Впрочем, при некотором опыте дизассемблирования многие машинные команды распознаются в hex-дампе с первого взгляда. Пользуясь случаем, отсылаю вас к «Технике и философии хакерских атак/дизассемблирование в уме», ставшей уже библиографической редкостью, так как ее дальнейших переизданий не планируется, а появившаяся в продаже «Техника и философия хакерских атак II – записки мыщъх'а» представляет собой совсем другую книгу.