ПРОЕКТИРОВАНИЕ МЕТОДИКИ ОБУЧЕНИЯ ОСНОВАМ
ВИРУСНОГО АНАЛИЗА В.Д. Стремоухов, А.В. Клейменов, А.А. Калашникова Научный руководитель - д.т.н., профессор Л.Г. Осовецкий
В статье рассмотрены основные принципы формирования учебного курса по анализу объектов исполняемого кода на предмет вредоносного функционала на примере методики, разработанной на кафедре БИТ.
Введение
Несмотря на то, что вирусные аналитики, как правило, составляют большую часть штата любой антивирусной компании, часто актуальной является задача обучения основам анализа подозрительных объектов сотрудников АВ-компаний, не связанных напрямую с техническими аспектами исследования вредоносного кода (ведущих аналитиков, маркетологов и т.п.). На нашей кафедре существует антивирусная лаборатория, занимающаяся, в частности, подготовкой описаний вредоносного кода для АВ-компаний, для которой задача начального обучения вирусного аналитика стоит так же остро. В связи с этим по инициативе компании «Лаборатория Касперского» на нашей кафедре был разработан курс «Анализ подозрительных объектов на предмет вредоносного функционала».
Постановка задачи
Задача - создать курс (т.е. методическое пособие + необходимое ПО) для самостоятельного изучения методов вирусного анализа. Целевая аудитория - продвинутые пользователи ПК, имеющие представление о устройстве ОС и ее исполняемых файлов, однако не знакомые с теоретическими основами низкоуровнего программирования и методами реверсивной инженерии.
Основной целью курса является обучение методам определения вредоносности подозрительного объекта. Предполагается, что читатель в достаточной мере обладает навыками работы с ПК и базовыми знаниями об устройстве ОС Windows и исполняемых файлов под эту ОС. В курсе предполагается описать приемы работы с рядом специализированных утилит, в частности с дизассемблером. Однако от читателя не требуется каких-либо специализированных знаний, в том числе знаний языка ассемблера -все необходимые сведения читатель получит в процессе изучения методического пособия.
Следует отметить, что авторы курса не ставили перед собой цели научить читателя подробному анализу объекта с выяснением в точности всего функционала - это задача для технически подготовленного вирусного аналитика (обладающего фундаментальными навыками программирования, дизассемблирования и отладки, знаниями языка ассемблера). Будут показаны лишь способы выяснения функционала в первом приближении. Следует также отметить, что эти методы не дают полной уверенности в обнаружении искомого функционала при его наличии в силу ряда причин, которые будут указаны позднее.
Рассматриваемые типы ВК
В настоящее время ОС семейства Windows являются наиболее распространенными, а потому основной поток вредоносного кода рассчитан именно на работу в этой среде. Это вполне логично, так как основная цель создателей вредоносного кода - извлечение прибыли различными способами, такими как кража, модификация или унич-
тожение ценной информации, вывод из строя информационных ресурсов «вражеской» компании. Кроме того, косвенным следствием распространенности ОС Windows является то, что зачастую с ней работают малоподготовленные в техническом плане люди, неспособные вовремя обнаружить факт заражения компьютера вредоносным кодом, что еще более облегчает работу вирусописателю.
Исходя из сказанного, авторами пособия было принято решение ограничиться рассмотрением исполняемых файлов Win32 (32-разрядных ОС семейства Windows), так как в ином случае пришлось бы рассматривать вопросы устройства альтернативных ОС, их исполняемых файлов и т.п. Кроме того, в пособии кратко будет рассмотрены файлы командного интерпретатора (.bat).
Структура методического пособия
Наиболее логичным является, на наш взгляд, построение методического пособия на основе обобщенного алгоритма анализа win32-сэмпла, который выглядит примерно следующим образом:
1. проверка валидности PE,
2. распаковка (если требуется),
3. динамический анализ,
4. статический анализ,
5. исследование в отладчике.
Сразу хотелось бы отметить, что данный алгоритм является неким обобщенным шаблоном, и в зависимости от ситуации те или иные шаги могут не выполняться (как правило, для выяснения функционала несложного сэмпла достаточно одного-двух методов). Именно поэтому, если какие-то последующие главы пособия будут читателю непонятны (курс рассчитан на читателей с разным уровнем технической подготовки), предполагается возможность их пропустить и вернуться к ним, когда за плечами уже будет какой-то опыт анализа исполняемых файлов. Также следует отметить, что метод исследования сэмпла в отладчике в основной части данного пособия рассматриваться не будет, вследствие его сложности и необходимости определенной технической базы (в частности, хорошего знания языка ассемблера), однако ему будет посвящено одно из приложений. Остальным же методам будут посвящены главы основной части методического пособия, после чего, в приложении будут даны несколько примеров полного разбора типовых сэмплов.
Первичный анализ сэмпла
В данной главе будут рассмотрены методы получения начальных сведений об изучаемом объекте и подготовка его к последующим стадиям анализа.
На начальном этапе анализа сэмпла необходимо выяснить несколько важных сведений о нем, а именно:
• является ли он вообще PE-файлом (PE, portable executable - стандарт исполняемых файлов, являющийся на текущий момент основным для win32-систем. Характеризуется наличием PE-заголовка, в котором, в частности, содержатся различные данные о структуре исполняемого файла);
• язык написания и компилятор, использовавшийся при сборке исполняемого файла (если это возможно установить);
• упаковщик/протектор, которым был упакован исполняемый файл, если упаковка производилась.
С большинством этих задач в автоматическом/полуавтоматическом режиме успешно справляются ряд специализированных утилит, работа с которыми рассматривается в данной главе.
Распаковка упакованного файла
Для начала - несколько слов об упаковщиках и протекторах. Принцип работы данных утилит довольно прост: код упаковываемого исполняемого файла обрабатывается определенным алгоритмом («упаковывается»), далее создается новый исполняемый файл, в котором содержится обработанный код исходного файла и код функции-распаковщика. Сначала управление передается на функцию-распаковщик, задача которой - привести код исходного файла к изначальному состоянию, после чего управление передается на так называемую оригинальную точку входа (первую инструкцию оригинального исполняемого файла). Различие между упаковщиками и протекторами - лишь в целях, преследуемых теми и другими: если упаковщики созданы для уменьшения размеров исполняемых файлов, то протекторы созданы для усложнения исследования кода исполняемого файла посредством дизассемблирования.
При исследовании запакованного исполняемого файла его часто распаковывают. Под распаковкой понимают получение оригинального файла (т.е. в таком же виде, в каком он был до упаковки) из запакованного.
Процесс так называемой «ручной распаковки», т. е. распаковки без использования специализированных утилит, довольно сложен и потому рассматриваться здесь не будет. В ознакомительных целях укажем лишь, что он включает 3 основные стадии:
1) поиск так называемых OEP (Original Entry Point - оригинальная точка входа) - наи-
более сложная стадия, часто требующая умения логически мыслить и импровизировать. Остальные стадии, как правило, - чисто технические;
2) снятие дампа (образа процесса из оперативной памяти);
3) восстановление таблицы импорта.
Вместе с тем для большинства известных упаковщиков/протекторов имеются утилиты для автоматической распаковки - распаковщики и депротекторы. Здесь следует отметить, что, прежде чем приступить к распаковке, следует сначала определиться, а нужна ли она вообще? К примеру, если вы собираетесь исследовать сэмпл в дизассемблере и/или отладчике, то, конечно, распаковка необходима, в ином случае к сэмплу как правило, относятся как к некоему «черному ящику», а, значит, и его распаковка малоцелесообразна.
Статический анализ
В данной главе рассматриваются основные принципы статического анализа, а также дается ряд теоретических сведений, необходимых при СА.
Понятие статического анализа. Условия, при которых он имеет смысл. В данном пособии под понятием «статический анализ» подразумевается исследование сэмпла в дизассемблере (вообще, понятие статического анализа более широко, так как для некоторых типов исполняемых файлов дизассемблер бессилен, в этом случае на помощь приходят другие утилиты, например, декомпиляторы, однако данная тема выходит за рамки этого методического пособия).
Рассмотрим условия, при которых имеет смысл статический анализ. В общем случае можно выделить 2 наиболее важных условия.
1. Native-code. Целый ряд современных языков программирования (ex.: VisualBasic, отчасти .Net-семейство, или Java, практически полностью реализовавшая концепцию, заложенную в Oberon от не унимающегося Н. Вирта) реализуют так называемый «виртуальный процессор». Суть концепции в следующем: формируется виртуальный язык программирования низкого уровня со своим набором инструкций и/или API, отличным от ассемблера («виртуальный ассемблер»), под который будут компилироваться программы на одном из языков высокого уровня. Далее, под каждую из необходимых платформ (т.е., по сути, ОС) пишется виртуальная машина (ex.: .NET framework, Java-machine) , транслирующая «на лету» - в процессе выполнения программы - «вир-
туальные» инструкции в реальные. Языки программирования, отличные от вышеописанных (т.е. напрямую компилируемые в машинный код), называют также native-языками. Очевидно, что исследование в обыкновенном дизассемблере чего-либо, кроме native-кода, бесполезно.
2. Необходимость такого анализа. Как правило, динамический анализ довольно трудоемок и требует больших затрат по времени, а потому его целесообразно проводить, если другие методы результата не дали, либо критично выявление именно всего функционала.
Необходимые знания о языке ассемблера и устройстве PE-файла. Не вдаваясь в технические и исторические подробности, сразу следует отметить, что основным форматом исполняемых файлов в ОС семейства win32 является формат PE (portable executable). Общее устройство PE-файла показано в табл. 1.
DOS "MZ''-заголовок (IMAGE_DOS_HEADER)
Файловый заголовок (IMAGE_FILE_HEADER) Опциональный заголовок (IMAGE_OPTIONAL_HEADER) PE-заголовок (IMAGE_NT_ HEADERS)
Таблица секций (IMAGE SECTION HEADER)
.text
.data С CD
.bss Я a
.edata s s
.idata
Таблица 1. Структура PE-файла
Основная информация о структуре файла содержится в PE-заголовке и таблице секций. Секции - это «тело» программы. Каждая секция имеет свое назначение. Как правило (хотя и не обязательно), в секции ".text" находится код программы, в секции ".data" - инициализированные данные и т.д. В момент запуска исполняемого файла его содержимое подгружается в оперативную память и управление передается на точку входа, указанную в PE-заголовке.
Взаимодействие программы с ее «внешней средой» (операционной системой) происходит через вызов API-функций. API - основной интерфейс ОС к исполняемой программе; любое действие, которое позволено в системе исполняемой программе, реализуется через последовательный вызов определенных API-функций. Достаточно полные описания API-функций можно найти в Microsoft Developer Network (MSDN). Информация об API-функциях, к которым программа будет обращаться в процессе своей работы (импортируемых API-функциях), содержится в секции импорта (чаще всего .idata) PE-файла.
Авторы пособия не ставили перед собой цели предоставить полный обзор основ языка ассемблера или научить читателя на нем программировать. Мы хотим показать, что можно выяснить о функционале исполняемого файла, исходя из поверхностного изучения дизассемблерного листинга. Общий вид ассемблерной инструкции:
команда [операнд[,операнд2...]] [; комментарии]
Инструкции разделяются переносом на следующую строку (на каждой строке - только одна инструкция). Естественно, комментарии при ассемблировании исходного кода отбрасываются, однако большинство дизассемблеров пишут в комментариях различные пояснения, облегчающие анализ листинга.
Следует отметить, что существует ряд проблем, препятствующих корректному дизассемблированию исполняемого файла, вследствие чего, в частности, повторно ассемблированный дизассемблерный листинг уже не будет работать, как исходный исполняемый файл (если вообще ассемблируется удачно). Кроме того, при использовании определенных приемов программирования можно добиться того, что большая часть ди-зассемблерного листинга вообще будет представлять из себя «мусор» (неверно отдизас-семблированный код). В этом случае некоторые (так называемые «интерактивные») дизассемблеры предлагают аналитику возможность «подсказать» правильный ход дизас-семблирования, однако это требует от аналитика несколько больших познаний в ассемблере, чем предполагает данное методическое пособие. Поэтому, если вы предполагаете, что дизассемблерный листинг исследуемого сэмпла представляет собой «мусор» (основные признаки - малоосмысленный код, отсутствие вызовов АР1-функций в листинге сэмпла, который по другим признакам активно взаимодействует с ОС), от статического анализа лучше отказаться.
Динамический анализ
Динамический анализ - это метод исследования сэмпла, при котором последний запускается «под присмотром» различного рода следящих программ. Такие программы могут осуществлять слежение за исследуемым процессом в режиме «реального времени» либо анализировать 2 состояния системы - до и после запуска сэмпла.
У динамического анализа есть ряд преимуществ: быстрота анализа, невысокие требования к теоретической подготовке аналитика. Основным недостатком динамического анализа является риск невыяснения части функционала сэмпла, если поведение последнего зависит от параметров «внешней среды» (к примеру, версии ОС, системного времени и т. п.) либо в сэмпле реализованы приемы, противостоящие динамическому анализу.
Заключение
В рамках проекта разработан курс, включающий в себя методическое пособие и специальное ПО, упрощающее процесс вирусного анализа, в частности, экспертную систему соответствия подозрительных последовательностей вызовов АР1-функций определенным типам вредоносного функционала. В курсе представлены основные методы анализа сэмпла на предмет вредоносного функционала. Хотелось бы отметить несколько общих моментов.
Во-первых, если Вы хотите всерьез заниматься анализом исполняемых файлов, Вы в первую очередь должны понять, что в данном процессе не существует шаблонов. Все представленные алгоритмы - лишь примерные. Очень редко можно сказать «если Вы проделали то-то и получили то-то, то сэмпл относится к такому-то типу вредоносного кода». Одни и те же действия могут быть совершенно обыкновенным функционалом, а могут быть вредоносными. Не существует «вредоносных» АР1-функций - одна и та же функция может быть использована как в легальных, так и во вредоносных целях. При анализе необходимо подключать логику.
Во-вторых, авторы курса не ставили перед собой цели рассказать читателю всю теорию по каждому рассматриваемому вопросу, обучить работе с каждой упоминаемой утилитой, привести большое количество справок и спецификаций. Как известно, лучший способ получения данных знаний - практический опыт. Приступая к анализу, следует запастись справочниками и терпением. Если Вы видите, что сэмпл, к примеру, модифицирует
тот или иной системный файл или ключ реестра, имеет смысл посмотреть в Интернете назначение этого файла/ключа - это поможет Вам сделать заключение о цели, которую преследовал программист. При статическом анализе (особенно небольших сэмплов) необходимо читать в MSDN назначение ВСЕХ неизвестных API-функций - со временем Вы научитесь отделять «важные» вызовы от тех, которые можно пропустить. Если Вы собираетесь использовать статический анализ, имеет смысл постепенно изучать основы языка ассемблера.
Литература
1. Касперский Е. Вирусы и средства борьбы с ними - М., 2005.
2. Крис Касперски. Образ мышления - дизассемблер IDA - М.: СОЛОН-Р, 2001.
3. Крис Касперски. Техника сетевых атак. - М.: СОЛОН-Р, 2001.
4. Хакер. Спец-выпуск [anti]cracking. - 2005. - №57.