Torna agli aggiornamenti
New releaseSep 16, 2026

SindriKit v2.0.0

Una libreria C fondamentale per costruire capacità offensive credibili a livello operativo

Condividi

SindriKit

Lo sviluppo offensivo merita un'architettura migliore.
Una libreria C per costruire capacità offensive.


Concetto fondamentale

La maggior parte delle utility offensive codifica in modo rigido i propri meccanismi di esecuzione all'interno della logica della tecnica. Un reflective loader non si limita a mappare un'immagine; la mappa utilizzando una catena specifica e hardcoded di chiamate VirtualAlloc o NTAPI native. Quando un EDR inizia a monitorare quella catena specifica, sei costretto a riscrivere l'intero strumento.

SindriKit risolve questo problema imponendo una separazione delle responsabilità tramite tabelle di astrazione delle interfacce:

  1. La logica della tecnica: (ad es. loader, injection, patcher) si occupa del tracciamento dello stato e dell'orchestrazione dei dati. Non ha alcuna conoscenza di come viene allocata la memoria o di come vengono creati i thread.
  2. I meccanismi di esecuzione: (ad es. Win32 API, NTAPI native, Direct Syscalls) risiedono in tabelle API indipendenti e vengono iniettati nella tecnica a runtime.

Spostando i meccanismi di esecuzione su puntatori a funzione a runtime, puoi scambiare l'intera strategia da chiamate Win32 a syscall dirette raw con una singola riga di codice—senza modificare la logica di esecuzione del payload.


Architettura di progettazione

  • Profili di esecuzione disaccoppiati: scambia i comportamenti sottostanti di manipolazione di memoria, moduli e thread tramite tabelle di puntatori a funzione senza rompere la tecnica chiamante.
  • Fallback a cascata per le syscall: resolver SSN pluggable (snd_syscall_resolve_ssn_scan, snd_syscall_resolve_ssn_sort) con una catena di priorità — scambia o estendi le strategie senza toccare il codice di dominio.
  • Offuscamento a compile-time: gli algoritmi di hashing di stringhe e API (DJB2, FNV1A) possono essere scambiati globalmente tramite CMake. La compilazione randomizza automaticamente il seed globale per alterare le firme statiche.
  • Motore di mutazione: abilita un polimorfismo profondo tramite SND_MORPH. Genera firme binarie uniche a ogni build iniettando predicati opachi volatili nel codice C, math/NOP funzionalmente equivalenti negli stub Assembly e rimescolando il layout di memoria delle strutture core.
  • Build di release: un tier silenzioso rimuove tutte le stringhe diagnostiche, i descrittori di file e i frame di tracciamento dal binario finale, riducendo il tuo footprint statico a primitive pure.

Integrare 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 due righe perché il tuo strumento erediti tutte le capacità di SindriKit: parsing PE, risoluzione delle syscall, reflective loading...


Il motore

Livello di astrazione delle API

        ┌────────────────────────────────────────────────────────────────────────────┐
        │                          QUALSIASI INTENTO OFFENSIVO                       │
        │    Loader · Injector · Spoofer · Patcher · Bypasser · Harvester · ...      │
        ├────────────────────────────────────────────────────────────────────────────┤
        │                     LIVELLO DI ASTRAZIONE API DI 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  │
        │      [ tabelle future ] ->  thread · object · ...                          │
        ├──────────────────┬──────────────────────┬──────────────────────────────────┤
        │   Profilo Win32  │   Profilo Nativo     │    Porta il Tuo Meccanismo       │
        │  VirtualAlloc    │  NtAllocateVirtual   │  Driver · ROP · Esotico          │
        │  LoadLibraryA    │  PEB Walk + EAT      │  Funzioni definite dall'operatore│
        └──────────────────┴──────────────────────┴──────────────────────────────────┘

In pratica, questo significa che ogni dominio segue lo stesso contratto:

// 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 a cascata per le syscall

SindriKit tratta la risoluzione delle syscall come un meccanismo iniettabile, impilando le strategie in ordine di priorità. Il motore procede a cascata finché una non riesce:

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);

L'invoker è disaccoppiato dalla risoluzione SSN — passa tra syscall dirette e indirette senza modificare il codice di dominio. L'invocazione indiretta salta a un gadget legittimo di NTDLL, mantenendo l'indirizzo di ritorno della syscall all'interno di ntdll.dll.

