Вирусы в UNIX, или Гибель Титаника II

       

Заражение посредством расширения последней секции файла


Простейший способ неразрушающего заражения файла состоит в расширении последней секции/сегмента жертвы и дозаписи своего тела в ее конец (далее по тексту просто "секции", хотя применительно к ELF-файлам это будет несколько некорректно, т.к. системный загрузчик исполняемых ELF-файлов работает исключительно с сегментами, а секции игнорирует). Строго говоря, это утверждение не совсем верно. Последней секцией файла, как правило, является секция .bss, предназначенная для хранения неинициализированных данных. Внедряться сюда можно, но бессмысленно, поскольку загрузчик не настолько глуп, чтобы тратить драгоценное процессорное время на загрузку неинициализированных данных с медленного диска. Правильнее было бы сказать "последней значимой секции", но давайте не будем придираться, это ведь не научная статья, верно?

Перед секций .bss

обычно располагается секция .data, содержащая инициализированные данные. Вот она-то и становится основным объектом вирусной атаки! Натравив дизассемблер на исследуемый файл, посмотрите – в какой секции расположена точка входа. И, если этой секцией окажется секция данных (как например в случае, изображенном в листинге 5), исследуемый файл с высокой степенью вероятности заражен вирусом.

При внедрении в a.out файл вирус в общем случае должен проделать следующие действия:

q       считав заголовок файла, убедиться, что это действительно a.out файл;

q       увеличить поле a_data на величину, равную размеру своего тела;

q       скопировать себя в конец файла;

q       скорректировать содержимое поля a_entry для перехвата управления (если вирус действительно перехватывает управление таким образом);

Внедрение в ELF-файлы происходит несколько более сложным образом:

q       вирус открывает файл и, считывая его заголовок, убеждается, что это действительно ELF;


q       просматривая Program Header Table, вирус отыскивает сегмент, наиболее подходящий для заражения (для заражения подходит любой сегмент с атрибутом PL_LOAD; собственно говоря, остальные сегменты более или менее подходят тоже, но вирусный код в них будет смотреться несколько странно);

q       найденный сегмент "распахивается" до конца файла и увеличивается на величину, равную размеру тела вируса, что осуществляется путем синхронной коррекции полей p_filez и p_memz;



q       вирус дописывает себя в конец заражаемого файла;

q       для перехвата управления вирус корректирует точку входа в файл (e_entry), либо же внедряет в истинную точку входа jmp на свое тело (впрочем, методика перехвата управления тема отдельного большого разговора).

Маленькое техническое замечание. Секция данных, как правило, имеет всего лишь два атрибута: атрибут чтения (Read) и атрибут записи (Write). Атрибут исполнения (Execute) у нее по умолчанию отсутствует. Означает ли это, что выполнение вирусного кода в ней окажется невозможным? Вопрос не имеет однозначного ответа. Все зависит от особенностей реализации конкретного процессора и конкретной операционной системы. Некоторые из них игнорируют отсутствие атрибута исполнения, полагая, что право исполнения кода напрямую вытекает из права чтения. Другие же возбуждают исключение, аварийно завершая выполнение зараженной программы. Для обхода этой ситуации вирусы могут присваивать секции данных атрибут Execute, выдавая тем самым себя с головой, впрочем такие экземпляры встречаются крайне редко, и подавляющее большинство вирусописателей оставляет секцию данных с атрибутами по умолчанию.

Другой немаловажный и не очевидный на первый взгляд момент. Задумайтесь, как измениться поведение зараженного файла при внедрении вируса в не-последнюю секцию .data, следом за которой расположена .bss? А никак не измениться! Несмотря на то, что последняя секция будет спроецирована совсем не по тем адресам, программный код об этом "не узнает" и продолжит обращаться к неинициализированным переменным по их прежним адресам, теперь занятых кодом вируса, который к этому моменту уже отработал и возвратил оригинальному файлу все бразды правления. При условии, что программный код спроектирован корректно и не закладывается на начальное значение неинициализированных переменных, присутствие вируса не нарушит работоспособности программы.



Однако в суровых условиях реальной жизни этот элегантный прием заражения перестает работать, поскольку среднестатистическое UNIX-приложение содержит порядка десяти различных секций всех назначений и мастей.

Взгляните, например, на строение утилиты ls, позаимствованной из следующего дистрибьютива UNIX: Red Hat 5.0:

Name      Start    End      Align Base Type Class 32 es   ss   ds   fs   gs

 .init     08000A10 08000A18 para  0001 publ CODE  Y  FFFF FFFF 0006 FFFF FFFF

 .plt      08000A18 08000CE8 dword 0002 publ CODE  Y  FFFF FFFF 0006 FFFF FFFF

 .text     08000CF0 08004180 para  0003 publ CODE  Y  FFFF FFFF 0006 FFFF FFFF

 .fini     08004180 08004188 para  0004 publ CODE  Y  FFFF FFFF 0006 FFFF FFFF

 .rodata   08004188 08005250 dword 0005 publ CONST Y  FFFF FFFF 0006 FFFF FFFF

 .data     08006250 08006264 dword 0006 publ DATA  Y  FFFF FFFF 0006 FFFF FFFF

 .ctors    08006264 0800626C dword 0007 publ DATA  Y  FFFF FFFF 0006 FFFF FFFF

 .dtors    0800626C 08006274 dword 0008 publ DATA  Y  FFFF FFFF 0006 FFFF FFFF

 .got      08006274 08006330 dword 0009 publ DATA  Y  FFFF FFFF 0006 FFFF FFFF

 .bss      080063B8 08006574 qword 000A publ BSS   Y  FFFF FFFF 0006 FFFF FFFF

 extern    08006574 08006624 byte  000B publ       N  FFFF FFFF FFFF FFFF FFFF

 abs       0800666C 08006684 byte  000C publ       N  FFFF FFFF FFFF FFFF FFFF

Листинг 5 так выглядит типичная карта памяти нормального файла

Секция .data

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

(смещение секции от начала файла) надлежащим образом. Некоторые вирусы этого не делают, в результате чего зараженные файлы не запускаются.

С другой стороны, секция .data

рассматриваемого файла насчитывает всего 10h байт, поскольку львиная часть данных программы размещена в секции .rodata (секции данных, доступной только на чтение). Это – типичная практика современных линкеров, и большинство исполняемых файлов организованы именно так. Вирус не может разместить свой код в секции .data поскольку это делает его слишком заметным, не может он внедриться и в .rodata, т. к. в этом случае он не сможет себя расшифровать (выделить память на стеке и скопировать туда свое тело – не предлагать: для современных вирусописателей это слишком сложно). Да и смысла в этом будет немного. Коль скоро вирусу приходится внедряться не в конец, а в середину файла, уж лучше ему внедриться не в секцию данных, а в секцию .text, содержащую машинный код. Там вирус будет не так заменен (он об этом мы поговорим позже см. "Заражение посредством расширения кодовой секции файла").



Рисунок 3 0x005 типовая схема заражения исполняемого файла путем расширения его последней секции



Рисунок 4 0x009 внешний вид файла, зараженного вирусом PolyEngine.Linux.LIME.poly; вирус внедряет свое тело в конец секции данных и устанавливает на него точку входа. Наличие исполняемого кода в секции данных делает присутствие вируса чрезвычайно заметным.


Содержание раздела