Click here to Skip to main content
Click here to Skip to main content

Tagged as

Keyboard Hooking In Kernel

, 11 May 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
A post of how to do keyboard hooking in kernel
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:

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.

	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)

Share

About the Author


Comments and Discussions

 
Questionwhy not work ? PinmemberMember 108817403-Oct-14 9:33 
QuestionNice Article!!! Pinmembersuneet.saini15-Jul-14 22:51 
QuestionKeyboard driver notify PinmemberAster Veigas9-Jul-13 20:36 
AnswerRe: Keyboard driver notify PingroupGünter Bergmann11-Jul-13 5:50 
GeneralRe: Keyboard driver notify PinmemberAster Veigas23-Jul-13 22:02 
QuestionJust disable Print screen key Pinmemberfakharmalik7-Mar-13 19:40 
GeneralMy vote of 5 PinmemberMichael_Romanov9-Dec-12 4:20 
BugA minor correction for 64 bit compatibility Pinmemberozgurbtr28-Oct-12 14:54 
GeneralMy vote of 5 Pinmemberozgurbtr28-Oct-12 14:39 
GeneralMy vote of 5 PinmemberSteve Ween10-Apr-12 23:57 
Questionnice work PinmemberAlexAlvarez6-Oct-11 7:27 
AnswerRe: nice work Pingroupxnli19-Mar-12 0:00 
QuestionMy vote of 5 and a small question Pinmembernbgangsta15-Jun-11 4:34 
AnswerRe: My vote of 5 and a small question Pingroupxnli15-Jun-11 5:00 
GeneralRe: My vote of 5 and a small question PinmemberIzybell27-Jun-11 17:42 
GeneralRe: My vote of 5 and a small question Pingroupxnli27-Jun-11 17:59 
GeneralCool Post ;-) PinmemberMember 156277917-May-11 0:02 
GeneralMy vote of 5 PinmemberSAKryukov16-May-11 16:50 
GeneralMy vote of 2 Pinmember428811-May-11 21:53 
GeneralRe: My vote of 2 PinmemberSkymir12-May-11 8:13 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.1411023.1 | Last Updated 11 May 2011
Article Copyright 2011 by Günter Bergmann
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid