В этой статье я покажу, как с помощью ути­литы INetSim эму­лиро­вать вза­имо­дей­ствие мал­вари с управля­ющим сер­вером. Так­же рас­смот­рим работу заг­рузчи­ка, рас­паку­ем основную наг­рузку вре­доно­са и иссле­дуем схе­му работы сти­лера.

Мы будем раз­бирать задание UnPackMe Blue Team Lab с пло­щад­ки Cyber Defenders. Уро­вень задания — слож­ный. В лабора­тор­ной работе тебе пот­ребу­ется отве­тить на ряд воп­росов по ито­гам про­хож­дения, одна­ко при­водить отве­ты мы не будем — если ты пов­торишь про­хож­дение, то без тру­да отве­тишь на всё сам.

warning

Ана­лиз вре­донос­ных фай­лов необ­ходимо про­водить в изо­лиро­ван­ной сре­де. О том, как соб­рать лабора­торию для ана­лиза вре­доно­сов, под­робно рас­ска­зано в статье «Код под над­зором. Соз­даем вир­туаль­ную лабора­торию для ана­лиза мал­вари».

 

Используемые утилиты

  1. DIE — прог­рамма для опре­деле­ния типов фай­лов.
  2. PeStudio — прог­рамма для поис­ка арте­фак­тов исполня­емых фай­лов.
  3. IDA Pro — инте­рак­тивный дизас­сем­блер, исполь­зуемый для реверс‑инжи­нирин­га.
  4. Wireshark — инс­тру­мент для ана­лиза сетево­го тра­фика.
  5. Burp Suite — плат­форма, которая исполь­зует­ся в качес­тве проз­рачно­го прок­си‑сер­вера для ана­лиза вза­имо­дей­ствия вре­донос­ного фай­ла по про­токо­лу HTTPS.
  6. x64dbg — опен­сор­сный отладчик для Windows, пред­назна­чен­ный для ана­лиза вре­донос­ных прог­рамм.
  7. INetSim — эму­лятор работы с интерне­том.
 

Первичный анализ

По­лучим пер­вичную информа­цию об иссле­дуемом образце. Заг­рузим файл в DIE и выберем ана­лиза­тор Nauz File Detector.

Информация о файле
Ин­форма­ция о фай­ле

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

Энтропия исполняемого файла
Эн­тро­пия исполня­емо­го фай­ла

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

 

Исследуем загрузчик

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

Псевдокод функции WinMain
Псев­докод фун­кции WinMain

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

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

Шиф­рование сос­тоит из пре­обра­зова­ния клю­ча и опе­рации XOR.

Функция преобразования ключа
Фун­кция пре­обра­зова­ния клю­ча
Функция расшифровки шелл-кода
Фун­кция рас­шифров­ки шелл‑кода

На­чаль­ное зна­чение клю­ча — 0xD5AF2F45. Для рас­шифров­ки шелл‑кода мы раз­работа­ем скрипт для IDA, на вход которо­го переда­дим адрес зашиф­рован­ного шелл‑кода, его раз­мер, началь­ное зна­чение клю­ча и имя фай­ла для сох­ранения дан­ных.

import struct
import idaapi
HIWORD = lambda x: x >> 16
def GenerateKey(key):
key = (key * 0x343fd) & 0xffffffff
key = (key + 0x269ec3) & 0xffffffff
return key
def DecryptShellcode(data,key):
result = bytearray()
for i in data:
key = GenerateKey(key)
k = HIWORD(key) & 0xFF
result.append(i ^ k)
return result
def 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
Фун­кция получе­ния адре­сов 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».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    3 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии