R0 CREW

Malware Analysis Tutorial 5: Int 2D in Max++ (Part III) - (Перевод: Prosper-H)

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

Цели урока:

  1. Применить техники, представленные в Уроках 3 и 4 для анализа анти-отладочного трюка Max++.
  2. Поупражняться в реверсинге приложений на x86 платформе.

Задача дня:

  1. Написать кусок кода на Python, для Immunity Debugger, который исполнит Max++ и сгенерирует Log для каждого вызова инструкции INT 2D.

1. Введение

Примечание: мы предполагаем, что вы будете запускать виртуальную машину в режиме NON-DEBUG. В этом уроке мы будем использовать Immunity Debugger.

Давайте вернемся к Max++ и применим знания, полученные из Уроков 3 и 4. На рис. 1 представлено дизассемблированное представление первых 20 инструкция Max++. Точка входа расположена по адресу 0x00403BC8. Пошагово выполните код до адреса 0x403BD5, там вы столкнетесь с первой задачей: Как обойти инструкцию INT 2D?

Есть несколько вариантов: (1) Просто нажать F8 и IMM ПРОПУСТИТ (SKIP) инструкцию RETN и перейдет прямо на адрес 0x413BD8 (выполняя инструкцию CALL 0x413BD8, которая находится сразу после инструкции RETN); (2) Либо выполнить инструкцию RETN, изменив значение регистра EIP. В IMM можно изменить значение EIP с помощью командного окна Python (нажмите на 2-ю кнопку в toolbar, с права от кнопки «open file») в котором нужно выполнить следующую команду Python:

«imm.setReg("EIP", 0x00413BD7);»

Рис. 1. Точка входа в Max++

Какое из действий будет зависеть от поведения IMM? Если мы нажмем F8, то будет ли его поведение тем же, что и у программы без присоединенного отладчика? Или нет? Следуя аналогичному подходу из Урока 4, можно произвести эксперимент для случая, когда EAX = 1 (т.е. вызвать из INT 2D сервис «Debug print»). Ниже дан вывод, сделанный после проведения эксперимента:

Когда загрузка операционной системы производится в режиме NON-DEBUG, поведение IMM будет точно таким же, как и вовремя обычного исполнения, при EAX = 1 (обратите внимание, что в Уроке 4, в нашем эксперименте рассматривался случай с EAX = 0). Исходя из этого, можно [B]спокойно нажать F8 (и пропустить инструкцию RETN) в IMM![/B]

2. Отклонение потока управления инструкцией INT 2D

Сейчас мы находимся по адресу 0x00413A38 (Рис. 2). Эта функция состоит всего из четырех инструкций: STD, MOV EDI, EDI, CALL 0x00413BB4 и IRETD.

Цель инструкции STD состоит в том, чтобы установить направление роста EDI (т.е. флаг направления, direction flag, df) в 1. Регистры EDI/ESI часто используются с инструкциями копирования памяти, такими как «REP STOSB» (для многократного копирования из памяти, адрес которой указан в ESI, в адрес назначения, указанный в EDI). Позже мы увидим использование этих инструкций в операциях кодирования/декодирования злонамеренного кода в Max++.

Инструкция «MOV EDI, EDI» ничего не делает (и не воздействует ни на какие флаги регистров). После нее идет вызов функции из адреса 0x00413BB4.

Обратите внимание, что как только мы вернемся из функции 0x00413BB4, следующей инструкцией для выполнения будет (IRETD), однако, это не так. Функция 0x00413BB4 получит участок зашифрованного кода, расшифрует и поместит его, начиная от места размещения инструкции IRETD. Таким образом, если инструмент статического анализа произведет анализ данной программы, т.е. отобразит графит потока исполнения Max++, то он введет в заблуждение аналитиков малвари. Мы вернемся к функции декодирования в следующем уроке.

Рис. 2. Функция 0x413A38

Нажмите «F7», чтобы войти внутрь функции 0x00413BB4. Тут мы подходим к интересной точке. Посмотрите на инструкцию CALL 0x00413BB9 по адресу 0x413BB4 (Рис. 3)!

В основном, инструкция CALL делает две вещи: (1) помещает адрес следующей инструкции в стэк (так, что когда мы возвратимся из функции, выполнение возобновится со следующей инструкции); если вы понаблюдаете за содержимым стэка (в IMM это нижняя правая панель), то заметите, что в него помещается 0x413BB9. (2) Затем она переходит на адрес функции, который равен 0x00413BB9.

Следующие две инструкции должны вызвать сервис INT 2D. Заметьте, что EAX = 3 (означая сервис «Load image»). И снова, используя тот же подход из Урока 4, можно придумать эксперимент, чтобы ответить на вопрос: «каким будет следующее действие?». Проведя эксперимент, вывод будет следующим: когда EAX = 3, при режиме NON-DEBUG, поведение IMM будет таким же, как и при нормальном выполнении, а именно: одно-байтовая инструкция, следующая сразу за инструкцией INT 2D, будет пропущена.

