Exploit.SWF.Agent.br Pdfka.asd Pidief.cvl TDSS TDSS removal binary planting bios infection blind sqli bootkit bootkit remover browser exploitation com hijacking disassembling dll hijacking drive-by downloads hack online banks heap-spray hijack botnet ibank kernel protection kernel-mode rootkit keylogger malware analysis rootkit detection trojan virus removal

Анализ и лечение классических вирусов

Андрей Рассохин
специалист по информационной безопасности, Esage Lab
andrey@esagelab.com

Будучи актуальной угрозой, вредоносные программы представляют собой популярную тему современных новостей. Часто вместо термина «вредоносная программа», подразумевающего самостоятельный, целенаправленно разработанный исполняемый файл, используется старый термин «вирус». Между тем, техника распространения вредоносного кода путём заражения исполняемых файлов, благодаря которой и возник термин «компьютерный вирус», давно отошла в прошлое — примерно тогда, когда повсеместное распространение интернета вытеснило дискеты как средство для обмена данными между пользователями. На смену вирусам пришли трояны и черви.

Приложение к статье

Исходный код утилиты для лечения вируса Win32.Parite.C

Загрузить архив

Но история циклична: по мере исчерпания тех или иных методов решения насущных задач, разработчики вредоносного кода обращаются к старым техникам, приспосабливая их под новые условия. В рамках этой тенденции, в последние годы техника инфицирования исполняемых модулей вновь стала актуальна — с тем отличием, что заражение исполняемых файлов теперь решает задачу не распространения, а сокрытия и самозащиты вредоносной программы. Современные файловые инфекторы — это «профессиональные» вредоносные программы, реализующие сложные технологии: заражение системных драйверов (TDSS, ZeroAccess) и полиморфное заражение обычных исполняемых файлов (Virut, Sality).

В контексте этой тенденции актуально вновь поднять тему файловых инфекторов. Одна из задач данной статьи — представить обзор известных на сегодняшний день техник заражения исполняемых файлов. Во второй части статьи рассматривается «шаг за шагом» процесс анализа и разработки процедуры лечения для относительно старого, но не потерявшего своей актуальности файлового инфектора Win32.Parite.C.

Обзор вирусных технологий

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

Добавление новой секции

Это самый распространённый метод заражения файлов, не утрачивающий своей популярности вопреки его успешному обнаружению всеми антивирусами. Суть данного метода заключается в добавлении секции в конец исполняемого файла. Далее, вирус пересчитывает размер образа всего файла (SizeOfImage), выставляет на секцию нужные флаги, включая флаг исполнения (0x20000000), и меняет точку входа (EntryPoint) на начало новой секции.

При запуске заражённого файла сначала выполнится код из вирусной секции, а затем произойдет переход на оригинальную точку входа (Original Entry Point, OEP). Обычно такой переход осуществляется с помощью следующих инструкций процессора:

jmp     OEP

call    OEP

push    OEP
retn

Для лечения файлов, заражённых описанным методом, достаточно удалить последнюю секцию и восстановить оригинальную точку входа. Лечение затрудняется, если запутан алгоритм вычисления точки входа, или если адрес точки входа зашифрован. Обычно шифрование адреса точки входа осуществляется с помощью простого алгоритма типа XOR, но встречаются и намного более сложные случаи.

Расширение последней секции

Это также один из наиболее популярных методов заражения исполняемых файлов. Вирус получает указатель на последнюю секцию исполняемого файла и увеличивает её атрибуты физического размера (SizeOfRawData) и виртуального размера (VirtualSize), тем самым расширяя секцию. Затем вирус пересчитывает размер образа (SizeOfImage) и выставляет на последнюю секцию нужные флаги, включая флаг исполнения (0x20000000), вычисляет новую точку входа и заменяет оригинальную.

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

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

Заражение методом EPO (Entry Point Obscuring)

