首页
社区
课程
招聘
[旧帖] [求助]驱动初学者,关于键盘过滤(Kbdclass)驱动的1个问题,请高手赐教。 0.00雪花
发表于: 2009-10-30 19:54 1584

[旧帖] [求助]驱动初学者,关于键盘过滤(Kbdclass)驱动的1个问题,请高手赐教。 0.00雪花

2009-10-30 19:54
1584

驱动初学者,关于键盘过滤(Kbdclass)驱动的1个问题,请高手赐教。
问题请看代码中的注释(红色的文字),或者直接查找 问题 就可以了。

申明:本代码参考了《寒江独钓——Windows内核安全编程》
/*
描述 : 键盘过滤(Kbdclass)
*/
#include <ntddk.h>
#include <ntddkbd.h>

// 这个全局变量是存在的,声明一下就可以用
extern POBJECT_TYPE IoDriverObjectType;
// 这个例程是存在的,声明一下就可以用
extern NTKERNELAPI NTSTATUS ObReferenceObjectByName(
       IN PUNICODE_STRING ObjectName,               // 驱动对象的名字
       IN ULONG Attributes,                         // OBJ_CASE_INSENSITIVE
       IN PACCESS_STATE PassedAccessState OPTIONAL, // NULL
       IN ACCESS_MASK DesiredAccess OPTIONAL,       // 0
       IN POBJECT_TYPE ObjectType OPTIONAL,         // IoDriverObjectType
       IN KPROCESSOR_MODE AccessMode,               // KernelMode
       IN OUT PVOID ParseContext OPTIONAL,          // NULL
       OUT PVOID *Object                            // 取得的对象指针的指针
);

// 过滤设备的设备扩展
typedef struct _KB_FILTER_DEV_EXT {
        // 设备栈上位于过滤设备对象的下一层设备对象,过滤设备卸载时用
        PDEVICE_OBJECT LowerDeviceObject;
} KB_FILTER_DEV_EXT, *PKB_FILTER_DEV_EXT;

// 按键处理计数器
ULONG gKeyCount = 0;

// 驱动入口例程
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);

// IRP处理例程
NTSTATUS Dispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);

// 驱动卸载例程
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject);

// Kbdclass挂载例程
VOID AttachKbdclass(IN PDRIVER_OBJECT DriverObject);

// IRP_MJ_READ完成回调例程
NTSTATUS ReadCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context);

// 定义各例程位于分页内存(PAGE)/非分页内存(???)/只运行一次就从内存释放(INIT)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, Dispatch)
#pragma alloc_text(PAGE, DriverUnload)
#pragma alloc_text(INIT, AttachKbdclass)
#pragma alloc_text(PAGE, ReadCompletionRoutine)
#endif

/*
驱动入口例程
*/
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
        USHORT idx;
        // 所有IRP处理例程设置为Dispatch
        KdPrint(("DriverEntry in\n"));
        for (idx = 0; idx < IRP_MJ_MAXIMUM_FUNCTION; ++idx)
        {
                DriverObject->MajorFunction[idx] = Dispatch;
        }
        // 设置驱动卸载例程,否则无法动态卸载
        DriverObject->DriverUnload = DriverUnload;
        // 挂载Kbdclass
        AttachKbdclass(DriverObject);
        KdPrint(("DriverEntry end\n"));
        return STATUS_SUCCESS;
}

/*
IRP处理例程
*/
NTSTATUS Dispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
        NTSTATUS status;
        // 取得IRP对应的StackLocation
        PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
        // 取得过滤设备的设备扩展
        PKB_FILTER_DEV_EXT kbDevExt = (PKB_FILTER_DEV_EXT)DeviceObject->DeviceExtension;
        switch (irpsp->MajorFunction)
        {
                case IRP_MJ_POWER :
                        KdPrint(("IRP=IRP_MJ_POWER\n"));
                        // IRP_MJ_POWER特别处理
            // 准备处理下一个电源IRP
                        PoStartNextPowerIrp(Irp);
                        // 跳过当前堆栈,其实是为了平衡堆栈
                    IoSkipCurrentIrpStackLocation(Irp);
                    return PoCallDriver(kbDevExt->LowerDeviceObject, Irp);
                        break;
                case IRP_MJ_READ :
                        KdPrint(("IRP=IRP_MJ_READ\n"));
                        ++gKeyCount;
                    // 把当前StackLocation拷贝到下一个StackLocation
                    IoCopyCurrentIrpStackLocationToNext(Irp);
                    // 设置完成例程的回调
                        IoSetCompletionRoutine(Irp, ReadCompletionRoutine, DeviceObject, TRUE, TRUE, TRUE);
                    return IoCallDriver(kbDevExt->LowerDeviceObject, Irp);
                        break;
                case IRP_MJ_PNP :
                        KdPrint(("IRP=IRP_MJ_PNP\n"));
                        // IRP_MJ_PNP中再分别处理irpsp->MinorFunction
                        switch (irpsp->MinorFunction)
                    {
                            case IRP_MN_REMOVE_DEVICE :
                                    KdPrint(("IRP=<IRP_MJ_PNP>IRP_MN_REMOVE_DEVICE\n"));
                                    // PNP 管理器要移除设备
                                    IoSkipCurrentIrpStackLocation(Irp);
                                status = IoCallDriver(kbDevExt->LowerDeviceObject, Irp);
                                // 卸载过滤设备对象
                                IoDetachDevice(kbDevExt->LowerDeviceObject);
                                // 删除过滤设备对象
                                IoDeleteDevice(DeviceObject);
                                return status;
                                    break;
                            default :
                                    // 其他的IRP,默认不处理
                                    KdPrint(("IRP=<IRP_MJ_PNP>Default\n"));
                                    // 跳过当前堆栈,其实是为了平衡堆栈
                                    IoSkipCurrentIrpStackLocation(Irp);
                                return IoCallDriver(kbDevExt->LowerDeviceObject, Irp);
                                    break;
                    }
                        break;
                default :
                        // 其他的IRP,默认不处理
                        KdPrint(("IRP=Default\n"));
                        // 跳过当前堆栈,其实是为了平衡堆栈
                        IoSkipCurrentIrpStackLocation(Irp);
                    return IoCallDriver(kbDevExt->LowerDeviceObject, Irp);
                        break;
        }
}

/*
驱动卸载例程
*/
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
        PDEVICE_OBJECT DeviceObject;
        LARGE_INTEGER inteval;
        // 100ms延时
        inteval.QuadPart = 100 * 1000 * (-10);
        KdPrint(("DriverUnload in\n"));
        // 把当前线程设置为低实时模式,让它的运行尽量少影响其他程序
        KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
        DeviceObject = DriverObject->DeviceObject;
        while (DeviceObject != NULL)
        {
                PKB_FILTER_DEV_EXT kbDevExt = (PKB_FILTER_DEV_EXT)DeviceObject->DeviceExtension;
                // 卸载设备
                IoDetachDevice(kbDevExt->LowerDeviceObject);
                // 删除设备
                IoDeleteDevice(DeviceObject);
                DeviceObject = DeviceObject->NextDevice;
        }
        // 直到没有按键在处理才退出驱动程序,因为键盘的处理方式是始终有一个IRP_MJ_READ,所以实际是
        // 准备卸载驱动以后,直到按下一个键以后才会完成卸载
        // 问题1 : 有没有更好的卸载方法呢?
        while (gKeyCount > 0)
        {
        KdPrint(("DriverUnload delay...\n"));
                KeDelayExecutionThread(KernelMode, FALSE, &inteval);
        }
        KdPrint(("DriverUnload end\n"));
}

/*
Kbdclass 挂载例程
*/
VOID AttachKbdclass(IN PDRIVER_OBJECT DriverObject)
{
        NTSTATUS status;
        UNICODE_STRING driverName;
        PDEVICE_OBJECT targetDeviceObject = NULL;
        PDEVICE_OBJECT lowerDeviceObject = NULL;
        PDEVICE_OBJECT filterDeviceObject = NULL;
        PKB_FILTER_DEV_EXT kbDevExt = NULL;
        PDRIVER_OBJECT kbdDriverObject = NULL;
        KdPrint(("AttachKbdclass in\n"));
        // 键盘驱动串\\Driver\\Kbdclass
        RtlInitUnicodeString(&driverName, L"\\Driver\\Kbdclass");
        // 取得驱动对象
        status = ObReferenceObjectByName(&driverName,
                                             OBJ_CASE_INSENSITIVE,
                                             NULL,
                                             0,
                                             IoDriverObjectType,
                                             KernelMode,
                                             NULL,
                                             &kbdDriverObject
                                            );
        if (!NT_SUCCESS(status))
        {
                KdPrint(("ObReferenceObjectByName failed\n"));
                // 根据名字取得驱动对象指针失败,退出
                return;
        }
        targetDeviceObject = kbdDriverObject->DeviceObject;
        while (targetDeviceObject != NULL)
        {
                status = IoCreateDevice(DriverObject,
                                        sizeof(KB_FILTER_DEV_EXT),
                                        NULL,
                                        targetDeviceObject->Type,
                                        targetDeviceObject->Characteristics,
                                        FALSE,
                                        &filterDeviceObject);
                if (!NT_SUCCESS(status))
                {
                        KdPrint(("IoCreateDevice failed\n"));
                        // 创建过滤对象失败,退出
                        return;
                }
                // 设置过滤设备对象的Flags属性和要绑定的对象的Flags属性一致
                filterDeviceObject->Flags |= targetDeviceObject->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
                // 挂载
                lowerDeviceObject = IoAttachDeviceToDeviceStack(filterDeviceObject, targetDeviceObject);
                if (lowerDeviceObject == NULL)
                {
                        // 绑定失败
                        KdPrint(("IoAttachDeviceToDeviceStack failed\n"));
                        // 删除已经创建的过滤设备对象
                        IoDeleteDevice(filterDeviceObject);
                        // 退出
                        return;
                }
                kbDevExt = (PKB_FILTER_DEV_EXT)filterDeviceObject->DeviceExtension;
                kbDevExt->LowerDeviceObject = lowerDeviceObject;
                // 设置过滤设备为已经启动的状态,可以接收IRP
                filterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
                // 循环下一个Kbdclass驱动对象的设备对象
                targetDeviceObject = targetDeviceObject->NextDevice;
        }
        KdPrint(("AttachKbdclass end\n"));
}

/*
IRP_MJ_READ完成回调例程
*/
NTSTATUS ReadCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
        ULONG numKeys;
        ULONG idx;
        PUCHAR buf = NULL;
        PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(Irp);
        KdPrint(("ReadCompletionRoutine in\n"));
        // 如果读请求是成功的
        if (NT_SUCCESS(Irp->IoStatus.Status))
        {
                // 取得按键的个数
                numKeys = Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);
                // 取得缓冲区的内容
                buf = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
                // 输出
                KdPrint(("numKeys : %d\n", numKeys));
                for (idx = 0; idx < numKeys; ++idx)
                {
                        PKEYBOARD_INPUT_DATA keyData = (PKEYBOARD_INPUT_DATA)(buf + idx * sizeof(KEYBOARD_INPUT_DATA));
                        KdPrint(("ScanCode : %x\n", keyData->MakeCode));
                        KdPrint(("PressState : %s\n", keyData->Flags == KEY_MAKE ? "DOWN" :
                                                      keyData->Flags == KEY_BREAK ? "UP" : "Unknown"));
                        // 这里只是个测试,按下a,会被修改为c
                        if (keyData->MakeCode == 30)
                        {
                                keyData->MakeCode = 46;
                        }
                }
                --gKeyCount;
                if (Irp->PendingReturned)
                {
                        IoMarkIrpPending(Irp);
                }
        }
        KdPrint(("ReadCompletionRoutine end\n"));
        return Irp->IoStatus.Status;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (5)
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
高手呢?
2009-10-30 21:22
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
自己顶
2009-10-31 08:28
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
高手呢?不要沉
2009-10-31 21:19
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
这个问题没有解了吗?我睡不着啊,每天看几回,就是没人回贴
2009-11-1 11:18
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
再顶一把,希望版主不要把我赶出去
2009-11-1 14:23
0
游客
登录 | 注册 方可回帖
返回
//