吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 9325|回复: 8
收起左侧

[系统底层] 一个键盘过滤驱动的问题

[复制链接]
Robot 发表于 2013-2-21 09:47
//在删除设备的时候 蓝屏 请高手帮忙看看 到底哪里出错了
//IoDeleteDevice 穿进去的不为空 但还是蓝屏了
#include<ntddk.h>
#define  DELAY_ONE_MILLISECOND (-10*1000)
/**********************************
    键盘过滤驱动

***********************************/
//声明全局变量
//在Win7中 这个变量为 多重指针 而不是指针 对象
extern POBJECT_TYPE *IoDriverObjectType;
//KbdClass 驱动名字
#define KBD_DRIVER_NAME L"\\Driver\\Kbdclass"
ULONG gC2pKeyCount=0; //当有键盘按下的请求则加1请求结束则减1
//声明 ObReferenceObjectByName 函数 根据驱动名获得对象指针
//此函数需要声明  输入微软未公开的API函数
NTSTATUS ObReferenceObjectByName(
                                        PUNICODE_STRING ObjectName,
                                        ULONG Attributes,
                                        PACCESS_STATE AccessState,
                                        ACCESS_MASK DesiredAccess,
                                        POBJECT_TYPE *ObjectType,
                                        KPROCESSOR_MODE AccessMode,
                                        PVOID ParseContext,
                                        PVOID *Object  //OUT
);
//设备扩展结构
typedef struct _C2P_DEV_EXT{
                                //结构大小
                                ULONG NodeSize;
                                //过滤设备对象
                                PDEVICE_OBJECT pFilterDeviceObject;
                                //同时调用时保护锁
                                KSPIN_LOCK IoRequestsSpinLock;
                                //进程同步处理
                                KEVENT IoInProgressEvent;
                                //绑定的设备对象
                                PDEVICE_OBJECT pTargetDeviceObject;
                                //绑定前底层设备对象
                                PDEVICE_OBJECT pLowerDeviceObject;
}C2P_DEV_EXT,*PC2P_DEV_EXT;
//初始化扩展
NTSTATUS c2pDevExtInit(
                                IN PC2P_DEV_EXT devExt,
                                IN PDEVICE_OBJECT pFilterDeviceObject,
                                IN PDEVICE_OBJECT pTargetDeviceObject,
                                IN PDEVICE_OBJECT pLowerDeviceObject
){
                        //开辟空间
                        memset(devExt,0,sizeof(C2P_DEV_EXT));
                        devExt->NodeSize = sizeof(C2P_DEV_EXT);
                        devExt->pFilterDeviceObject = pFilterDeviceObject;
                        KeInitializeSpinLock(&(devExt->IoRequestsSpinLock));
                        KeInitializeEvent(&(devExt->IoInProgressEvent),NotificationEvent,FALSE);
                        devExt->pTargetDeviceObject = pTargetDeviceObject;
                        devExt->pLowerDeviceObject  = pLowerDeviceObject;
                        return STATUS_SUCCESS;
}
//绑定设备
NTSTATUS keycupAttachDevice(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath){
                                //初始化变量
                                NTSTATUS status;
                                UNICODE_STRING uniNtNameString;
                                PC2P_DEV_EXT devExt;
                               
                                PDEVICE_OBJECT pFilterDeivceObject =NULL;  //过滤的设备
                                PDEVICE_OBJECT pTargetDeivceObject =NULL;  //目标设备
                                PDEVICE_OBJECT pLowerDeviceObject = NULL;  //下一个设备
                               
                                //键盘过滤驱动对象
                                PDRIVER_OBJECT KbdDriverObject = NULL;
                               
                                DbgPrint(("MyAttach\n"));
                               
                                //初始化字符串
                                RtlInitUnicodeString(&uniNtNameString,KBD_DRIVER_NAME);
                               
                                //打开驱动对象
                                status = ObReferenceObjectByName(&uniNtNameString,//驱动名称
                                                                                                                                                                 OBJ_CASE_INSENSITIVE, //不区分大小写
                                                                                                                                                                 NULL,
                                                                                                                                                                 0, //权限
                                                                                                                                                                 *IoDriverObjectType,
                                                                                                                                                                 KernelMode,
                                                                                                                                                                 NULL,
                                                                                                                                                           &KbdDriverObject); //OUT
                               
                                //判断是否成功
                                if(!NT_SUCCESS(status)){
                                                        DbgPrint("Attach error");
                                                        return status;
                                }else{
                                         //调用ObReferenceObjectByName 会导致内核的引用计数 加1
                                         //必须调用ObDereferenceObject 函数 递减
                                         ObDereferenceObject(DriverObject);
                                }
                               
                                //设备链 第一个设备
                                pTargetDeivceObject = KbdDriverObject->DeviceObject;
                               
                                //遍历设备链
                                while(pTargetDeivceObject){
                                                        //生成一个过滤设备
                                                        status = IoCreateDevice(
                                                                                        DriverObject, //驱动对象
                                                                                        sizeof(PC2P_DEV_EXT),
                                                                                        NULL,
                                                                                        pTargetDeivceObject->DeviceType,
                                                                                        pTargetDeivceObject->Characteristics,
                                                                                        FALSE,
                                                                                        &pFilterDeivceObject
                                                        );
                                                        //如果失败 返回状态
                                                        if(!NT_SUCCESS(status)){
                                                                        DbgPrint("Attach Could not create filter device");
                                                                        return status;
                                                        }
                                                        //进行绑定
                                                        //filter 过滤的设备
                                                        //target 设备栈中的设备 函数作用 这两个设备进行绑定 返回 pLowerDeviceObject 的指针
                                                        IoAttachDeviceToDeviceStackSafe(pFilterDeivceObject,pTargetDeivceObject,&pLowerDeviceObject);
                                                        //如果绑定失败 则退出
                                                        if(pLowerDeviceObject==NULL){
                                                                                DbgPrint("IoAttachDeviceToDeviceStackSafe error");
                                                                                IoDeleteDevice(pFilterDeivceObject);
                                                                                pFilterDeivceObject= NULL;
                                                                                return status;
                                                        }
                                                        //设备扩展
                                                        devExt = (PC2P_DEV_EXT)(pFilterDeivceObject->DeviceExtension);
                                                        c2pDevExtInit(
                                                                        devExt,
                                                                        pFilterDeivceObject,
                                                                        pTargetDeivceObject,
                                                                        pLowerDeviceObject
                                                        );
                                                       
                                                        //拷贝标志位
                                                        pFilterDeivceObject->DeviceType = pLowerDeviceObject->DeviceType;
                                                        pFilterDeivceObject->Characteristics = pLowerDeviceObject->Characteristics;
                                                        pFilterDeivceObject->StackSize = pLowerDeviceObject->StackSize+1; //设备栈个数
                                                        pFilterDeivceObject->Flags |= pLowerDeviceObject->Flags&(DO_BUFFERED_IO|DO_DIRECT_IO|DO_POWER_PAGABLE );
                                                       
                                                        //移动到下一个设备
                                                        pTargetDeivceObject = pTargetDeivceObject->NextDevice;
                                                       
                                }
                               
                                return status;
                                                                                                                                                                 

}
PDRIVER_OBJECT gDriverObject = NULL;  //暂时不知道是用作什么
VOID c2pDetach(IN PDEVICE_OBJECT pDeviceObject)
{
        PC2P_DEV_EXT devExt;
        //BOOLEAN NoRequestsOutstanding = FALSE;
        devExt = (PC2P_DEV_EXT)pDeviceObject->DeviceExtension;
        __try
        {
                __try
                {
                        IoDetachDevice(devExt->pTargetDeviceObject);
                        devExt->pTargetDeviceObject = NULL;
                        IoDeleteDevice(pDeviceObject); //在删除设备的时候 出错蓝屏 这里值不为空
                        DbgPrint(("Detach Finished\n"));
                }
                __except (EXCEPTION_EXECUTE_HANDLER){}
        }
        __finally{}
        return;
}
//卸载函数
VOID c2pUnload(IN PDRIVER_OBJECT DriverObject)
{
                PDEVICE_OBJECT DeviceObject;
                PDEVICE_OBJECT OldDeviceObject;
                PC2P_DEV_EXT devExt;  
               
               
                LARGE_INTEGER lDelay; //延迟时间
                PRKTHREAD CurrentThread;
                #if DBG
                        _asm int 3
                #endif
                //设置延迟时间
                lDelay = RtlConvertLongToLargeInteger(100*DELAY_ONE_MILLISECOND);
                CurrentThread = KeGetCurrentThread(); //获取当前运行的线程指针
                //把当前线程 设置为低实时模式
                KeSetPriorityThread(CurrentThread,LOW_REALTIME_PRIORITY);
                UNREFERENCED_PARAMETER(DriverObject); //防止编译器提示变量为引用的警告
               
                DbgPrint("driver unloading ....");
               
                //遍历所有对象
                DeviceObject =DriverObject->DeviceObject;
                while(DeviceObject)
                {
                                 //解除并删除 设备对象
                                 c2pDetach(DeviceObject);
                                 //next
                                 DeviceObject=DeviceObject->NextDevice;
                }
                ASSERT(NULL==DriverObject->DeviceObject); //如果设备对象不为NULL 则不会向下执行
               
                while(gC2pKeyCount)
                {
                                KeDelayExecutionThread(KernelMode,FALSE,&lDelay); //吧线程进入等待状态 时间为lDelay
                }
                DbgPrint("unload driver success!");
                return ;
}

