Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / C++

Keyboard Hooking In Kernel

Rate me:
Please Sign up or sign in to vote.
4.78/5 (23 votes)
11 May 2011CPOL2 min read 76.3K   6.1K   73   22
A post of how to do keyboard hooking in kernel

KeyboardHookingInKernel/screen_shot.GIF

Introduction

Please imagine that there's no input signal from the keyboard. It can be used to secure a computer from anybody. For example, if you leave the computer, you can lock the keyboard in this way. After returning to your computer, you can type specific keys to unlock the computer. So the other man who doesn't know your secret password can't access your computer. This can be implemented through Keyboard Hooking.

What is keyboard hooking?

We also called it keyboard filtering. And it can be explained in a simple manner. The user presses the key and from Keyboard device driver sends signals to User's application. And we hook the stream of that.

Keyboard hooking can be accomplished in several ways. In Userland and Kernelland.
You can see userland sample from Adam Roderick J's article.
He shows keyboard hooking skills in userland and few articles also explain keyboard hooking. But using this technique, you can't hook several times by several applications and it can also be uninstalled easily. So I'll introduce another way to hook keyboard in Kernelland. I focused on Driver Hooking in this article. You can not only stop key signals, but also modify signals from User by using this technique, then it can become a virus or malware. But I don't want that. Then how can it be implemented? Let's see together.

How To Use

Place Application.exe and HK_KBD.sys in the same folder, and execute Application.exe. Then press any key. You can see that there's no input from key. OK! That's it!

Using the Code

First, we should find keyboard device object handle. In order to do, you should list all the devices of your computer. And from them, you should find Keyboard Class Device.
You can implement that in the following way:

C++
NTSTATUS
KeyFlt_CreateClose(
		IN PDEVICE_OBJECT DeviceObject,
		IN PIRP Irp
		)
{
	...
	switch (stack->MajorFunction)
	{
	case IRP_MJ_CREATE:
		{
			...
				RtlInitUnicodeString(&uniOa, L"\\Device");

				InitializeObjectAttributes(
					&oa,
					&uniOa,
					OBJ_CASE_INSENSITIVE,
					NULL,
					NULL
					);
				
				status = ZwOpenDirectoryObject(
					&hDir,
					DIRECTORY_ALL_ACCESS,
					&oa
					);
				if(!NT_SUCCESS(status))
				{
					break;
				}
				
				pBuffer = ExAllocatePoolWithTag
					(PagedPool, ALLOC_SIZE, Tag);
				pContext = ExAllocatePoolWithTag
					(PagedPool, ALLOC_SIZE, Tag);
				memset(pBuffer, 0, ALLOC_SIZE);
				memset(pContext, 0, ALLOC_SIZE);
				memset(arKbdCls, 0, 0x10);
				counter = 0;
				g_kbdclsnum = 0;
				
				while(TRUE)
				{
					status = ZwQueryDirectoryObject(
						hDir,
						pBuffer,
						ALLOC_SIZE,
						TRUE,
						FALSE,
						pContext,
						&RetLen
						);
					if(!NT_SUCCESS(status))
					{
						break;
					}
					
					pDirBasicInfo =	
					(PDIRECTORY_BASIC_INFORMATION)pBuffer;
					pDirBasicInfo->ObjectName.Length -= 2;
					
					RtlInitUnicodeString(&uniKbdDrv, 
						L"KeyboardClass");
					
					if(RtlCompareUnicodeString(
						&pDirBasicInfo->ObjectName,
						&uniKbdDrv,
						FALSE
						) == 0)
					{
						KbdclsNum = (char*) ((ULONG) 
						(pDirBasicInfo->
						ObjectName.Length) + 
						(ULONG) (pDirBasicInfo->
							ObjectName.Buffer));
						arKbdCls[counter] = *KbdclsNum;
						counter++;
					}
					pDirBasicInfo->ObjectName.Length += 2;
				}
				ExFreePool(pBuffer);
				ExFreePool(pContext);
				ZwClose(hDir);
				for(i = 0; i < 0x10; i++)
				{
					if(arKbdCls[i] == 0)
						break;
					else if(arKbdCls[i] == 0x30)
						g_kbdclsnum |= KBDCLASS_0;
					else if(arKbdCls[i] == 0x31)
						g_kbdclsnum |= KBDCLASS_1;
					else if(arKbdCls[i] == 0x32)
						g_kbdclsnum |= KBDCLASS_2;
				}
				if(g_kbdclsnum & KBDCLASS_0)
				{
					RtlInitUnicodeString(
					&uniKbdDeviceName,
					L"\\Device\\KeyboardClass0"
					);
				}
				else
				{
					if(g_kbdclsnum & KBDCLASS_2)
					{
						RtlInitUnicodeString(
						&uniKbdDeviceName,
						L"\\Device\\KeyboardClass2"
						);
					}
					else if(g_kbdclsnum & KBDCLASS_1)
					{
						RtlInitUnicodeString(
						&uniKbdDeviceName,
						L"\\Device\\KeyboardClass1"
						);
					}
					else
					{
						g_nop = 1;
						break;
					}
				}
				status = KeyFlt_IoGetDeviceObjectPointer(
					&uniKbdDeviceName,
					0,
					&KbdFileObject,
					&KbdDeviceObject
					);
				...
			}
			break;
		}
	...
}

Now we found the pointer. Then, we should attach to keyboard device object. Here IoAttachDeviceToDeviceStack() function is used to filter keyboard device.

But unfortunately, if that function fails, then we should replace Major function of that keyboard driver.

