首页 > 代码库 > 一个简单的截取键盘按键的驱动

一个简单的截取键盘按键的驱动

近来在学驱动开发,自己写了一个简单地驱动程序,截取键盘按键,另外写的应用程序会显示按键。下面是驱动部分的关键代码,完整代码点击:猛戳这里

/**************************************************************/
#include "KeyFilter.h"
/************************************************************************
* 函数名称:DriverEntry
* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
* 参数列表:
      pDriverObject:从I/O管理器中传进来的驱动对象
      pRegistryPath:驱动程序在注册表的中的路径
* 返回 值:返回初始化驱动状态
*************************************************************************/
#pragma INITCODE 
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,
								IN PUNICODE_STRING pRegistryPath)
{
	KdPrint(("Enter DriverEntry\n"));

	pDriverObject->DriverExtension->AddDevice = KeyFilterAddDevice;

	pDriverObject->MajorFunction[IRP_MJ_PNP] = KeyFilterPnp;
	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KeyFilterDeviceIoCtl;
	pDriverObject->MajorFunction[IRP_MJ_CREATE] = KeyFilterDispatchRoutine;
	pDriverObject->MajorFunction[IRP_MJ_CLOSE] = KeyFilterDispatchRoutine;
	pDriverObject->MajorFunction[IRP_MJ_READ] = KeyFilterRead;
	pDriverObject->MajorFunction[IRP_MJ_WRITE] = KeyFilterDispatchRoutine;
	pDriverObject->DriverUnload = KeyFilterUnload;
	pDriverObject->DriverStartIo = KeyFilterStartIO;

	KdPrint(("Leave DriverEntry\n"));
	return STATUS_SUCCESS;
}

