• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Глубокий анализ Mars Stealer

yashechka

Генератор контента.Фанат Ильфака и Рикардо Нарвахи
Эксперт
Регистрация
24.11.2012
Сообщения
2 344
Реакции
3 563
Введение

Mars Stealer — улучшенная копия Oski Stealer. Недавно я видел много твитов об этом, поэтому решил написать анализ новой версии V8. Наслаждайся чтением!

Отличия от предыдущей версии:

1. Техника антианализа

2. Различные алгоритмы шифрования

3. Представлена новая техника защиты от отладки

4. Новый формат конфигурации

5. Внешние dll находятся в одном zip-архиве

Обзор

1657313824460.png


Антианализ

Открыв marssteler в ida, мы можем увидеть прием антианализа под названием Opaque Predicates. Это широко используемый метод запутывания программ, предназначенный для усложнения потока управления.

Эта обфускация просто берет абсолютный переход (JMP) и преобразует его в два условных перехода (JZ/JNZ). В зависимости от значения флага Zero (ZF) выполнение будет следовать по первой или второй ветви.

Однако дизассемблеры спотыкаются, думая, что существует сквозная ветвь, если второй прыжок не выполнен (что невозможно, поскольку должен быть выполнен один из них), и пытаются дизассемблировать недостижимые инструкции (часто недействительные), что приводит к мусорному коду.

1657313840002.png


Деобфускация проста, нам просто нужно исправить первый условный переход на абсолютный переход и исключить второй переход, мы можем использовать IDAPython для достижения этого:

Python:
import idc

ea = 0
while True:
    ea =  min(ida_search.find_binary(ea,idc.BADADDR, "74 ? 75 ?",16 ,idc.SEARCH_NEXT | idc.SEARCH_DOWN),  # JZ / JNZ
    ida_search.find_binary(ea,idc.BADADDR, "75 ? 74 ?",16, idc.SEARCH_NEXT | idc.SEARCH_DOWN))  # JNZ / JZ
    if ea == idc.BADADDR:
        break
    idc.patch_byte(ea, 0xEB)
    idc.patch_byte(ea+2, 0x90)
    idc.patch_byte(ea+3, 0x90)
    idc.patch_byte(ea+4, 0x90)

После запуска скрипта

1657313876684.png


Теперь мы можем видеть четкий вид, после реверса и переименования

1657313885534.png


Сначала Mars получает дескриптор kernel32.dll, анализируя InLoadOrderModuleList, затем он передает дескриптор функции, которая перебирает экспортированные функции DLL, чтобы получить адрес функций LocalAlloc() и VirtualProtect().

1657313895893.png


Строковое шифрование

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

1657313905755.png


1657313913778.png


Однако мы можем видеть, что функция xor используется в другой функции, которую я переименовал в Decrypt_String_2, если вредоносное ПО проходит проверки, которые, как мы скоро увидим, расшифровывают те строки, которые содержат строки, необходимые вредоносному ПО для кражи конфиденциальных данных.

1657313922835.png


Мы используем скрипт idapython, чтобы получить эти строки и переименовать переменные, чтобы упростить реверс.

1657313933564.png



Python:
import string

def sanitize_string(name):
        return "".join([c for c in name if c in string.ascii_letters])[:20].capitalize()

def X0r(key, data, length):
    res = ""
    for i in range(length):
        res += chr(key[i] ^ data[i])
    return res


start_Addrs = [0x00401770,0x00401990  ]
end_Addrs = [0x00401967,0x0405444 ]

string_list = []
dectypred_data = b''
addrs = []

for i in range(len(start_Addrs)):
    ea = start_Addrs[i]
    end = end_Addrs[i]

    while ea <= end:
        if idc.get_operand_type(ea, 0) == idc.o_imm:
            addrs.append((idc.get_operand_value(ea, 0)))

        if len(addrs) == 3:
            length = addrs[0]
            data = idc.get_bytes(addrs[1], length)
            key = idc.get_bytes(addrs[2], length)
            dectypred_data = X0r(key, data, length)
            string_list.append(dectypred_data)
            addrs = []

        if idc.print_insn_mnem(ea) == "call":
            idc.set_cmt(ea, dectypred_data, 1)

        if idc.print_insn_mnem(ea) == "mov" and (idc.get_operand_type(ea, 0) == idc.o_mem) and (
                idc.get_operand_type(ea, 1) == idc.o_reg):
            global_var = idc.get_operand_value(ea, 0)
            idc.set_name(global_var, "Str" + sanitize_string(dectypred_data), SN_NOWARN)

        ea = idc.next_head(ea, end)

