Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
В этой статье я покажу, как с помощью утилиты INetSim эмулировать взаимодействие малвари с управляющим сервером. Также рассмотрим работу загрузчика, распакуем основную нагрузку вредоноса и исследуем схему работы стилера.
Мы будем разбирать задание UnPackMe Blue Team Lab с площадки Cyber Defenders. Уровень задания — сложный. В лабораторной работе тебе потребуется ответить на ряд вопросов по итогам прохождения, однако приводить ответы мы не будем — если ты повторишь прохождение, то без труда ответишь на всё сам.
warning
Анализ вредоносных файлов необходимо проводить в изолированной среде. О том, как собрать лабораторию для анализа вредоносов, подробно рассказано в статье «Код под надзором. Создаем виртуальную лабораторию для анализа малвари».
Получим первичную информацию об исследуемом образце. Загрузим файл в DIE и выберем анализатор Nauz File Detector.

Информация о файле
Исследуемый образец собран для 32-разрядных систем, разработан на языке C/C++ и скомпилирован в Microsoft Visual Studio. Получим энтропию исполняемого файла по секциям. Перейдем на вкладку Entropy и определим его показатель.

Энтропия исполняемого файла
Энтропия исследуемого файла — 7,389, в секции .text — самое высокое значение. Значит, исследуемый файл упакован.
Загрузим файл в IDA и приступим к анализу. Точка входа указывает на функцию WinMain, а основной поток выполнения реализован в функции sub_468480.

Псевдокод функции WinMain
Перейдем в данную функцию двойным нажатием и декомпилируем, нажав F5.

В функции WrapGlobalAlloc реализовано получение адреса GlobalAlloc и выделение в куче памяти, равной длине шелл‑кода. Далее в функции WrapVirtualProtect выделенному участку памяти назначаются права на выполнение, чтение и запись (PAGE_EXECUTE_READWRITE) с помощью функции VirtualProtect. Следующим этапом начинается процесс расшифровки шелл‑кода.
Шифрование состоит из преобразования ключа и операции XOR.

Функция преобразования ключа

Функция расшифровки шелл‑кода
Начальное значение ключа — 0xD5AF2F45. Для расшифровки шелл‑кода мы разработаем скрипт для IDA, на вход которого передадим адрес зашифрованного шелл‑кода, его размер, начальное значение ключа и имя файла для сохранения данных.
import structimport idaapiHIWORD = lambda x: x >> 16def GenerateKey(key): key = (key * 0x343fd) & 0xffffffff key = (key + 0x269ec3) & 0xffffffff return keydef DecryptShellcode(data,key): result = bytearray() for i in data: key = GenerateKey(key) k = HIWORD(key) & 0xFF result.append(i ^ k) return resultdef main(start,size,key,filename): w = open(filename,'wb') b = bytearray() for i in range(size): x = idaapi.get_byte(start + i) b.append(x) d = DecryptStage(b,key) w.write(d) w.close()
Расшифровывать будем в режиме отладки. Поставим точку останова на функции WrapDecryptShellcode (горячая клавиша F2) и запустим отладку (F9). Двойным нажатием на переменную shellcode получим адрес исполняемого кода, а его размер узнаем из переменной size_shellcode.
Загрузим разработанный скрипт, для этого зайдем на вкладку File → Script File. В командной строке Python вызовем функцию main.
main(start=0x7B96E8,size=0x4e9d3,key=0xD5AF2F45,filename='stage01')
Мы получили значение расшифрованного исполняемого кода. Загрузим его в IDA и проведем статический анализ. Полученный шелл‑код состоит из функций получения адресов используемых WinAPI и расшифровки основной нагрузки.

Функция получения адресов Windows API
Преобразуем декомпилируемый код в читаемый вид. Для этого выберем переменную a1, кликнем правой кнопкой мыши и выберем пункт Create Struct. IDA сформирует структуру. Далее переименовываем каждое значение поля (горячая клавиша N).
Для получения функций WinAPI LoadLibraryA и GetProcAddress из библиотеки kernel32.dll используется хеширование. Из поля InMemoryOrderModuleList структуры PEB процесса считываются имена динамических библиотек. Из каждого имени вычисляется значение хеша и сравнивается со значением 0xd4e88. Такая же процедура производится с именами функций экспорта найденной динамической библиотеки.
Алгоритм хеширования представлен ниже.
def ApiHashing(name_func,hashing): res = 0 for i in name_func: v5 = (ord(i) | 0x60) & 0xff res = (res + v5) * 2 if res == hashing: return True return False
Значение 0xd4e88 соответствует kernel32.dll.

Функция расшифровки основной нагрузки
Процесс получения основной нагрузки состоит из этапов расшифровки и разархивирования.

Процесс расшифровки и разархивирования
Алгоритм расшифровки тот же, а вот алгоритм декомпрессии сильно обфусцирован и содержит множество переходов (goto). Распакуем нашу нагрузку. Для этого в режиме отладки переходим к выполнению шелл‑кода и находим функцию DecryptUnpackShellcode. Далее спускаемся к выполнению функции Unpack, переходим на вкладку Hex View (клавиша G) и вводим адрес, который хранится в переменной data. Размер получаем из значения переменной unpack_size.
Дампим полученный после разархивирования шелл‑код с помощью IDA API. Для этого переходим в командную оболочку Python и вводим следующую команду:
idc.savefile('path_filename', 0, address_shellcode, unpack_size)
Мы получили основную нагрузку, она представляет собой шелл‑код, задача которого — загрузить методом Process Hollowing исполняемый файл и начать выполнение с его точки входа. Загрузим полученный файл в Hex-редактор, скопируем данные, начиная с сигнатуры MZ, и приступим к его анализу.

Содержимое основной нагрузки
На этом этапе мы с тобой распаковали основную нагрузку, которая представляет собой исполняемый файл. Работа загрузчика разделена на несколько этапов: сначала расшифровывается исполняемый код, основная задача которого — расшифровать и распаковать шелл‑код следующего этапа. Шелл‑код следующего этапа загружает в память исполняемый файл и продолжает выполнение с его точки входа.

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

Информация об основной нагрузке
Источник: xakep.ru