R0 CREW

Malware Analysis Tutorial 2 - Introduction to Ring3 Debugging (Перевод: Prosper-H)

Перейти к содержанию

Цели урока:

  • Освоить отладчик пользовательского уровня (в нашем случае Immunity Debugger).
  • Научиться контролировать поток выполнения программы с помощью средств отладчика (step in, step over, breakpoints).
  • Научиться следить за состоянием программы (регистрами, памятью).
  • Научиться изменять состояние программы (регистры, память).
  • Научиться пользоваться комментариями в Immunity Debugger.

1. Введение

Качественный отладчик имеет большое значение при реверсинге вредоносного программного обеспечения. Существует два типа отладчиков: отладчики уровня пользователя (такие как: OllyDbg, Immunity Debugger, IDA Pro) и отладчики уровня ядра (такие как WinDbg, SoftIce, Syser). Разница между отладчиками уровня пользователя и ядра заключается в том, что последние выполняются с более высокими привилегиями – следовательно, они могут отлаживать работу драйверов и устройств ядра, в то время как отладчики уровня пользователя этого не могут. Хорошо известно, что современная операционная система, такая как Windows полагается на «кольца защиты», которые реализованные в совместимых x86-процессорах (например, Intel CPU), что позволяет обеспечить разграничение доступа между разными по значимости участками кода. Например, на типичном процессоре Intel, программы могут работать в четырех режимах, начиная с Ring0 (режима ядра) и заканчивая Ring3 (режимом пользователя). В нашем случае, мы будем использовать отладчик уровня пользователя «ring3 debuggers».

Может возникнуть естественный вопрос: раз уж отладчики уровня ядра (Ring0) более мощные, чем отладчики уровня пользователя (Ring3), то почему бы просто не использовать отладчики уровня ядра? Ну, Ring0 менее удобны в использовании, чем Ring3, поскольку (вместо всеми привычного GUI-интерфейса) они предлагают использовать командную строку. Ring3 же отладчики обычно поставляются с хорошим GUI-интерфейсом, который может значительно улучшить производительность реверс инженера. Мы будем использовать командную строку Ring0 отладча (в нашем случае это будет WinDbg), только в тех случаях, когда он нам действительно понадобятся. Правда есть одно исключение – недавно, IDA Pro представила модуль GUI-интерфейса, который может управлять ядерным отладчиком WinDbg. Это хорошая фича, но за нее нужно платить.

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

2. Краткое введение в Immunity Debugger

Пришло время произвести краткое знакомство с Immunity Debugger. Если у вас не установлена виртуальная экспериментальная среда, то ознакомьтесь с первым уроком для ее настройки.

Рис. 1. Скриншот IMM

Начнем с обзора интерфейса IMM (Рис. 1), будем двигаться почасовой стрелке, начиная с левого верхнего угла скриншота. Итак, первое, что мы видим – это панель «CPU», которая отображает последовательность машинных инструкций + комментарии пользователя. Затем идет панель «Register» при помощи которой можно наблюдать за значениями регистров, а также модифицировать их. После нее идут панели отображающие «Stack» и «Memory Dump». Прежде чем мы приступим к реверсингу первой секции Max++, было бы неплохо выучить комбинации быстрых клавиш, что позволит более эффективно работать с отладчиком.

Для эффективного использования отладчика нужно знать следующие комбинации клавиш:

  1. Для управления потоком исполнения программы используются следующие сочетания: F8 – обойти процедуру (step over), F7 – войти в процедуру (step in), F9 – продолжить выполнение (continue), Shift+F9 – продолжить выполнение с перехватом исключений (continue and intercept exceptions).
  2. Для манипулирования данными воспользуйтесь следующими действиями: в панели «Memory Dump» – «right click => binary => edit»; в панели «Register» - «right click => edit»
  3. Для установки брэкпойнтов используйте: F2 для установки программных брэкйпонтов; F4 для «выполнения кода до курсора»; действие «right click на инструкции => Breakpoint» и далее выберите установку аппаратных (hardware) брэкпойнтов или брэйкпойнтов на доступ к памяти (memory access point)
  4. Для размещения комментариев используйте клавишу «;»

Большинство из выше перечисленных комбинаций можно найти в меню «Debug» отладчика IMM, однако, всегда полезно помнить и сочетания быстрых клавиш. Теперь перейдем к краткому объяснению некоторых функций (действий), которые очень полезны во время анализа.

2.1 Управление потоком исполнения программы

Действия «step over» и «step in» реализованы одинаково во всех отладчиках. «Step over» (F8) отличается от «step in» (F7) тем, что «step in» заходит внутрь тела функции (т.е. инструкции CALL), в то время как «step over» выполняет всю функцию и останавливается наследующей инструкции после CALL. Стоит заметить, что по «F8» не всегда можно получить ожидаемый результат, поскольку многие вредоносы используют анти-отладочные методы и технику возвратно-ориентированного программирования (return-oriented programming) для того, чтобы перенаправить поток управления программы и выйти из под контроля отладчика, что в свою очередь означает, что вы никогда не достигните инструкции следующей за CALL. Позже мы увидим реализацию подобного примера в Max++.

F9 (continue) часто используется для продолжения выполнения, после остановки на брэйкпойнте. Заметьте, что отладчик автоматически обрабатывает за вас множество исключений. Если хотите перехватывать все исключения, то вы должны использовать «Shift+F9». Позже, мы увидим пример, где Max++ перезаписывает SHE (Structured Exception Handler) в попытке определить наличие отладчика. Для обхода этого анти-отладочного трюка, мы воспользуемся «Shift+F9», чтобы вручную осмотреть код в SEH.

2.2 Манипулирование данными

В общем, у нас есть три типа данных, которыми можно управлять: (1) регистры, (2) стэк и все сегменты (кода, данных и кучи).

Чтобы изменить значение регистра можно нажать «правой кнопкой мыши» (right click) на регистре и выбрать «Edit». Обратите внимание, что в случае, когда регистр содержит указатель на память (адрес ячейки памяти), очень удобно нажать «right click» на нем и выбрать «Follow in Dump» или «Follow in Stack», чтобы посмотреть его значение.

IMM не позволяет напрямую изменять значение регистра EIP в панели «Register». Однако, это можно сделать с использованием командного окна Питона (the Python shell window). Как это сделать? Поиск ответа на этот вопрос мы оставим вам в качестве домашнего задания.

В панели «Memory Dump» выберите какие-либо данные и нажмите «right click» на них и выберите «Binary->Edit».

Вы можете to reset the code (as data). Для этого, в панели «CPU» нажмите правой кнопкой мыши и выберите «Assemble», после чего вы сможете напрямую модифицировать сегмент кода, вводя ассемблерные инструкции! Йо-у! Кроме того, можно даже изменить саму программу (прим. пер. то есть сам файл программы, например, EXE) используя для этих целей замечательную фичу. Например, после модификации сегмента кода, вы можете сохранить измененную программу, используя следующий подход:

  1. «Right click» в панели «CPU»
  2. Выберите «Copy to Executable => All Modifications»
  3. После чего перед вами появится табличка, в котором нужно выбрать «Copy All».
  4. Сразу после этого появится новое окно (со списком модифицированных инструкций), его нужно просто закрыть.
  5. Когда вы будете закрывать его – вас спросят «save the file»? Выберите «yes» и сохраните измененный файл как новый исполнимый файл.

2.3 Breakpoints

Программные брэйкпойнты (F2) являются наиболее популярными. Они похожи на брэйкпойнты используемые при отладке высокоуровневых языков в различных средах программирования (например, Visual Studio). Вы можете устанавливать неограниченное количество брэйкпойнтов (далее «BP», от англ. «Breakpoint»), помимо этого, на эти программные брэйкпойнты, можно устанавливать условия (например, чтобы указать что «BP» должен останавливать программу только тогда, когда значение регистра равно определенному числу).

