Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Tagged as

Keyboard Hooking In Kernel

, 11 May 2011
A post of how to do keyboard hooking in kernel
demo.zip
source.zip
Application
Application.dsp
Application.dsw
Application.plg
HK_KBD.sys
Debug
Application.exe
HK_KBD.sys
Application.opt
Driver
MAKEFILE
Sources
Sources.bak
objchk_wxp_x86
i386
HK_KBD.sys
Drv
Drv.vcproj.CAPTAIN_HOOK.Administrator.user
//Author : LiXianNan
#include <NTddk.h> 
#include "ioctl.h" 

#define NT_DEVICE_NAME  L"\\Device\\HK_KBD" 
#define DOS_DEVICE_NAME L"\\DosDevices\\HK_KBD" 
#define Tag		'KYBD'
#define KBDCLASS_0			0x1
#define KBDCLASS_1			0x2
#define KBDCLASS_2			0x4
#define ALLOC_SIZE				0x1000
typedef struct _DIRECTORY_BASIC_INFORMATION {

	UNICODE_STRING          ObjectName;
	UNICODE_STRING          ObjectTypeName;
	char                    Data[1];
} DIRECTORY_BASIC_INFORMATION, *PDIRECTORY_BASIC_INFORMATION;

NTSYSAPI 
NTSTATUS
NTAPI
ZwOpenDirectoryObject(

					  OUT PHANDLE             DirectoryObjectHandle,
					  IN ACCESS_MASK          DesiredAccess,
					  IN POBJECT_ATTRIBUTES   ObjectAttributes );

NTSYSAPI 
NTSTATUS
NTAPI
ZwQueryDirectoryObject(
					   IN HANDLE						DirectoryObjectHandle,
					   OUT PDIRECTORY_BASIC_INFORMATION	DirObjInformation,
					   IN ULONG							BufferLength,
					   IN BOOLEAN						GetNextIndex,
					   IN BOOLEAN						IgnoreInputIndex,
					   IN OUT PULONG					ObjectIndex,
					   OUT PULONG						DataWritten OPTIONAL );

typedef NTSTATUS (*IRPMJREAD) (IN PDEVICE_OBJECT, IN PIRP);

NTSTATUS KeyFlt_CreateClose(
					 IN PDEVICE_OBJECT DeviceObject,
					 IN PIRP Irp
					 );

NTSTATUS KeyFlt_IoGetDeviceObjectPointer(
	IN PUNICODE_STRING ObjectName,
	IN ACCESS_MASK DesiredAccess,
	OUT PFILE_OBJECT *FileObject,
	OUT PDEVICE_OBJECT *DeviceObject
	);

NTSTATUS KeyFlt_HookProc(
						   IN PDEVICE_OBJECT DeviceObject,
						   IN PIRP Irp
						   );

NTSTATUS KeyFlt_DispatchRead(
							   IN PDEVICE_OBJECT DeviceObject,
							   IN PIRP Irp
							   );

NTSTATUS KeyFlt_ReadComplete(
							   IN PDEVICE_OBJECT DeviceObject,
							   IN PIRP Irp,
							   IN PVOID Context
							   );

NTSTATUS KeyFlt_DispatchPassThrough(
									  IN PDEVICE_OBJECT DeviceObject,
									  IN PIRP Irp
									  );

ULONG	g_kbdclsnum;
ULONG	g_StartCount;
ULONG	g_nop;
PDEVICE_OBJECT	g_KbdDeviceObject;
PDEVICE_OBJECT	g_TopOfStack;
IRPMJREAD		g_OldFunction;

