SindriKit 1.1.0: Injection Without Rewriting Your Implant

The initial release showed that offensive C tooling can be structured without sacrificing stealth. By applying Dependency Injection to execution mechanics, the reflective loader demonstrated that you don’t have to choose between clean code and operational stealth.

1.1.0 extends that architecture to remote process injection which shares the exact same design language as loaders, parsers, and syscalls.

A full injection engine being shipped in less than a week after launch is a side effect of the architecture being right from the start. When the foundation is right new capabilities just snap into place.

Source, architecture docs, and PoCs: SindriKit on GitHub.

The Injection Coupling Problem

Traditional injectors hardcode Win32 apis throughout their implementations (OpenProcess, VirtualAllocEx…)

When you want to swap those for stealthier alternatives, you fork the injector, create custom syscall stubs… The technique logic and the execution profile are fused.

PE injection makes it worse. You dont copy DLL’s bytes into a remote process and you’re done, relocations and imports must target the remote base. Most teams maintain a separate “manual map” injector that diverges from their local reflective loader after some updates.

Dependency Injection Across Domains

SindriKit fixes this by separating what you’re doing from how it get done. Injection delegates cross-process operations to an injectable proc_api.

A standard injection chain looks like this:

inj.target_pid = pid;
inj.payload    = &shellcode_buf;
inj.proc_api   = &snd_proc_win;   // diagnostics, lab work...

snd_inj_classic_shell(&inj);

When the first profile gets flagged, you bootstrap syscalls once and change one pointer:

inj.proc_api = &snd_proc_sys;   // stealth execution surface
snd_inj_classic_shell(&inj);

The delivery path and state machine does not change.

PE Injection

PE injection is the real test.

1.1.0 wires the existing loader into injection without duplicating logic. You easily reuse the existing snd_ldr_pe_ctx_t, point local work at snd_mem_sys, point remote work at snd_proc_sys, and call one chain:

snd_ldr_pe_ctx_t ldr = {0};
snd_inj_ctx_t    inj = {0};

ldr.raw_source = &file_buf;
ldr.mem_api    = &snd_mem_sys;   // local mapping
ldr.mod_api    = &snd_mod_nt;    // imports

inj.target_pid = 6767;
inj.proc_api   = &snd_proc_sys;  // remote delivery

snd_inj_classic_pe(&ldr, &inj);

snd_inj_classic_pe maps the PE locally, applies relocations against the remote delta, and safely writes the baked image across the process boundary. The parser doesn’t need to know where the image runs. The loader doesn’t care how memory is allocated.

snd_inj_ctx_t is the one responsible of the stages, allocations, and the remote entry point.

The Syscall Pipeline

Early SindriKit carried separate resolver implementations (Hell’s Gate, Halo’s Gate, Tartarus) that competed with each other.

1.1.0 converges them into an explicit priority pipeline.

snd_syscall_strategy_set(snd_syscall_resolve_ssn_scan);
snd_syscall_strategy_add(snd_syscall_resolve_ssn_sort);

Scan for clean stubs first. Fallback to export sorting if hooks break the bytes.

The Point

The framework absorbed a full injection domain in six days. Shellcode delivery, PE mapping… all of it fitting into what was already there without friction.

*