Files
youssefnoob003-SindriKit/docs/getting_started/basic_usage.md
T
sibouzitoun aea2eb6cfb Release v1.1.0: Process Injection & Architecture Hardening
- Implement complete cross-process injection engine via snd_inj_ctx_t
- Track explicit remote_entry_point for safe thread hijacking and PE execution
- Refactor standalone syscall resolvers into a unified pipeline (scan/sort)
- Perfect status code system by purging generic fallbacks in favor of highly-specific, domain-aware error codes
- Fix minor pointer validation and parsing bugs in the reflective loader
2026-06-28 14:14:54 +01:00

7.6 KiB

Basic Usage: The Core Engine

SindriKit is an extensible evasion and execution toolkit. Reflective loading and classic remote injection are domains built on top of shared primitives — memory, modules, process, mapping, syscalls, and execution bridges (FFI, Heaven's Gate).

To use the framework effectively, separate Intent (what you want to accomplish) from Execution mechanics (how the OS is contacted).


1. Include hierarchy

Include Pulls in
sindri.h Everything: common, parsers, primitives, loaders, injection
sindri/primitives.h Memory, modules, process, mapping, syscalls, FFI, Heaven's Gate
sindri/common.h Buffer, hash, status, debug, disk, string, memory helpers
sindri/loaders.h Reflective PE loader context and chains
sindri/injection.h Shared injection context and classic chains

PoCs typically include sindri.h plus any headers needed for explicit bootstrap (e.g. sindri/primitives/syscalls.h).


2. Core philosophy: dependency injection

High-level domains never call VirtualAlloc or NtAllocateVirtualMemory directly. They call through injected API tables:

Table Examples Used by
snd_memory_api_t (mem_api) snd_mem_win, snd_mem_nt, snd_mem_sys Loaders, local mapping
snd_module_api_t (mod_api) snd_mod_win, snd_mod_nt Loaders, import resolution
snd_process_api_t (proc_api) snd_proc_win, snd_proc_nt, snd_proc_sys Injection
snd_mapping_api_t snd_map_win, snd_map_nt, snd_map_sys KnownDlls bootstrap

Swapping ctx.mem_api = &snd_mem_win to &snd_mem_sys changes the entire operational footprint without touching loader logic.

See Dependency injection for the full pattern.


3. Explicit bootstrap (no implicit globals)

Important

Syscall-backed backends (snd_mem_sys, snd_proc_sys) and the syscall resolution pipeline require explicit initialization. The engine does not auto-discover a clean ntdll base or SSN table.

Minimum syscall bootstrap

PVOID ntdll = NULL;

// Option A: KnownDlls (preferred for inject_pe / production syscall paths)
status = snd_om_knowndll_map(&snd_map_nt, L"ntdll.dll", &ntdll);

// Option B: disk load (loader_nowinapi default)
// status = snd_disk_buffer_load("C:\\Windows\\System32\\ntdll.dll", &ntdll_buf);
// ntdll = ntdll_buf.data;

// Option C: PEB walk (no disk I/O)
// status = snd_peb_get_module_base_hash(SND_HASH_NTDLL_DLL, &ntdll);

snd_syscall_set_ntdll(ntdll);
snd_syscall_strategy_set(snd_syscall_resolve_ssn_scan);
snd_syscall_strategy_add(snd_syscall_resolve_ssn_sort);
Step Purpose
Obtain ntdll base SSN scan/sort read export stubs from this image
snd_syscall_set_ntdll Registers the base for all resolvers
snd_syscall_strategy_set Primary resolver (scan)
snd_syscall_strategy_add Fallback resolver (sort)

Even when using snd_mem_nt (in-process ntdll stubs, not direct syscalls), PoCs still bootstrap the pipeline so upgrading to snd_mem_sys requires no other code changes.

Details: Syscalls pipeline.


4. Loader workflow

Reflective loading uses a per-technique context snd_ldr_pe_ctx_t:

snd_ldr_pe_ctx_t ctx = {0};
ctx.mem_api    = &snd_mem_win;   // or snd_mem_nt / snd_mem_sys
ctx.mod_api    = &snd_mod_win;   // or snd_mod_nt
ctx.raw_source = &file_buf;      // snd_buffer_t from snd_disk_buffer_load

status = snd_ldr_pe_prepare_image(&ctx);   // map, relocate, imports, protections
if (SND_FAILED(status)) { /* handle */ }

status = snd_ldr_pe_execute_image(&ctx);   // TLS + DllMain / EXE entry (chain.c)
if (SND_FAILED(status)) { /* handle */ }

// Optional: call a named export with arbitrary args
FARPROC fn = NULL;
snd_ldr_pe_get_proc_address(&ctx, "MyExport", &fn);
UINT_PTR args[] = { (UINT_PTR)0x1337 };
UINT_PTR ret = snd_ffi_execute((PVOID)(UINT_PTR)fn, 1, args);

snd_ldr_pe_detach_image(&ctx);       // after EXECUTED: DllMain/TLS detach + free (local only)
snd_ldr_pe_free_mapped_image(&ctx);  // free if detach was skipped or already partially cleaned
snd_buffer_free(&file_buf);

Execution bridge: snd_ffi_execute (include/sindri/primitives/ffi.h) is the public API for calling resolved exports with unknown signatures. See FFI.


5. Injection workflow

Injection uses a shared context snd_inj_ctx_t across classic techniques (unlike loaders, where each technique owns its own loader context):

snd_ldr_pe_ctx_t ldr_ctx = {0};  // local bake
snd_inj_ctx_t    inj_ctx = {0};  // remote target

ldr_ctx.mem_api    = &snd_mem_sys;
ldr_ctx.mod_api    = &snd_mod_nt;
ldr_ctx.raw_source = &file_buf;

inj_ctx.target_pid = target_pid;
inj_ctx.proc_api   = &snd_proc_sys;

status = snd_inj_classic_pe(&ldr_ctx, &inj_ctx);   // PE map + remote execute
// or: snd_inj_classic_shell(&inj_ctx) with inj_ctx.payload set

snd_inj_cleanup(&inj_ctx);

Shellcode-only injection skips the loader context:

snd_inj_ctx_t inj_ctx = {0};
inj_ctx.proc_api   = &snd_proc_win;
inj_ctx.target_pid = pid;
inj_ctx.payload    = &shellcode_buf;

status = snd_inj_classic_shell(&inj_ctx);
snd_inj_cleanup(&inj_ctx);

6. OpSec profiles (PoC mapping)

Profile PoC Memory Modules Process Syscall bootstrap
Diagnostic loader_winapi snd_mem_win snd_mod_win Optional
NT stubs loader_nowinapi snd_mem_nt snd_mod_nt Required (disk ntdll)
Direct syscalls inject_pe snd_mem_sys snd_mod_nt snd_proc_sys Required (KnownDlls)
CRT-less loader_noCRT_nowinapi snd_mem_win snd_mod_nt Minimal
Shellcode inject inject_shell snd_proc_win Yes (KnownDlls; unused while _win)
WoW64 x64 exec heavens_gate Win32 demo alloc N/A

Full walkthroughs: Examples.

Profile A — Win32 (loader_winapi)

snd_ldr_pe_ctx_t ctx = {0};
ctx.mem_api = &snd_mem_win;
ctx.mod_api = &snd_mod_win;
// prepare → execute → optional snd_ffi_execute for -e export

Maximum stability; every memory operation hits hooked userland stubs.

Profile B — NT API (loader_nowinapi)

// Bootstrap (Section 3), then:
ctx.mem_api = &snd_mem_nt;
ctx.mod_api = &snd_mod_nt;

Avoids VirtualAlloc / LoadLibrary telemetry; calls still pass through in-process ntdll where hooks may fire.

Profile C — Direct syscalls (inject_pe)

snd_om_knowndll_map(&snd_map_nt, L"ntdll.dll", &ntdll);
snd_syscall_set_ntdll(ntdll);
snd_syscall_strategy_set(snd_syscall_resolve_ssn_scan);
snd_syscall_strategy_add(snd_syscall_resolve_ssn_sort);

ldr_ctx.mem_api = &snd_mem_sys;
ldr_ctx.mod_api = &snd_mod_nt;
inj_ctx.proc_api = &snd_proc_sys;
snd_inj_classic_pe(&ldr_ctx, &inj_ctx);

Bypasses userland hooks for local syscall memory ops and remote process manipulation.


7. Status handling

All domain functions return snd_status_t. Use SND_SUCCEEDED / SND_FAILED macros:

if (SND_FAILED(status)) {
    snd_status_print(status);  // meaningful when SND_ENABLE_DEBUG=ON
    return status.code;
}

See Status system and Common status API.


Next steps