Большинство вирусов для передачи управления на свой код изменяют точку входа заражаемой программы. Но в данном случае переход на вредоносный код осуществляется из оригинального кода программы без изменения точки входа.

Для осуществления заражения вирус ищет в секции, из которой начинается выполнение программы, опкод инструкции типа call (E8) или jmp (E9), после чего подставляет в эту инструкцию адрес перехода на вирусный код. Последний при этом может храниться в произвольном участке файла: в расширенной последней секции, в добавленной секции, в конце последней секции и т.п.

Для лечения вирусов этого типа не существует универсального подхода. В общем случае, необходимо найти адрес перехода оригинальной инструкции call или jmp и восстановить изменённую инструкцию с последующем удалением вредоносного кода из тела исполняемого файла.

Учитывая, что большинство EPO-вирусов добавляют новую секцию или расширяют последнюю секцию, такие вирусы могут быть выявлены путем поиска в коде программы инструкций типа call или jmp, которые передают управление коду, находящемуся в последней секции.

Оверлейное заражение

Оверлей — часть исполняемого файла, которая не проецируется загрузчиком в память. Чаще всего оверлей находится в конце файла.

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

Лечение заражённого файла в данном случае сводится к удалению оверлея и его загрузчика. Для удаления оверлея — если достоверно известно, что в нём хранится только вирус — достаточно получить его смещение в файле, сложив значения атрибутов PointerToRawData и SizeOfRawData последней секции, и обрезать файл до полученного размера.

Модификация секций

Манипулирование секциями исполняемого файла является более искусным методом заражения. Автору встречались на практике только две разновидности данного метода: с заменой секции таблицы переадресаций (relocation table, в заголовке модуля обычно именуемой .reloc) и со сдвигом секции ресурсов (обычно — .rsrc).

В первом случае вирус внедряет свой код вместо секции с таблицей переадресаций и перенаправляет на него точку входа. После того, как внедренный код отработал, вирус восстанавливает в памяти оригинальную секцию переадресаций, а затем передает управление на OEP.

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

Лечение вируса с заменой секции переадресаций заключается в восстановлении оригинальных данных этой секции и точки входа. Для лечения исполняемых файлов, в которых использовалась техника заражения предпоследней секции со сдвигом ресурсов, требуется также восстановить OEP и удалить все данные между вирусной точкой входа и секцией ресурсов.

Заражение динамической библиотекой

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

Динамическая библиотека, содержащая в себе вирусную функцию, размещается в директории %SYSTEMROOT%\system32. Вирус заражает файл путем добавления в его таблицу импорта имени библиотеки и имени (реже — порядкового номера) экспортируемой функции, после чего меняет адрес ImportTable на новый, внедряет в тело исполняемого файла вызов вирусной функции и направляет точку входа на этот вызов. После того, как вирусная функция отработана, вирус передает управление на OEP.

Лечение подобного заражения заключается в восстановлении точки входа и пересборке таблицы импорта.

Метод «украденных байт»

Метод «украденных байт» — техника передачи управления вирусному коду, как и в случае с методом EPO.

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

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

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

В качестве примера такого вируса, простого только на первый взгляд, рассмотрим полиморфный вирус Win32.Parite.C.

Анализ Win32.Parite.C

Вирус Win32.Parite.C известен тем, что хранит основной вредоносный код в отдельной DLL размером около 180 кБ и реализует нестандартный метод защиты зараженных файлов. Глобальной эпидемии этого вируса не было зафиксировано, однако в 2003 году его образцы занимали почетные места в Top 20 вирусных угроз. В последнее время информация о данном семействе вирусов начинает появляться снова.

Образец этого вируса можно загрузить с сайта vx.netlux.org. Для анализа будем использовать связку IDA Pro 5.5, HexRays 1.1 и IDAPython 2.5, а также Shadow OllyDbg и LordPE.

