CII_GZH
驱动中牛
驱动中牛
  • 注册日期2005-06-16
  • 最后登录2007-08-27
  • 粉丝0
  • 关注0
  • 积分257分
  • 威望127点
  • 贡献值0点
  • 好评度33点
  • 原创分0分
  • 专家分0分
阅读:1444回复:0

ctrl2cap动态卸载问题请指点一下

楼主#
更多 发布于:2007-01-15 17:03
  对键盘过滤驱动动态御载时蓝屏的深入分析以及可行的解决方案(1)

如何动态御载键盘过滤驱动(参考一份e文资料+我自己的理解)

最近写个键盘过滤驱动,遇到的问题是动态御载后再有按键操作就会蓝屏,看了些资料终于明白了原因,写出来供大家参考,免得后来的朋友再重复这个郁闷的过程。

要做到动态御载键盘过滤驱动,明白其工作运行的原理是很重要的。首先必须要知道键盘过滤驱动是工作在异步模式下的,这一点很重要。为了得到一个按键操作,首先需要发送一个IRP_MJ_READ到驱动的设备栈,驱动收到这个irp会做什么样的处理呢?它会一直保持这个irp为pending未确定状态,因为其实现在一直没有按键操作,直到一个键被真正的按下,驱动此时就会立刻完成这个irp,并将刚按下的键的相关数据做为该irp的返回值。在该irp带着对应的数据返回后,操作系统将这些值传递给对应的事件系统来处理,然后做什么呢??系统紧接着又会立刻发送一个IRP_MJ_READ请求,等待下次的按键操作,重复以上的步骤。也就是说,任何时候设备栈底都会有一个键盘的IRP_MJ_READ请求处于pending未确定状态。这意味着只有在该irp完成返回,并却新的irp请求还未发送到的时候才会有一个很短暂的时间。由此我们想到,我们按照一般的方式动态御载键盘过滤驱动的时候,基本都是有IRP_MJ_READ请求处于pending未确定状态,而我们却御载了驱动,以后按键的时候需要处理这个irp却找不到对应的驱动当然会蓝屏。

以上分析了动态御载键盘过滤驱动蓝屏的原因,分析到了中间存在一个短暂的时间栈底是没有irp的,那么让我们想办法来解决它。

网上一份e文资料显示,只有使用IoAttachDevice挂接\Device\KeyboardClass0(or others)才可以动态御载,而加载到UpperFilters的却不能。以下是该段的原文:

This problem occurs in most of the keyloggers based on the sysinternals Ctrl2cap model, which has been widely adopted and adapted. It applies to the earlier versions of the filter, which manually attach to \Device\KeyboardClass0 (or others) using IoAttachDevice. (If you install your filter by adding it to the UpperFilters value of HKCR\CCS\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318} key as more recent versions of Ctrl2cap do, you just can't unload: your filter is wedged into the stack for as long as the system is running and can't get out. But if you wedge by IoAttachDevice, unloading is still possible in theory.)。


让我们再深入分析下蓝屏的原因,栈底有irp为什么我们的驱动御载就会有问题呢?这是由于IRM_MJ_READ是异步的,对于异步的请求,基本上我们会关心这个异步请求的结果,如何得到完成后的数据呢?大家一定想到了,设置完成例程。对,就是这样,由于我们给IRP_MJ_READ设置了完成例程,该irp完成后会调用我们的完成例程,使我们有处理返回数据的机会。在这样的情况下,我们动态御载了键盘过滤驱动,也就是说完成例程已经被我们御载掉了,而以后的再次按键在完成这个irp后会调用这个根本已经不存在了的东东,结果蓝屏就可想而知了。