Вот список расшифрованных строк:

1657313965374.png


Динамическое связывание

Адрес GetProcAddress() и LoadLibraryA() извлекается тем же методом в Dynamic_Linking_1, перебирая экспортированные функции kernel32.DLL, затем используется LoadLibraryA() для загрузки указанного модуля в адресное пространство и получения дескриптора, который получает передается в GetProcAddress() для получения адреса экспортируемой функции из указанной библиотеки динамической компоновки.

Dynamic_Linking_2 загружает API-интерфейсы, необходимые только для выполнения некоторых проверок, если он пройдет, он загрузит другие, необходимые для кражи функций.

1657313975433.png


dword_42774 — это GetProcAddress(), он вызывается в другой функции Dynamic_Linking_3, которая будет загружать другие API, необходимые для кражи функциональности.

1657313984993.png


Мы используем idapython для переименования глобальных переменных с именем API, чтобы упростить реверс.

1657313993827.png


Python:
import idc

start_Addrs = [0x00415F86,0x00415FC0 ,0x004161A0 ]
end_Addrs = [0x00415FB7,0x00416176,0x00417034]

string_list = []

for i in range(len(start_Addrs)):
    ea = start_Addrs[i]
    end = end_Addrs[i]

    while ea <= end:

        if (idc.print_insn_mnem(ea) == "push"  )and (idc.get_operand_type(ea, 0) == idc.o_imm):
            name = idc.get_strlit_contents(idc.get_operand_value(ea, 0)).decode()

        if (idc.print_insn_mnem(ea) == "mov"  and (idc.get_operand_type(ea, 0) == idc.o_reg)and (idc.get_operand_type(ea, 1) == idc.o_mem)) :
            temp_name = idc.get_name(idc.get_operand_value(ea, 1))
            if "Str_" == temp_name[0:4]:
                name = temp_name[4::]

        if (idc.print_insn_mnem(ea) == "mov") and (idc.get_operand_type(ea, 0) == idc.o_mem) and (idc.get_operand_type(ea, 1) == idc.o_reg):
            global_var = idc.get_operand_value(ea, 0)
            idc.set_name(global_var, name, SN_NOWARN)

        ea = idc.next_head(ea, end)

Анти-песочница

Многие песочницы перехватывают и обходят Sleep(), предотвращая бездействие вредоносных программ во время их выполнения. Сначала вредоносная программа вызывает функцию GetTickCount(), которая извлекает количество миллисекунд, прошедших с момента запуска системы, до 49,7 дней, то есть нашу первую метку времени. Затем вызывает Sleep() для приостановки на 16 секунд. Вызов GetTickCount() снова получает нашу вторую метку времени. Вредоносное ПО проверяет, есть ли разница между двумя временными метками не менее 12 секунд. Если функция возвращает flase, это означает, что Sleep() не был пропущен, вредоносное ПО предполагает, что оно запущено в песочнице, и немедленно завершает работу.

1657314021574.png


Anti-CIS

Это один из простых способов проверить, не заражены ли вредоносным ПО пользователи из определенных стран.

1657314033989.png


Mars проверяет язык пользователя, чтобы определить, является ли он частью страны Содружества Независимых Государств (СНГ), получает идентификатор языка пользователя с помощью GetUserDefaultLangID и сравнивает идентификатор языка пользователя с:

1657314041836.png



Если идентификатор языка пользователя совпадает с одним из приведенных выше идентификаторов, он завершится.

Антиэмуляция

Если вредоносное ПО запущено с именем компьютера HAL9TH и именем пользователя JohnDoe, оно завершится. Эта проверка выполняется, потому что это имя, данное эмулятору Защитника Windows. Этот метод используется вредоносными программами, чтобы предотвратить их запуск в эмулируемой среде.

1657314053863.png


Мьютекс

Вредоносное ПО создает объект мьютекса с помощью CreateMutexA(), чтобы избежать запуска более одного экземпляра. Затем вызывает GetLastError(), который получает последнюю ошибку, и если код ошибки равен 183 (ERROR_ALREADY_EXIST), это означает, что мьютекс уже существует и экземпляр вредоносного ПО уже запущен, поэтому вредоносное ПО завершает работу.

1657314062061.png


Анти-отладка

