Записки исследователя компьютерных вирусов
Шрифт:
Рис. 1.4. Так выглядит дизассемблерный листинг файла, зараженного вирусом WinNT.Infis.4608: точка входа расположена в секции. reloc, помещенной непосредственно за концом инициализированных данных у самой «кромки» исполняемого файла
Рассмотрим, например, как устроен стандартный «блокнот». Пропустив notepad.exe через утилиту efd.exe от Ильфака Гуильфанова, мы обнаружим разрыв в 6BCh байт, разделяющий секции. data и. rsrc. Причем непосредственно в самом исполняемом файле этот разрыв отсутствует (секции примыкают друг к другу вплотную, без зазора), и он образуется уже после проецирования секций в память (листинг 1.7).
Листинг 1.7. Расположение секций РЕ-файла до их проекции в память и после
Поэтому
Некоторые антивирусы (и DrWeb в частности), обнаружив, что точка входа указывает на секцию с атрибутом writable, сообщают, что файл, возможно, заражен. Однако это очень ненадежный признак, уверенно распознающий вторжение вируса в последнюю секцию файла, но пропускающий остальные типы внедрений. К тому же в атрибуте writable нуждаются многие вполне законопослушные упаковщики и навесные защиты, вызывающие ложное срабатывание эвристического анализатора (впрочем, про то, что антивирусам доверять не стоит, мы уже говорили).
Убедитесь также, что точка входа не начинается с машинной команды jump или call, передающей управление куда-то в конец файла. Обычно вирусы либо накладывают jump непосредственно поверх «живого» кода исходной программы (естественно, предварительно сохранив его оригинальное содержимое в своем теле), либо внедряют сюда целую функцию, предназначенную для отвода глаз («голый» jump привлекает к себе слишком много внимания). Реже здесь удается встретить текстовые строки или какой-нибудь забавный код, как, например, в случае с Win 32.cabanas.b(рис. 1.5).
Рис. 1.5. Так выглядит дизассемблерный листинг файла, пораженного вирусом Win32.Cabanas.b – непосредственно в точке входа находится jump
Рис. 1.6. Изменение окрестностей точки входа после заражения файла вирусом Win32.КМЕ. На место оригинальной инструкции mov eax, large fs:0 вирус внедряет команду передачи управления на свое тело
Кстати говоря, вирус может внедриться и не в первую машинную команду, а, пропустив несколько инструкций, пристроиться где-то в середину стартового кода. Для этого ему даже не потребуется включать в свое тело трассировщик или дизассемблер – с некоторым риском можно ограничиться и поиском опо-кода инструкции call (E8h XXh XXh XXh XXh, где XXh – относительный адрес перехода, отсчитываемый от конца команды) или mov хх, dword prt fs:(00000000h), загружающей в регистр хх указатель на текущий обработчик структурных исключений и встречающейся в подавляющем большинстве современных программ. Взгляните на файл, зараженный вирусом Win32.КМЕ (рис. 1.6). Окрестности точки входа на первый взгляд выглядят вполне нормально, но, если присмотреться к ним повнимательнее, можно обнаружить весьма подозрительный cal 1, вылетающий за пределы кодовой секции файла. Он-то и передает управление вирусному телу!
Между прочим, точка входа имеет смысл не только в исполняемых файлах, но и в динамических библиотеках тоже. При загрузке DLL в память (и выгрузке тоже) управление автоматически передается стартовой функции, подготавливающей библиотеку к нормальной работе. С точки зрения вируса, заражение DLL по своей природе ничем не отличается от обычного исполняемого файла и осуществляется аналогичным образом. Аналогичным образом оно и распознается.
Рис. 1.7. Так выглядит дизассемблерный листинг файла, зараженного вирусом WinNT.Chatter: исполняемый код, расположенный в секции. reloc, предназначенной для хранения перемещаемых данных, сигнализирует о ненормальности ситуации
Нестандартные секции
При заражении исполняемого файла методом дозаписи своего тела в его конец у вируса есть альтернатива: либо увеличить размер последней секции файла, слившись с ней в алхимическом браке, либо создать свою собственную секцию. Оба этих способа легко распознаются визуально:
1. Код, расположенный в конце последней секции файла (.data, relос. rsrc), – весьма характерный признак наличия вируса, равно как и секция. text, замыкающая собой файл и после недолгих мытарств передающая управление «вперед» – на нормальную точку входа (рис. 1.7).
2. То же самое относится и к секциям с нестандартными именами, зачастую совпадающими с именем самого вируса или маскирующимися под секции, создаваемые упаковщиками исполняемых файлов (но сам файл при этом остается не упакован!) (рис. 1.8). Вирус может внедриться и между уже существующими секциями, проецируя «свою» секцию в любой свободный участок виртуальной памяти, не перекрываемый секциями жертвы. Поскольку в «честных» программах секции чаще всего проецируются в память строго в порядке своего физического расположения в файле, то появление секции, нарушающей этот порядок, вызывает большие подозрения.
Рис. 1.8. Так выглядит дизассемблерный листинг файла, зараженного вирусом Win32.Nathan, внедряющегося в собственноручно созданную секцию с нестандартным именем «Nathan», разоблачающую вирус с головой
Таблица импорта
Операционные системы семейства Windows поддерживают два основных способа компоновки: статический и динамический. При статической компоновке имена (ординалы) вызываемых API-функций выносятся в специальную таблицу – таблицу импорта, изучение которой дает более или менее полное представление о природе исследуемой программы и круге ее интересов. К потенциально опасным функциям в первую очередь относятся сетевые функции, функции поиска, вызова и удаления файлов, ТО OLHELP – функции, используемые для просмотра списка активных процессов и внедрения в них…
Конечно, зловредной программе ничего не стоит загрузить все эти функции и самостоятельно, путем динамической компоновки, в простейшем случае опирающейся на вызов LoadLibrary/GetProcAddress, a то и вовсе на «ручной» поиск API-функций в памяти (адрес системного обработчика структурных исключений дает нам адрес, принадлежащий модулю KERNEL32.DLL, базовый адрес которого определяется сканированием памяти на предмет выявления сигнатур «MZ» и «РЕ» с последующим разбором РЕ-заголовка). Но в этом случае текстовые строки с именами соответствующих функций должны присутствовать в теле программы (если только они не зашифрованы и не импортируются по ординалу). Подробнее см. главу 4, разделы «Секреты проектирования shell-кода» и «Техника вызова системных функций».
ВНИМАНИЕ
Статистика показывает, что таблица импорта троянских программ обычно носит резко полярный характер. Либо она вообще практически пуста, что крайне нетипично для нормальных, неупакованных, программ, либо содержит обращения к потенциально опасным функциям в явном виде. Конечно, сам факт наличия потенциально опасных функций еще не свидетельствует о троянской природе программы, но без особой нужды ее все-таки лучше не запускать.
Анализ таблицы импорта позволяет выявить также и ряд вирусных заражений. Собственно, у вируса есть два пути: использовать таблицу импорта файла-жертвы или создавать свою. Если необходимых вирусу API-функций в импорте жертвы нет и она не импортирует функции LoadLibrary/GetProcAddress, вирус должен либо отказаться от ее заражения, либо тем или иным образом импортировать недостающие функции самостоятельно. Некоторые вирусы используют вызов по фиксированным адресам, но это делает их крайне нежизнеспособными, ограничивая ареал обитания лишь теми версиями ОС, на которые явно рассчитывали их создатели; другие же определяют адреса функций «вручную»: по сигнатурному поиску или ручным анализом таблицы импорта; первое – громоздко и ненадежно, второе – слишком сложно в реализации для начинающих.