关于在驱动当中使用__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版本的汇编:
……………
从上面可以看出这儿直接就返回了,并没有执行到__finally当中的代码,return的代码被先执行到了!
再看看free版本的汇编是什么样子:
上图中当IoCreateDevice失败之后就直接返回了,并没有执行到__finally当中
而真正的__finally块则是被放在最后执行了一下,__try块中间有任何返回都不会执行到__finally当中。
因此,在__try中直接返回,不管是checked还是free版本,都不会执行到__finally块中的代码,这样使用会非常危险。我的结论是最好不要在驱动当中使用异常处理。今天写下来做一个备忘!