Вредоносное ПО создает поток, который проверяет флаг BeingDebugged, который является специальным флагом в системных таблицах, который находится в памяти процесса и который устанавливает операционная система, может использоваться для указания того, что процесс отлаживается. Состояния этих флагов можно проверить либо с помощью определенных функций API, либо изучив системные таблицы в памяти. Если вредоносное ПО отлаживается, оно завершается. Поток будет продолжать работать до тех пор, пока вредоносное ПО не завершит выполнение или поток не завершит выполнение вредоносного ПО, если его отлаживают.

1657314071987.png


Проверка срока действия

Переменная Срок действия содержит дату 26.04.2022 20:00:00.

Mars использует GetSystemTime() для получения текущей системной даты и времени в виде структуры SYSTEMTIME, а затем вызывает sscanf() для преобразования даты истечения срока действия в структуру SYSTEMTIME. SystemTimeToFileTime() принимает структуру SYSTEMTIME в качестве аргумента, затем преобразует ее во время файла и дату истечения срока действия, хотя преобразуется во время файла.

Если текущее время превышает время истечения срока действия, вредоносная программа вызывает ExitProcess() для немедленного выхода.

1657314084263.png


Основная функциональность

1657314093828.png


Марс генерирует случайную строку, которая будет именем zip-файла, содержащего украденные данные.

Связь между c2 и вредоносным ПО описывается как:

1. отправляется запрос GET на URL-адрес C2 в конечной точке /RyC66VfSGP.php, чтобы получить его конфигурацию.

2. извлекаюся все библиотеки DLL в конечной точке /request, библиотеки заархивированы.

3. украденные данные отправляются на C2 по тому же URL-адресу, который использовался на шаге 1.

Извлеченные DLL:

1657314118494.png


Еще одно отличие от последней версии заключается в том, что sqlite3 не записывается на диск, он просто анализируется и передается другой функции, чтобы получить дескриптор и начать загрузку необходимой функции, другие dll записываются.

1657314126492.png


