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