今天调试一个驱动发现了一些平时没有考虑过的问题,在驱动当中使用__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块中的代码,这样使用会非常危险。我的结论是最好不要在驱动当中使用异常处理。今天写下来做一个备忘!