关于在驱动当中使用__try __finally的问题

今天调试一个驱动发现了一些平时没有考虑过的问题,在驱动当中使用__try和__finally时,在__try块直接使用return时会出现什么情况!

我用wdk里面的例子做为我的测试代码,通过逆向发现在__try块执行return不会被执行到__finally中,而是马上就返回了。因此在__try块中直接使用return会非常的危险,强烈建议不要这样做!我今天就吃了大苦头。

 

下面是我用来测试的代码,反汇编如下代码可看出一些端倪来:

 

NTSTATUS DriverEntry(__in PDRIVER_OBJECT  DriverObject, __in PUNICODE_STRING RegistryPath)
{

    

    PDEVICE_OBJECT      deviceObject;
    PDEVICE_EXTENSION   deviceExtension;
    UNICODE_STRING      ntDeviceName;
    UNICODE_STRING      symbolicLinkName;
    NTSTATUS            status;

    UNREFERENCED_PARAMETER(RegistryPath);

    DebugPrint(("==>DriverEntry\n"));
    
    __try
    {

        //
        // Create the device object
        //
        RtlInitUnicodeString(&ntDeviceName, NTDEVICE_NAME_STRING);

        status = IoCreateDevice(DriverObject,               // DriverObject
                                sizeof(DEVICE_EXTENSION), // DeviceExtensionSize
                                &ntDeviceName,              // DeviceName
                                FILE_DEVICE_UNKNOWN,        // DeviceType
                                FILE_DEVICE_SECURE_OPEN,    // DeviceCharacteristics
                                FALSE,                      // Not Exclusive
                                &deviceObject               // DeviceObject
                               );
        if (!NT_SUCCESS(status))
        {
            DebugPrint(("\IoCreateDevice returned 0x%x\n", status));
            return status;
        }
        else
        {
            //
            // Set up dispatch entry points for the driver.
            //
            DriverObject->MajorFunction[IRP_MJ_CREATE]          = EventCreateClose;
            DriverObject->MajorFunction[IRP_MJ_CLOSE]           = EventCreateClose;
            DriverObject->MajorFunction[IRP_MJ_CLEANUP]         = EventCleanup;
            DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = EventDispatchIoControl;
            DriverObject->DriverUnload                          = EventUnload;

            //
            // Create a symbolic link for userapp to interact with the driver.
            //
            RtlInitUnicodeString(&symbolicLinkName, SYMBOLIC_NAME_STRING);
            status = IoCreateSymbolicLink(&symbolicLinkName, &ntDeviceName);

            //
            // Initialize the device extension.
            //
            deviceExtension = deviceObject->DeviceExtension;

            InitializeListHead(&deviceExtension->EventQueueHead);

            KeInitializeSpinLock(&deviceExtension->QueueLock);

            deviceExtension->Self = deviceObject;

            //
            // Establish user-buffer access method.
            //
            deviceObject->Flags |= DO_BUFFERED_IO;

            DebugPrint(("<==DriverEntry\n"));

            ASSERT(NT_SUCCESS(status));        
        }
    }
    __finally
    {
        if (!NT_SUCCESS(status))
        {
            IoDeleteDevice(deviceObject);
            DebugPrint(("\tIoCreateSymbolicLink returned 0x%x\n", status));
        }
    }

    return status;
}

 

上面的函数当中__try块中会直接返回,我们用IDA看一下汇编代码是什么样子。

我把它分成checked和free两个版本来看一下

 

先看Checked版本的汇编:

 

c_1

……………

c_2

从上面可以看出这儿直接就返回了,并没有执行到__finally当中的代码,return的代码被先执行到了!

 

 

再看看free版本的汇编是什么样子:

f_1

上图中当IoCreateDevice失败之后就直接返回了,并没有执行到__finally当中

f_2

 

而真正的__finally块则是被放在最后执行了一下,__try块中间有任何返回都不会执行到__finally当中。

 

 

因此,在__try中直接返回,不管是checked还是free版本,都不会执行到__finally块中的代码,这样使用会非常危险。我的结论是最好不要在驱动当中使用异常处理。今天写下来做一个备忘!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2011-06-13 22:36  Russinovich`s Blog  阅读(2000)  评论(4编辑  收藏  举报