From fc65395be63dfc19ccd12cd75747c601520d89a8 Mon Sep 17 00:00:00 2001 From: sibouzitoun Date: Mon, 22 Jun 2026 20:51:58 +0100 Subject: [PATCH] Refactor: Encapsulate NTDLL state within syscall subsystem --- CMakeLists.txt | 1 - docs/domains/loaders/techniques.md | 2 +- docs/domains/primitives/README.md | 14 ----------- docs/domains/primitives/memory/techniques.md | 2 +- .../primitives/modules/api_reference.md | 6 ----- docs/domains/primitives/syscalls/README.md | 2 +- .../primitives/syscalls/api_reference.md | 18 ++++++++++++++- include/sindri/primitives.h | 1 - include/sindri/primitives/ntdll.h | 23 ------------------- include/sindri/primitives/syscalls.h | 12 ++++++++++ src/primitives/modules/ntdll.c | 14 ----------- src/primitives/syscalls/syscalls.c | 13 ++++++++++- 12 files changed, 44 insertions(+), 64 deletions(-) delete mode 100644 include/sindri/primitives/ntdll.h delete mode 100644 src/primitives/modules/ntdll.c diff --git a/CMakeLists.txt b/CMakeLists.txt index db3f7b4..e1e7ee8 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,6 @@ add_library(sindri_engine STATIC src/primitives/modules/win.c src/primitives/modules/native.c src/primitives/modules/peb.c - src/primitives/modules/ntdll.c # Syscall resolvers src/primitives/syscalls/syscalls.c src/primitives/syscalls/hellsgate.c diff --git a/docs/domains/loaders/techniques.md b/docs/domains/loaders/techniques.md index ea4e476..8368622 100644 --- a/docs/domains/loaders/techniques.md +++ b/docs/domains/loaders/techniques.md @@ -57,7 +57,7 @@ When operating in native mode, SindriKit needs a clean `ntdll.dll` to extract SS At boot, the Session Manager (`smss.exe`) creates pre-mapped, read-only section objects for core system DLLs under the `\KnownDlls` Object Manager directory. These sections are snapshots taken before any userland security software is initialized. Opening `\KnownDlls\ntdll.dll` via `NtOpenSection` and mapping it into the current process with `NtMapViewOfSection` yields a pristine image whose text section has never been touched by EDR hooks. -The base address of this clean mapping is then fed directly to `snd_set_ntdll()` (from `sindri/primitives/ntdll.h`), ensuring that all subsequent SSN resolution operate on unmodified stubs. +The base address of this clean mapping is then fed directly to `snd_set_ntdll()`, ensuring that all subsequent SSN resolution operate on unmodified stubs. ```c PVOID clean_ntdll = NULL; diff --git a/docs/domains/primitives/README.md b/docs/domains/primitives/README.md index c2f1253..d0be14a 100644 --- a/docs/domains/primitives/README.md +++ b/docs/domains/primitives/README.md @@ -14,17 +14,3 @@ The primitives domain forms the absolute foundation of SindriKit. Everything bui Techniques for interacting with loaded DLLs and extracting function addresses via PEB traversal. - [syscalls/](syscalls/) The framework's advanced system for bypassing userland EDR hooks via a cascading fallback mechanism. - ---- - -## Global Primitives (`sindri/primitives/ntdll.h`) - -SindriKit maintains global state for the `ntdll.dll` base address. This address is used ubiquitously by native components (like the syscall resolver and the native module API) to extract clean stubs or parse export tables without relying on repetitive PEB lookups or the potentially hooked PEB-resident image. - -### `snd_set_ntdll` -Sets the globally cached base address of `ntdll.dll`. -- **`ntdll_base`**: Base address to cache. Typically obtained via KnownDlls mapping or PEB walking. - -### `snd_get_ntdll` -Retrieves the globally cached base address. -- **Returns:** `PVOID` The base address, or `NULL` if not set. diff --git a/docs/domains/primitives/memory/techniques.md b/docs/domains/primitives/memory/techniques.md index 511ebf2..fbbf142 100644 --- a/docs/domains/primitives/memory/techniques.md +++ b/docs/domains/primitives/memory/techniques.md @@ -27,4 +27,4 @@ The `snd_mem_native` implementation bypasses `kernel32.dll` and `ntdll.dll` enti By executing the `syscall` instruction directly, the implant cleanly bypasses userland EDR hooks placed inside the `ntdll.dll` stubs. The kernel receives the memory request without userland telemetry sensors ever recording the event. > [!WARNING] -> `snd_mem_native` requires the operator to manually configure the syscall pipeline (via `snd_set_syscall_strategy` and `sindri/primitives/ntdll.h`'s `snd_set_ntdll`) prior to invocation. If the pipeline is not bootstrapped, the native memory calls will immediately fail. +> `snd_mem_native` requires the operator to manually configure the syscall pipeline (via `snd_set_syscall_strategy` and `snd_set_ntdll`) prior to invocation. If the pipeline is not bootstrapped, the native memory calls will immediately fail. diff --git a/docs/domains/primitives/modules/api_reference.md b/docs/domains/primitives/modules/api_reference.md index 8fa6afb..6060c88 100644 --- a/docs/domains/primitives/modules/api_reference.md +++ b/docs/domains/primitives/modules/api_reference.md @@ -56,9 +56,3 @@ Hash-based variant. Eliminates the plaintext module name string from the binary | `out_base` | `PVOID*` | Receives the base address of the located module | **Returns:** `snd_status_t` — `SND_OK` on success. - ---- - -## Global NTDLL State (`sindri/primitives/ntdll.h`) - -SindriKit maintains global state for the `ntdll.dll` base address. This address is used ubiquitously by native components to extract clean stubs or parse export tables without relying on repetitive PEB lookups or the potentially hooked PEB-resident image. diff --git a/docs/domains/primitives/syscalls/README.md b/docs/domains/primitives/syscalls/README.md index a3463fe..65a01e6 100644 --- a/docs/domains/primitives/syscalls/README.md +++ b/docs/domains/primitives/syscalls/README.md @@ -3,7 +3,7 @@ This directory details SindriKit's advanced system for extracting System Service Numbers (SSNs) and bypassing inline userland EDR hooks. > [!WARNING] -> **Initialization Constraint:** The syscall pipeline requires setting up the NTDLL base address. `snd_set_ntdll()` (from `sindri/primitives/ntdll.h`) must be called prior to invoking any resolution function. +> **Initialization Constraint:** The syscall pipeline requires setting up the NTDLL base address. `snd_set_ntdll()` must be called prior to invoking any resolution function. ## Table of Contents - [pipeline.md](pipeline.md) diff --git a/docs/domains/primitives/syscalls/api_reference.md b/docs/domains/primitives/syscalls/api_reference.md index cba6e8e..e83e921 100644 --- a/docs/domains/primitives/syscalls/api_reference.md +++ b/docs/domains/primitives/syscalls/api_reference.md @@ -65,7 +65,7 @@ Appends a fallback strategy to the resolution pipeline. The pipeline is evaluate ### NTDLL Base Address > [!NOTE] -> The `ntdll.dll` base address is managed globally via `snd_set_ntdll` and `snd_get_ntdll` from `sindri/primitives/ntdll.h`. You MUST set the global base before attempting to resolve syscalls. +> The `ntdll.dll` base address is managed globally via `snd_set_ntdll` and `snd_get_ntdll`. You MUST set the global base before attempting to resolve syscalls. --- @@ -91,3 +91,19 @@ ASM stub that performs the actual `syscall` instruction. Architecture-specific i | `args` | `snd_syscall_args_t*` | Pointer to a populated arguments structure | **Returns:** `NTSTATUS` — the raw kernel return value. + +### `snd_set_ntdll` +Sets the global `ntdll.dll` base address. + +| Parameter | Type | Description | +|---|---|---| +| `base` | `PVOID` | The base address of the `ntdll.dll` image | + +**Returns:** `void` + +--- + +### `snd_get_ntdll` +Returns the global `ntdll.dll` base address. + +**Returns:** `PVOID` — the base address of the `ntdll.dll` image, or `NULL` if not set. diff --git a/include/sindri/primitives.h b/include/sindri/primitives.h index c77f15a..4ddd9a2 100644 --- a/include/sindri/primitives.h +++ b/include/sindri/primitives.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/include/sindri/primitives/ntdll.h b/include/sindri/primitives/ntdll.h deleted file mode 100644 index c5f1d08..0000000 --- a/include/sindri/primitives/ntdll.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef SND_PRIMITIVES_NTDLL_H -#define SND_PRIMITIVES_NTDLL_H - -#include -#include - -SND_BEGIN_EXTERN_C - -/** - * @brief Sets the global base address of the ntdll.dll module. - * @param ntdll_base The base address of the ntdll module. - */ -void snd_set_ntdll(PVOID ntdll_base); - -/** - * @brief Retrieves the global base address of the ntdll.dll module. - * @return The base address of the ntdll module, or NULL if not set. - */ -PVOID snd_get_ntdll(void); - -SND_END_EXTERN_C - -#endif // SND_PRIMITIVES_NTDLL_H diff --git a/include/sindri/primitives/syscalls.h b/include/sindri/primitives/syscalls.h index 21bd1a7..66c1f93 100644 --- a/include/sindri/primitives/syscalls.h +++ b/include/sindri/primitives/syscalls.h @@ -59,6 +59,18 @@ void snd_set_syscall_strategy(snd_syscall_resolver_t resolver); */ snd_status_t snd_add_syscall_strategy(snd_syscall_resolver_t resolver); +/** + * @brief Sets the global base address of the ntdll.dll module. + * @param ntdll_base The base address of the ntdll module. + */ +void snd_set_ntdll(PVOID ntdll_base); + +/** + * @brief Retrieves the global base address of the ntdll.dll module. + * @return The base address of the ntdll module, or NULL if not set. + */ +PVOID snd_get_ntdll(void); + /** * @brief Core resolution entrypoint (evaluates the internal fallback chain * automatically). diff --git a/src/primitives/modules/ntdll.c b/src/primitives/modules/ntdll.c deleted file mode 100644 index e55093c..0000000 --- a/src/primitives/modules/ntdll.c +++ /dev/null @@ -1,14 +0,0 @@ -#include - -static PVOID g_PristineNtdll = NULL; - -void snd_set_ntdll(PVOID ntdll_base) { - if (ntdll_base == NULL) { - return; - } - g_PristineNtdll = ntdll_base; -} - -PVOID snd_get_ntdll(void) { - return g_PristineNtdll; -} diff --git a/src/primitives/syscalls/syscalls.c b/src/primitives/syscalls/syscalls.c index fb7de3d..4f4b05b 100644 --- a/src/primitives/syscalls/syscalls.c +++ b/src/primitives/syscalls/syscalls.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -9,6 +8,18 @@ // State management for the resolution pipeline static snd_syscall_resolver_t g_strategy_chain[SND_MAX_INTERNAL_STRATEGIES] = {0}; static int g_strategy_count = 0; +static PVOID g_syscall_ntdll_target = NULL; + +void snd_set_ntdll(PVOID ntdll_base) { + if (ntdll_base == NULL) { + return; + } + g_syscall_ntdll_target = ntdll_base; +} + +PVOID snd_get_ntdll(void) { + return g_syscall_ntdll_target; +} void snd_set_syscall_strategy(snd_syscall_resolver_t resolver) { if (!resolver)