
SindriKit v2.0.0
Una biblioteca C fundamental para construir capacidades ofensivas operativamente creíbles.
SindriKit
El desarrollo ofensivo merece una mejor arquitectura.
Una biblioteca en C para construir capacidades ofensivas.
Concepto central
La mayoría de las utilidades ofensivas codifican de forma rígida sus mecánicas de ejecución dentro de la lógica de la técnica. Un cargador reflexivo no solo mapea una imagen; la mapea usando una cadena específica y codificada de llamadas a VirtualAlloc o a la NTAPI nativa. Cuando un EDR comienza a monitorear esa cadena específica, te ves obligado a reescribir toda la herramienta.
SindriKit resuelve esto imponiendo una separación de responsabilidades mediante tablas de abstracción de interfaces:
- La lógica de la técnica: (p. ej., cargadores, inyecciones, parcheadores) se ocupa del seguimiento de estado y la orquestación de datos. No tiene conocimiento de cómo se asigna la memoria ni de cómo se crean los hilos.
- Las mecánicas de ejecución: (p. ej., Win32 API, NTAPI nativa, syscalls directas) residen en tablas de API independientes y se inyectan en la técnica en tiempo de ejecución.
Al trasladar las mecánicas de ejecución a punteros a funciones en tiempo de ejecución, puedes cambiar toda tu estrategia de llamadas Win32 a syscalls directas en bruto con una sola línea de código, sin cambiar la lógica de ejecución de tu payload.
Arquitectura de diseño
- Perfiles de ejecución desacoplados: Intercambia los comportamientos subyacentes de manipulación de memoria, módulos e hilos mediante tablas de punteros a funciones sin romper la técnica que los invoca.
- Fallbacks en cascada de syscalls: Resolvedores de SSN conectables (
snd_syscall_resolve_ssn_scan,snd_syscall_resolve_ssn_sort) con una cadena de prioridad: intercambia o amplía estrategias sin tocar el código de dominio. - Ofuscación en tiempo de compilación: Los algoritmos de hashing de cadenas y API (DJB2, FNV1A) pueden intercambiarse globalmente mediante CMake. La compilación aleatoriza automáticamente la semilla global para alterar las firmas estáticas.
- Motor de mutación: Habilita polimorfismo profundo mediante
SND_MORPH. Genera firmas binarias únicas en cada compilación inyectando predicados opacos volátiles en el código C, matemáticas/NOPs funcionalmente equivalentes en los stubs de ensamblador, y alterando la disposición en memoria de las estructuras principales. - Compilaciones de release: Un nivel silencioso elimina todas las cadenas de diagnóstico, descriptores de archivo y marcos de seguimiento del binario final, reduciendo tu huella estática a primitivas básicas.
Integración de 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
Solo dos líneas para que tu herramienta herede todas las capacidades de SindriKit: análisis de PE, resolución de syscalls, carga reflexiva...
El motor
Capa de abstracción de API
┌────────────────────────────────────────────────────────────────────────────┐
│ CUALQUIER INTENCIÓN OFENSIVA │
│ Loader · Injector · Spoofer · Patcher · Bypasser · Harvester · ... │
├────────────────────────────────────────────────────────────────────────────┤
│ CAPA DE ABSTRACCIÓN DE API DE 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 │
│ [ tablas futuras ] -> thread · object · ... │
├──────────────────┬──────────────────────┬──────────────────────────────────┤
│ Perfil Win32 │ Perfil Nativo │ Trae tu propia mecánica │
│ VirtualAlloc │ NtAllocateVirtual │ Driver · ROP · Exótico │
│ LoadLibraryA │ PEB Walk + EAT │ Funciones definidas por el │
│ │ │ operador │
└──────────────────┴──────────────────────┴──────────────────────────────────┘
En la práctica, esto significa que cada dominio sigue el mismo contrato:
// 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);
Pipeline de syscalls en cascada
SindriKit trata la resolución de syscalls como una mecánica inyectable, apilando estrategias en orden de prioridad. El motor va pasando a la siguiente hasta que una tiene éxito:
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);
// or for indirect syscalls:
// snd_syscall_set_invoker(snd_syscall_indirect_invoke_asm);
// snd_syscall_set_gadget_finder(snd_syscall_find_gadget_scan);
El invocador está desacoplado de la resolución de SSN: cambia entre syscalls directas e indirectas sin modificar el código de dominio. La invocación indirecta salta a un gadget legítimo de NTDLL, manteniendo la dirección de retorno de la syscall dentro de ntdll.dll.
Agilidad de algoritmos en tiempo de compilación
Cada nombre de API y cadena de módulo se elimina del binario final en tiempo de compilación mediante una única variable de 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
Cada hash se calcula con una semilla generada aleatoriamente (si SND_RANDOMIZE_SEED=ON). La huella estática cambia por completo entre compilaciones sin tocar una sola línea de C.
FFI dinámica consciente de la arquitectura
Un puente de ensamblador MASM personalizado para la invocación arbitraria de funciones en tiempo de ejecución. Las compilaciones x64 siguen con precisión la convención de llamada de Microsoft x64 (shadow space, colocación de argumentos en registros, alineación de pila). Las compilaciones x86 empujan los argumentos en orden inverso con soporte tanto para objetivos cdecl como stdcall.
Analizador de PE con comprobación de límites
Un analizador unificado PE32/PE32+ con un flag is_mapped que maneja correctamente tanto imágenes en bruto en disco como vistas mapeadas en memoria. Cada acceso a un directorio de datos se valida contra los límites del búfer rastreado antes de desreferenciarlo. La resolución de exportaciones admite cadenas de forwarders de hasta profundidad 4 con búsqueda basada en hash.
Probado contra:
- Más de 40 combinaciones de pruebas principales dirigidas a EXEs y DLLs de casos límite, argumentos incorrectos, exportaciones faltantes y callbacks TLS en x86 y x64.
- Más de 100 mutaciones dinámicas de PE generadas por el módulo
pe_mutator: nombres de sección puestos a cero, desbordamientos de enteros, límites inválidos dee_lfanew, importaciones alteradas. - Corpus completo de Corkami: carga limpiamente muestras válidas, rechaza limpiamente las malformadas sin fallar en el 99% de las muestras.
Contextos de dominio con seguimiento de estado
Cada operación ofensiva se gestiona mediante una estructura de contexto discreta con enumeración de etapas. Las operaciones pueden pausarse entre etapas para ofuscación de sueño o despliegue por etapas, reanudarse limpiamente e inspeccionarse para determinar el punto exacto de fallo hasta el subsistema y la razón.
La filosofía de diseño de la API
Inicializa el pipeline de syscalls una vez (patrón típico):
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);
// or for indirect syscalls:
// snd_syscall_set_invoker(snd_syscall_indirect_invoke_asm);
// snd_syscall_set_gadget_finder(snd_syscall_find_gadget_scan);
El invocador está desacoplado de la resolución de SSN: cambia entre syscalls directas e indirectas sin modificar el código de dominio. La invocación indirecta salta a un gadget legítimo de NTDLL, manteniendo la dirección de retorno de la syscall dentro de ntdll.dll.
Intercambia el perfil de ejecución con una sola asignación:
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)
La resolución de módulos sigue el mismo patrón (snd_mod_win vs snd_mod_nt). No existe un backend de módulos respaldado por syscalls: las importaciones usan PEB walk + EAT incluso en perfiles _sys completos.
Niveles de compilación
Nivel Debug — SND_ENABLE_DEBUG=ON
Para desarrollo local. snd_status_t se expande para incluir file, line y un búfer de cadena context de 128 bytes. SND_ERR_CTX y SND_DEBUG_PRINT emiten transiciones de la máquina de estados, valores de campos de PE analizados y resultados de resolución de syscalls. Usa SND_USE_PRINTF=ON para dirigir la salida a stdout en lugar de la consola de depuración.
Nivel silencioso — SND_ENABLE_DEBUG=OFF
La configuración de despliegue estándar para binarios operativos. Cada cadena de diagnóstico, referencia a archivo y número de línea se elimina por completo en la compilación. snd_status_t se reduce a dos enteros. Nada más.
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)
Documentación
Referencia completa en docs/:
- Primeros pasos — CMake, niveles de compilación, bootstrap de DI, primer flujo de trabajo de cargador/inyección
- Arquitectura — Inyección de dependencias, máquinas de estados, sistema de estado
- Primitivas — Memoria, módulos, proceso, mapeo, syscalls, ejecución (FFI)
- Cargadores — Pipeline de PE reflexivo
- Inyección — Inyección clásica de shellcode y PE
- Analizadores — Subdominios de PE y env (PEB)
- Común — Helpers sin CRT, búferes, hashing, estado
- Ejemplos y PoCs — Perfiles ejecutables
unified(load, inject, hg) - Pruebas — Runner de integración, mutador de PE
Planeado: dominio de Evasión.
Aviso legal
SindriKit está construido únicamente con fines educativos, de investigación y de Red Teaming autorizado. Para el aviso legal completo y la información sobre consideraciones de OpSec, consulta la Política de seguridad.
Licencia