А что, если инструкция RETN выполнится (т.е. однобайтовая инструкция не будет пропущена, предположим, что автоматический анализатор не правильно обрабатывает INT 2D)? Если это произойдет, то вы начнете выходить из раннее вызванных функций, что в свою очередь, приведет к завершению программы. Этот трюк заключается в следующем: напомним, что RETN снимает верхний элемент из стэка и переходит на этот адрес. Верхний элемент стэка сейчас равен 0x00413BB9. Поэтому, произойдет возврат выполнения, обратно к адресу 0x00413BB9. Затем снова выполнится INT 2D и снова инструкцию RETN заставят выполниться и перейти на адрес 0x00413A40 (где расположена инструкция IRETD, которая идет сразу после CALL 0X00413BB4 в функции 0x00413A38, см. Рис. 2.). Что в свою очередь приведет к возврату в main program и завершит саму программу. Таким образом, какие-либо другие вредоносные действия не будут выполняться в этом сценарии. К этому моменту, вы уже можете видеть цель трюка с INT 2D: автор вредоноса пытается избежать инструментов автоматического анализа (если они не правильно обрабатывают INT 2D) и некоторые отладчики ядра, такие как WinDbg.

Вопрос дня: воспользуйтесь WinDbg, вместо Immunity Debugger, для отладки Max++ (c режимом DEBUG, включенным при загрузке). Что вы наблюдаете?

Рис. 3. Трюк: бесконечный цикл вызовов

3. Заключение

Мы показали вам несколько примеров использования инструкции INT 2D в Max++, которые позволяют определить наличие отладчика и изменить поведение вредоносной программы, чтобы избежать анализ с помощью отладчика. Отладчику, автоматически справиться с инструкцией INT 2D, будет не легко. Во-первых, существует множество сценариев для борьбы с ним (зависит от типа отладчика, наличия отладчика ядра, и (booting options) опций загрузки). Во-вторых, во время загрузки программы, не ожидайте перехвата всех инструкций INT 2D, потому что программа может быть самораспаковывающейся (т.е. модифицирующей свой сегмент кода, во время выполнения).

4. Задача дня

Вам будет полезно написать Python-скрипт для управления Immunity Debugger, который будет автоматически справляться с инструкцией INT 2D. Ниже мы предлагаем несколько основных идей для решения этой задачи:

В IMM, есть глобальная переменна «imm», которая предназначена для того, чтобы управлять отладчиком. Можно использовать «imm» для установки и наблюдения за всеми значениями регистров, а так же для осмотра и изменения памяти (RAM). В вашей программе может быть использован простой цикл, который мог бы выполнять инструкцию за инструкцией (чтобы сделать это, вы можете использовать «breakpoint functions», доступные в Python API отладчика IMM). Перед выполнением каждой инструкции, можно было бы проверить ее опкод (используя «libanalyze.opcode», см. документацию IMM), и затем предпринять соответствующие действия (пропуская следующий байт, основываясь на значение регистра EAX, имитируя нормальную NON-DEBUG среду), если встретилась инструкция INT 2D.

© Translated by Prosper-H from r0 Crew

Что-то у меня не то. Похоже IMM воспринимает код как данные. Как исправить?

[URL=http://savepic.net/4244966.htm]

[/URL]

P.S. Не могу прикрепить скриншот средствами форума, проблема с правами?

Походу отладчик не нашёл связей с другим кодом, поэтому анализатор его и не зацепил. Выделите кусок кода который нужно проанализировать и в контекстном меню тыкните чтото вроде Analysis -> Remove analysis from selection

Урок 10 (Подраздел “Подготовка”): Если вы видите много инструкций DB, то выберите их и нажмите «right click => Analysis => During next analysis, treat selection as => Command».

Разрешённые типы файлов: 7z doc pdf rar txt zip

Правильно ли я понял, что после выполнения int 2d по адресу 0x00413b5 (как при его отсутствии отладчика, так и при его присутствии) пропускается следующая однобайтовая инструкция RETN и происходит вызов функции по адресу 0x0041a38? Если да, то зачем это нужно? Только лишь чтобы запутать анализатор кода?

Правильно.

Да, конкретно в данном примере, чтобы запутать статический/динамический анализатор или человека.

Дебри интернетов пишут:

На экспериментах в предыдущем уроке у меня было так, что если EAX не был установлен в 0 перед INT 2D, то F8 перепрыгивало на 2 байта, вместо одного. Значит в нашем случае:

Прерывание 0x413BD5: без дебаггера прыгнет на 0x413BD8, а с дебаггером по F8 прыгнет на 0x413BDD. Может быть такое, что автор статьи ошибся, и тогда коммент к 0x413BD8 неверный и это вызов какой-то нужной функции для вируса, а не обманка?

Перед вызовом прерывания по адресу 0x413BD5, зайди внутрь функции 0x413A38 и поставь там брейкпойнт.

У автора все верно. В случае отладки INT 2D перепрыгивает черз один байт и выполняет CALL, который зацикливает программу.
А вот скриншот из предыдущего урока:

В этом случае INT 2D перепрыгивает через 2 инструкции на адресс 40120D. Так в чем разница?

Не может оно так прыгать, ставь брейкпойнт на CMP EAX, 2

Точно, спасибо. F8 просто не показывало выполнение комманды, а с бряком всё же остановилось на CMP EAX, 2

Из мануала не совсем ясно , эта тема с int 2d работает во всех версиях windows ? И во всех ли работает одинаково ?