Rust окончательно закрепился в роли главного инструмента для усложнения жизни вирусным аналитикам. Недавно мы столкнулись подтверждением этого тренда: сильно обфусцированным образцом, который при первичном осмотре выглядел как сложная новая вредоносная программа, написанная с нуля на Rust.
По характерным признакам мы выявили, что это был знакомый SantaStealer, но слабо верилось, что автор всего за один-два месяца смог полностью его переписать на Rust и настолько тяжело обфусцировать. Да и сама изначальная логика быстрой работы стилера при таком подходе просто ломалась.
Реальность оказалась проще: саму малварь никто не переписывал, злоумышленники просто собрали вокруг нее многослойный «бутерброд»:
Ядро — классический SantaStealer, заточенный исключительно под быструю кражу данных.
Обертка — промежуточная DLL на Rust, маскирующая сигнатуры стилера.
Защита — сжатие растовой библиотеки алгоритмом LZMA и финальная упаковка под коммерческий виртуализатор Oreans CodeVirtualizer.
Этот случай наглядно иллюстрирует динамику последних лет. Переход малвари на нетипичные компилируемые языки (Rust, Go) наметился еще в районе 2023 года, когда уход от традиционного C/C++ только начинали обсуждать на Reddit и в профильных блогах.
Сегодня это мейнстрим. Операторы RansomExx в свое время переписали вымогатель на Rust ради обхода сигнатурных детектов, а авторы бэкдора SysJoker и вовсе свернули кодовые базы на C++ и Go в пользу единого растового билда. Масштаб этой тенденции стал настолько заметным, что этой теме сегодня все чаще посвящают отдельные статьи и аналитические материалы.
💡 Причина такой популярности проста. Злоумышленникам не нужна хваленая безопасность памяти (в малвари повсеместно используют unsafe) и редко критична производительность. Главная цель — намеренное разрушение статического анализа:
1️⃣ Статическая линковка: стандартные библиотеки и рантайм языка намертво зашиваются в бинарник, раздувая его до десятков мегабайт.
2️⃣ Каша в дизассемблере: развитая система типов, сложные абстракции и специфичная обработка паник превращают граф вызовов в IDA Pro или Ghidra в трудночитаемое полотно.
3️⃣ Низкий порог входа: благодаря генеративным нейросетям и публичным шаблонам на GitHub даже начинающим операторам достаточно пары запросов, чтобы собрать рабочий растовый лоадер, завернуть в него чужой стилер и натянуть готовый протектор.
Однако Rust и виртуализация бессильны перед динамикой. Как бы глубоко ни прятали логику, процессу все равно нужно взаимодействовать с системой: выделять память, обращаться к файлам браузеров и слать данные на C2. В рантайме такая переусложненная цепочка мгновенно триггерит EDR и песочницы характерными вызовами и другой аномальной активностью.
✅ Как понять, что на реверс Rust-бинарника не стоит тратить время:
1️⃣ В песочнице видны маркеры распаковщика/инжектора. К примеру, если процесс использует VirtualAlloc/NtAllocateVirtualMemory с правами RWX, пишет данные и создает поток — это обычный стейджер. Распутывать растовую инициализацию бессмысленно.
В данном случае удобна утилита API Monitor, особенно если полезная нагрузка инжектится через WriteProcessMemory, поскольку программа может сразу перехватить записываемый буфер.
2️⃣ Полезную нагрузку можно забрать из памяти. Снять чистый дамп процесса (через брейкпоинты, pe-sieve, HollowsHunter) получится только в том случае, если под виртуализатором спрятан дроппер, раскручивающий пейлоад в память. Если виртуализирован сам стиллер, сдампить исходный исполняемый код не выйдет — тут придется разбирать байткод ВМ. В нашем случае под защитой был лишь лоадер.
3️⃣ Сетевые и файловые IoC уже зафиксированы. Если инфраструктура C2, извлекаемые пути и ключи реестра перехвачены в динамике, глубокий реверс растовой обертки может не дать ничего нового.
Разбирать растовый код до последнего опкода имеет смысл только тогда, когда в него зашита уникальная логика или виртуализирован сам вредоносный функционал. Если же Rust выступает просто упакованным лоадером чужого софта, динамика экономит десятки часов работы.