//总分发函数
NTSTATUS c2pAllFunction(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp){
        DbgPrint("other Diapatch");
        //向下执行 Skip 吧IRP 给真实的设备进行操作
        IoSkipCurrentIrpStackLocation(Irp);
        return IoCallDriver(((PC2P_DEV_EXT)DeviceObject->DeviceExtension)->pLowerDeviceObject,Irp);
       
}
//电源处理
//处理类型为 IRP_MJ_POWER
NTSTATUS c2pPower(IN PDEVICE_OBJECT DeviceObject,PIRP Irp){
        PC2P_DEV_EXT devExt;
        devExt = (PC2P_DEV_EXT)DeviceObject->DeviceExtension; //设备扩展
        PoStartNextPowerIrp(Irp); //Vista 之后估计不用写也可以
        IoSkipCurrentIrpStackLocation(Irp);
        return PoCallDriver(devExt->pLowerDeviceObject,Irp);
       
}
//PNP处理
NTSTATUS c2pPnP(IN PDEVICE_OBJECT DeviceObject ,IN PIRP Irp){
        PC2P_DEV_EXT devExt;
        NTSTATUS status = STATUS_SUCCESS;
        PIO_STACK_LOCATION irpStack;
       
        //获取真实的设备
        devExt = (PC2P_DEV_EXT)DeviceObject->DeviceExtension;
        irpStack = IoGetCurrentIrpStackLocation(Irp); //获取Irp栈段
        switch(irpStack->MinorFunction){
                                //移除操作
                                case IRP_MN_REMOVE_DEVICE:
                                        DbgPrint("IRP_MN_REMOVE_DEVICE\n");
                                        //请求下发
                                        IoSkipCurrentIrpStackLocation(Irp);
                                        IoCallDriver(devExt->pLowerDeviceObject,Irp);
                                        //解除绑定
                                        IoDetachDevice(devExt->pLowerDeviceObject);
                                        //删除设备
                                        IoDeleteDevice(DeviceObject);
                                 break;
                                 
                                 default:
                                                 //其他类型IRP直接下发
                                                 IoSkipCurrentIrpStackLocation(Irp);
                                                 IoCallDriver(devExt->pLowerDeviceObject,Irp);
                                                 break;
                                       
        }
        return status;
}

//回调函数
NTSTATUS irpCallBackFunction(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID Context){
                PIO_STACK_LOCATION irpStack;
                ULONG bufLen = 0;
                PCHAR buf = NULL;
                size_t i ;
               
                //获取Stack location
                irpStack = IoGetCurrentIrpStackLocation(Irp);
               
                //如果请求成功 获取进一步信息
                if(NT_SUCCESS(Irp->IoStatus.Status)){
                                //获得请求后输出到缓冲区
                                buf = Irp->AssociatedIrp.SystemBuffer;
                                //获取缓冲区的长度
                                //一般情况下返回值都会保存在 Information 中
                                bufLen = Irp->IoStatus.Information;
                                //打印出扫描码
                                for(i=0;i<bufLen;i++){
                                                DbgPrint("键盘扫描码为: %2x\r\n",buf);
                                }
                }
                //全局变量递减
                gC2pKeyCount--;
                //个人理解 将IRP至于等待/保留状态  如果为True 调用IoMarkIrpPending 函数使Irp调用下层驱动进行处理
                if(Irp->PendingReturned){
                                IoMarkIrpPending(Irp);
                }
                return Irp->IoStatus.Status; //返回Irp Status
}
//处理Read请求
NTSTATUS c2pDispatchRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp){
        PIO_STACK_LOCATION irpStack;
        PC2P_DEV_EXT devExt;
        NTSTATUS status = STATUS_SUCCESS;
        KEVENT waitEvent;
        /*
          IN PRKEVENT Event,   //这个参数是初始化事件对象的指针   
    IN EVENT_TYPE Type, //这个参数是时间的类型。事件的类型分为两类,一类是"通知事件",对应参数是NotificationEvent.另一类是"同步事件",对应参数是SynchronizationEvent  
    IN BOOLEAN State     //这个参数如果为真,事件对象初始化状态为激发状态。如果该参数为假,则事件对象的初始化状态为未激发态  
        */
        KeInitializeEvent(&waitEvent,NotificationEvent,FALSE); //初始化事件对象为通知型 并且未激活
        //如果是 IRP栈中的最后1个 出栈 SP = sp-2 所以当标示为1的时候 则是最后一个设备 直接返回
        //IRP 下标CurrentLocation
        if(Irp->CurrentLocation==1){  
                ULONG ReturnedInformation = 0;
                DbgPrint("Dispatch encountered bogus current location\n");
                status = STATUS_INVALID_DEVICE_REQUEST;
                //设置IRP状态 返回IRP 固定写法
                Irp->IoStatus.Status = status; //设置IRP状态
                Irp->IoStatus.Information = ReturnedInformation;
                IoCompleteRequest(Irp,IO_NO_INCREMENT);
                return status;
        }
        //全局变量+1
        gC2pKeyCount++;
        //得到设备扩展 目的获得下一个设备的指针
        devExt = (PC2P_DEV_EXT)DeviceObject->DeviceExtension;
        //设置回调函数 吧IRP继续传递 读请求结束 剩下的交给回调函数
        irpStack = IoGetCurrentIrpStackLocation(Irp);
        IoCopyCurrentIrpStackLocationToNext(Irp); //复制当前栈空间
        //设置回调
        //当IRP完成之后会调用它,需要注意的是完成函数运行在DISPATCH中断级,因此此函数里面的代码尽量不要太多,还有必须使用DISPATCH中断级的函数。
        IoSetCompletionRoutine(Irp,
                                                                                                irpCallBackFunction, //回调函数
                                                                                                DeviceObject, //上下文对象
                                                                                                TRUE,TRUE,TRUE
                                                                                                );
        //传递到下一个设备
        return IoCallDriver(devExt->pLowerDeviceObject,Irp);
       
}


//入口函数
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING regPath){
         
                        ULONG i;
                        NTSTATUS status;
                        DbgPrint("Driver start loading。。。。");
                       
                        //填写所有的分发函数
                        for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++){
                                                        DriverObject->MajorFunction = c2pAllFunction; //(总分发函数)
                        }
                       
                        //读取请求分发函数 用来读取键盘的信息
                        DriverObject ->MajorFunction[IRP_MJ_READ] = c2pDispatchRead;
                       
                        //电源处理 函数
                        DriverObject ->MajorFunction[IRP_MJ_POWER] = c2pPower;
                       
                        //如果键盘被拔掉 这里是一个PNP即插即用函数
                        DriverObject ->MajorFunction[IRP_MJ_PNP] = c2pPnP;
                       
                        //卸载函数  
                        DriverObject ->DriverUnload = c2pUnload;
                        gDriverObject = DriverObject;
                       
                        //绑定所有键盘设备
                        status = keycupAttachDevice(DriverObject,regPath);
                       
                        return status;
}

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

LeoSky 发表于 2013-2-21 10:37
咱小白。

KeInitializeSpinLock(&(devExt->IoRequestsSpinLock));
KeInitializeEvent(&(devExt->IoInProgressEvent),NotificationEvent,FALSE);

这两个不知道是否需要呢?
KeReleaseSpinLock
KeResetEvent
 楼主| Robot 发表于 2013-2-21 11:20
LeoSky 发表于 2013-2-21 10:37
咱小白。

KeInitializeSpinLock(&(devExt->IoRequestsSpinLock));

这个应该需要的 这个是事件 还有通知类型 我也就大概知道这个意思
WinDbg调试的时候 在IoDeleteDevice的时候报错了 我刚又看了看书上的代码 原来问题出在创建设备的时候
//生成一个过滤设备
                                                        status = IoCreateDevice(
                                                                                        DriverObject, //驱动对象
                                                                                        sizeof(PC2P_DEV_EXT),
                                                                                        NULL,
                                                                                        pTargetDeivceObject->DeviceType,
                                                                                        pTargetDeivceObject->Characteristics,
                                                                                        FALSE,
                                                                                        &pFilterDeivceObject
                                                        );
sizeof(PC2P_DEV_EXT), 设备大小 应该设置成结构 而不是指针的 所以在删除的时候会报错

还有在调用ObReferenceObjectByName 函数打开设备对象的时候 调用
ObDereferenceObject 函数 使引用对象-1 里面应该填写的是 打开设备对象的指针 而不是DriverObject 这个是在网上发现的 如果不这样写 卸载之后 在按一个按钮结束循环的时候会蓝屏
LeoSky 发表于 2013-2-21 14:53
Robot 发表于 2013-2-21 11:20
这个应该需要的 这个是事件 还有通知类型 我也就大概知道这个意思
WinDbg调试的时候 在IoDeleteDevice的 ...

呵呵。
sizeof(PC2P_DEV_EXT) 这个比较隐蔽。。。直接肉眼看很难发现。。这就是平时写代码要仔细哦。。
 楼主| Robot 发表于 2013-2-21 15:16
LeoSky 发表于 2013-2-21 14:53
呵呵。
sizeof(PC2P_DEV_EXT) 这个比较隐蔽。。。直接肉眼看很难发现。。这就是平时写代码要仔细哦。。

嗯  在获取键盘扫描码的时候 用循环获得后 知道怎么处理能显示为ASCLL码吗
  _printKey((UCHAR)(kData->MakeCode));

//过滤功能按键
VOID __stdcall _printKey(UCHAR ch){
                        DbgPrint("Ascll: %x",ch);
}
这个我直接打出来 好像不是全部的扫描码 是不是得用UNICODE_STRING 这样的类型传?
1354669803 发表于 2013-2-21 15:31
蓝屏很奇怪么
_Shelleyan_ 发表于 2015-1-17 10:25
问下键盘驱动是不能在虚拟机中运行吧 ? 只有驱动挂载在主机的keyboardclass上才行吧,个人理解~
738345099 发表于 2015-7-24 18:17 来自手机
有什么用啊
Memory_时差 发表于 2015-7-24 18:24 来自手机
不错支持。。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-20 08:31

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表