Уроки форензики. Изучаем поведение стилера при помощи INetSim и IDA Pro

Содержание статьи

  • Используемые утилиты
  • Первичный анализ
  • Исследуем загрузчик
  • Исследуем основную нагрузку
  • Взаимодействие с управляющим сервером
  • Сбор информации о системе
  • Выводы

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

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

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

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

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

По­лучим пер­вичную информа­цию об иссле­дуемом образце. Заг­рузим файл в 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.

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

Фун­кция рас­шифров­ки шелл‑кода

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.

Ин­форма­ция об основной наг­рузке

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *