2010-02-26 09:07:16 阅读22 评论0 字号:大中小
支持 PS/2 与 USB 的键盘过滤驱动(可卸载)
Author: sinister
Email:
Homepage:http://www.whitecell.org
Date: 2007-02-26
/*******************************************************************
这
个键盘过滤驱动是一个定时锁定计算机程序的功能部分,以前 lgx
写过一个 linux 版,现在我们需要实现一个 windows
版。这部分的
功能要求如下:
1、强制锁定键盘/鼠标。
2、可动态加/解锁
3、兼容所有 NT 系列的操作系统。
就
这个需求而言,能马上能想到的就有7,8种方案,这些方案可以说都能够实
现,但如何更合理,更稳定、更彻底的实现,如何尽量少的消耗系统资源,如
何
保证其兼容性,等一系列问题不得不让我们去重新评估这几种方法。首先在
上层实现,一是怕被饶过,二是怕调用频繁影响系统性能。在底层实现,一是
怕
考虑不周有兼容性问题,二是怕过多使用未公开方法导致系统不稳定。下面
就来看一下我想到的几种实现方法:
1、全局键盘/鼠标钩子
2、
BlockInput() API
3、使用 setupapi 进行控制
4、全局键盘/鼠标钩子+远线程插入 WINLOGON
进程屏蔽 CTRL+AL+DEL
5、拦截 win23k!RawInputThread() 函数
6、修改 DDK 中自带的
kbfilter 的键盘(Port Driver)过滤驱动
7、拦截 kdbclass 驱动的 driver dispatch
routine
8、实现一个 PS/2 与 USB 键盘过滤驱动
我们先看一下以上这些方案的实用性与通用性。第1,2套
方案不在考虑
之内了,因为有办法解锁,屏蔽不了 CTRL+ALT+DEL 组合键。第3套方
案经过我的测试使用 Keyboard 的
CLASSID 不是什么环境都好使,存在
兼容性的问题。第4套方案系统效率会大大降低,而且存在很多不稳定因
素,对于全局钩子这种东
西我一直很排斥。第5套方案,同样存在兼容性
问题和不稳定因素。第6套方案看似xx,但无法实现动态卸载,无法卸
载就意味着你需要一个开
关来控制是否锁定,这样还要与应用层通讯,我
的目的是不让应用层与驱动有任何交互。且使用 WDM 形式这种安装起来
也很麻烦,要么
INF 要么自己 setupapi,这都不是我想看到的,还有如
果仅为实现这么一个功能,就让一个核心驱动一直存在系统中的话,我有
障
碍。第7套方案看似实现起来很简单,其实有很多问题。如仅是拦截
IRP_MJ_READ 并粗暴的返回拒绝后,系统无法恢复到初始状态。且对于
USB
键盘存在兼容性问题。那么{zh1}只有自己实现一个 PS/2 与 USB 键
盘过滤驱动了,既然要实现这么一个驱动,那么就必须能实现到第6套方
案
的全部功能且不存在它所带来的问题,否则就没有什么意义了。
我们都知道实现一个可直接使用 SERVICE API 来动态装载的
KMD 键盘过
滤驱动,首先需要先 ATTACH 到
设备上再进
行按键过滤。但如果仅 ATTACH 这个设备的话,会存在很多问题,那就是
只能过滤到 PS/2 键盘,而对于使用
USB 键盘的机器毫无作用。现在越
来越多的品牌机都预配的是 USB 键盘(如:DELL)。大家可能会想,从
KeyboardClass0
一直到 N 都 ATTACH 不就可以了么?总有一个是 USB
键盘设备,经过实践这是不可行的,只要是 USB 键盘设备的话,在使用
IoGetDeviceObjectPointer()
函数从设备名得到设备对象都会获取失败,
我还曾尝试使用 USB 键盘设备名来转换,还是一样失败。还有一个问题
就是 USB
键盘设备不是都有名称的,即使有它的名称也都是动态生成的
而不是固定的。那么这就带来了一个问题,既然系统提供的函数无法使
用,且我们又
是为了动态安装/卸载,使用的是 KMD 类型驱动,无法通
过 AddDevice 例程来获得 USB 键盘的设备对象进行挂接。那么如何来
屏
蔽 USB 键盘按键?要达到这个目的只有自己分析下 USB 协议栈,通
过使用 DriverTree 观察发现,所有 USB 外设都挂在了
\Driver\hidusb
上面,USB 键盘驱动名为 \Driver\kbdhid,而它则是 \Driver\kbdhid
的
一个 FilterDriver,且这个 \Driver\kbdhid 没有设备名称,也就意
味着,我们无法
IoGetDeviceObjectPointer() 得到设备对象并 ATTACH。
经过对多个系统多台使用 USB
键盘机器的分析,可以确定让我使用它们
来作为得到 USB 键盘设备的依据。(这里仅是对 USB 键盘设备很功利
的分析,如果想了解
WINDOWS 的 USB 设备栈如何组建,请阅读 tiamo
的 《Windows 的 USB 体系结构》。在此向所有公开研究成果的人致
敬!)
有了这些依据,下面就没什么好说的了,自己遍历 USB 设备栈,
根据驱动名称获得 USB 设备对象,然后 ATTACH,过滤按键。具体流程
见
下面代码。
这里有必要说下动态卸载,我尝试了两种方式,一种是在 UNLOAD 例程
里直接取消 IRP,这种方法在 W2K
系统下,无论是 PS/2 还是 USB 键
盘都可以很好的实现。但在 XP/2003 系统上则无法成功,在 XP/2003
上暂时使
用一个 IRP 计数器,在 UNLOAD 例程里判断如果还有一个没有
完成的 IRP 则等待,这样的话,需要在 UNLOAD
后用户按下任意键才可
继续,虽然能够安全卸载但还需要一次用户介入。考虑实现的仅是一个
锁定功能,这样也算是能够忍受了。以后考虑在驱动
中直接模拟用户按
键来实现,当然这种按键要有通用性和兼容性,支持 PS/2 与 USB 键盘。
完成了上述工作后看起来
好象xx了,其实不然,当你屏蔽了当前使用
的键盘时别忘了还可以再插入一个 USB 键盘,而后续插入的这个键盘是
可以被识别的。这就需
要我们处理 IRP_MJ_PNP 选项,对其中我们有兴趣
的 IRP_MN_XXX 做相应处理,可以处理
IRP_MN_START_DEVICE,在这时我
们动态挂接。还可以处理其他的 IRP,索性返回错误,让识别失效。但我
们的驱动是
KMD 类型,只要加上一句对 DriverObject->DriverExtension
->AddDevice
的赋值操作则无法直接使用 SERVICE API 来动态加载了。
如何保持 KMD 又可以获得 PNP 的处理权呢?这可能要直接对
PnpManager
进行操作了。这个问题有待大家来完善了。
要问为什么把文章插在代码当中,那可能是我觉得,既然把全部
代码都贴出
来了,写文章就不如直接看代码来的真切。我这里所写也仅仅是对这些天的
分析做个记录而已。我更愿意把它看做是一段注释。
最 后在此代码中要
感谢:PolyMeta,他在放假前提醒我 USB 键盘的不同。
感谢:lgx,过节前给我找了些事,以至于 没有让我觉得过节那么无聊。
感谢:齐佳佳,过节请我吃好吃的。
崞類浶愭蝰櫉炈棡溫滠飲钕唹徕熸唹戹樤樯殢餀膑?崞烊旡唹澾崞
懽碡飲嵯
愥撫剢淦泮嵯駨耒栃撣
******************************************************************/
/*****************************************************************
文
件名 : WssLockKey.c
描述 : 键盘过滤驱动
作者 :
sinister
{zh1}修改日期 : 2007-02-26
*****************************************************************/
#include
"WssLockKey.h"
NTSTATUS
DriverEntry( IN PDRIVER_OBJECT
KeyDriverObject,
IN PUNICODE_STRING RegistryPath )
{
UNICODE_STRING KeyDeviceName;
PDRIVER_OBJECT KeyDriver;
PDEVICE_OBJECT UsbDeviceObject;
NTSTATUS ntStatus;
ULONG i;
//
// 保存设备名,调试使用
//
WCHAR szDeviceName[MAXLEN + MAXLEN] =
{
0
};
KeyDriverObject->DriverUnload = KeyDriverUnload;
//
// 先尝试获得 USB 键盘设备对象,如果成功则挂接 USB 键盘
//
// 注意:因为 USB 键盘设备名不固定,且即使得到名称也无法
// 使用
IoGetDeviceObjectPointer() 函数根据设备名称得到其
// 设备对象,所以这里我们只能自己枚举 USB
设备栈,并得到
// USB 键盘设备来进行挂接
//
ntStatus =
GetUsbKeybordDevice( &UsbDeviceObject );
if ( NT_SUCCESS(
ntStatus ) && UsbDeviceObject != NULL )
{
//
// 调试使用,USB 键盘设备 kbdhid 没有设备名只有驱动名
// 所以这里打印为空
//
RtlInitUnicodeString( &KeyDeviceName, szDeviceName ); // USB
KEYBOARD
DbgPrint( "KeyDeviceName:%S\n", KeyDeviceName.Buffer );
//
// 挂接 USB 键盘设备
//
ntStatus =
AttachUSBKeyboardDevice( UsbDeviceObject, KeyDriverObject );
if (
!NT_SUCCESS( ntStatus ) )
{
DbgPrint( "Attach USB
Keyboard Device to failed!\n" );
return
STATUS_INSUFFICIENT_RESOURCES;
}
}
else
{
//
// 如果没有 USB 键盘,则尝试挂接 PS/2 键盘设备
//
RtlInitUnicodeString( &KeyDeviceName, PS2KEYBOARDNAME );
ntStatus = AttachPS2KeyboardDevice( &KeyDeviceName,
KeyDriverObject,
&KeyDriver );
if ( !NT_SUCCESS( ntStatus ) || KeyDriver ==
NULL )
{
DbgPrint( "Attach PS2 Keyboard Device to
failed!\n" );
return STATUS_INSUFFICIENT_RESOURCES;
}
}
//
// 这里没有过滤其他例程,仅处理了按键操作。这样处理会禁止
//
休眠。因在锁定时不允许休眠,所以也就无须处理其他例程
//
KeyDriverObject->MajorFunction[IRP_MJ_READ] = KeyReadPassThrough;
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////
//
函数类型 : 系统函数
// 函数模块 : 键盘过滤模块
////////////////////////////////////////////////////////////////
//
功能 : 尝试取消队列里的异步 IRP,如果失败则等待用户按键,
// 卸载键盘过滤驱动
// 注意 : 取消
IRP 操作在 2000 系统上可以成功,在 XP / 2003 上
// 则需要等待用户按键,以后有待完善
/////////////////////////////////////////////////////////////////
//
作者 : sinister
// 发布版本 : 1.00.00
// 发布日期 : 2005.12.27
/////////////////////////////////////////////////////////////////
//
重 大 修 改 历 史
////////////////////////////////////////////////////////////////
//
修改者 :
// 修改日期 :
// 修改内容 :
/////////////////////////////////////////////////////////////////
VOID
KeyDriverUnload(
PDRIVER_OBJECT KeyDriver )
{
PDEVICE_OBJECT KeyFilterDevice
;
PDEVICE_OBJECT KeyDevice ;
PDEVICE_EXTENSION
KeyExtension;
PIRP Irp;
NTSTATUS ntStatus;
KeyFilterDevice = KeyDriver->DeviceObject;
KeyExtension = (
PDEVICE_EXTENSION ) KeyFilterDevice->DeviceExtension;
KeyDevice
= KeyExtension->TargetDevice;
IoDetachDevice( KeyDevice );
//
// 如果还有 IRP 未完成,且当前 IRP 有效则尝试取消这个 IRP
//
if (
KeyExtension->IrpsInProgress > 0 &&
KeyDevice->CurrentIrp != NULL )
{
if ( CancelKeyboardIrp(
KeyDevice->CurrentIrp ) )
{
//
//
成功则直接退出删除键盘过滤设备
//
DbgPrint( "CancelKeyboardIrp() is
ok\n" );
goto __End;
}
}
//
//
如果取消失败,则一直等待按键
//
while ( KeyExtension->IrpsInProgress >
0 )
{
DbgPrint( "Irp Count:%d\n",
KeyExtension->IrpsInProgress );
}
__End:
IoDeleteDevice( KeyFilterDevice );
return ;
}
/////////////////////////////////////////////////////////////////
//
函数类型 : 自定义工具函数
// 函数模块 : 键盘过滤模块
/////////////////////////////////////////////////////////////////
//
功能 : 取消 IRP 操作
// 注意 : 这个函数仅是为配合在 UNLOAD 例程使用,其他例程中不能
//
使用此方法来取消 IRP
/////////////////////////////////////////////////////////////////
//
作者 : sinister
// 发布版本 : 1.00.00
// 发布日期 : 2007.02.20
/////////////////////////////////////////////////////////////////
//
重 大 修 改 历 史
/////////////////////////////////////////////////////////////////
//
修改者 :
// 修改日期 :
// 修改内容 :
/////////////////////////////////////////////////////////////////
BOOLEAN
CancelKeyboardIrp(
IN PIRP Irp )
{
if ( Irp == NULL )
{
DbgPrint(
"CancelKeyboardIrp: Irp error\n" );
return FALSE;
}
//
// 这里有些判断应该不是必须的,比如对 CancelRoutine 字段,
// 因为 IoCancelIrp()
函数中有判断了。但只有偏执狂才能生存 :)。
// 小波说 低智、偏执、思想贫乏是最不可容忍的。我这一行代码就占
//
了两条 :D,不知 xiaonvwu 看过后会作何感想?:DDD
//
//
//
如果正在取消或没有取消例程则直接返回 FALSE
//
if ( Irp->Cancel ||
Irp->CancelRoutine == NULL )
{
DbgPrint( "Can't Cancel
the irp\n" );
return FALSE;
}
if ( FALSE ==
IoCancelIrp( Irp ) )
{
DbgPrint( "IoCancelIrp() to failed\n"
);
return FALSE;
}
//
// 取消后重设此例程为空
//
IoSetCancelRoutine( Irp, NULL );
return TRUE;
}
/////////////////////////////////////////////////////////////////
//
函数类型 : 自定义工具函数
// 函数模块 : 设备栈信息模块
/////////////////////////////////////////////////////////////////
//
功能 : 遍历 DEVICE_OBJECT 中 AttachedDevice 域,找到 USB 键盘
// 设备上名为
kbdhid 的过滤驱动(Upper Filter Driver)
// 注意 :
/////////////////////////////////////////////////////////////////
//
作者 : sinister
// 发布版本 : 1.00.00
// 发布日期 : 2005.06.02
/////////////////////////////////////////////////////////////////
//
重 大 修 改 历 史
/////////////////////////////////////////////////////////////////
//
修改者 : sinister
// 修改日期 : 2007.2.12
// 修改内容 : 为匹配 USB 键盘驱动做了相应的修改
/////////////////////////////////////////////////////////////////
BOOLEAN
GetAttachedDeviceInfo(
IN PDEVICE_OBJECT DevObj )
{
PDEVICE_OBJECT DeviceObject;
BOOLEAN bFound = FALSE;
if ( DevObj == NULL )
{
DbgPrint( "DevObj is NULL!\n" );
return FALSE;
}
DeviceObject = DevObj->AttachedDevice;
while ( DeviceObject )
{
//
// 一些 OBJECT 的名称都存在分页区,虽然大部分时候不会被交换出去,但
//
有一次足够了。这算是经验之谈
//
if ( MmIsAddressValid(
DeviceObject->DriverObject->DriverName.Buffer ) )
{
DbgPrint( "Attached Driver Name:%S,Attached Driver
Address:0x%x,Attached DeviceAddress:0x%x\n",
DeviceObject->DriverObject->DriverName.Buffer,
DeviceObject->DriverObject,
DeviceObject );
//
// 找到 USB 键盘驱动的 kbdhid 设备了么?找到了就不继续了
//
if ( _wcsnicmp( DeviceObject->DriverObject->DriverName.Buffer,
KDBDEVICENAME,
wcslen( KDBDEVICENAME ) ) == 0 )
{
DbgPrint( "Found kbdhid Device\n" );
bFound =
TRUE;
break;
}
}
DeviceObject =
DeviceObject->AttachedDevice;
}
return bFound;
}
/////////////////////////////////////////////////////////////////
//
函数类型 : 自定义工具函数
// 函数模块 : 设备栈信息模块
/////////////////////////////////////////////////////////////////
//
功能 : 从 DEVICE_OBJECT 中得到设备与驱动名称并打印地址
// 注意 :
函数功能只是打印信息,不同环境使用中应该会做修改
/////////////////////////////////////////////////////////////////
//
作者 : sinister
// 发布版本 : 1.00.00
// 发布日期 : 2006.05.02
/////////////////////////////////////////////////////////////////
//
重 大 修 改 历 史
/////////////////////////////////////////////////////////////////
//
修改者 : sinister
// 修改日期 : 2007.2.12
// 修改内容 : 打印出 USB
键盘驱动的设备名称,仅作调试使用
/////////////////////////////////////////////////////////////////
VOID
GetDeviceObjectInfo(
IN PDEVICE_OBJECT DevObj )
{
POBJECT_HEADER ObjectHeader;
POBJECT_HEADER_NAME_INFO ObjectNameInfo;
if ( DevObj == NULL )
{
DbgPrint( "DevObj is NULL!\n" );
return;
}
//
// 得到对象头
//
ObjectHeader = OBJECT_TO_OBJECT_HEADER(
DevObj );
if ( ObjectHeader )
{
//
//
查询设备名称并打印
//
ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(
ObjectHeader );
if ( ObjectNameInfo &&
ObjectNameInfo->Name.Buffer )
{
DbgPrint( "Device
Name:%S - Device Address:0x%x\n",
ObjectNameInfo->Name.Buffer,
DevObj );
//
// 复制 USB 键盘设备名到一个全局 BUFFER 里,为调试时显示
//
用,没有实际的功能用途
//
RtlZeroMemory( szUsbDeviceName, sizeof(
szUsbDeviceName ) );
wcsncpy( szUsbDeviceName,
ObjectNameInfo->Name.Buffer,
ObjectNameInfo->Name.Length / sizeof( WCHAR ) );
}
//
// 对于没有名称的设备,则打印 NULL
//
else if (
DevObj->DriverObject )
{
DbgPrint( "Driver Name:%S -
Device Name:%S - Driver Address:0x%x - Device Address:0x%x\n",
DevObj->DriverObject->DriverName.Buffer,
L"NULL",
DevObj->DriverObject,
DevObj );
}
}
}
/////////////////////////////////////////////////////////////////
//
函数类型 : 自定义工具函数
// 函数模块 : 键盘过滤模块
/////////////////////////////////////////////////////////////////
//
功能 : 得到 USB 驱动 hidusb 的驱动对象,并遍历以上所有设备
// 对象,过滤出 USB
键盘设备,将其设备对象返回
// 注意 :
/////////////////////////////////////////////////////////////////
//
作者 : sinister
// 发布版本 : 1.00.00
// 发布日期 : 2007.02.13
/////////////////////////////////////////////////////////////////
//
重 大 修 改 历 史
/////////////////////////////////////////////////////////////////
//
修改者 :
// 修改日期 :
// 修改内容 :
/////////////////////////////////////////////////////////////////
NTSTATUS
GetUsbKeybordDevice(
OUT PDEVICE_OBJECT* UsbDeviceObject )
{
UNICODE_STRING
DriverName;
PDRIVER_OBJECT DriverObject = NULL;
PDEVICE_OBJECT
DeviceObject = NULL;
BOOLEAN bFound = FALSE;
RtlInitUnicodeString( &DriverName, USBKEYBOARDNAME );
ObReferenceObjectByName( &DriverName,
OBJ_CASE_INSENSITIVE,
NULL,
0,
( POBJECT_TYPE ) IoDriverObjectType,
KernelMode,
NULL,
&DriverObject );
if ( DriverObject == NULL )
{
DbgPrint( "Not found USB Keyboard Device hidusb!\n" );
return
STATUS_UNSUCCESSFUL;
}
DeviceObject = DriverObject->DeviceObject;
while ( DeviceObject )
{
GetDeviceObjectInfo( DeviceObject );
if (
DeviceObject->AttachedDevice )
{
//
// 查找
USB 键盘设备
//
if ( GetAttachedDeviceInfo( DeviceObject )
)
{
bFound = TRUE;
goto __End;
}
}
DeviceObject = DeviceObject->NextDevice;
}
__End:
if ( bFound )
{
//
// 找到则返回 USB 键盘设备对象
//
*UsbDeviceObject = DeviceObject;
}
else
{
*UsbDeviceObject = NULL;
}
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////
//
函数类型 : 自定义工具函数
// 函数模块 : 键盘过滤模块
////////////////////////////////////////////////////////////////
//
功能 : 创建过滤设备将其附加到需要跟踪的设备上,保存设备相关
// 信息,返回附加后的驱动对象
// 注意 :
此函数仅挂接 USB 键盘设备
/////////////////////////////////////////////////////////////////
//
作者 : sinister
// 发布版本 : 1.00.00
// 发布日期 : 2005.12.27
/////////////////////////////////////////////////////////////////
//
重 大 修 改 历 史
////////////////////////////////////////////////////////////////
//
修改者 :
// 修改日期 :
// 修改内容 :
/////////////////////////////////////////////////////////////////
NTSTATUS
AttachUSBKeyboardDevice(
IN PDEVICE_OBJECT UsbDeviceObject,
IN
PDRIVER_OBJECT DriverObject )
{
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT TargetDevice;
PDEVICE_EXTENSION DevExt;
NTSTATUS ntStatus;
//
// 创建过滤设备对象
//
ntStatus =
IoCreateDevice( DriverObject,
sizeof(
DEVICE_EXTENSION ),
NULL,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&DeviceObject );
if
( !NT_SUCCESS( ntStatus ) )
{
DbgPrint( "IoCreateDevice()
0x%x!\n", ntStatus );
return ntStatus;
}
DevExt = ( PDEVICE_EXTENSION ) DeviceObject->DeviceExtension;
//
// 初始化自旋锁
//
KeInitializeSpinLock( &DevExt->SpinLock );
//
// 初始化 IRP 计数器
//
DevExt->IrpsInProgress = 0;
//
// 将过滤设备对象附加在目标设备对象之上,并返回附加后的原设备对象
//
TargetDevice
= IoAttachDeviceToDeviceStack( DeviceObject, UsbDeviceObject );
if ( !TargetDevice )
{
IoDeleteDevice( DeviceObject );
DbgPrint( "IoAttachDeviceToDeviceStack() 0x%x!\n", ntStatus );
return STATUS_INSUFFICIENT_RESOURCES;
}
//
//
保存过滤设备信息
//
DevExt->DeviceObject = DeviceObject;
DevExt->TargetDevice = TargetDevice;
//
// 设置过滤设备相关信息与标志
//
DeviceObject->Flags |= ( DO_BUFFERED_IO | DO_POWER_PAGABLE
);
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////
//
函数类型 : 自定义工具函数
// 函数模块 : 键盘过滤模块
////////////////////////////////////////////////////////////////
//
功能 : 创建过滤设备将其附加到需要跟踪的设备上,保存设备相关
// 信息,返回附加后的驱动对象
// 注意 :
此函数仅挂接 PS/2 键盘设备
/////////////////////////////////////////////////////////////////
//
作者 : sinister
// 发布版本 : 1.00.00
// 发布日期 : 2005.12.27
/////////////////////////////////////////////////////////////////
//
重 大 修 改 历 史
////////////////////////////////////////////////////////////////
//
修改者 :
// 修改日期 :
// 修改内容 :
/////////////////////////////////////////////////////////////////
NTSTATUS
AttachPS2KeyboardDevice(
IN UNICODE_STRING* DeviceName, // 需要跟踪的设备名
IN PDRIVER_OBJECT DriverObject, // 过滤驱动也就是本驱动的驱动对象
OUT PDRIVER_OBJECT* FilterDriverObject ) // 返回附加后的驱动对象
{
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT FilterDeviceObject;
PDEVICE_OBJECT TargetDevice;
PFILE_OBJECT FileObject;
PDEVICE_EXTENSION DevExt;
NTSTATUS ntStatus;
//
//
根据设备名称找到需要附加的设备对象
//
ntStatus = IoGetDeviceObjectPointer(
DeviceName,
FILE_ALL_ACCESS,
&FileObject,
&DeviceObject );
if ( !NT_SUCCESS( ntStatus ) )
{
DbgPrint( "IoGetDeviceObjectPointer() 0x%x\n", ntStatus );
return ntStatus;
}
//
// 创建过滤设备对象
//
ntStatus = IoCreateDevice( DriverObject,
sizeof( DEVICE_EXTENSION ),
NULL,
FILE_DEVICE_KEYBOARD,
0,
FALSE,
&FilterDeviceObject );
if ( !NT_SUCCESS( ntStatus ) )
{
ObDereferenceObject(
FileObject );
DbgPrint( "IoCreateDevice() 0x%x!\n", ntStatus );
return ntStatus;
}
//
// 得到设备扩展结构,以便下面保存过滤设备信息
//
DevExt = ( PDEVICE_EXTENSION )
FilterDeviceObject->DeviceExtension;
//
// 初始化自旋锁
//
KeInitializeSpinLock( &DevExt->SpinLock );
//
// 初始化 IRP 计数器
//
DevExt->IrpsInProgress = 0;
//
// 将过滤设备对象附加在目标设备对象之上,并返回附加后的原设备对象
//
TargetDevice =
IoAttachDeviceToDeviceStack( FilterDeviceObject,
DeviceObject );
if ( !TargetDevice )
{
ObDereferenceObject( FileObject );
IoDeleteDevice(
FilterDeviceObject );
DbgPrint( "IoAttachDeviceToDeviceStack()
0x%x!\n", ntStatus );
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// 保存过滤设备信息
//
DevExt->DeviceObject =
FilterDeviceObject;
DevExt->TargetDevice = TargetDevice;
DevExt->pFilterFileObject = FileObject;
//
//
设置过滤设备相关信息与标志
//
FilterDeviceObject->DeviceType =
TargetDevice->DeviceType;
FilterDeviceObject->Characteristics =
TargetDevice->Characteristics;
FilterDeviceObject->Flags
&= ~DO_DEVICE_INITIALIZING;
FilterDeviceObject->Flags |= (
TargetDevice->Flags & ( DO_DIRECT_IO |
DO_BUFFERED_IO ) );
//
// 返回附加后的驱动对象
//
*FilterDriverObject = TargetDevice->DriverObject;
ObDereferenceObject( FileObject );
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////
//
函数类型 : 自定义工具函数
// 函数模块 : 键盘过滤模块
////////////////////////////////////////////////////////////////
//
功能 : 键盘过滤驱动的 IRP_MJ_READ 派遣例程,所有按键将触发
// 这个 IRP 的完成
// 注意 :
/////////////////////////////////////////////////////////////////
//
作者 : sinister
// 发布版本 : 1.00.00
// 发布日期 : 2007.2.15
/////////////////////////////////////////////////////////////////
//
重 大 修 改 历 史
////////////////////////////////////////////////////////////////
//
修改者 :
// 修改日期 :
// 修改内容 :
/////////////////////////////////////////////////////////////////
NTSTATUS
KeyReadPassThrough(
IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
{
NTSTATUS
status;
KIRQL IrqLevel;
PDEVICE_OBJECT pDeviceObject;
PDEVICE_EXTENSION KeyExtension = ( PDEVICE_EXTENSION )
DeviceObject->DeviceExtension;
IoCopyCurrentIrpStackLocationToNext( Irp );
//
// 将 IRP
计数器加一,为支持 SMP 使用自旋锁
//
KeAcquireSpinLock(
&KeyExtension->SpinLock, &IrqLevel );
InterlockedIncrement( &KeyExtension->IrpsInProgress );
KeReleaseSpinLock( &KeyExtension->SpinLock, IrqLevel );
IoSetCompletionRoutine( Irp,
KeyReadCompletion,
DeviceObject,
TRUE,
TRUE,
TRUE );
return IoCallDriver( KeyExtension->TargetDevice, Irp
);
}
/////////////////////////////////////////////////////////////////
//
函数类型 :系统回调函数
// 函数模块 : 键盘过滤模块
////////////////////////////////////////////////////////////////
//
功能 : 获得键盘按键,用无效扫描码替换,以达到屏蔽键盘的目的
// 注意 :
/////////////////////////////////////////////////////////////////
//
作者 : sinister
// 发布版本 : 1.00.00
// 发布日期 : 2007.2.12
/////////////////////////////////////////////////////////////////
//
重 大 修 改 历 史
////////////////////////////////////////////////////////////////
//
修改者 :
// 修改日期 :
// 修改内容 :
/////////////////////////////////////////////////////////////////
NTSTATUS
KeyReadCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context )
{
PIO_STACK_LOCATION IrpSp;
PKEYBOARD_INPUT_DA
PDEVICE_EXTENSION KeyExtension = (
PDEVICE_EXTENSION )
DeviceObject->DeviceExtension;
int numKeys, i;
KIRQL
IrqLevel;
IrpSp = IoGetCurrentIrpStackLocation( Irp );
if ( Irp->IoStatus.Status != STATUS_SUCCESS )
{
DbgPrint( "ntStatus:0x%x", Irp->IoStatus.Status );
goto
__RoutineEnd;
}
//
// 系统在 SystemBuffer 中保存按键信息
//
KeyData = Irp->AssociatedIrp.SystemBuffer;
if ( KeyData == NULL
)
{
DbgPrint( "KeyData is NULL\n" );
goto
__RoutineEnd;
}
//
// 得到按键数
//
numKeys =
Irp->IoStatus.Information / sizeof( KEYBOARD_INPUT_DA
if (
numKeys < 0 )
{
DbgPrint( "numKeys less zero\n" );
goto __RoutineEnd;
}
//
// 使用 0 无效扫描码替换,屏蔽所有按键
//
for ( i = 0; i < numKeys; i++ )
{
DbgPrint(
"KeyDwon: 0x%x\n", KeyData[i].MakeCode );
KeyData[i].MakeCode =
0x00;
}
__RoutineEnd :
if (
Irp->PendingReturned )
{
IoMarkIrpPending( Irp );
}
//
// 将 IRP 计数器减一,为支持 SMP 使用自旋锁
//
KeAcquireSpinLock(
&KeyExtension->SpinLock, &IrqLevel );
InterlockedDecrement( &KeyExtension->IrpsInProgress );
KeReleaseSpinLock( &KeyExtension->SpinLock, IrqLevel );
return Irp->IoStatus.Status ;
}
/*****************************************************************
文
件名 : WssLockKey.h
描述 : 键盘过滤驱动
作者 :
sinister
{zh1}修改日期 : 2007-02-26
*****************************************************************/
#ifndef
__WSS_LOCKKEY_H_
#define __WSS_LOCKKEY_H_
#include "ntddk.h"
#include
"ntddkbd.h"
#include "string.h"
#include
#define MAXLEN 256
#define KDBDEVICENAME L""
#define
USBKEYBOARDNAME L""
#define PS2KEYBOARDNAME L""
typedef
struct _OBJECT_CREATE_INFORMATION
{
ULONG Attributes;
HANDLE RootDirectory;
PVOID ParseContext;
KPROCESSOR_MODE
ProbeMode;
ULONG PagedPoolCharge;
ULONG
NonPagedPoolCharge;
ULONG SecurityDescriptorCharge;
PSECURITY_DESCRIPTOR SecurityDescriptor;
PSECURITY_QUALITY_OF_SERVICE SecurityQos;
SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
}
OBJECT_CREATE_INFORMATION, * POBJECT_CREATE_INFORMATION;
typedef
struct _OBJECT_HEADER
{
LONG PointerCount;
union
{
LONG HandleCount;
PSINGLE_LIST_ENTRY SEntry;
};
POBJECT_TYPE Type;
UCHAR NameInfoOffset;
UCHAR
HandleInfoOffset;
UCHAR QuotaInfoOffset;
UCHAR Flags;
union
{
POBJECT_CREATE_INFORMATION ObjectCreateInfo;
PVOID QuotaBlockCharged;
};
PSECURITY_DESCRIPTOR
SecurityDescriptor;
QUAD Body;
} OBJECT_HEADER, *
POBJECT_HEADER;
#define NUMBER_HASH_BUCKETS 37
typedef
struct _OBJECT_DIRECTORY
{
struct _OBJECT_DIRECTORY_ENTRY*
HashBuckets[NUMBER_HASH_BUCKETS];
struct
_OBJECT_DIRECTORY_ENTRY** LookupBucket;
BOOLEAN LookupFound;
USHORT SymbolicLinkUsageCount;
struct _DEVICE_MAP* DeviceMap;
}
OBJECT_DIRECTORY, * POBJECT_DIRECTORY;
typedef struct
_OBJECT_HEADER_NAME_INFO
{
POBJECT_DIRECTORY Directory;
UNICODE_STRING Name;
ULONG Reserved;
#if DBG
ULONG
Reserved2 ;
LONG DbgDereferenceCount ;
#endif
}
OBJECT_HEADER_NAME_INFO, * POBJECT_HEADER_NAME_INFO;
#define
OBJECT_TO_OBJECT_HEADER( o ) \
CONTAINING_RECORD( (o),
OBJECT_HEADER, Body )
#define OBJECT_HEADER_TO_NAME_INFO( oh )
((POBJECT_HEADER_NAME_INFO) \
((oh)->NameInfoOffset == 0 ?
NULL : ((PCHAR)(oh) - (oh)->NameInfoOffset)))
typedef struct
_DEVICE_EXTENSION
{
PDEVICE_OBJECT DeviceObject;
PDEVICE_OBJECT TargetDevice;
PFILE_OBJECT pFilterFileObject;
ULONG DeviceExtensionFlags;
LONG IrpsInProgress;
KSPIN_LOCK SpinLock;
}DEVICE_EXTENSION, * PDEVICE_EXTENSION;
VOID
KeyDriverUnload( PDRIVER_OBJECT KeyDriver );
BOOLEAN
CancelKeyboardIrp(
IN PIRP Irp );
extern POBJECT_TYPE* IoDriverObjectType;
NTSYSAPI
NTSTATUS
NTAPI
ObReferenceObjectByName( IN PUNICODE_STRING ObjectName,
IN ULONG Attributes,
IN PACCESS_STATE
AccessState OPTIONAL,
IN ACCESS_MASK
DesiredAccess OPTIONAL,
IN
POBJECT_TYPE ObjectType,
IN
KPROCESSOR_MODE AccessMode,
IN OUT
PVOID ParseContext OPTIONAL,
OUT
PVOID* Object );
NTSTATUS
GetUsbKeybordDevice( OUT
PDEVICE_OBJECT* UsbDeviceObject );
BOOLEAN
GetAttachedDeviceInfo(
IN PDEVICE_OBJECT DevObj );
VOID
GetDeviceObjectInfo( IN
PDEVICE_OBJECT DevObj );
NTSTATUS
AttachUSBKeyboardDevice( IN
PDEVICE_OBJECT UsbDeviceObject,
IN
PDRIVER_OBJECT DriverObject );
NTSTATUS
AttachPS2KeyboardDevice(
IN UNICODE_STRING* DeviceName,
IN
PDRIVER_OBJECT DriverObject,
OUT
PDRIVER_OBJECT* FilterDriverObject );
NTSTATUS
KeyReadCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP
Irp,
IN PVOID Context );
NTSTATUS
KeyReadPassThrough(
IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
WCHAR szUsbDeviceName[MAXLEN];
#endif