Поскольку C2 не работал, я получил pcap из песочницы Hatching (https://tria.ge/220406-k1kttacaf2) .

1657314139538.png


1657314150329.png


Понимание формата конфигурации

Конфигурация закодирована в base64

MXwxfDF8MXwxfDVxRGxQdVZLb1J8RGlzY29yZHwwfCVBUFBEQVRBJVxkaXNjb3JkXExvY2FsIFN0b3JhZ2VcfCp8MXwwfDB8VGVsZWdyYW1 8MHwlQVBQREFUQSVcVGVsZWdyYW0gRGVza3RvcFx0ZGF0YVx8KkQ4NzdGNzgzRDVEM0VGOEMqLCptYXAqLCpjb25maWdzKnwxfDB8MHw=


1|1|1|1|1|5qDlPuVKoR|Discord|0|%APPDATA%\discord\Local Storage\ |*|1|0|0|Telegram|0|%APPDATA%\Telegram Desktop\tdata\ |*D877F783D5D3EF8C*,*map*,*configs*|1|0|0|

Первая часть

1657314179120.png


Вторая часть

1657314191571.png


Граббер

Давайте покопаемся в функции Config_Grabber, чтобы увидеть, как она работает

После получения конфига мы видим, что в нем много | поэтому он разделил конфигурацию с помощью разделителя |. Первая часть включает / отключает некоторые функции стилера, затем начинается вторая часть, которая начинает захват нужных файлов.

Как пример

[‘Discord’, ‘0’, ‘%APPDATA%\discord\Local Storage\’, ‘*’, ‘1’, ‘0’, ‘0’]

Он начинает рекурсивно захватывать все файлы в discord\\Local Storage\\ под %APPDATA% и помещать их в discord.zip

1657314209687.png


1657314219609.png


Если существует более одного регулярного выражения, как в

[‘Telegram’, ‘0’, ‘%APPDATA%\Telegram Desktop\tdata\’, ‘D877F783D5D3EF8C,map,configs’, ‘1’, ‘0’, ‘0’]

он перебирает их и вызывает Recursive_Grabber для каждого регулярного выражения.

1657314231450.png


Браузеры

Mars крадет учетные данные из браузеров по статическим путям. Он имеет четыре различных метода кражи данных из разных типов браузеров, таких как браузеры на основе Gecko, Opera, Internet Explorer и браузеры на основе Chromium.

1657314242398.png


1657314249766.png


1657314259020.png


1657314267187.png


Извлечение данных

Все функции извлечения имеют одинаковую схему:

1. Вредонос сохраняет адреса функций из sqlite3.dll
  • sqlite3_open
  • sqlite3_prepare_v2
  • sqlite3_step
  • sqlite3_column_bytes
  • sqlite3_column_blob
  • sqlite3_column_text
  • sqlite3_column_finalize
  • sqlite3_column_close

2. Генерирует случайную строку (длиной 8 символов) и копирует файл БД во временную папку с именем случайной строки — все методы извлечения будут в скопированной БД. Чтобы извлечь данные из БД, вредоносная программа должна создать SQL-запрос и запросить БД с помощью функций sqlite3.dll.

3. Вредоносная программа открывает БД с помощью sqlite3_open и передает путь к БД.

4. Он вызывает sqlite3_prepare_v2, функция получает дескриптор БД и SQL-запроса и возвращает дескриптор оператора.

5. Используя sqlite3_column_bytes/sqlite3_column_blob/sqlite3_column_text, вредоносное ПО может получить результаты запросов

6. Учетные данные в БД браузеров на базе Chromium шифруются DPAPI, поэтому вредоносное ПО использует функцию CryptUnprotectData для расшифровки учетных данных.

Mars крадет информацию из хранилища Windows, которое является хранилищем по умолчанию для информации диспетчера учетных данных. Это делается с помощью Vaultcli.dll, который инкапсулирует необходимые функции для доступа к хранилищу. Вредонос просматривает свои элементы, используя:

* VaultEnumerateVaults

* VaultOpenVault

* VaultEnumerateItems

* VaultGetItem

* VaultFree

Целевые файлы БД


1657314310223.png


Используемые запросы

1657314322547.png


Криптовалютные кошельки через расширения браузера

Похоже, что Mars также нацелен на дополнительные расширения браузера для Chrome, связанные с двухфакторной аутентификацией (2FA).

1657314333949.png


Марс ворует файлы из 3-х папок:

  1. \Local Extension Settings\Extension ID from Google Store
  2. \Sync Extension Settings\ Extension ID from Google Store
  3. \IndexedDB\Domain Name.indexeddb.leveldb

Например, если жертва использует Google Chrome с расширением кошелька криптобраузера, файлы расширения будут храниться в:

C:\Users\Username\AppData\Local\Google\Chrome\User Data\Default\Local Extension Settings\Extension ID from Google Store C:\Users\Username\AppData\Local\Google\Chrome\User Data\Default\Sync Extension Settings\ Extension ID from Google Store C:\Users\Username\AppData\Local\Google\Chrome\User Data\Default\IndexedDB\Domain Name.indexeddb.leveldb


CryptoTronLinkibnejdfjmmkpcnlpebklmnkoeoihofec
CryptoMetaMasknkbihfbeogaeaoehlefnkodbefgpgknn
CryptoBinance Chain Walletfhbohimaelbohpjbbldcngcnapndodjp
CryptoYoroiffnbelfdoeiohenkjibnmadjiehjhajb
CryptoNifty Walletjbdaocneiiinmjbjlgalhcelgbejmnid
CryptoMath Walletafbcbjpbpfadlkmhmclhkeeodmamcflc
CryptoCoinbase Wallethnfanknocfeofbddgcijnmhnfnkdnaad
CryptoGuardahpglfhgfnhbgpjdenjgmdgoeiappafln
CryptoEQUAL Walletblnieiiffboillknjnepogjhkgnoapac
CryptoJaxx Libertycjelfplplebdjjenllpjcblmjkfcffne
CryptoBitApp Walletfihkakfobkmkjojpchpfgcmhfjnmnfpi
CryptoiWalletkncchdigobghenbbaddojjnnaogfppfj
CryptoWombatamkmjjmmflddogmhpjloimipbofnfjih
CryptoMEW CXnlbmnnijcnlegkjjpcfjclmcfggfefdm
CryptoGuildWalletnanjmdknhkinifnkgdcggcfnhdaammmj
CryptoSaturn Walletnkddgncdjgjfcddamfgcmfnlhccnimig
CryptoRonin Walletfnjhmkhhmkbjkkabndcnnogagogbneec
CryptoNeoLinecphhlgmgameodnhkjdmkpanlelnlohao
CryptoClover Walletnhnkbkgjikgcigadomkphalanndcapjk
CryptoLiquality Walletkpfopkelmapcoipemfendmdcghnegimn
CryptoTerra Stationaiifbnbfobpmeekipheeijimdpnlpgpp
CryptoKeplrdmkamcknogkgcdfhhbddcghachkejeap
CryptoSolletfhmfendgdocmcbmfikdcogofphimnkno
CryptoAuro Walletcnmamaachppnkjgnildpdmkaakejnhae
CryptoPolymesh Walletjojhfeoedkpkglbfimdfabpdfjaoolaf
CryptoICONexflpiciilemghbmfalicajoolhkkenfel
CryptoNabox Walletnknhiehlklippafakaeklbeglecifhad
CryptoKHChcflpincpppdclinealmandijcmnkbgn
CryptoTempleookjlbkiijinhpmnjffcofjonbfbgaoc
CryptoTezBoxmnfifefkajgofkcjkemidiaecocnkjeh
CryptoCyano Walletdkdedlpgdmmkkfjabffeganieamfklkm
CryptoByonenlgbhdfgdhgbiamfdfmbikcdghidoadd
CryptoOneKeyinfeboajgfhgbjpjbeppbkgnabfdkdaf
CryptoLeafWalletcihmoadaighcejopammfbmddcmdekcje
CryptoDAppPlaylodccjjbdhfakaekdiahmedfbieldgik
CryptoBitClipijmpgkjfkbfhoebgogflfebnmejmfbml
CryptoSteem Keychainlkcjlnjfpbikmcmbachjpdbijejflpcm
CryptoNash Extensiononofpnbbkehpmmoabgpcpmigafmmnjhl
CryptoHycon Lite Clientbcopgchhojmggmffilplmbdicgaihlkp
CryptoZilPayklnaejjgbibmhlephnhpmaofohgkpgkd
CryptoCoin98 Walletaeachknmefphepccionboohckonoeemg
2FAAuthenticatorbhghoamapcdpbohphigoooaddinpkbai
2FAAuthygaedmjdfmmahhbjefcbgaolhhanlaolb
2FAEOS Authenticatoroeljdldpnmdbchonielidgobddffflal
2FAGAuth Authenticatorilgcnhelpchnceeipipijaljkblbcobl
2FATrezor Password Managerimloifkgjagghnncjkhggdhalmcnfklk

Криптовалютные кошельки

Mars не ограничивается только таргетингом на криптовалюты с помощью расширений браузера. Многие люди предпочитают не использовать сторонние приложения и сервисы для хранения своей цифровой валюты. Марс просматривает различные папки в поисках определенных файлов, связанных с криптовалютой.

Первый параметр определяет путь: если 0, то он находится в %appdata%, если 1 — в %localappdata%, то он ищет другие кошельки с регулярным выражением *wallet*.dat в %appdata%

1657314396162.png


У Mars есть специальные функции для работы со следующими криптокошельками.

1657314409385.png


Системная информация

Вредоносная программа захватывает системную информацию и сохраняет ее в файле system.txt.

1. IP и страна

2. Рабочий путь к EXE-файлу

3. Местное время и часовой пояс

4. Языковая система

5. Языковая раскладка клавиатуры

6. Ноутбук или рабочий стол

7. Модель процессора

8. Имя компьютера

9. Имя пользователя

10. Доменное имя компьютера

11. Идентификатор машины

12. GUID

13. Установленные программы и их версии

Марс делает снимок экрана, а затем добавляет все украденные файлы в zip-файл, который он будет эксфильтровать обратно в c2 и получать конфигурацию загрузчика.

Загрузчик

Вредоносное ПО получает конфигурацию загрузчика в ответ после эксфильтрации данных. Эта конфигурация выглядит следующим образом: download_URL|Имя переменной среды и имя папки |параметр_запуска| .

После обработки конфигурации Mars вызывает функцию download_file() с URL-адресом и путем, в котором файл будет сохранен. Затем вызывает ShellExecuteExA() для выполнения исполняемого файла с заданными параметрами, полученными из конфигурации.

1657314438691.png


1657314447175.png


Самостоятельное удаление

Вредоносная программа получает путь к себе с помощью GetModuleFileName() и вызывает ShellExecuteExA(), которая выполняет следующую команду

"C:/Windows/System32/cmd.exe" /c timeout /t 5 & del /f / path_To_file & exit

Через 5 секунд исполняемый файл будет удален.

1657314468722.png


Обобщенный скрипт idapython с использованием шаблонов

Python:
import idautils , idc, idaapi, ida_search, ida_bytes, ida_auto
import string



seg_mapping = {idaapi.getseg(x).name: (idaapi.getseg(x).start_ea, idaapi.getseg(x).end_ea) for x in
                   idautils.Segments()}
start = seg_mapping[0x1][0]
end = seg_mapping[0x1][1]
   
def sanitize_string(name):
    return "".join([c for c in name if c in string.ascii_letters])[:20].capitalize()

def Xor(key, data, length):
    res = ""
    for i in range(length):
        res += chr(key[i] ^ data[i])
    return res

def getData (addr):
    key_addr = idc.prev_head(addr)
    data_addr = idc.prev_head(key_addr)
    key_length_addr = idc.prev_head(data_addr)
    length = idc.get_operand_value(key_length_addr, 0)
    key = idc.get_bytes(idc.get_operand_value(key_addr,0),length)
    data =  idc.get_bytes(idc.get_operand_value(data_addr,0),length)
    return  key , data ,length


def rename_APIs(ea,end):
   
    func_addr = ea
    for i in range(20):
        if (idc.print_insn_mnem(ea) == "push"  )and (idc.get_operand_type(ea, 0) == idc.o_imm):
            name = idc.get_strlit_contents(idc.get_operand_value(ea, 0)).decode()
            break
       
        if (idc.print_insn_mnem(ea) == "mov"  and (idc.get_operand_type(ea, 0) == idc.o_reg)and (idc.get_operand_type(ea, 1) == idc.o_mem)) :
            temp_name = idc.get_name(idc.get_operand_value(ea, 1))
            if "Str_" == temp_name[0:4]:
                name = temp_name[4::]
                break      
        ea =  idc.prev_head(ea)
       
    ea = func_addr
   
    for i in range(20):
        if (idc.print_insn_mnem(ea) == "mov") and (idc.get_operand_type(ea, 0) == idc.o_mem) and (idc.get_operand_type(ea, 1) == idc.o_reg):
                global_var = idc.get_operand_value(ea, 0)
                idc.set_name(global_var, name, SN_NOWARN)
                return name        
        ea = idc.next_head(ea, end)


def API_resolve(start,end):
    Loadlibrarya_addr = 0x0
    GetProcAddress_pattern = "8B 55 ?? 52 8B 45 ?? 8B 4D ??  8B 55 ?? 03 14 ?? 52 E8 ?? ?? ?? ?? 83 C4 ??  85 C0 75 ??"
    GetProcAddress_addr = ida_search.find_binary(start, end, GetProcAddress_pattern, 16, idc.SEARCH_DOWN)
    GetProcAddress_addr = idaapi.get_func(GetProcAddress_addr).start_ea
    print('[*] Traget fucntion found at {}'.format(hex(GetProcAddress_addr)))

    for ref in idautils.XrefsTo(GetProcAddress_addr):
        addr = ref.frm
        x = rename_APIs(addr, end)
        if "Loadlibrarya" in x:
                Loadlibrarya_addr = idc.get_operand_value(idc.next_head(idc.next_head(addr, end), end), 0)


    new_GetProcAddress_addr = idc.get_operand_value(idc.next_head(idc.next_head(addr, end), end), 0)
   
    for ref in idautils.XrefsTo(new_GetProcAddress_addr):
        addr = ref.frm
        rename_APIs(addr, end)

    for ref in idautils.XrefsTo(Loadlibrarya_addr):
        addr = ref.frm
        rename_APIs(addr, end)

       
def Strings_resolve(start,end):
    xor_pattern = "8b 4d ?? 03 4d ?? 0f be 19 8b 55 ?? 52 e8 ?? ?? ?? ?? 83 c4 ?? 8b c8 8b 45 ?? 33 d2 f7 f1 8b 45 ?? 0f be 0c 10 33 d9 8b 55 ?? 03 55 ?? 88 1a eb be"
    xor_fun_addr = ida_search.find_binary(start, end, xor_pattern, 16, idc.SEARCH_DOWN)
    xor_fun_addr = idaapi.get_func(xor_fun_addr).start_ea
    print('[*] Traget fucntion found at {}'.format(hex(xor_fun_addr)))

    for ref in idautils.XrefsTo(xor_fun_addr):
        addr = ref.frm
        key, data, length = getData(addr)
        decrypt_string = Xor(key, data, length)
        idc.set_cmt(addr, decrypt_string, 1)
        ea = idc.next_head(idc.next_head(addr, end),end)
        global_var = idc.get_operand_value(ea, 0)
        idc.set_name(global_var, "Str_" + sanitize_string(decrypt_string), SN_NOWARN)
       
def Anit_Reverse():
    ea = 0
    while True:
        ea = min(ida_search.find_binary(ea, idc.BADADDR, "74 ? 75 ?", 16, idc.SEARCH_NEXT | idc.SEARCH_DOWN),
                 # JZ / JNZ
                 ida_search.find_binary(ea, idc.BADADDR, "75 ? 74 ?", 16,
                                        idc.SEARCH_NEXT | idc.SEARCH_DOWN))  # JNZ / JZ
        if ea == idc.BADADDR:
            break
        idc.patch_byte(ea, 0xEB)
        idc.patch_byte(ea + 2, 0x90)
        idc.patch_byte(ea + 3, 0x90)
        idc.patch_byte(ea + 4, 0x90)



def main():
    Anit_Reverse()
    Strings_resolve(start,end)
    API_resolve(start,end)

main()

для получения дополнительных сценариев Idapython проверьте мой репозиторий. (https://github.com/X-Junior/Malware-IDAPython-Scripts/)

IOCs​


  • Хэши:
    1. md5 : 880924E5583978C615DD03FF89648093
    2. sha1 : EF759F6ECA63D6B05A7B6E395DF3571C9703278B
    3. sha256 : 4bcff4386ce8fadce358ef0dbe90f8d5aa7b4c7aec93fca2e605ca2cbc52218b
    4. imphash : 4E06C011D59529BFF8E1F1C88254B928
    5. ssdeep : 3072:U/E8k9fjpIg+zNch12KbAwSaSMtmSu4/bVBt4b8EG:U/E8k9bwz6/tJc/4xM8EG
  • Мьютексы: 92550737836278980100
  • Файлы:
    1. C:\ProgramData\freebl3.dll
    2. C:\ProgramData\mozglue.dll
    3. C:\ProgramData\msvcp140.dll
    4. C:\ProgramData\nss3.dll
    5. C:\ProgramData\softokn3.dll
    6. C:\ProgramData\vcruntime140.dll
  • C2 сервер: 194.87.218.39
  • C2 домены:
    1. http://194.87.218.39/request
    2. http://194.87.218.39/RyC66VfSGP.php

YARA

rule Mars_Stealer: Mars Stealer
{
meta:
Author = "X__Junior"
Description = "Mars Stealer v8 Detection"

strings:
$xor ={8b 4d ?? 03 4d ?? 0f be 19 8b 55 ?? 52 e8 ?? ?? ?? ?? 83 c4 ?? 8b c8 8b 45 ?? 33 d2 f7 f1 8b 45 ?? 0f be 0c 10 33 d9 8b 55 ?? 03 55 ?? 88 1a eb be}
$debug = {64 A1 30 00 00 00 80 78 02 00}
$thread_func = {B8 01 00 00 00 85 ?? 74 ?? E8 ?? ?? ?? ?? 85 ?? 74 ?? 6A 00 FF ?? ?? ?? ?? ?? 6A ?? FF ?? ?? ?? ?? ?? EB ??}

$api1 = "LocalAlloc" ascii
$api2 = "VirtualProtect" ascii
$api3 = "SetFileTime" ascii
$api4 = "LocalFileTimeToFileTime" ascii
$api5 = "HeapFree" ascii
$api6 = "VirtualFree" ascii
$api7 = "VirtualAlloc" ascii

$s1 = "DPAPI" ascii
$s2 = "memset" ascii
$s3 = "msvcrt.dll" ascii
$s4 = "_mbsnbcpy" ascii
$s5 = "_mbsstr" ascii

condition:
uint16(0) == 0x5A4D and 2 of($api*) and 3 of($s*) and $debug and $xor and $thread_func

}

Вывод

Последний образец mars, который я видел, был упакован со специальным упаковщиком, его легко распаковать с помощью x32dbg, просто установив точку останова на VirtualAlloc(), больше ничего не менялось, кроме C2.

Использованная литература

Отличный анализ предыдущей версии https://3xp0rt.com/posts/mars-stealer


Переведено специально для xss.pro
Автор перевода: yashechka
Источник: https://x-junior.github.io/malware analysis/2022/05/19/MarsStealer.html
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх