Voltar às atualizações
New releaseSep 16, 2026

SindriKit v2.0.0

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

Compartilhar

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:

  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.: Win32 API, NTAPI Nativa, Syscalls Diretas) estão 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 os comportamentos subjacentes de manipulação de memória, módulo e thread por meio de tabelas de ponteiros de função sem quebrar a técnica chamadora.
  • Fallbacks em Cascata de Syscalls: Resolvedores de 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. 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 em código C, matemática/NOPs funcionalmente equivalentes em stubs Assembly, e embaralhar o layout de memória de structs centrais.
  • Builds de Release: Uma camada silenciosa remove todas as strings de diagnóstico, descritores de arquivo e frames de rastreamento do binário final, reduzindo sua pegada estática a primitivas básicas.

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, resolução de syscalls, carregamento reflexivo...


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  │
        │      [ tabelas futuras ] ->  thread · object · ...                         │
        ├──────────────────┬──────────────────────┬──────────────────────────────────┤
        │   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 a cadeia 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);

O invocador é desacoplado da resolução de SSN — alterne entre syscalls diretas e indiretas 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 da syscall dentro de ntdll.dll.

Agilidade 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 seed gerada aleatoriamente (se SND_RANDOMIZE_SEED=ON). A pegada estática muda completamente entre compilações sem tocar em uma linha de C.

FFI Dinâmica com Consciência de 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 Microsoft x64 (shadow space, posicionamento de argumentos em registradores, alinhamento de pilha). Builds x86 empilham argumentos em ordem reversa com suporte tanto para alvos cdecl quanto stdcall.

Parser de PE com Verificação de Limites

Um parser unificado PE32/PE32+ com uma flag is_mapped que lida corretamente tanto com imagens brutas em disco quanto com views mapeadas em memória. Todo acesso a data directory é validado contra os limites do buffer rastreado antes da desreferenciação. A resolução de exportações suporta cadeias de forwarders até profundidade 4 com busca baseada em hash.

Testado contra:

  • Mais de 40 combinações de testes centrais visando EXEs de casos extremos, DLLs, argumentos inválidos, exportações 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, overflows de inteiros, limites inválidos de e_lfanew, imports corrompidos.
  • Corpus completo do Corkami: carrega amostras válidas de forma limpa, rejeita amostras malformadas de forma limpa 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 sleep ou implantação em estágios, retomadas de forma limpa, e inspecionadas quanto ao 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_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);

O invocador é desacoplado da resolução de SSN — alterne entre syscalls diretas e indiretas 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 da 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 há backend de módulo baseado em syscalls — os imports usam PEB walk + EAT mesmo em perfis _sys completos.


Camadas de Build

Camada de Debug — SND_ENABLE_DEBUG=ON

Para desenvolvimento local. snd_status_t 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 estados, valores de campos de PE parseados 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.

Camada Silenciosa — 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 é compilada para fora completamente. snd_status_t colapsa para 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/:

  • Getting Started — CMake, camadas de build, bootstrap de DI, primeiro fluxo de trabalho de loader/injeção
  • Architecture — Injeção de dependência, máquinas de estado, sistema de status
  • Primitives — Memória, módulos, processo, mapeamento, syscalls, execução (FFI)
  • Loaders — Pipeline de PE reflexivo
  • Injection — Injeção clássica de shellcode e PE
  • Parsers — Subdomínios PE e env (PEB)
  • Common — Helpers sem CRT, buffers, hashing, status
  • Examples & PoCs — Perfis executáveis unified (load, inject, hg)
  • Tests — Runner de integração, mutador de PE

Planejado: domínio Evasion.


O SindriKit é construído apenas para fins educacionais, de pesquisa e 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