
Генератор загрузчиков шеллкода с поддержкой множества техник инъекций, созданный для проведения операций «красной команды».
hollow — это генератор загрузчиков shellcode. Вы передаёте ему сырой бинарный файл shellcode и профиль, а он выдаёт скомпилированный загрузчик Windows PE с зашифрованным внутри shellcode.
Бинарные файлы доступны на странице релизов, либо соберите из исходников:
go build -o hollow .
Требуется x86_64-w64-mingw32-gcc для кросс-компиляции.
В Arch Linux: pacman -S mingw-w64-gcc
В Debian/Ubuntu: apt install gcc-mingw-w64-x86-64
./hollow -shellcode payload.bin -profile profiles/new_process_injection_sc.json
| Флаг | Описание |
|---|---|
-shellcode | Путь к raw shellcode (.bin) |
-profile | Путь к файлу профиля JSON |
-templates | Директория шаблонов (по умолчанию: ./templates) |
hollow следует трёхэтапному конвейеру: шифрование, подстановка, компиляция.
Ваш shellcode шифруется AES-256-CBC с использованием случайно генерируемых ключа и IV при каждом запуске. Оба встраиваются в выходной бинарный файл. Затем в выбранном C-шаблоне заполнители заменяются зашифрованным shellcode, ключом и IV, и результат компилируется в stripped, статически слинкованный PE с помощью MinGW.
Во время выполнения загрузчик расшифровывает shellcode, используя Windows BCrypt, и выполняет его с помощью того метода инжектирования, который реализован в шаблоне.
Шаблоны — это исходные файлы на C, реализующие логику инжектирования. Каждый из них находится в templates/ и содержит токены-заполнители (${SHELLCODE}, ${KEY}, ${IV}, ${TARGET_PROCESS}), которые hollow заменяет перед компиляцией. Шаблон выбирается через ваш профиль.
hollow поставляется с шестью шаблонами:
Вы можете написать собственные шаблоны и поместить их в templates/ — hollow автоматически их подхватит, если профиль будет на них ссылаться.
Профили — это JSON-файлы, которые указывают hollow, какой шаблон использовать, какой процесс является целевым и как компилировать выходной файл. Они находятся в profiles/ и предназначены для настройки под каждую задачу.
{
"name": "New Process Injection via Direct Syscalls",
"author": "",
"template": "new_process_injection_sc",
"target_process": "C:\\Windows\\System32\\cmd.exe",
"arch": "x64",
"compile": {
"automatic": true,
"gcc": "x86_64-w64-mingw32-gcc",
"strip": true,
"output_type": "exe"
},
"output_dir": "./output"
}
output_type может быть exe или dll. Установите automatic: false, чтобы вместо компиляции сохранить на диск подставленный C-исходник — полезно, если хотите изменить код перед сборкой.
Выходной файл записывается в output_dir с именем {template}_loader.{exe|dll}.
Шаблон: new_process_injection
Методика: Инжектирование удалённого потока в только что запущенный процесс.
Запускает целевой процесс с флагами CREATE_BREAKAWAY_FROM_JOB | CREATE_NO_WINDOW, ждёт две секунды для его инициализации, затем выделяет память в его адресном пространстве, записывает расшифрованный shellcode, делает её исполняемой и создаёт удалённый поток, указывающий на него. Флаг BREAKAWAY необходим, когда загрузчик запускается из WinRM, который помещает все процессы в объект задания. Цель — полный путь к исполняемому файлу.
Вызовы Win32: CreateProcessA, VirtualAllocEx, WriteProcessMemory, VirtualProtectEx, CreateRemoteThread.
Шаблон: new_process_injection_sc
Методика: Инжектирование удалённого потока в только что запущенный процесс через прямые системные вызовы (Hell's Gate).
Поведение такое же, как у new_process_injection, но все операции выделения памяти и работы с потоками обходят уровень Win32. SSN определяются из ntdll во время выполнения и выполняются через сырую инструкцию syscall. Смотрите раздел с бенчмарками.
Шаблон: remote_thread_injection
Методика: Классическое инжектирование удалённого потока в существующий процесс.
Находит запущенный процесс по имени с помощью CreateToolhelp32Snapshot, открывает его дескриптор, затем выделяет память, записывает shellcode и создаёт удалённый поток. Новый процесс не запускается. Лучше всего использовать против долгоживущих процессов, таких как explorer.exe. Цель — имя образа процесса, а не полный путь.
Вызовы Win32: OpenProcess, VirtualAllocEx, WriteProcessMemory, VirtualProtectEx, CreateRemoteThread.
Шаблон: remote_thread_injection_sc
Методика: Классическое инжектирование удалённого потока в существующий процесс через прямые системные вызовы (Hell's Gate).
Поведение такое же, как у remote_thread_injection, с обходом уровня Win32. Смотрите раздел с бенчмарками.
Шаблон: earlybird_apc
Методика: Инжектирование APC Early Bird (CyberArk, 2018).
Запускает целевой процесс в приостановленном состоянии (CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB | CREATE_NO_WINDOW), записывает расшифрованный shellcode в его адресное пространство, затем ставит в очередь асинхронный вызов процедуры (APC) для главного потока, указывающий на shellcode через QueueUserAPC, и возобновляет выполнение с помощью ResumeThread. Поскольку APC срабатывает до того, как точка входа процесса выполнится, shellcode выполняется до инициализации любых защитных средств в процессе. Полностью обходит триаду VirtualAllocEx + WriteProcessMemory + CreateRemoteThread.
Шаблон: dll_sideload
Методика: DLL Sideloading / выполнение shellcode внутри процесса.
Создаёт DLL вместо EXE. При DLL_PROCESS_ATTACH запускается поток, который расшифровывает и выполняет shellcode внутри процесса: VirtualAlloc, memcpy, VirtualProtect, затем прямой вызов функции shellcode. Хост-процесс должен оставаться активным, пока инициализируется полезная нагрузка (около 10 секунд для Sliver beacon). Разверните DLL в месте, где легитимный бинарный файл загрузит её через отсутствующую запись в пути поиска DLL.
Тестировалось на Windows 10 Build 19041, защита в реальном времени Windows Defender включена, определения 1.453.354.0, с полезной нагрузкой Sliver beacon размером 17 МБ, обёрнутой в Donut:
Trojan:Win64/AsyncRat.RPY!MTB — это правило машинного поведенческого обнаружения, срабатывающее на классическую последовательность удалённого инжектирования: VirtualAllocEx + WriteProcessMemory + CreateRemoteThread, вызываемые для удалённого дескриптора процесса через уровень Win32 API. Defender регистрирует колбэк ядра, который срабатывает при появлении этих трёх вызовов подряд.
Шаблоны _sc обходят это, никогда не вызывая эти функции Win32. Вместо этого они определяют соответствующие номера системных вызовов (SSN) ядра непосредственно из ntdll во время выполнения с помощью Hell's Gate: каждая не-хукованная заглушка ntdll начинается с четырёхбайтового пролога 4C 8B D1 B8, а SSN находится на смещении 4. Сам системный вызов — это naked-функция GCC, содержащая только movq %rcx, %r10 / movl ssn(%rip), %eax / syscall / ret, то есть точную последовательность, которую выполнила бы сама заглушка ntdll. Колбэк Defender не срабатывает, так как отслеживаемые обёртки Win32 никогда не вызываются.
В системах, где заглушки ntdll пропатчены полноценным EDR (пролог заменён на переход), проверка чистой заглушки не проходит, и загрузчик завершает работу досрочно. Halo's Gate (сканирование соседних заглушек для вывода SSN) не реализован.
Код загрузчика добавляет примерно 19 КБ накладных расходов. Размер выходного файла практически равен размеру входного shellcode. Sliver beacon размером 17 МБ даёт загрузчик размером 18 МБ. Типичный shellcode Metasploit (~200 КБ) даст загрузчик размером ~220 КБ.
Приветствуются любые вклады. Если у вас есть написанный вами шаблон и вы хотите его добавить, или улучшения существующих — смело открывайте PR. Если вы нашли ошибку или у вас есть предложение — создайте issue.
Цель этого инструмента — упростить процесс разработки загрузчиков, а не быть готовым продуктом. Новые шаблоны, лучшие профили и улучшения ядра — всё приветствуется. Также hollow создавался с намерением помочь людям понять концепции загрузчиков shellcode и методов инжектирования, поэтому чёткий и читаемый код шаблонов не менее ценен, чем функциональность.
В ближайшее время я подробно опишу концепции каждой методики и полное использование hollow в своём блоге. Следите за обновлениями.
| Шаблон | Методика |
|---|
new_process_injection | Инжектирование удалённого потока в только что запущенный процесс |
new_process_injection_sc | То же, через прямые системные вызовы (Hell's Gate) |
remote_thread_injection | Классическое инжектирование удалённого потока в существующий процесс |
remote_thread_injection_sc | То же, через прямые системные вызовы (Hell's Gate) |
earlybird_apc | Инжектирование APC Early Bird |
dll_sideload | DLL sideloading, создаётся DLL вместо EXE |
| Шаблон | Поведенческое предупреждение Defender | Сессия установлена |
|---|
| new_process_injection | Trojan:Win64/AsyncRat.RPY!MTB | да |
| remote_thread_injection | Trojan:Win64/AsyncRat.RPY!MTB | да |
| earlybird_apc | нет | да |
| dll_sideload | нет | да |
| new_process_injection_sc | нет | да |
| remote_thread_injection_sc | нет | да |