1. 程式人生 > >關於《竹林蹊徑 深入淺出Windows驅動開發》第一個例子在Win7下藍屏

關於《竹林蹊徑 深入淺出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;這一句藍屏,複製操作會導致藍屏?什麼鬼,再看下呼叫堆疊 原來還沒到賦值語句,在處於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進行除錯分析