NTSTATUS DriverEntry(
					 IN PDRIVER_OBJECT DriverObject,
					 IN PUNICODE_STRING RegistryPath
					 )
{
	ULONG i;
	PDEVICE_OBJECT DeviceObject;
	NTSTATUS status = STATUS_SUCCESS;
	UNICODE_STRING uniNtDeviceName;
	UNICODE_STRING uniDosDeviceName;
	
	KdPrint(("KeyFlt: DriverEntry. \n"));
	
	for(i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
	{
		DriverObject->MajorFunction[i] = KeyFlt_DispatchPassThrough;
	}
	
	DriverObject->MajorFunction[IRP_MJ_CREATE] = KeyFlt_CreateClose;
	DriverObject->MajorFunction[IRP_MJ_CLOSE] =	KeyFlt_CreateClose;
	DriverObject->MajorFunction[IRP_MJ_READ] = KeyFlt_DispatchRead;
	//DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KeyFlt_DeviceIoControl;
	
	RtlInitUnicodeString(&uniNtDeviceName, NT_DEVICE_NAME);
	RtlInitUnicodeString(&uniDosDeviceName, DOS_DEVICE_NAME);
	
	status = IoCreateDevice(
		DriverObject,
		0,
		&uniNtDeviceName,
		FILE_DEVICE_UNKNOWN,
		0,
		FALSE,
		&DeviceObject
		);
	
	if(!NT_SUCCESS(status))
	{
		return status;
	}
	
	status = IoCreateSymbolicLink(&uniDosDeviceName, &uniNtDeviceName);
	
	if(status != STATUS_SUCCESS )
	{
		IoDeleteDevice(DeviceObject);
		return status;
	}
	
	DeviceObject->Flags |= DO_BUFFERED_IO;
	DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
	g_nop = 0;
	return status;
} 

NTSTATUS
KeyFlt_CreateClose(
					 IN PDEVICE_OBJECT DeviceObject,
					 IN PIRP Irp
					 )
{
	ULONG i;
	NTSTATUS status;
	PIO_STACK_LOCATION stack;
	UNICODE_STRING uniKbdDeviceName;
	PFILE_OBJECT KbdFileObject;
	PDEVICE_OBJECT KbdDeviceObject;
	ULONG counter;
	HANDLE hDir;
	OBJECT_ATTRIBUTES oa;
	UNICODE_STRING uniOa;
	PVOID pBuffer;
	PVOID pContext;
	ULONG RetLen;
	PDIRECTORY_BASIC_INFORMATION pDirBasicInfo;
	UNICODE_STRING uniKbdDrv;
	char* KbdclsNum;
	char arKbdCls[0x10];
	
	stack = IoGetCurrentIrpStackLocation(Irp);
	
	switch (stack->MajorFunction)
	{
	case IRP_MJ_CREATE:
		{
			if(InterlockedIncrement(&g_StartCount) == 1)
			{
				if(g_nop)
				{
					break;
				}
				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
					);

				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;
				}
			}
			break;
		}
	case IRP_MJ_CLOSE:
		{
			if(InterlockedDecrement(&g_StartCount) == 0)
			{
				if(g_nop)
				{
					break;
				}
				__try
				{
					if(g_TopOfStack)
					{
						if(g_OldFunction)
						{
							g_KbdDeviceObject->DriverObject->MajorFunction[IRP_MJ_READ] = g_OldFunction;
							g_OldFunction = NULL;
						}
						KdPrint(("KeyFlt: Detach Device. \n"));
						IoDetachDevice(g_TopOfStack);
						g_TopOfStack = NULL;
					}
				}
				__except(1)
				{
					g_nop = 1;
					break;
				}
			}
			break;
		}
	}
	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

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;
}

NTSTATUS KeyFlt_HookProc(
						   IN PDEVICE_OBJECT DeviceObject,
						   IN PIRP Irp
						   )
{
	NTSTATUS status;
	status = g_OldFunction(DeviceObject, Irp);
	return status;
}

NTSTATUS KeyFlt_DispatchRead(
							   IN PDEVICE_OBJECT DeviceObject,
							   IN PIRP Irp
							   )
{
	PIO_STACK_LOCATION currentIrpStack;
	PIO_STACK_LOCATION nextIrpStack;
	NTSTATUS status;
	KdPrint(("KeyFlt: DispatchRead Start \n"));
	//
	currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
	nextIrpStack = IoGetNextIrpStackLocation(Irp);
	//
	*nextIrpStack = *currentIrpStack;
	IoSetCompletionRoutine(
		Irp,
		KeyFlt_ReadComplete,
		DeviceObject,
		TRUE,
		TRUE,
		TRUE
		);
	status = IoCallDriver(g_TopOfStack, Irp);
	KdPrint(("KeyFlt: DispatchRead End\n"));
	return status;
}

NTSTATUS KeyFlt_ReadComplete(
							   IN PDEVICE_OBJECT DeviceObject,
							   IN PIRP Irp,
							   IN PVOID Context
							   )
{	
	KdPrint(("KeyFlt: ReadComplete Start\n"));
	if(Irp->PendingReturned)
	{
		IoMarkIrpPending(Irp);
	}

	Irp->IoStatus.Information = 0;
	KdPrint(("KeyFlt: ReadComplete End.\n"));
	return STATUS_ACCESS_DENIED;
}

NTSTATUS KeyFlt_DispatchPassThrough(
									  IN PDEVICE_OBJECT DeviceObject,
									  IN PIRP Irp
									  )
{
	NTSTATUS status;
	KdPrint(("KeyFlt: Start KeyFlt_DispatchPassThrough\n"));
	if(!g_nop)
	{
		// Pass the IRP to the target
		IoSkipCurrentIrpStackLocation(Irp);
		status = IoCallDriver(g_TopOfStack, Irp);
	}
	KdPrint(("KeyFlt: End KeyFlt_DispatchPassThrough\n"));
	return status;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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

Share

About the Author


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