Как и многие другие файловые вирусы, Win32.Parite.C начинает поиск жертвы для заражения по маске *.exe в трех самых популярных местоположениях:

  1. в текущей директории;
  2. на первом разделе жесткого диска;
  3. в системных директориях — %systemroot% и %systemroot%\system32.

Запустим образец вируса на виртуальной машине с установленной ОС Windows XP Pro SP3 и позволим ему заразить несколько файлов. Файлы для заражения рекомендуется выбирать простые, с хорошо известной структурой — таким образом, ее изменения в результате заражения файла будет проще обнаружить. Автор статьи использует для заражения файлы из уроков Iczelion. При написании данной статьи был использован исполняемый файл из урока 13.

После того, как вирус заразит исходный файл, внесенные им изменения можно просмотреть с помощью утилиты LordPE. Для этого следует открыть в LordPE оригинальный, незаражённый файл, нажав на кнопку «PE Editor», затем нажать кнопку «Compare» и открыть уже заражённый файл. Таким образом можно оценить, какие действия были совершены вирусом, без анализа процедуры заражения.

Сравнение зараженного и чистого файлов

Сравнение зараженного и чистого файлов

В данном случае наблюдаются следующие изменения в структуре файла:

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

Запустив заражённый файл в OllyDbg, мы получим предупреждение о том, что файл может быть упакован, так как точка входа не указывает в секцию кода. Попав на точку входа, видим слегка искажённый код, похожий на код расшифровки.

Код искаженного расшифровщика

Код искаженного расшифровщика

При пошаговом исполнении (F8) становится ясно, что перед нами действительно код расшифровщика. Таким же способом дойдем до того момента, когда циклический переход по адресу 0x00405025 не будет осуществлен, либо поставим аппаратную точку останова на адрес 0x00405027, продолжим выполнение файла (F9) и дождемся остановки.

Остановка на точке останова после цикла расшифровки

Остановка на точке останова после цикла расшифровки

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

Переход на OEP

Переход на OEP

Итак, видно, что после исполнения инструкции retn по адресу 0x0040524A произойдет переход на OEP, так как в стек записана оригинальная точка входа. Похоже на стандартную комбинацию push addr; retn, за тем исключением, что отсутствует инструкция push. Однако, если присмотреться, то по адресу 0x00405242 можно увидеть запись данных из регистра EDX в стек (о чем свидетельствует значение регистра ECX, равное 0x0012FFC0). Еще выше по коду видно, что в EDX данные попадают из памяти по адресу EDI+0Ch и суммируются с данными из памяти по адресу EDI+08h. По-видимому, таким образом происходит вычисление ImageBase и оригинальной точки входа.

Продолжим выполнение до адреса 0x00405237, перезапустив программу (Ctrl-F2).

Остановка на записи в EDX оригинальной точки входа

Остановка на записи в EDX оригинальной точки входа

Так и есть: OEP вычисляется из значения ImageBase, которое хранится по адресу памяти EDI+08h, и значения EntryPoint, которое хранится по адресу EDI+0Ch. Таким образом, адрес точки входа хранится в памяти непосредственно после значения ImageBase.

Если перезапустить программу в отладчике и подождать завершения цикла расшифровки, а затем посмотреть, какие данные хранятся по адресу, где только что была точка входа, то там окажется набор байт, непохожий на EntryPoint. Это значит, что либо по адресу хранения OEP происходит запись из другой точки программы, либо точка входа зашифрована.

Поставим аппаратную точку останова при записи на адрес, где будет храниться точка входа, и продолжим выполнение до остановки.

Остановка при обращении по адресу хранения точки входа

Остановка при обращении по адресу хранения точки входа

Карта памяти с отображением загруженного лишнего модуля

Карта памяти с отображением загруженного лишнего модуля

Остановка произошла в неком модуле pvf1 по адресу 0x008F231E. Если продолжить выполнение до выхода из текущей функции (Ctrl-F9), то после завершения и остановки на инструкции retn по адресу, где предположительно должна появиться точка входа, появляется значение, очень похожее на EntryPoint. Значит, в модуле pvf1 в функции по адресу, где сработала точка останова, и происходит расшифровка.

Для дальнейшего анализа удобнее использовать дизассемблер IDA. Сохранить модуль для анализа можно следующими способами:

Вручную загрузим модуль в IDA (manual load), указав в качестве ImageBase значение 0x008F0000. Перейдя (G) на адрес 0x008F231E и вызвав дополнение Hex-Rays (F5), получим псевдокод на C. Это и есть процедура декодирования точки входа. Трассировка кода процедуры в отладчике показывает, что декодирование происходит в цикле, отображенном на рисунке ниже:

Дизассемблерный листинг цикла декодирования OEP

Дизассемблерный листинг цикла декодирования OEP

В ходе исследования цикла в отладчике можно установить, что точка входа расшифровывается методом XOR. Декодирование происходит с использованием четырех различных ключей длиной по 4 байта. Значения ключей генерируются из двух разных массивов длиной по 8 байт каждый, находящихся по смещениям +28h относительно адреса, где должна храниться ImageBase (первый массив из 8 байт), и +0Сh относительно начала первой таблицы (второй массив из 8 байт).

Адреса и данные таблиц для расшифровки

Адреса и данные таблиц для расшифровки

Подготовка ключей происходит чуть выше процедуры декодирования, в цикле по адресу 0x008F22EE.

Дизассемблерный листинг цикла подготовки ключа

Дизассемблерный листинг цикла подготовки ключа

Псевдокод цикла подготовки ключа

Псевдокод цикла подготовки ключа

Псевдокод функции подготовки ключа

Псевдокод функции подготовки ключа

Помимо вышеописанного, вирус заменяет два первых значения ThunkValue из таблицы импорта для kernel32.dll значениями, указывающими на LoadLibraryA и GetProcAddress.

Адреса памяти, где хранятся оригинальные ThunkValue

Адреса памяти, где хранятся оригинальные ThunkValue

Значение оригинальных ThunkValue вирус прячет по смещениям +1Ch и +20h относительно адреса значения ImageBase.

Подменённые значения для kernel32.dll

Подменённые значения для kernel32.dll

Теперь, когда алгоритм разобран, можно приступить к лечению.

Лечение Win32.Parite.C

Опишем вкратце схему лечения файлов, зараженных вирусом Win32.Parite.C.

  1. Вначале необходимо получить ключ расшифровки OEP. Поскольку в каждом инфицированном файле ключ хранится по разным адресам, запустим программу в режиме отладки и выставим точку останова на точку входа.
  2. Когда сработает точка останова, найдем значение 75h, соответствующее коду инструкции jnz short, и выставим по найденному адресу вторую точку останова.
  3. При каждом срабатывании второй точки останова будем проверять флаг ZF. Если он установлен, то код расшифрован, и можно приступить к поиску необходимых данных.
  4. После расшифровки тела вируса становится возможным просканировать память от точки входа в сторону увеличения адресов, найти значение ImageBase и запомнить его адрес.
  5. Далее, зная адрес значения ImageBase, можно вычислить адреса всех необходимых данных: зашифрованной точки входа, двух таблиц, из которых собирается ключ, и двух значений ThunkValue, «украденных» из таблицы импорта.
  6. Имея все необходимые данные и зная алгоритм шифрования, мы можем расшифровать и восстановить точку входа, исправить импорты и удалить последнюю секцию, тем самым вылечив заражённый файл.
  7. Полный исходный код для процедуры лечения находится в архиве, приложенном к данной статье.
Протокол работы утилиты лечения

Протокол работы утилиты лечения

Список литературы

  1. Offensive Computing. Win32.Parite.B Unpacking and Anatomy Reversing and Network Analysis.
  2. Iczelion. Win32 Assembly Tutorials.

Last updated: 17.03.2012