天天看点

关于《竹林蹊径 深入浅出Windows驱动开发》第一个例子在Win7下蓝屏

在尝试运行《竹林蹊径 深入浅出Windows驱动开发》的第一个例子-HelloDRIVER时,在XP下没有问题,但在Win7下却发生蓝屏,蓝屏发生点在于卸载函数DriverUnload。

先看看卸载驱动的代码

VOID DriverUnload (
    __in PDRIVER_OBJECT DriverObject
    )
{
    PDEVICE_OBJECT deviceObject;
    UNICODE_STRING linkName;
    KdPrint(("Enter HelloDRIVER DriverUnload!\n"));
    
    deviceObject = DriverObject->DeviceObject;
    
    while(NULL != deviceObject)
    {
        PDEVICE_EXTENSION deviceExtesion = 
                   (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
        
        // 删除符号链接与设备
        linkName = deviceExtesion->SymbolicLink;
        IoDeleteSymbolicLink(&linkName);
	deviceObject = deviceObject->NextDevice;
        IoDeleteDevice(deviceExtesion->DeviceObject);
    }
  
    KdPrint(("End of HelloDRIVER DriverUnload!\n"));
}
           

很通用的卸载驱动例程,按道理是不会出现问题的,从dump文件进行进一步分析,定位到deviceObject = deviceObject->NextDevice;这一句蓝屏,复制操作会导致蓝屏?什么鬼,再看下调用堆栈

关于《竹林蹊径 深入浅出Windows驱动开发》第一个例子在Win7下蓝屏

原来还没到赋值语句,在处于IoDeleteSymbolicLink阶段就发生蓝屏了,于是就断点调试看下IoDeleteSymbolicLink的参数linkName是否正常,一调试发现memory can't access, 为什么会出现内存不可访问,于是追溯到DriverEntry,下面看下这个函数里面做了什么操作

NTSTATUS DriverEntry (
    __in PDRIVER_OBJECT DriverObject,
    __in PUNICODE_STRING RegistryPath
    )
{
    NTSTATUS status;
    PDEVICE_OBJECT deviceObject;
    PDEVICE_EXTENSION deviceExtension;
    UNICODE_STRING symbolicLink;
    UNICODE_STRING deviceName;
    ULONG i;
    KdPrint(("Enter HelloDRIVER DriverEntry!\n"));
    
    UNREFERENCED_PARAMETER(RegistryPath); 
    
    RtlInitUnicodeString(&deviceName, L"\\Device\\HelloDRIVER");

    // 处理派遣例程 
    for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
    {
        DriverObject->MajorFunction[i] = DefaultDispatch; 
    }
    
    DriverObject->DriverUnload = DriverUnload;
    DriverObject->MajorFunction[IRP_MJ_CREATE] = DefaultDispatch; 
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = DefaultDispatch; 
    DriverObject->MajorFunction[IRP_MJ_READ] = DefaultDispatch; 
    DriverObject->MajorFunction[IRP_MJ_WRITE] = DefaultDispatch; 
    
    // 创建设备 
    status = IoCreateDevice( DriverObject,
                             sizeof(DEVICE_EXTENSION),
                             &deviceName,
                             FILE_DEVICE_UNKNOWN,
                             0,
                             TRUE,
                             &deviceObject);
    if(!NT_SUCCESS(status))
    {
        return status;
    }
    
    deviceObject->Flags = DO_BUFFERED_IO;
    deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
    deviceExtension->DeviceObject = deviceObject;
    deviceExtension->DeviceName = deviceName;
    
    RtlInitUnicodeString(&symbolicLink, L"\\??\\HelloDRIVER");
    deviceExtension->SymbolicLink = symbolicLink;
    
    // 创建符号链接 
    status = IoCreateSymbolicLink(&symbolicLink, &deviceName);
    
    if(!NT_SUCCESS(status))
    {
        IoDeleteDevice(deviceObject);
        return status;
    }
    
    KdPrint(("End of HelloDRIVER DriverEntry!\n")); 
    return status;
}
           

重点在于这两句

    RtlInitUnicodeString(&symbolicLink, L"\\??\\HelloDRIVER");

    deviceExtension->SymbolicLink = symbolicLink;

在网上查找资料RtlInitUnicodeString并没有动态分配内存,而是指向应用,而由于

#pragma alloc_text(INIT, DriverEntry)

DriverEntry函数是运行完后就退出内存,所以 RtlInitUnicodeString(&deviceName, L"\\Device\\HelloDRIVER");这个赋值方式不可靠。

解决方案:

在头文件或者函数外声明一个全局变量来存储符号链接,如

WCHAR  linkNameBuffer[] =  L"\\??\\HelloDRIVER";

然后再在函数内

RtlInitUnicodeString(&symbolicLink, linkNameBuffer);

即可解决读取符号链接不可访问的问题。

总结:

1.Win7会出现蓝屏,而XP不会,可能涉及到IoDeleteSymbolicLink里面的实现,会判断字符串的合法性问题

2.INIT和PAGE的区别,在驱动加载入口函数要注意字符串变量的生命周期

3.学会利用windbg进行调试分析

继续阅读