Программные «BP» реализованы благодаря использованию инструкции INT 3. По сути, когда вы устанавливаете брэйкпойнт, отладчик заменяет первый байт инструкцией INT 3 (которая является однобайтовой) и запоминает старый байт. Каждый раз, когда программа достигает место с установленным брэйкпойнтом – генерируется прерывание, которое вызывает отладчик, чтобы обработать появившееся исключение. Таким образом, отладчик, в момент обработки исключения, может проверить установленное условие и если оно совпадет – остановить программу.

Аппаратные брэйкпойнты могут быть установлены через «панель CPU => right click => Breakpoints => Hardware, on execution». Так же обратите внимание, что доступно еще два типа аппаратных «BP» (memory read, memory access). Как и следует из названия, аппаратные «BP» реализуются за счет использования аппаратного обеспечения. У процессоров Intel имеется четыре регистра, отвечающие за аппаратные «BP», в которые собственно и записывается их место размещения.

Аппаратные BP очень полезны в те моменты, когда нужно узнать, какая часть кода изменяет интересующую вас переменную. Для этого нужно просто установить «BP» на «memory access» вместо того, чтобы тщательно изучать исходный код в поисках участка кода ее модифицирующего.

2.4 Пользовательские комментарии

Не смотря на то, что пользовательские комментарии кажутся тривиальной вещью – это очень важная функция во время реверсинга. Использование кнопки «;», в панели «CPU», позволяет добавить пользовательский комментарий, а использование кнопки «:» позволяет добавить «label» для машинной инструкции. Позже, когда будет выполнена инструкция, которая была промаркированная функцией «label», отобразится соответствующий ей текст маркера.

3. Вопросы дня

Пришло время засучить рукава и закрепить всю ранее полученную теорию на практике! Сегодняшняя задача состоит в анализе фрагмента кода, начиная с 0x413BC8 до 0x413BD8 (Рис. 1). Дайте ответы на вопросы ниже.

Q1. Чему равно значение EAX по адресу 0x413BD5 (до выполнения «int 2d»)?
Q2. Будет ли выполнена инструкция «RET» по адресу 0x413BD7?
Q3. Если вы измените значение EAX на 0 (по адресу 0x413BD5), то повлияет ли это как-то на «Q2»?
Q4. Можете ли вы изменить значение EIP по адресу 0x413BD5 так, чтобы инструкция int 2d была пропущена?
Q5. Измените инструкцию int 2d на «NOP» (пустая команда) и сохраните файл как «max2.exe». Выполните max2.exe. Наблюдаете ли вы какие-либо различия в поведении зловреда? (повторите «Урок 1 Malware Analysis Tutorial - A Reverse Engineering Approach (Lesson 1: VM Based Analysis Platform)», чтобы понаблюдать за сетевой активностью)

© Translated by Prosper-H from r0 Crew

Hide

Q1: EAX = 1
Q2: В дебаггере нет
Q3: Да, выполнится RET, так как следующий байт (собсно RET) за int 20 не будет пропущен
Q4: Установить в EIP адресс RET
Q5: Вобще не было никакой сетевой активности при попытка запуска max2.exe . Хотя сетевая активность была во время дебага, когда я достиг иснтрукции int 2d (но её ещё не выполнил). Хоть она и отличалась от той, что в уроке 1. Уже забыл, но запрос содержал что-то об immunity_debuger.py и о каких-то баннерах, так что возможно эти запросы шли не с вируса, а с самого дебаггера, может какая-то часть рекламы, в имьюнити вроде есть какие-то баннеры, скорее всего эти запросы их и обновили.

Верно?

Одно но, я не совсем понял, как перепрыгивается байт в дебаг режиме. int 2d, как сказано на сайте оригинала статьи, заставляет программу пропустить следующий байт за этой инструкцией, вызывая эксепшин. Сейчас не все ссылки с оригинала статьи доступны, как раз пример высокоуровневого кода подобной ситуации отсутствует. Может дадите пример, или немного более детальный алгоритм того почему так происходит? ОТРЕДАКТИРОВАНО: Сорри, оказывается это тема следующего урока, ещё не вникал, но только что начал и там вроде это разжовывается. Но всё-равно, если будет какой-то доп пример, я не обижусь =)