这篇深入分析了动态御载键盘过滤驱动蓝屏的原因,让大家理解了本质的东西,如果大家觉得这篇文章还有些作用,我会继续补上后面的分析及可行的解决方案.
参照前人的说明,自己试了许久,还是不成功。请帮忙。
NTSTATUS Ctrl2capDispatchRead(
      IN PDEVICE_OBJECT DeviceObject,
      IN PIRP Irp )
{
    NTSTATUS status = STATUS_SUCCESS;
    PMyFilter_DeviceExtension pMyFilter_DeviceExtension;
    PIO_STACK_LOCATION currentIrpStack;
    PIO_STACK_LOCATION nextIrpStack;
    LARGE_INTEGER StartingOffset;
    KEVENT       event;
    ULONG BufferLength = 0;
    PCHAR Buffer;
    PIRP SelfIrp;
    
    IO_STATUS_BLOCK ioStatus;
    //
    // Gather our variables.
    //
    if (Irp->CurrentLocation == 1)
    {
        ULONG ReturnedInformation = 0;
        
        DbgPrint(("Dispatch encountered bogus current location\n"));
            
        status = STATUS_INVALID_DEVICE_REQUEST;
        Irp->IoStatus.Status = status;
        Irp->IoStatus.Information = ReturnedInformation;
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
        
        return(status);
    }
    // 这里是自己的irp,处理就是先设置取消历程,在设置完成历程。不知道是对是错。
    pMyFilter_DeviceExtension = (PMyFilter_DeviceExtension)DeviceObject->DeviceExtension;
    if(pMyFilter_DeviceExtension->BuildIrp == 1)
    {
        pMyFilter_DeviceExtension->BuildIrp = 3;
        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.
        //
        //read_run ++;

        //
        // Return the results of the call to the keyboard class driver.
        //
        IoSetCancelRoutine(Irp,DriverUserMessageCancelIrp);//见5  
        IoSetCompletionRoutine( Irp, Ctrl2capReadComplete,
            DeviceObject, TRUE, TRUE, TRUE );
        return IoCallDriver( pMyFilter_DeviceExtension->LowerDeviceObject, Irp );
        /*status = IoCallDriver( pMyFilter_DeviceExtension->LowerDeviceObject, Irp );
        if (status == STATUS_PENDING)
        {
            IoMarkIrpPending( Irp );
            //KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
        }
        status = Irp->IoStatus.Status;
    
        IoCompleteRequest( Irp, IO_NO_INCREMENT );
        return status;
        */
    
    }
    else
    {//系统的IRP来了,我就自己创建一个irp。将原来的irp等待。(还不清楚怎样处理这个等待),
        DbgPrint (("=======BuildIrp=else=%u=====\n", pMyFilter_DeviceExtension->BuildIrp));
        pMyFilter_DeviceExtension->BuildIrp = 1;
        StartingOffset.QuadPart = (LONGLONG)0;    
        currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
        nextIrpStack = IoGetNextIrpStackLocation(Irp);
        
        BufferLength = currentIrpStack->Parameters.Read.Length;
        
        Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferLength, 'dtri');    
        if (!Buffer)
        {
            return STATUS_INSUFFICIENT_RESOURCES;
        }

        //
        // We're going to build the I/O request. Note that this is an
        // ASYNCHRONOUS request, so we don't provide it with an Event
        // to set when the I/O itself is done.
        //
        KeInitializeEvent(&event, NotificationEvent, FALSE);
    
        SelfIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
                                            DeviceObject,
                                            Buffer,
                                            BufferLength,
                                            &StartingOffset,
                                            &ioStatus);
    
        if (!SelfIrp)
        {
            return FALSE;
        }
        /*
        status = IoCallDriver( pMyFilter_DeviceExtension->LowerDeviceObject, SelfIrp );
        if (status == STATUS_PENDING)
        {
            KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
            status = ioStatus.Status;
        }
        status = Irp->IoStatus.Status;
    
        IoCompleteRequest( Irp, IO_NO_INCREMENT );
        
        return status;
        */
        pMyFilter_DeviceExtension->OriginalIrp   =   Irp;  
        pMyFilter_DeviceExtension->OwnIrp   =   SelfIrp;  
        status  =  
        Irp->IoStatus.Status   =   STATUS_PENDING;  
        Irp->IoStatus.Information   =   0;  
        IoMarkIrpPending(Irp);  
        
        return   STATUS_PENDING;
    }
}
Ctrl2capUnload中根据
    OriginalIrp   =   deviceExtension->OriginalIrp;  
    OwnIrp   =   deviceExtension->OwnIrp;  
    DbgPrint(("===========DriverProcessOriginalIrp=====1====\n"));

    if(OwnIrp   ==   NULL || OriginalIrp == NULL)  
来取消自己的irp,将原来的irp向下传递.
这是我现在的理解,希望知道的说明以下.谢谢.
学习
游客

返回顶部