C++
	if(NT_SUCCESS(status))
	{
		g_KbdDeviceObject = KbdDeviceObject;
		ObDereferenceObject(KbdFileObject);
		KdPrint(("KeyFlt: Attach Device. \n"));
		__try
		{
			g_TopOfStack = IoAttachDeviceToDeviceStack
					(DeviceObject, KbdDeviceObject);
			
			if (g_TopOfStack != NULL)
			{
				g_OldFunction = g_KbdDeviceObject->
				DriverObject->MajorFunction[IRP_MJ_READ];
				g_KbdDeviceObject->DriverObject->
				MajorFunction[IRP_MJ_READ] = KeyFlt_HookProc;
			}
			else
			{
				g_nop = 1;
				g_TopOfStack = NULL;
				break;
			}
		}
		__except(1)
		{
			g_nop = 1;
			break;
		}
	}
	else
	{
		g_nop = 1;
		break;
	}
	...

NTSTATUS KeyFlt_IoGetDeviceObjectPointer(
IN PUNICODE_STRING ObjectName,
IN ACCESS_MASK DesiredAccess,
OUT PFILE_OBJECT *FileObject,
OUT PDEVICE_OBJECT *DeviceObject
)
{
	NTSTATUS status;
	OBJECT_ATTRIBUTES oa;
	IO_STATUS_BLOCK iostatus;
	PVOID ptr;

	InitializeObjectAttributes(
		&oa,
		ObjectName,
		OBJ_KERNEL_HANDLE,
		NULL,
		NULL
		);
	status = ZwOpenFile(
		&ObjectName,
		DesiredAccess,
		&oa,
		&iostatus,
		0x07,
		0x40
		);
	if(!NT_SUCCESS(status))
	{
		return status;
	}
	status = ObReferenceObjectByHandle(
		ObjectName,
		DesiredAccess,
		0,
		KernelMode,
		&ptr,
		0
		);
	if(!NT_SUCCESS(status))
	{
		ZwClose(ObjectName);
		return status;
	}
	*FileObject = ptr;
	*DeviceObject = IoGetRelatedDeviceObject(ptr);
	ZwClose(ObjectName);
	return status;
}

You can change the key information in KeyFlt_DispatchPassThrough() function and KeyFlt_DispatchRead() function.

So the rest of the code is simple.

Conclusion

How did you find my post? I hope that this code can help in your development. Please vote for me.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Comments and Discussions

 
QuestionVote of 5 and 2 questions Pin
Member 1331165716-Jul-17 13:44
Member 1331165716-Jul-17 13:44 
AnswerRe: Vote of 5 and 2 questions Pin
Member 1331165725-Jul-17 8:55
Member 1331165725-Jul-17 8:55 
Questionwhy not work ? Pin
Member 108817403-Oct-14 8:33
Member 108817403-Oct-14 8:33 
QuestionNice Article!!! Pin
suneet.saini15-Jul-14 21:51
suneet.saini15-Jul-14 21:51 
QuestionKeyboard driver notify Pin
Aster Veigas9-Jul-13 19:36
Aster Veigas9-Jul-13 19:36 
AnswerRe: Keyboard driver notify Pin
Otto Lehmann11-Jul-13 4:50
Otto Lehmann11-Jul-13 4:50 
GeneralRe: Keyboard driver notify Pin
Aster Veigas23-Jul-13 21:02
Aster Veigas23-Jul-13 21:02 
QuestionJust disable Print screen key Pin
fakharmalik7-Mar-13 18:40
fakharmalik7-Mar-13 18:40 
hii!!

the article was very helpful as i am new in windows programming need little help. i just want to disable print screen button not the whole keyboard can any one help me and guide me through


regards
GeneralMy vote of 5 Pin
Michael_Romanov9-Dec-12 3:20
Michael_Romanov9-Dec-12 3:20 
BugA minor correction for 64 bit compatibility Pin
Ozgur Batur28-Oct-12 13:54
Ozgur Batur28-Oct-12 13:54 
GeneralMy vote of 5 Pin
Ozgur Batur28-Oct-12 13:39
Ozgur Batur28-Oct-12 13:39 
GeneralMy vote of 5 Pin
Steve Ween10-Apr-12 22:57
Steve Ween10-Apr-12 22:57 
Questionnice work Pin
AlexAlvarez6-Oct-11 6:27
AlexAlvarez6-Oct-11 6:27 
AnswerRe: nice work Pin
Otto Lehmann18-Mar-12 23:00
Otto Lehmann18-Mar-12 23:00 
QuestionMy vote of 5 and a small question Pin
Groulien15-Jun-11 3:34
Groulien15-Jun-11 3:34 
AnswerRe: My vote of 5 and a small question Pin
Otto Lehmann15-Jun-11 4:00
Otto Lehmann15-Jun-11 4:00 
GeneralRe: My vote of 5 and a small question Pin
Izybell27-Jun-11 16:42
Izybell27-Jun-11 16:42 
GeneralRe: My vote of 5 and a small question Pin
Otto Lehmann27-Jun-11 16:59
Otto Lehmann27-Jun-11 16:59 
GeneralCool Post ;-) Pin
swdld16-May-11 23:02
swdld16-May-11 23:02 
GeneralMy vote of 5 Pin
Sergey Alexandrovich Kryukov16-May-11 15:50
mvaSergey Alexandrovich Kryukov16-May-11 15:50 
GeneralMy vote of 2 Pin
428811-May-11 20:53
428811-May-11 20:53 
GeneralRe: My vote of 2 PinPopular
Skymir12-May-11 7:13
Skymir12-May-11 7:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.