
Восстанавливает то, что скрывает обфускация в бинарниках Rust (строки, крейты, библиотечные функции, сплющенный поток управления), с помощью статического анализа и эмуляции Unicorn, без их запуска. Для триажа вредоносного ПО, аудита защищённых приложений. ELF/PE/Mach-O, x86-64/ARM64/32-bit.
strings не видит ничего. FLOSS не видит ничего. rust-deobf видит C2.
rust-deobf восстанавливает то, что скрывают обфусцированные Rust-бинарники — адреса C2, пути к файлам, мьютексы, ключи реестра, конфигурацию — так и не запустив образец.
Демо · Использование из AI-агента · Быстрый старт · Результаты · Реальный вредоносный код · Ограничения
Скомпилированная Rust-программа без символов, собранная так, как поставляется вредоносное ПО (opt-level="z", fat LTO, panic=abort), с восемью индикаторами, зашифрованными с помощью obfstr — строки находятся в структуре, ветках match, сравнениях и ветке, которая никогда не выполняется. Ни одна из них никогда не выводится.
Создано из захваченного вывода реального запуска (Linux x86-64, rustc 1.97): текст дословный, цвета и анимация набора добавлены, ~8-секундное ожидание эмуляции ускорено, а вывод обрезан до декодированных строк. Приведённый ниже вывод в виде простого текста — тот же самый запуск.
Что показывает вам файл:
$ B=build/scatter_obfstr__elf__size-lto__strip
$ strings $B | grep -ciE 'northwind|10\.66|NW-5c1e9a|skip-update'
0
Что восстанавливает rust-deobf (статический анализ + эмуляция Unicorn; бинарный файл никогда не выполняется):
$ python3 scripts/recover.py $B
binary: scatter_obfstr__elf__size-lto__strip format=ELF arch=x86_64
static x86-64 (recover_callsite): 0 strings decoders=9 seconds=0.2
emulation (recover_emulate): 8 strings functions=416/416 timed_out=False workers=1 seconds=6.8
== decoded strings ==
10.66.12.7:8443 [ip]
function 0xf20c (emulation)
C:\ProgramData\NorthwindSvc\state.db [path]
function 0xf20c (emulation)
Mozilla/5.0 (Windows NT 10.0; Win64; x64) NorthwindAgent/2.1
function 0xf20c (emulation)
--skip-update-check
function 0xf443 (emulation)
Software\Northwind\Agent\Settings [registry]
function 0xf51b (emulation)
Global\NW-5c1e9a [mutex]
function 0xf5a8 (emulation)
https://telemetry.northwind.example/api/v3/beacon [url]
function 0xfd58 (emulation)
nw-agent::stage=collect
function 0xfd58 (emulation)
8/8 менее чем за 10 секунд, каждая строка помечена тегом и прослежена до функции, которая её создаёт.
Воспроизведите это с помощью ONLY=scatter_obfstr PROFILES=size-lto FORMATS=elf bash scripts/build_all.sh
(вывод обрезан до декодированных строк). (Входные данные — это безобидная бенчмарк-программа;
каждая внедрённая строка перечислена в bench_src/manifest.json.)
Малварь на Rust растёт, а инструменты для её деобфускации фактически отсутствуют. FLOSS — стандартный открытый деобфускатор строк — ничего не восстанавливает из распространённых крейтов обфускации Rust:
| обфускатор | strings | FLOSS | rust-deobf |
|---|---|---|---|
| litcrypt / litcrypt2 | 0/5 | 0/5 | 5/5 |
| obfstr (встроенный XOR+ADD) | 0/5 | 0/5 | 5/5 |
| cryptify (ключ по умолчанию) | 0/5 | 0/5 | 5/5 |
| muddy (ChaCha20-Poly1305 AEAD) | 0/5 | 0/5 | 5/5 |
| компактные строки в стеке | 0/5 | 0/5 | 5/5 |
| самописные XOR / ADD / SUB | 0/5 | 0/5 | 5/5 |
Канареечный бенчмарк, релизные сборки, ELF и PE x86-64 и AArch64, со stripped и без. Полная таблица, включая единственный случай, требующий динамического восстановления (cryptify с пользовательским ключом), приведена в разделе Результаты.
На реальных образцах: EDDIESTEALER (PE) — 32 обфусцированные строки, включая скрытый домен C2 и URL-путь, где статические инструменты и FLOSS восстанавливают 0. AmnesiaStealer (macOS Mach-O) — URL эксфильтрации C2, конфигурация крипто-клиппера, пути для размещения. Подробнее ниже.
Деобфускация строк — статическое восстановление по местам вызовов (секунды) + движок эмуляции Unicorn с
настоящим загрузчиком, средой выполнения C, исследованием путей и воспроизведением глобальных конструкторов. Восстанавливает строки, построенные
только в одной ветви match или в ветви, которая никогда не выполняется.
Триаж SOC на одном экране — soc_triage.py: формат/архитектура, тулчейн Rust, отпечаток возможностей
крейтов (сеть / криптография / разведка / закрепление / размещение), индикаторы, сгруппированные по типу, и
калиброванный сигнал LOW / MEDIUM / HIGH с его обоснованием. --json для SIEM, --fail-on HIGH
для скриптового гейтинга. --fast (метаданные + литеральные индикаторы, без декодирования) масштабируется с размером
бинарника: менее секунды на небольшом образце, ~20 с на 20-МБ бинарнике.
Мультиархитектурность, мультиформатность — x86-64, ARM64 и 32-битный x86 для ELF, PE и Mach-O.
Вписывается в ваш рабочий процесс — экспорт, совместимый с FLOSS (--floss-json), безголовая аннотация Ghidra
(комментарии-плашки, закладки, переименования), идентификация библиотечных функций по байтовой сигнатуре
(lib_<name> в stripped-бинарниках), пакетный режим по каталогу (--jsonl).
Больше, чем строки — извлечение конфигурации/C2, разрешение API-импортов, обфусцированных хешами, извлечение
распакованного stage-2, обнаружение и реконструкция уплощения потока управления (x86-64 и AArch64,
проверено на goldberg, OLLVM -fla и реальном проходе уплощения LLVM-18), упрощение MBA / непрозрачных предикатов
с помощью Z3, восстановление таблиц виртуальных методов трейт-объектов Rust (recover_types.py) и
обращение оптимизаций (отмена переключения таблиц переходов, обнаружение развёрнутых циклов — premium/opt_reverse.py).
Виртуализация кода — detect_vm.py помечает байткод-виртуальные машины в стиле VMProtect/Themida/Tigress;
премиальный девиртуализатор поднимает их обратно. Из ВМ с рандомизированными опкодами и зашифрованными
операндами он восстанавливает:
return (((a0 > 1000) & (((((a0 * 31) + a1) ^ (a0 >> 3)) % 97) == 0)) ? (a1 + a0) : 0xffffffff);