by Kiy0w0
Full kernel-mode PE manual mapping · Zero usermode injection APIs · MDL Stealth IPC · Thread Hijacking
Nanahira is a ring-0 kernel manual map DLL injector. Every step of the injection PE parsing, section mapping, base relocations, import resolution, per-section memory protection, TLS callbacks, exception directory registration, and DllMain execution runs entirely inside the Windows kernel.
The usermode side (nanahira.exe) reads the DLL from disk and drops it into a shared memory section. That's it. No VirtualAllocEx, no WriteProcessMemory, no CreateRemoteThread the kernel driver does all of it.
Three injection modes are available depending on your situation:
| Mode | How it works |
|---|---|
kernel |
Full ring-0 manual map via driver (default) |
hook |
Shellcode injected via SetWinEventHook no CreateRemoteThread |
usermode |
Direct inject without driver VirtualAllocEx + self-contained shellcode |
nanahira.exe driver.sys
───────────── ─────────────────────────────────
Find target PID SharedMemory Parse PE headers
Read DLL from disk ════════════════► Allocate memory in target
Write to SHM Map sections
Send IPC command ◄════════════════ Fix relocations
Show progress + base Status / Base Resolve imports (name + ordinal)
Delay-load imports
Set per-section protections
Register exception table (.pdata)
Run TLS callbacks
Erase / stomp PE headers
Call DllMain
The IPC channel between usermode and the kernel driver uses an anonymous MDL-mapped buffer — no named section objects, no visible handles in the global namespace. The driver auto-maps the buffer into nanahira.exe via a process notify callback when the injector starts.
| Feature | Details |
|---|---|
| Full kernel manual map | PE ops in ring 0 — no usermode injection APIs |
| Thread hijacking execution | Hijacks an existing game thread instead of creating a new one — avoids CreateThread callbacks monitored by Anti-Cheat |
| Import by name + ordinal | Both forms handled — previously ordinal imports were skipped |
| Delay-load import support | IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT resolved at inject time |
| Forwarded export resolution | Chains like ntdll.RtlXxx → ntdllp.RtlXxx are followed |
| TLS callback execution | Callbacks run before DllMain, as the loader would |
| Exception directory (.pdata) | RtlAddFunctionTable called in-process so C++ exceptions / SEH work inside injected DLL |
| Header erase / stomp | Zero or LFSR-junk overwrite — controlled per-inject via flags |
| Stealth IPC | Anonymous MDL-mapped buffer — no named kernel objects visible to scanners |
| WinEventHook injection | Alternative entry via SetWinEventHook + self-contained shellcode |
| Usermode fallback | Works without driver — full PE shellcode runs inside target |
| Compile-time XOR strings | Sensitive literals encrypted at compile time via template metaprogramming |
| Signature randomization | Source-level identifier mutation + binary PE mutations every build |
| Discord Rich Presence | Status updates while injecting |
| Gradient console UI | 24-bit ANSI color, live progress bar |
kernel-mmi/
├── nanahira.sln
├── build_release.bat
├── quick_spoof.bat
│
├── driver/
│ ├── driver.cpp Manual map engine
│ └── driver.h Internal declarations + dynamic import typedefs
│
├── usermode/
│ ├── nanahira.cpp Injector UI + IPC client
│ ├── nanahira.h Utilities + mode definitions
│ ├── hook_inject.h WinEventHook injection mode
│ ├── usermode_inject.h Usermode fallback injection mode
│ ├── xor.h Compile-time XOR string obfuscation
│ ├── lazy_importer.h PEB-walk API resolution (LI_FN)
│ ├── discord_rpc.cpp Discord Rich Presence over named pipe
│ └── discord_rpc.h
│
└── shared/
└── protocol.h Shared memory layout + IPC commands + flags
| Details | |
|---|---|
| Windows 10 / 11 x64 | Tested on 22H2 / 23H2 |
| Administrator | Everything needs elevation |
| Visual Studio 2022 | Desktop development with C++ workload |
| Windows Driver Kit | Match your Windows SDK version |
| PowerShell 7+ | Required for signature randomization scripts |
1. Build → 2. Load driver → 3. Start target → 4. Inject
build_release.batRuns source mutation, compiles both projects, restores source, then applies 10 binary PE mutations. Output goes to output/.
Or build manually in VS2022 Release | x64, then run quick_spoof.bat for PE mutations.
Test signing (recommended):
:: One-time setup run as admin, then reboot
bcdedit /set testsigning on
bcdedit /set nointegritychecks on# Self-sign the driver
$cert = New-SelfSignedCertificate -Subject "CN=Nanahira" -Type CodeSigningCert -CertStoreLocation "Cert:\LocalMachine\My"
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("Root","LocalMachine")
$store.Open("ReadWrite"); $store.Add($cert); $store.Close()
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("TrustedPublisher","LocalMachine")
$store.Open("ReadWrite"); $store.Add($cert); $store.Close()
Set-AuthenticodeSignature -FilePath "output\driver.sys" -Certificate $certsc create nanahira type= kernel binPath= "C:\path\to\output\driver.sys"
sc start nanahirakdmapper:
kdmapper.exe output\driver.sys:: Default kernel mode
output\nanahira.exe target.exe C:\path\to\dll.dll
:: Thread hijack execution (no new thread — avoids CreateThread callbacks)
output\nanahira.exe target.exe C:\path\to\dll.dll --hijack
:: WinEventHook mode (no CreateRemoteThread)
output\nanahira.exe target.exe C:\path\to\dll.dll --mode=hook
:: Usermode fallback (no driver needed)
output\nanahira.exe target.exe C:\path\to\dll.dll --mode=usermode
:: Interactive (prompts for process + DLL + mode)
output\nanahira.exequick_spoof.batApplies fresh PE mutations without recompiling. Re-sign driver.sys after.
sc stop nanahira
sc delete nanahiraPer-injection behavior can be controlled via flags set in shared/protocol.h:
| Flag | Effect |
|---|---|
INJ_FLAG_ERASE_HEADERS |
Zero out PE headers in target after mapping |
INJ_FLAG_STOMP_HEADERS |
Overwrite headers with LFSR junk instead of zeros |
INJ_FLAG_SKIP_TLS |
Skip TLS callback execution |
INJ_FLAG_SKIP_EXCEPTIONS |
Skip RtlAddFunctionTable call |
INJ_FLAG_THREAD_HIJACK |
Hijack an existing thread to call DllMain — no RtlCreateUserThread |
Before compilation, identifiers in protocol.h are randomized shared memory name, magic value, pool tag. The compiled binary contains completely different strings and constants each time.
After compilation, 10 mutations are applied:
| # | Target | What changes |
|---|---|---|
| 1 | TimeDateStamp | Random compile timestamp |
| 2 | Checksum | Random PE checksum |
| 3 | Rich header | Destroys MSVC toolchain fingerprint |
| 4 | Section names | .text → .code, .rdata → .cnst, etc. |
| 5 | Debug directory | Wipes PDB path and CodeView GUID |
| 6 | Linker version | Fakes MSVC version fields |
| 7 | OS version | Randomizes minimum OS version fields |
| 8 | Code caves | NOP-like junk in padding regions |
| 9 | Build GUID | Unique 128-bit watermark per build |
| 10 | DOS stub | Randomizes unused DOS header bytes |
Every run produces binaries with a different SHA256 hash.
Build errors
| Error | Fix |
|---|---|
WDK not found |
Install WDK matching your SDK version |
'cl.exe' not recognized |
Use x64 Native Tools Command Prompt |
LNK2001 unresolved external |
Undocumented APIs are resolved dynamically don't link them statically |
Driver loading
| Error | Fix |
|---|---|
Access denied |
Run as Administrator |
StartService FAILED 577 |
Driver unsigned enable test signing + self-sign |
Value protected by Secure Boot |
Disable Secure Boot in BIOS first |
Memory Integrity blocking |
Windows Security → Core Isolation → Memory integrity → Off |
| BSOD with kdmapper | Use test signing method instead |
Injection issues
| Error | Fix |
|---|---|
Cannot connect |
Driver not loaded run sc start nanahira first |
Process not found |
Target must already be running |
Invalid PE |
Must be a valid x64 DLL |
Import resolution failed |
Required DLL not loaded in target try hook or usermode mode |
| Target crashes | Check Event Viewer for 0xC0000005 DLL access violation |
- Thread hijack execution path — hijacks an existing thread to call
DllMain, avoidsRtlCreateUserThreadentirely (--hijackflag) - Forwarded export resolution — chains like
ntdll.RtlXxx → ntdllp.RtlXxxare followed correctly - Delay-load import support —
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORTresolved at inject time - Exception directory registration via in-process
RtlAddFunctionTableshellcode — C++ exceptions work inside injected DLLs - IPC shared memory scan hardened —
ConnectToDrivernow works correctly across all Windows 10/11 builds
- Initial release
Special thanks to the following projects and authors for their contributions to the injection techniques used in this project:
- TTKKO/Kernel-Manual-Map-Injector WinEventHook and shellcode logic.
- TheCruZ/Simple-Manual-Map-Injector Manual mapping concepts and IAT references.
For educational and research purposes only. The author takes no responsibility for misuse. Use responsibly and in compliance with applicable laws.
