LDK stands for Load DLL into Kernel space.
LDK is an experimental Windows kernel-mode support library for drivers that
need a familiar Win32/NTDLL-like surface inside kernel space. It provides a
static WDK library, public headers under include/Ldk, and partial
implementations of APIs normally provided by kernel32.dll and ntdll.dll.
The project is useful when a driver needs to reuse carefully controlled DLL code or when kernel-mode code benefits from familiar primitives such as critical sections, condition variables, fibers, heap helpers, loader helpers, environment handling, and path/string utilities.
LDK is not a general-purpose Windows compatibility layer. It implements only a small subset of APIs, and the DLL-loading path is intentionally experimental. Every DLL or driver integration should be audited and tested in an isolated driver test environment before use.
Avoid loading modules that rely on user-mode TEB/PEB assumptions, unsupported Win32 subsystems, GUI APIs, COM, CRT startup behavior, or other user-mode-only runtime features.
- Windows 7 or later
- Visual Studio 2017 or later
- Windows Driver Kit compatible with your Visual Studio toolset
- CMake 3.14 or later
The CMake build uses FindWDK through
CPM, so the WDK must be installed and discoverable on the build machine.
Choose the integration path that matches your driver project:
| Path | Use when | Start here |
|---|---|---|
| NuGet / MSBuild | Visual Studio or Build Tools WDK driver project | Install-Package ldk or PackageReference |
| CMake prebuilt | Offline, cached, or pinned release dependency | find_package(ldk CONFIG REQUIRED) |
| CMake / CPM | CMake-based driver project that wants to consume LDK from GitHub | CPMAddPackage("gh:ntoskrnl7/ldk@0.7.5") |
For a Visual Studio WDK driver project, install the NuGet package:
Install-Package ldkPackageReference-style projects can reference the package directly:
<ItemGroup>
<PackageReference Include="ldk" Version="0.7.5" />
</ItemGroup>Then restore and build with MSBuild:
msbuild .\MyDriver.vcxproj /restore /p:Configuration=Debug /p:Platform=x64The package imports native MSBuild props/targets automatically for normal
Visual Studio NuGet restore. It adds LDK headers, links the matching Ldk.lib,
defines _KERNEL32_, and uses LdkDriverEntry as the default driver entry
point. Your driver should still implement the normal WDK DriverEntry;
LdkDriverEntry initializes LDK, calls your DriverEntry, and terminates LDK
on unload.
Set LdkUseDriverEntry=false before importing ldk.targets if your driver
uses its own PE entry point and calls LdkInitialize / LdkTerminate
manually.
GitHub Releases include ldk-<version>-prebuilt.zip, which is useful for
offline builds or CI systems that cache third-party dependencies. Unpack the
bundle and point CMake at it:
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(MyDriver C)
find_package(ldk CONFIG REQUIRED PATHS "path/to/ldk-0.7.5" NO_DEFAULT_PATH)
ldk_add_driver(MyDriver main.c)The prebuilt package contains toolset-specific Ldk.lib builds under
lib/native/<toolset>/<arch>/<config>, plus headers, docs, native MSBuild
imports, and CMake helpers.
Current prebuilt toolset coverage is:
v142:x86,x64,ARM, andARM64v143:x86,x64,ARM, andARM64v145:x86,x64, andARM64
Visual Studio 2026 / v145 no longer targets 32-bit ARM, so
lib/native/v145/ARM is intentionally not published.
Use this in a third-party driver project's CMakeLists.txt when you want to
consume LDK directly from GitHub. CPMAddPackage makes LDK's CMake helpers and
targets available to that project. To clone and build the LDK repository itself,
use the Build From Source section.
First add CPM.cmake to your own driver project:
New-Item -ItemType Directory -Force cmake
Invoke-WebRequest `
https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.32.0/CPM.cmake `
-OutFile cmake/CPM.cmakeThen consume LDK from that project:
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
project(MyDriver C)
include("${CMAKE_CURRENT_LIST_DIR}/cmake/CPM.cmake")
CPMAddPackage("gh:ntoskrnl7/ldk@0.7.5")
include(${ldk_SOURCE_DIR}/cmake/Ldk.cmake)
ldk_add_driver(MyDriver main.c)Using LdkDriverEntry as the custom entry point lets LDK run its initialization
and termination hooks automatically. If you use your own driver entry point,
call LdkInitialize during driver startup and LdkTerminate before unload.
#include <Ldk/Windows.h>
DRIVER_INITIALIZE DriverEntry;
DRIVER_UNLOAD DriverUnload;
typedef struct _WORKER_STATE {
BOOL ready;
LONG processed;
CONDITION_VARIABLE cv;
CRITICAL_SECTION cs;
} WORKER_STATE, *PWORKER_STATE;
DWORD
WINAPI
WorkerThread(
LPVOID Context
)
{
PWORKER_STATE state = (PWORKER_STATE)Context;
EnterCriticalSection(&state->cs);
while (!state->ready) {
SleepConditionVariableCS(&state->cv, &state->cs, INFINITE);
}
InterlockedIncrement(&state->processed);
WakeConditionVariable(&state->cv);
LeaveCriticalSection(&state->cs);
return 0;
}
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
UNREFERENCED_PARAMETER(RegistryPath);
WORKER_STATE state = {0};
InitializeCriticalSection(&state.cs);
InitializeConditionVariable(&state.cv);
HANDLE thread = CreateThread(NULL, 0, WorkerThread, &state, 0, NULL);
EnterCriticalSection(&state.cs);
state.ready = TRUE;
WakeAllConditionVariable(&state.cv);
LeaveCriticalSection(&state.cs);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
DeleteCriticalSection(&state.cs);
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
VOID
DriverUnload(
_In_ PDRIVER_OBJECT DriverObject
)
{
UNREFERENCED_PARAMETER(DriverObject);
}Clone the repository and build with CMake:
git clone https://github.com/ntoskrnl7/ldk
cd ldk
cmake -S . -B build_x64 -A x64 -DWDK_WINVER=0x0602
cmake --build build_x64 --config ReleaseThe helper script wraps the same flow:
build.bat . x64 Release
build.bat . x86 Release
build.bat . ARM Release
build.bat . ARM64 ReleaseRelease libraries are written under:
lib/<architecture>/Ldk.lib
The test directory builds a sample kernel driver that links against LDK.
cd test
..\build.bat . x64 ReleaseThe build output includes LdkTest.sys. Loading and unloading the driver must
be done manually in an appropriate Windows driver test environment. GitHub
Actions verifies x64 and ARM64 test driver builds, plus x86 and ARM package
layout checks, but it does not load kernel drivers.
Additional implementation and test notes live under docs/.
The Package GitHub Actions workflow builds prebuilt Debug/Release libraries
under a toolset-specific package layout, packs the ldk NuGet package,
validates the package with minimal WDK consumer drivers, and prepares GitHub
Release assets. v142 packages cover x86/x64/ARM/ARM64, v143 packages cover
x86/x64/ARM/ARM64, and v145 packages cover x86/x64/ARM64.
The Release workflow is the publishing entry point. It updates
include/Ldk/internal/version.h, creates a v<version> tag, then dispatches
the Package workflow. NuGet publishing uses NuGet Trusted Publishing and
requires the repository variable NUGET_TRUSTED_PUBLISHING_USER.
Tagged releases are built by GitHub Actions. Pushing a tag such as v0.7.6
builds x86, x64, ARM, and ARM64 package artifacts and can attach the generated
NuGet package and prebuilt ZIP bundle to the GitHub Release.
The normal publishing path is to run the Release workflow manually with the
target version. It creates the version commit and tag, then dispatches the
Package workflow against that tag.
Release assets contain:
ldk.<version>.nupkgldk-<version>-prebuilt.zipldk-<version>-SHA256SUMS.txt
include/Ldk/ Public headers
src/ LDK runtime implementation
src/kernel32/ Kernel-mode implementations of selected Kernel32 APIs
src/ntdll/ Kernel-mode implementations of selected NTDLL APIs
test/ Sample/test driver project
cmake/ CMake helper modules
msvc/ Visual Studio solution and project files
- The API surface is intentionally incomplete.
- Treat DLL loading in kernel space as a last-resort technique, not as a normal driver architecture.