xinali/articles

IoDeleteSymbolicLink遇到的问题

xinali opened this issue · 0 comments

IoDeleteSymbolicLink遇到的问题

遇到问题

在学习NT driver过程中,遇到了一个比较奇怪的问题,在NTDDKUnload中,删除符号链接,出现蓝屏

DEVICE_EXTENSION结构

typedef struct _DEVICE_EXTENSION {
	PDEVICE_OBJECT pDevice;
	UNICODE_STRING ustrDeviceName;
	UNICODE_STRING ustrSymLinkName;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

创建设备和卸载设备代码,其中CreateDevice属性为INITCODENTDDKUnload属性为PAGEDCODE

#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_seg("INIT")
#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")

#pragma INITCODE
NTSTATUS CreateDevice(
	IN PDRIVER_OBJECT	pDriverObject)
{
	// PAGED_CODE();
	NTSTATUS status;
	PDEVICE_OBJECT pDevObj;
	PDEVICE_EXTENSION pDevExt;

	UNICODE_STRING devName;
	RtlInitUnicodeString(&devName, L"\\Device\\MyDDKDevice");

	status = IoCreateDevice(pDriverObject,
		sizeof(DEVICE_EXTENSION),
		&devName,
		FILE_DEVICE_UNKNOWN,
		0, TRUE,
		&pDevObj);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("CreateDevice Error...\n");
		return status;
	}
	pDevObj->Flags |= DO_BUFFERED_IO;
	pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
	pDevExt->pDevice = pDevObj;
	pDevExt->ustrDeviceName = devName;

	UNICODE_STRING symLinkName;
	RtlInitUnicodeString(&symLinkName, DOS_DEVICE_NAME);
	pDevExt->ustrSymLinkName = symLinkName;
	status = IoCreateSymbolicLink(&symLinkName, &devName);
	if (!NT_SUCCESS(status))
	{
		IoDeleteDevice(pDevObj);
		DbgPrint("Create SymbolicLink Error...\n");
		return status;
	}
	DbgPrint("CreateDevice successfully...\n");

	return STATUS_SUCCESS;
}

#pragma PAGEDCODE
VOID NTDDKUnload(IN PDRIVER_OBJECT pDriverObject)
{
	NTSTATUS status;
	PDEVICE_OBJECT	pNextObj;
	DbgPrint(("Enter DriverUnload\n"));
	pNextObj = pDriverObject->DeviceObject;
	UNICODE_STRING pLinkName;

	while (pNextObj != NULL)
	{
		PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextObj->DeviceExtension;
		DbgPrint("ustrSymLinkName: %wZ\n", pDevExt->ustrSymLinkName);
		pLinkName = pDevExt->ustrSymLinkName;
		DbgPrint("Start delete symlinkname %wZ by pLinkName...\n", pLinkName);
		DbgPrint("Start delete symlinkname %wZ by ustrSymLinkName...\n", pDevExt->ustrSymLinkName);
		status = IoDeleteSymbolicLink(&pLinkName);
		// status = IoDeleteSymbolicLink(&(pDevExt->ustrSymLinkName));
		if (!NT_SUCCESS(status))
		{
			DbgPrint("Delete SymbolLink Error\n");
			goto finish;
		}
		pNextObj = pNextObj->NextDevice;
		IoDeleteDevice(pDevExt->pDevice);
	}

finish:
	DbgPrint("Leave DriverUnload\n");
}

这么写卸载设备的代码会出现蓝屏,具体错误

可以看到在调用IoDeleteSymbolicLink(&pLinkName)出错了。

测试问题

现在设置一个断点,在未发生异常前断下来

继续执行

可以看到edi存放的是DEVICE_OBJECT结构,ebx存放的是DEVICE_EXTENSION结构,现在来看看UNICODE_STRING中的数据

可以发现这块内存中的数据是无法访问的,如果用这里的数据去删除符号链接肯定会出错的。

解决问题

经过不断的查询资料和stackoverflow上提问得知是CreateDevice函数的问题。该函数的内存属性为PAGEDCODE,在调用完之后就会被释放

/* 
 * These compiler directives tell the Operating System how to load the
 * driver into memory. The "INIT" section is discardable as you only
 * need the driver entry upon initialization, then it can be discarded.
 *
 */

所以为了解决这个问题,代码这么设置

#pragma PAGECODE
NTSTATUS CreateDevice(
	IN PDRIVER_OBJECT	pDriverObject)
{
	// PAGED_CODE();
	NTSTATUS status;
	PDEVICE_OBJECT pDevObj;
	PDEVICE_EXTENSION pDevExt;

	UNICODE_STRING devName;
	RtlInitUnicodeString(&devName, L"\\Device\\MyDDKDevice");

	status = IoCreateDevice(pDriverObject,
		sizeof(DEVICE_EXTENSION),
		&devName,
		FILE_DEVICE_UNKNOWN,
		0, TRUE,
		&pDevObj);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("CreateDevice Error...\n");
		return status;
	}
	pDevObj->Flags |= DO_BUFFERED_IO;
	pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
	pDevExt->pDevice = pDevObj;
	pDevExt->ustrDeviceName = devName;

	UNICODE_STRING symLinkName;
	RtlInitUnicodeString(&symLinkName, DOS_DEVICE_NAME);
	pDevExt->ustrSymLinkName = symLinkName;
	status = IoCreateSymbolicLink(&symLinkName, &devName);
	if (!NT_SUCCESS(status))
	{
		IoDeleteDevice(pDevObj);
		DbgPrint("Create SymbolicLink Error...\n");
		return status;
	}
	DbgPrint("CreateDevice successfully...\n");

	return STATUS_SUCCESS;
}

#pragma PAGEDCODE
VOID NTDDKUnload(IN PDRIVER_OBJECT pDriverObject)
{
	NTSTATUS status;
	PDEVICE_OBJECT	pNextObj;
	DbgPrint(("Enter DriverUnload\n"));
	pNextObj = pDriverObject->DeviceObject;
	UNICODE_STRING pLinkName;

	while (pNextObj != NULL)
	{
		PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pNextObj->DeviceExtension;
		pLinkName = pDevExt->ustrSymLinkName;
		DbgPrint("Start delete symlinkname %wZ by pLinkName...\n", &pLinkName);
		DbgPrint("Start delete symlinkname %wZ by ustrSymLinkName...\n", &pDevExt->ustrSymLinkName);
		status = IoDeleteSymbolicLink(&pLinkName);
		// status = IoDeleteSymbolicLink(&(pDevExt->ustrSymLinkName));
		if (!NT_SUCCESS(status))
		{
			DbgPrint("Delete SymbolLink Error\n");
			goto finish;
		}
		pNextObj = pNextObj->NextDevice;
		IoDeleteDevice(pDevExt->pDevice);
	}

finish:
	DbgPrint("Leave DriverUnload\n");
}

全部设置成PAGEDCODE正常执行