
SindriKit v2.0.0
Une bibliothèque C fondamentale pour la construction de capacités offensives opérationnellement crédibles
SindriKit
Le développement offensif mérite une meilleure architecture.
Une bibliothèque C pour construire des capacités offensives.
Concept central
La plupart des utilitaires offensifs codent en dur leurs mécanismes d'exécution à l'intérieur de la logique de la technique. Un loader réflexif ne se contente pas de mapper une image ; il la mappe en utilisant une chaîne spécifique et codée en dur d'appels VirtualAlloc ou NTAPI natifs. Lorsqu'un EDR commence à surveiller cette chaîne spécifique, vous êtes contraint de réécrire l'outil entier.
SindriKit résout ce problème en imposant une séparation des responsabilités via des tables d'abstraction d'interface :
- La logique de la technique : (par ex., loaders, injections, patchers) gère le suivi d'état et l'orchestration des données. Elle n'a aucune connaissance de la façon dont la mémoire est allouée ou dont les threads sont créés.
- Les mécanismes d'exécution : (par ex., API Win32, NTAPI natif, syscalls directs) résident dans des tables d'API indépendantes et sont injectés dans la technique à l'exécution.
En déplaçant les mécanismes d'exécution vers des pointeurs de fonction à l'exécution, vous pouvez remplacer toute votre stratégie, des appels Win32 aux syscalls directs bruts, avec une seule ligne de code — sans modifier votre logique d'exécution de payload.
Architecture de conception
- Profils d'exécution découplés : Remplacez les comportements sous-jacents de manipulation de mémoire, de modules et de threads via des tables de pointeurs de fonction sans casser la technique appelante.
- Replis de syscalls en cascade : Résolveurs de SSN enfichables (
snd_syscall_resolve_ssn_scan,snd_syscall_resolve_ssn_sort) avec une chaîne de priorité — remplacez ou étendez les stratégies sans toucher au code du domaine. - Obfuscation à la compilation : Les algorithmes de hachage de chaînes et d'API (DJB2, FNV1A) peuvent être remplacés globalement via CMake. La compilation randomise automatiquement la graine globale pour altérer les signatures statiques.
- Moteur de mutation : Permet un polymorphisme profond via
SND_MORPH. Génère des signatures binaires uniques à chaque build en injectant des prédicats opaques volatils dans le code C, des mathématiques/NOPs fonctionnellement équivalents dans les stubs Assembly, et en brouillant la disposition mémoire des structures principales. - Builds de release : Un palier silencieux supprime toutes les chaînes de diagnostic, les descripteurs de fichiers et les trames de suivi du binaire final, réduisant votre empreinte statique aux primitives nues.
Intégrer 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
Seulement deux lignes pour que votre outil hérite de toutes les capacités de SindriKit : parsing PE, résolution de syscalls, chargement réflexif...
Le moteur
Couche d'abstraction d'API
┌────────────────────────────────────────────────────────────────────────────┐
│ TOUTE INTENTION OFFENSIVE │
│ Loader · Injector · Spoofer · Patcher · Bypasser · Harvester · ... │
├────────────────────────────────────────────────────────────────────────────┤
│ COUCHE D'ABSTRACTION D'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 │
│ [ tables futures ] -> thread · object · ... │
├──────────────────┬──────────────────────┬──────────────────────────────────┤
│ Profil Win32 │ Profil natif │ Apportez votre propre mécanique│
│ VirtualAlloc │ NtAllocateVirtual │ Driver · ROP · Exotique │
│ LoadLibraryA │ PEB Walk + EAT │ Fonctions définies par l'opérateur│
└──────────────────┴──────────────────────┴──────────────────────────────────┘
En pratique, cela signifie que chaque domaine suit le même contrat :
// 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 cascade
SindriKit traite la résolution de syscalls comme une mécanique injectable, empilant les stratégies par ordre de priorité. Le moteur passe à la suivante jusqu'à ce que l'une réussisse :
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'invocateur est découplé de la résolution de SSN — basculez entre syscalls directs et indirects sans modifier le code du domaine. L'invocation indirecte saute vers un gadget NTDLL légitime, gardant l'adresse de retour du syscall à l'intérieur de ntdll.dll.
Agilité algorithmique à la compilation
Chaque nom d'API et chaîne de module est retiré du binaire final à la compilation via une seule variable 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
Chaque hachage est calculé avec une graine générée aléatoirement (si SND_RANDOMIZE_SEED=ON). L'empreinte statique change complètement entre les compilations sans toucher une ligne de C.
FFI dynamique conscient de l'architecture
Un pont assembly MASM personnalisé pour l'invocation arbitraire de fonctions à l'exécution. Les builds x64 suivent précisément la convention d'appel Microsoft x64 (shadow space, placement des arguments dans les registres, alignement de la pile). Les builds x86 empilent les arguments dans l'ordre inverse avec prise en charge des cibles cdecl et stdcall.
Parser PE avec vérification des limites
Un parser PE32/PE32+ unifié avec un flag is_mapped qui gère correctement à la fois les images brutes sur disque et les vues mappées en mémoire. Chaque accès à un répertoire de données est validé par rapport aux limites de tampon suivies avant déréférencement. La résolution des exports prend en charge les chaînes de forwarders jusqu'à une profondeur de 4 avec recherche basée sur le hachage.
Testé contre :
- Plus de 40 combinaisons de tests principaux ciblant des EXE, DLL, arguments invalides, exports manquants et callbacks TLS en cas limites, sur x86 et x64.
- Plus de 100 mutations PE dynamiques générées par le module
pe_mutator: noms de sections mis à zéro, dépassements d'entiers, limitese_lfanewinvalides, imports altérés. - Corpus Corkami complet : charge proprement les échantillons valides, rejette proprement les malformés sans planter sur 99 % des échantillons.
Contextes de domaine avec suivi d'état
Chaque opération offensive est gérée via une structure de contexte discrète avec énumération des étapes. Les opérations peuvent être mises en pause entre les étapes pour l'obfuscation de sommeil ou le déploiement par étapes, reprises proprement, et inspectées pour identifier le point de défaillance exact jusqu'au sous-système et à la raison.
La philosophie de conception de l'API
Initialisez le pipeline de syscalls une fois (schéma typique) :
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'invocateur est découplé de la résolution de SSN — basculez entre syscalls directs et indirects sans modifier le code du domaine. L'invocation indirecte saute vers un gadget NTDLL légitime, gardant l'adresse de retour du syscall à l'intérieur de ntdll.dll.
Remplacez le profil d'exécution avec une seule affectation :
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 résolution de modules suit le même schéma (snd_mod_win vs snd_mod_nt). Il n'existe pas de backend de modules basé sur les syscalls — les imports utilisent PEB walk + EAT même dans les profils _sys complets.
Paliers de build
Palier Debug — SND_ENABLE_DEBUG=ON
Pour le développement local. snd_status_t s'étend pour inclure file, line et un tampon de chaîne context de 128 octets. SND_ERR_CTX et SND_DEBUG_PRINT émettent les transitions de machine à états, les valeurs de champs PE analysés et les résultats de résolution de syscalls. Utilisez SND_USE_PRINTF=ON pour router la sortie vers stdout au lieu de la console de debug.
Palier silencieux — SND_ENABLE_DEBUG=OFF
La configuration de déploiement standard pour les binaires opérationnels. Chaque chaîne de diagnostic, référence de fichier et numéro de ligne est entièrement supprimée à la compilation. snd_status_t se réduit à deux entiers. Rien d'autre.
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)
Documentation
Référence complète sous docs/ :
- Pour commencer — CMake, paliers de build, bootstrap DI, premier workflow loader/injection
- Architecture — Injection de dépendances, machines à états, système de statut
- Primitives — Mémoire, modules, processus, mapping, syscalls, exécution (FFI)
- Loaders — Pipeline PE réflexif
- Injection — Injection classique de shellcode et de PE
- Parsers — Sous-domaines PE et env (PEB)
- Common — Helpers sans CRT, buffers, hachage, statut
- Exemples & PoCs — Profils d'exécutable
unified(load, inject, hg) - Tests — Runner d'intégration, mutateur PE
Prévu : domaine Evasion.
Avertissement
SindriKit est conçu uniquement à des fins éducatives, de recherche et de Red Teaming autorisé. Pour l'avertissement légal complet et les informations concernant les considérations OpSec, voir la Politique de sécurité.
Licence