Agilità degli algoritmi a compile-time

Ogni nome di API e stringa di modulo viene rimosso dal binario finale a compile-time tramite una singola variabile 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

Ogni hash viene calcolato con un seed generato casualmente (se SND_RANDOMIZE_SEED=ON). Il footprint statico cambia completamente tra le compilazioni senza toccare una riga di C.

FFI dinamica consapevole dell'architettura

Un bridge assembly MASM personalizzato per l'invocazione arbitraria di funzioni a runtime. Le build x64 seguono precisamente la calling convention Microsoft x64 (shadow space, posizionamento degli argomenti nei registri, allineamento dello stack). Le build x86 spingono gli argomenti in ordine inverso con supporto sia per target cdecl che stdcall.

Parser PE con controllo dei limiti

Un parser unificato PE32/PE32+ con un flag is_mapped che gestisce correttamente sia immagini raw su disco che viste mappate in memoria. Ogni accesso a una data directory viene validato rispetto ai limiti del buffer tracciati prima della dereferenziazione. La risoluzione degli export supporta catene di forwarder fino a profondità 4 con lookup basato su hash.

Testato contro:

  • Oltre 40 combinazioni di test core mirate a EXE, DLL, argomenti errati, export mancanti e callback TLS ai limiti tra x86 e x64.
  • Oltre 100 mutazioni PE dinamiche generate dal modulo pe_mutator: nomi di sezione azzerati, overflow di interi, limiti e_lfanew non validi, import manomessi.
  • Corpus completo Corkami: carica correttamente i campioni validi, rifiuta correttamente quelli malformati senza crashare sul 99% dei campioni.

Contesti di dominio con tracciamento dello stato

Ogni operazione offensiva è gestita tramite una struttura di contesto discreta con enumerazione delle fasi. Le operazioni possono essere messe in pausa tra le fasi per sleep obfuscation o deployment a stadi, riprese correttamente e ispezionate per individuare il punto esatto di fallimento fino al sottosistema e alla causa.


La filosofia di progettazione delle API

Inizializza la pipeline delle syscall una volta (pattern tipico):

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);

L'invoker è disaccoppiato dalla risoluzione SSN — passa tra syscall dirette e indirette senza modificare il codice di dominio. L'invocazione indiretta salta a un gadget legittimo di NTDLL, mantenendo l'indirizzo di ritorno della syscall all'interno di ntdll.dll.

Scambia il profilo di esecuzione con un'assegnazione:

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 risoluzione dei moduli segue lo stesso pattern (snd_mod_win vs snd_mod_nt). Non esiste un backend di moduli basato su syscall — gli import usano PEB walk + EAT anche nei profili _sys completi.


Tier di build

Tier Debug — SND_ENABLE_DEBUG=ON

Per lo sviluppo locale. snd_status_t si espande per includere file, line e un buffer di stringa context da 128 byte. SND_ERR_CTX e SND_DEBUG_PRINT emettono transizioni della macchina a stati, valori dei campi PE analizzati e esiti della risoluzione delle syscall. Usa SND_USE_PRINTF=ON per indirizzare l'output su stdout invece che sulla console di debug.

Tier Silenzioso — SND_ENABLE_DEBUG=OFF

La configurazione di deployment standard per binari operativi. Ogni stringa diagnostica, riferimento a file e numero di riga viene completamente rimosso in fase di compilazione. snd_status_t si riduce a due interi. Nient'altro.

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)

Documentazione

Riferimento completo in docs/:

  • Per iniziare — CMake, tier di build, bootstrap DI, primo workflow di loader/injection
  • Architettura — Dependency injection, macchine a stati, sistema di stato
  • Primitive — Memoria, moduli, processi, mapping, syscall, esecuzione (FFI)
  • Loader — Pipeline PE riflessiva
  • Injection — Injection classica di shellcode e PE
  • Parser — Sottodomini PE e env (PEB)
  • Common — Helper CRT-free, buffer, hashing, stato
  • Esempi e PoC — Profili eseguibili unified (load, inject, hg)
  • Test — Runner di integrazione, PE mutator

Pianificato: dominio Evasion.


Disclaimer

SindriKit è costruito esclusivamente per scopi educativi, di ricerca e Red Teaming autorizzato. Per il disclaimer legale completo e le informazioni sulle considerazioni OpSec, consulta la Security Policy.


Licenza

MIT


Categorie