阅读:1936回复:8
键盘过滤驱动的问题
为何我的程序可以挂接键盘,都正常,但退出以后,再按键盘系统就会崩溃呢??
Russinovich采用WDM方式,很不方便,改写为动态装卸载,可卸在后按键盘就兰屏,我SOFTICE调试发现是没有去除挂接,系统还是会调用已经释放的代码,导致页异常.难道是IODETACHDEVICE有问题吗?? //====================================================================== //====================================================================== // // Ctrl2cap // // Copyright (C) 1996-1999 Mark Russinovich // // Hook onto the keyboard I/O path and massage the input stream // converting caps-locks into controls. This example works on // NT 4 and Win2K and the Win2K version is very losely based on the // i8042 port filter driver sample, kbfiltr, from the Win2K DDK. // // For every function I list whether the function gets called // under NT 4, WIN2K, or both. // // File: ctrl2cap.c // //====================================================================== #include \"ntddk.h\" #include <ntddkbd.h> #include \"stdarg.h\" #include \"stdio.h\" #include \"ctrl2cap.h\" #include \"ntddkbd.h\" //---------------------------------------------------------------------- // // DriverEntry // // Installable driver initialization. Here we just set ourselves up. // // Called: NT4, WIN2K // //---------------------------------------------------------------------- NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { ULONG i; NTSTATUS status; DbgPrint ((\"Ctrl2cap.SYS: entering DriverEntry\\n\")); // // Fill in all the dispatch entry points with the pass through function // and the explicitly fill in the functions we are going to intercept // for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction = Ctrl2capDispatchGeneral; } // // Our read function is where we do our real work. // DriverObject->MajorFunction[IRP_MJ_READ] = Ctrl2capDispatchRead; // // Power IRPs are the only ones we have to handle specially under // Win2k since they require the special PoCallDriver and // PoStartNextPowerIrp function calls. // DriverObject->MajorFunction [IRP_MJ_POWER] = Ctrl2capPower; // // The only reason we need to handle PnP IRPs is to know when // a device we\'ve attached to disappears (is removed). // DriverObject->MajorFunction [IRP_MJ_PNP] = Ctrl2capPnP; // // Under Win2K we get told about the presence of keyboard // devices through our AddDevice entry point. // DriverObject->DriverUnload = Ctrl2capUnload; status =Ctrl2capAddDevice(DriverObject, RegistryPath);; return status;; } //---------------------------------------------------------------------- // // Ctrl2capAddDevice // // The PnP Manager calls us for each keyboard present on the system. // We attach to each one so that we can flip caps lock to controls. // // Called: WIN2K // //---------------------------------------------------------------------- NTSTATUS Ctrl2capAddDevice( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NTSTATUS status = 0; UNICODE_STRING uniNtNameString, linkString; PMyFilter_DeviceExtension pMyFilter_DeviceExtension; PDEVICE_OBJECT pFilterDeviceObject = NULL; PDEVICE_OBJECT pTargetDeviceObject = NULL; PFILE_OBJECT pTargetFileObject = NULL; PDEVICE_OBJECT pLowerDeviceObject = NULL; DbgPrint((\"MyAttach.\\n\")); RtlInitUnicodeString(&uniNtNameString, MYTEST_DEVICE_NAME); status = IoGetDeviceObjectPointer( IN &uniNtNameString, IN FILE_READ_ATTRIBUTES, OUT &pTargetFileObject, OUT &pTargetDeviceObject ); if(!NT_SUCCESS(status)) { DbgPrint((\"MyAttach: Couldn\'t get the MyTest Device Object\\n\")); pTargetFileObject = NULL; pTargetDeviceObject = NULL; return( status ); } // // Create a filter device and attach it to the device stack. // RtlInitUnicodeString(&uniNtNameString, MYFILTER__DEVICE_NAME); status = IoCreateDevice( IN DriverObject, IN sizeof(MyFilter_DeviceExtension), IN &uniNtNameString, IN pTargetDeviceObject->DeviceType, IN pTargetDeviceObject->Characteristics, IN FALSE, OUT &pFilterDeviceObject ); if (!NT_SUCCESS(status)) { DbgPrint((\"MyAttach: Couldn\'t create the MyFilter Filter Device Object\\n\")); ObDereferenceObject(pTargetFileObject); pTargetFileObject = NULL; pTargetDeviceObject = NULL; return (status); } pLowerDeviceObject = IoAttachDeviceToDeviceStack(pFilterDeviceObject, pTargetDeviceObject); if(!pLowerDeviceObject) { DbgPrint((\"MyAttach: Couldn\'t attach to MyTest Device Object\\n\")); IoDeleteDevice(pFilterDeviceObject); pFilterDeviceObject = NULL; ObDereferenceObject(pTargetFileObject); pTargetFileObject = NULL; pTargetDeviceObject = NULL; return( status ); } pMyFilter_DeviceExtension = (PMyFilter_DeviceExtension)(pFilterDeviceObject->DeviceExtension); MyFilter_InitDeviceExtension( IN pMyFilter_DeviceExtension, IN pFilterDeviceObject, IN pTargetDeviceObject, IN pTargetFileObject, IN pLowerDeviceObject ); pFilterDeviceObject->DeviceType=pLowerDeviceObject->DeviceType; pFilterDeviceObject->Characteristics=pLowerDeviceObject->Characteristics; pFilterDeviceObject->StackSize=pLowerDeviceObject->StackSize+1; pFilterDeviceObject->Flags |= pLowerDeviceObject->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO \\ | DO_POWER_PAGABLE) ; return status; } NTSTATUS MyFilter_InitDeviceExtension( IN PMyFilter_DeviceExtension pMyFilter_DeviceExtension, IN PDEVICE_OBJECT pFilterDeviceObject, IN PDEVICE_OBJECT pTargetDeviceObject, IN PFILE_OBJECT pTargetFileObject, IN PDEVICE_OBJECT pLowerDeviceObject ) { memset(pMyFilter_DeviceExtension, 0, sizeof(MyFilter_DeviceExtension)); pMyFilter_DeviceExtension->NodeSize = sizeof(MyFilter_DeviceExtension); pMyFilter_DeviceExtension->pFilterDeviceObject = pFilterDeviceObject; KeInitializeSpinLock(&(pMyFilter_DeviceExtension->IoRequestsSpinLock)); KeInitializeEvent(&(pMyFilter_DeviceExtension->IoInProgressEvent), NotificationEvent, FALSE); pMyFilter_DeviceExtension->TargetDeviceObject = pTargetDeviceObject; pMyFilter_DeviceExtension->TargetFileObject = pTargetFileObject; pMyFilter_DeviceExtension->LowerDeviceObject = pLowerDeviceObject; return( STATUS_SUCCESS ); } //---------------------------------------------------------------------- // // Ctrl2capPnP // // We have to handle PnP IRPs so that we detach from target // devices when appropriate. // // Called: WIN2K // //---------------------------------------------------------------------- NTSTATUS Ctrl2capPnP( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PMyFilter_DeviceExtension pMyFilter_DeviceExtension; PIO_STACK_LOCATION irpStack; NTSTATUS status = STATUS_SUCCESS; KIRQL oldIrql; KEVENT event; pMyFilter_DeviceExtension = (PMyFilter_DeviceExtension)(DeviceObject->DeviceExtension); irpStack = IoGetCurrentIrpStackLocation(Irp); switch (irpStack->MinorFunction) { case IRP_MN_REMOVE_DEVICE: DbgPrint((\"IRP_MN_REMOVE_DEVICE\\n\")); // // Detach from the target device after passing the IRP // down the devnode stack. // IoSkipCurrentIrpStackLocation(Irp); IoCallDriver(pMyFilter_DeviceExtension->LowerDeviceObject, Irp); IoDetachDevice(pMyFilter_DeviceExtension->LowerDeviceObject); IoDeleteDevice(DeviceObject); status = STATUS_SUCCESS; break; case IRP_MN_SURPRISE_REMOVAL: DbgPrint((\"IRP_MN_SURPRISE_REMOVAL\\n\")); // // Same as a remove device, but don\'t call IoDetach or IoDeleteDevice. // IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(pMyFilter_DeviceExtension->LowerDeviceObject, Irp); break; case IRP_MN_START_DEVICE: case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: case IRP_MN_CANCEL_REMOVE_DEVICE: case IRP_MN_CANCEL_STOP_DEVICE: case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: case IRP_MN_STOP_DEVICE: case IRP_MN_QUERY_DEVICE_RELATIONS: case IRP_MN_QUERY_INTERFACE: case IRP_MN_QUERY_CAPABILITIES: case IRP_MN_QUERY_DEVICE_TEXT: case IRP_MN_QUERY_RESOURCES: case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: case IRP_MN_READ_CONFIG: case IRP_MN_WRITE_CONFIG: case IRP_MN_EJECT: case IRP_MN_SET_LOCK: case IRP_MN_QUERY_ID: case IRP_MN_QUERY_PNP_DEVICE_STATE: default: DbgPrint((\"OTHER_IRP\\n\")); // // Pass these through untouched // IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(pMyFilter_DeviceExtension->LowerDeviceObject, Irp); break; } return status; } //---------------------------------------------------------------------- // // Ctrl2capPower // // We have to handle Power IRPs specially. // // Called: WIN2K // //---------------------------------------------------------------------- NTSTATUS Ctrl2capPower( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PMyFilter_DeviceExtension pMyFilter_DeviceExtension; pMyFilter_DeviceExtension = (PMyFilter_DeviceExtension)DeviceObject->DeviceExtension; // // Let the next power IRP out of the gate // PoStartNextPowerIrp( Irp ); // // Pass this power IRP to the keyboard class driver // IoSkipCurrentIrpStackLocation( Irp ); return PoCallDriver(pMyFilter_DeviceExtension->LowerDeviceObject, Irp ); } // WIN2K //---------------------------------------------------------------------- // // Ctrl2capReadComplete // // Gets control after a read operation has completed. // // Called: WIN2K, NT4 // //---------------------------------------------------------------------- NTSTATUS Ctrl2capReadComplete( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PIO_STACK_LOCATION IrpSp; PKEYBOARD_INPUT_DATA KeyData; int numKeys, i; // IrpSp = IoGetCurrentIrpStackLocation( Irp ); if( NT_SUCCESS( Irp->IoStatus.Status ) ) { // // Do caps-lock down and caps-lock up. Note that // just frobbing the MakeCode handles both the up-key // and down-key cases since the up/down information is specified // seperately in the Flags field of the keyboard input data // (0 means key-down, 1 means key-up). // KeyData = Irp->AssociatedIrp.SystemBuffer; numKeys = Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA); for( i = 0; i < numKeys; i++ ) { DbgPrint((\"ScanCode: %x \", KeyData.MakeCode )); DbgPrint((\"%s\\n\", KeyData.Flags ? \"Up\" : \"Down\" )); if( KeyData.MakeCode == CAPS_LOCK) { KeyData.MakeCode = LCONTROL; } } } // // Mark the Irp pending if required // if( Irp->PendingReturned ) { IoMarkIrpPending( Irp ); } return Irp->IoStatus.Status; } //---------------------------------------------------------------------- // // Ctrl2capDispatchRead // // Sets up to look at the read request completion so that we can // massage the input queue on IO completion. // // Called: WIN2K, NT4 // //---------------------------------------------------------------------- NTSTATUS Ctrl2capDispatchRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS RC = STATUS_SUCCESS; PMyFilter_DeviceExtension pMyFilter_DeviceExtension; PIO_STACK_LOCATION currentIrpStack; PIO_STACK_LOCATION nextIrpStack; // // Gather our variables. // if (Irp->CurrentLocation == 1) { ULONG ReturnedInformation = 0; DbgPrint((\"Dispatch encountered bogus current location\\n\")); RC = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Status = RC; Irp->IoStatus.Information = ReturnedInformation; IoCompleteRequest(Irp, IO_NO_INCREMENT); return(RC); } pMyFilter_DeviceExtension = (PMyFilter_DeviceExtension)DeviceObject->DeviceExtension; currentIrpStack = IoGetCurrentIrpStackLocation(Irp); nextIrpStack = IoGetNextIrpStackLocation(Irp); // // Push params down for keyboard class driver. // *nextIrpStack = *currentIrpStack; // // Set the completion callback, so we can \"frob\" the keyboard data. // IoSetCompletionRoutine( Irp, Ctrl2capReadComplete, DeviceObject, TRUE, TRUE, TRUE ); // // Return the results of the call to the keyboard class driver. // return IoCallDriver( pMyFilter_DeviceExtension->LowerDeviceObject, Irp ); } //---------------------------------------------------------------------- // // Ctrl2capDispatchGeneral // // This handles several functions we are not interested in // along to the keyboard class driver. // // Called: WIN2K, NT4 // //---------------------------------------------------------------------- NTSTATUS Ctrl2capDispatchGeneral( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { // // Pass the IRP to the target without touching the IRP // DbgPrint((\"Other Diapatch!\")); IoSkipCurrentIrpStackLocation(Irp); #ifdef WINNT4 // WIN2K // // This is the equivalent of the IoSkipCurrentIrpStackLocation macro, // which doesn\'t exist in the NT 4 DDK. // Irp->CurrentLocation++; Irp->Tail.Overlay.CurrentStackLocation++; #endif // WIN2K return IoCallDriver(((PMyFilter_DeviceExtension) DeviceObject->DeviceExtension)->LowerDeviceObject, Irp); } //---------------------------------------------------------------------- // // Ctrl2capUnload // // Our Win2K PnP unload function. We don\'t need to do anything. // // Called: WIN2K // //---------------------------------------------------------------------- VOID Ctrl2capUnload(IN PDRIVER_OBJECT DriverObject) { PDEVICE_OBJECT DeviceObject; PDEVICE_OBJECT OldDeviceObject; PMyFilter_DeviceExtension pMyFilter_DeviceExtension; UNREFERENCED_PARAMETER(DriverObject); DbgPrint((\"DriverEntry unLoading...\\n\")); DeviceObject = DriverObject->DeviceObject; MyDetach(DeviceObject); ASSERT(NULL == DriverObject->DeviceObject); return; } VOID MyDetach(IN PDEVICE_OBJECT pDeviceObject) { PMyFilter_DeviceExtension pMyFilter_DeviceExtension; BOOLEAN NoRequestsOutstanding = FALSE; pMyFilter_DeviceExtension = (PMyFilter_DeviceExtension)pDeviceObject->DeviceExtension; try { try { IoDetachDevice(pMyFilter_DeviceExtension->TargetDeviceObject);//LowerDeviceObject,TargetDeviceObject); if(pMyFilter_DeviceExtension->TargetFileObject) ObDereferenceObject(pMyFilter_DeviceExtension->TargetFileObject); pMyFilter_DeviceExtension->TargetFileObject = NULL; pMyFilter_DeviceExtension->TargetDeviceObject = NULL; IoDeleteDevice(pDeviceObject); pMyFilter_DeviceExtension->pFilterDeviceObject = NULL; DbgPrint((\"Detach Finished\\n\")); } except (EXCEPTION_EXECUTE_HANDLER){} } finally{} return; } |
|
|
沙发#
发布于:2003-09-22 21:16
头文件
//====================================================================== // // Ctrl2cap.h // // Copyright (C) 1996-1999 Mark Russinovich // // Hook onto the keyboard I/O path and massage the input stream // converting caps-locks into controls. This example works on // NT 4 and Win2K and the Win2K version is very losely based on the // i8042 port filter driver sample, kbfiltr, from the Win2K DDK. // //====================================================================== // // Define scan codes of interest here. For scan code tables, see // \"The Undocumented PC\", by Frank Van Gullwe, Addison-Wesley 1994. // #define MYTEST_DEVICE_NAME L\"\\\\Device\\\\KeyboardClass0\" #define MYFILTER__DEVICE_NAME L\"\\\\Device\\\\MyFilter\" #define KEY_UP 1 #define KEY_DOWN 0 #define LCONTROL ((USHORT)0x1D) #define CAPS_LOCK ((USHORT)0x3A) // // Print macro that only turns on when checked builds are on // #if DBG #define DbgPrint(arg) DbgPrint arg #else #define DbgPrint(arg) #endif // // Undocumented NT 4 function to print to the startup screen // NTSYSAPI NTSTATUS NTAPI ZwDisplayString( PUNICODE_STRING String ); // // Our device extension definition // typedef struct _MyFilter_DEVICE_EXTENSION { // // The top of the stack before this filter was added. AKA the location // to which all IRPS should be directed. // ULONG NodeSize; // 这个结构的大小 PDEVICE_OBJECT pFilterDeviceObject; // 过滤设备对象 KSPIN_LOCK IoRequestsSpinLock; // 同时调用时的保护锁 KEVENT IoInProgressEvent; // 进程间同步处理 PDEVICE_OBJECT TargetDeviceObject; // 绑定的设备对象 PFILE_OBJECT TargetFileObject; // 绑定设备的文件对象 PDEVICE_OBJECT LowerDeviceObject; // 绑定前底层设备对象 //PDEVICE_OBJECT TopOfStack; } MyFilter_DeviceExtension, *PMyFilter_DeviceExtension; // // Forwards // NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); NTSTATUS Ctrl2capAddDevice( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); NTSTATUS Ctrl2capPnP( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); NTSTATUS Ctrl2capPower( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); VOID Ctrl2capUnload( IN PDRIVER_OBJECT Driver ); NTSTATUS Ctrl2capInit( IN PDRIVER_OBJECT DriverObject ); NTSTATUS Ctrl2capDispatchRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); static NTSTATUS Ctrl2capDispatchGeneral( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); void MyDetach(IN PDEVICE_OBJECT pDeviceObject); NTSTATUS MyCompletion( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ); NTSTATUS MyFilter_InitDeviceExtension( IN PMyFilter_DeviceExtension pMyFilter_DeviceExtension, IN PDEVICE_OBJECT pFilterDeviceObject, IN PDEVICE_OBJECT pTargetDeviceObject, IN PFILE_OBJECT pTargetFileObject, IN PDEVICE_OBJECT pLowerDeviceObject ); |
|
|
板凳#
发布于:2003-09-22 21:49
可能卸载时候,还有irp没有完成?
|
|
地板#
发布于:2003-09-23 11:18
那么该如何解决呢???晕......
|
|
|
地下室#
发布于:2003-09-23 12:20
参考Filemon,用一个计数器来记载有多少Irp还没有完成。
过滤驱动本来就不应该卸载,如果别人还有个过滤驱动加载在你上边 这时卸载估计会死翘翘 |
|
5楼#
发布于:2003-09-23 23:06
我的意思能否象链表那样动态的添加和删除呢??
|
|
|
6楼#
发布于:2003-09-25 13:13
我用SOFTICE调试发现问题出在,可能驱动卸在的时候还有没有完成IRP,然后系统完成IRP后就返回到已经释放的代码初,导致页异常.该如何解决??
|
|
|
7楼#
发布于:2004-03-04 19:54
请问一下你这个键盘过滤驱动程序是不是只能挂接ps/2键盘,不能挂接USB键盘是吗?
|
|
8楼#
发布于:2004-03-05 11:27
过滤驱动通常是不建议卸载的,有没有irp没完成比较难确定
|
|