/************************************************************************
* 函数名称:KeyFilterAddDevice
* 功能描述:添加新设备
* 参数列表:
      DriverObject:从I/O管理器中传进来的驱动对象
      PhysicalDeviceObject:从I/O管理器中传进来的物理设备对象
* 返回 值:返回添加新设备状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS KeyFilterAddDevice(IN PDRIVER_OBJECT DriverObject,
                           IN PDEVICE_OBJECT PhysicalDeviceObject)
{ 
	PAGED_CODE();

	_asm int 3;

	NTSTATUS status;
	PDEVICE_OBJECT PDeviceObject;
	UNICODE_STRING strnum;
	UNICODE_STRING devName;
	UNICODE_STRING kbdclassname;
	UNICODE_STRING symLinkName;
	//PDRIVER_OBJECT kbdDriver;
	PDEVICE_OBJECT kbdDevice;
	int index = 0;
	PDEVICE_EXTENSION pdx;
	WCHAR DevnameBase[100] =  L"\\Device\\KeyFilterDevice";
	KdPrint(("Enter KeyFilterAddDevice\n"));
	//
	PFILE_OBJECT FileObject = NULL;
	RtlInitUnicodeString(&kbdclassname,L"\\Device\\KeyboardClass0");
	//通过classname得到设备对象
	status = IoGetDeviceObjectPointer(&kbdclassname,FILE_ALL_ACCESS,&FileObject,&kbdDevice);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("ObReferenceObjectByName error,0x%x\n",status));
		return status;
	}

	do{	
		RtlInitUnicodeString(&strnum,L"strnum");
		RtlIntegerToUnicodeString(index,10,&strnum);
		
		RtlInitUnicodeString(&devName,DevnameBase);
		RtlAppendUnicodeStringToString(&devName,&strnum);
		//创建设备
		status = IoCreateDevice(
			DriverObject,
			sizeof(DEVICE_EXTENSION),
			&devName,
			kbdDevice->DeviceType,
			kbdDevice->Characteristics,
			FALSE,
			&PDeviceObject);
		if( !NT_SUCCESS(status))
			break;
		pdx = (PDEVICE_EXTENSION)PDeviceObject->DeviceExtension;
		pdx->NextStackDevice = IoAttachDeviceToDeviceStack(PDeviceObject, kbdDevice);
		if (pdx->NextStackDevice == NULL) 
		{
			KdPrint(("IoAttachDeviceToDeviceStack failed,error = %x\n",status));
			IoDeleteDevice( PDeviceObject );
			break;
		}
		
		pdx->PDeviceObject = PDeviceObject;
		//创建符号链接
		RtlInitUnicodeString(&symLinkName,L"\\??\\KeyFilterSymLinkName");
		RtlAppendUnicodeStringToString(&symLinkName,&strnum);
		
		status = IoCreateSymbolicLink(&symLinkName,&devName);
		if( !NT_SUCCESS(status))
		{
			IoDeleteSymbolicLink(&pdx->ustrSymLinkName);
			break;
		}
		//保存设备名和符号链接名
		RtlCopyUnicodeString(&pdx->ustrDeviceName,&devName);
		RtlCopyUnicodeString(&pdx->ustrSymLinkName,&symLinkName);


		PDeviceObject->Flags |= kbdDevice->Flags & (DO_BUFFERED_IO | DO_POWER_PAGABLE);
		PDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;//将Flag上的DO_DEVICE_INITIALIZING位清零,保证设备初始化完毕,必须的。


	}while(FALSE);
	ObDereferenceObject(FileObject);
	ObDereferenceObject(kbdDevice);

	//初始化自旋锁
	KeInitializeSpinLock(&pdx->ListSpinLock);
	//初始化链表
	InitializeListHead(&pdx->linkListHead);	

	KdPrint(("Leave KeyFilterAddDevice\n"));
	return STATUS_SUCCESS;
}
#pragma PAGEDCODE
void KeyFilterCancelIRP(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
{
	KdPrint(("Enter HelloWDMOnCancelIRP\n"));

	if (Irp == fdo->CurrentIrp)
	{
		KIRQL oldirql = Irp->CancelIrql;
		//释放cancel自旋锁
		IoReleaseCancelSpinLock(Irp->CancelIrql);

		//继续下一个IRP
		IoStartNextPacket(fdo, TRUE);
		//降低IRQL
		KeLowerIrql(oldirql);
	}
	else
	{//还没有被执行,还在队列中
		KeRemoveEntryDeviceQueue(&fdo->DeviceQueue, &Irp->Tail.Overlay.DeviceQueueEntry);

		//释放cancel自旋锁
		IoReleaseCancelSpinLock(Irp->CancelIrql);
	}

	Irp->IoStatus.Status = STATUS_CANCELLED;
	Irp->IoStatus.Information = 0;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);

	KdPrint(("Leave HelloWDMOnCancelIRP\n"));
}
//************************************
// Method:    KeyFilterDeviceIoCtlStartio
// Qualifier: IRP_MJ_DEVICE_CONTROL 处理函数
//************************************
NTSTATUS KeyFilterDeviceIoCtlStartio(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
{
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	NTSTATUS status = STATUS_SUCCESS;
	ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
	ULONG readLen = stack->Parameters.Read.Length;
	PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)fdo->DeviceExtension;
	KdPrint(("++++++enter KeyFilterDeviceIoCtlStartio\n"));
	switch (code)
	{
	case IOCTL_SHOWKEYFILTER:
		KdPrint(("IOCTL_SHOWKEYFILTER KeyFilterDeviceIoCtlStartio\n"));
		if (IsListEmpty(&pDevExt->linkListHead))//队列为空,完成irp
		{
			KdPrint(("list is empty.\n"));
			Irp->IoStatus.Status = STATUS_SUCCESS;
			Irp->IoStatus.Information = 0;
			IoCompleteRequest(Irp, IO_NO_INCREMENT);
		}
		else//队列中有数据,取出数据
		{
			KdPrint(("list have data\n"));
			PLIST_ENTRY pEntry;
			PMYDATASTRUCT pData;
			memset(Irp->AssociatedIrp.SystemBuffer,0,readLen);
			int index = 0;
			USHORT buffer[MAX_KEY_COUNT*2] = {0};
			//获取自旋锁
			KIRQL oldIrql;
			KeAcquireSpinLock(&pDevExt->ListSpinLock,&oldIrql);
			KdPrint(("******>> DeviceIoCtlStartio spinlock\n"));
			//取出链表中数据
			while(!IsListEmpty(&pDevExt->linkListHead))
			{
				pEntry = RemoveTailList(&pDevExt->linkListHead);
				pData = http://www.mamicode.com/CONTAINING_RECORD(pEntry,MYDATASTRUCT,ListEntry);>应用程序部分代码:

void CShowInputKeyDlg::OnBnClickedStart()
{
	// TODO: Add your control notification handler code here
	CString ldebug;
	do 
	{
		mParamStruct.mHdevice = CreateFile(L"\\\\.\\KeyFilterSymLinkName0",
			GENERIC_READ | GENERIC_WRITE,
			FILE_SHARE_WRITE|FILE_SHARE_READ,		// share mode none
			NULL,	// no security
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL );		// no template

		if (mParamStruct.mHdevice == INVALID_HANDLE_VALUE)
		{
			CString ldebug;
			ldebug.Format(_T("--------------Failed to obtain file handle to device  error : %d"),GetLastError());
			OutputDebugString(ldebug);
			break;
		}

		mParamStruct.mHwndMain = GetSafeHwnd();
		mThreadHandle  = (HANDLE)_beginthreadex(NULL,0,ReadThread,(void*)&mParamStruct,0,NULL);

	} while (FALSE);

}
新建的线程函数为:

UINT CALLBACK ReadThread(LPVOID para)
{
	PPARAM_STRUCT lParamStruct = (PPARAM_STRUCT)para;
	BOOL lbRet = TRUE;
	DWORD ReturnLen = 0;
	USHORT readBuffer[MAX_KEY_COUNT*2] = {0};

	CString ldebug;
	do 
	{
		HANDLE lhDevice = lParamStruct->mHdevice;
		HWND lHwnd = lParamStruct->mHwndMain;

		if (lhDevice == NULL || lHwnd == NULL)
		{
			break;
		}

		OutputDebugString(L"---------->ReadThread");
		while(TRUE)
		{
			lbRet = DeviceIoControl(lhDevice,IOCTL_SHOWKEYFILTER,NULL,0,readBuffer,
				sizeof(readBuffer),&ReturnLen,NULL);
			if (lbRet == FALSE)
			{
				ldebug.Format(_T("DeviceIoControl error :0x%x."),GetLastError());
				OutputDebugString(ldebug);
				break;
			}
			ldebug.Format(_T("----------- DeviceIoControl returnlen : %d"),ReturnLen);
			OutputDebugString(ldebug);
			if (ReturnLen == 0)
			{
				continue;
			}

			PostMessage(lHwnd,WM_INSERT_ITEM_MESSAGE,(WPARAM)readBuffer,(LPARAM)&ReturnLen);
			
			ldebug.Format(_T("----------- DeviceIoControl insert list end "));
			OutputDebugString(ldebug);
		}
		
	} while (FALSE);
	OutputDebugString(L"<----------ReadThread");
	_endthreadex( 0 );
	return 0;
}
消息处理,界面显示:

BOOL CShowInputKeyDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: Add your specialized code here and/or call the base class

	USHORT Scancode;
	USHORT Flag;
	CString ldebug;

	if (pMsg->message == WM_INSERT_ITEM_MESSAGE)
	{
		OutputDebugString(L"WM_INSERT_ITEM_MESSAGE");

		USHORT * readBuffer = (USHORT  *)pMsg->wParam;
		PDWORD PReturnLen = (PDWORD)pMsg->lParam;
		CString lstrAction = NULL;
		for (DWORD index = 0;index < *PReturnLen/sizeof(USHORT);index += 2)
		{
			Scancode = readBuffer[index];
			Flag = readBuffer[index+1];

			lstrAction.Format(_T("%d"),mList.GetItemCount()+1);
			mList.InsertItem(mList.GetItemCount(),lstrAction);

			lstrAction.Format(_T("0x%x"),Scancode);
			mList.SetItemText(mList.GetItemCount()-1,1,lstrAction);
			UINT VkKey = MapVirtualKey(Scancode,MAPVK_VSC_TO_VK);
			if (VkKey != 0)
			{
				lstrAction.Format(_T("0x%x"),VkKey);
				mList.SetItemText(mList.GetItemCount()-1,2,lstrAction);
			}
			lstrAction.Format(_T("%ws"),Flag? L"Up" : L"Down");
			mList.SetItemText(mList.GetItemCount()-1,3,lstrAction);

			//确保List Control最后一行可见  
			mList.EnsureVisible(mList.GetItemCount()-1,FALSE);
		}
		return TRUE;//直接返回true
	}else
	{

		return CDialogEx::PreTranslateMessage(pMsg);
	}
	
}

完整代码请访问:猛戳这里


学驱动不久,有不妥之处还望大家指正。