我正在尝试替换一些遗留的DefineDosDevice
用户空间代码(由于提升的会话和正常会话由不同的DosDevice存储表示,因此在Vista和Administrator用户上不起作用,因此会产生一种相当奇怪的情况,即如果从未提升的进程创建,则驱动器可见,但如果从提升的进程中创建,则不可见)。
正如我通过检查Truecrypt源和这个WDM示例发现的那样,替代它的方法是向mountmgr.sys和IOCTL_MOUNTMGR_CREATE_POINT
/IOCTL_MOUNTMGR_DELETE_POINT
发出IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION
消息。
这就是我正在做的——我的代码看起来像这样:
首先,各种当地人:
NTSTATUS ntStatus;
PDEVICE_EXTENSION device_extension;
UNICODE_STRING uVolumeName;
ULONG mntNameLen = 0;
ULONG mntPointLen = 0;
PMOUNTMGR_TARGET_NAME mntName = NULL;
PMOUNTMGR_CREATE_POINT_INPUT mntPoint = NULL;
然后,我构建并提出两个请求。第一个失败,出现上述状态代码。第二个失败,状态代码不同(但如果第一个失败,则不起作用)。
mntNameLen = sizeof(MOUNTMGR_TARGET_NAME) + device_extension->sDevName.Length;
mntName = ExAllocatePool(PagedPool, mntNameLen);
mntName->DeviceNameLength = device_extension->sDevName.Length;
RtlCopyMemory(mntName->DeviceName, device_extension->sDevName.Buffer,
mntName->DeviceNameLength);
ntStatus = MakeDeviceIoRequest (MOUNTMGR_DEVICE_NAME,
IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
mntName, mntNameLen, 0, 0);
mntPointLen = sizeof(PMOUNTMGR_CREATE_POINT_INPUT) +
device_extension->sDevName.Length + uVolumeName.Length;
mntPoint = ExAllocatePool(PagedPool, mntPointLen);
mntPoint->SymbolicLinkNameOffset = sizeof (MOUNTMGR_CREATE_POINT_INPUT);
RtlCopyMemory(&mntPoint+mntPoint->SymbolicLinkNameOffset,
uVolumeName.Buffer, uVolumeName.Length * sizeof(WCHAR));
mntPoint->SymbolicLinkNameLength = uVolumeName.Length;
mntPoint->DeviceNameOffset = mntPoint->SymbolicLinkNameOffset +
mntPoint->SymbolicLinkNameLength;
RtlCopyMemory(&mntPoint+mntPoint->DeviceNameOffset,
device_extension->sDevName.Buffer, device_extension->sDevName.Length);
mntPoint->DeviceNameLength = device_extension->sDevName.Length;
ntStatus = MakeDeviceIoRequest(MOUNTMGR_DEVICE_NAME,
IOCTL_MOUNTMGR_CREATE_POINT, mntPoint,
mntPointLen, 0, 0);
然后我创建符号链接\GLOBAL??\L: ->\Device\DeviceName
ntStatus = IoCreateSymbolicLink(&uVolumeName, &(device_extension->sDevName));
DbgPrint("Mapped %wZ -> %wZn", &uVolumeName, &(device_extension->sDevName));
RtlFreeUnicodeString(&uVolumeName);
if ( mntName != NULL )
{
ExFreePool(mntName);
}
if ( mntPoint != NULL)
{
ExFreePool(mntPoint);
}
但是,来自装载管理器的ntStatus
响应是0xC0000010
STATUS_INVALID_DEVICE_REQUEST
;我的设备字符串的形式为DeviceDevName
,并响应以下各项:
- IOCTL_VOLUME_ONLINE
- IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME
- IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
- IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
以及期望用于存储设备的其他IOCTL的列表。然而,我在所有这些例程上都设置了断点,但没有一个可以到达。
我的设备是通过这个小片段创建的:
// Security descriptor
RtlInitUnicodeString(&sddl,
_T("D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;BU)(A;;GA;;;WD)"));
// named device
status = IoCreateDeviceSecure(
DriverObject,
sizeof(DEVICE_EXTENSION),
&device_name, // DeviceDeviceName
DeviceType, // valid devicetype.
0,
FALSE,
&sddl, // security descriptor
NULL, // no idea what this does.
&device_object // output device object.
);
那么,归结到一些问题:
- 我是否正确地为装载管理器创建了消息?MakeDeviceIoRequest调用基本上封装了
IoCallDriver
,我有理由相信这不是问题所在 - 我用
CreateDevice
做什么有问题吗?我之所以这么问,是因为我读了这篇博客文章,其中暗示了一些关于设备名称、FDO和PDO的内容,我真的不太理解 - 如果我看起来太深入了,有没有机会澄清我对这一切是如何运作的理解
注意:我有一些限制。我在上面构建的代码是相当遗留的,所以我包含了ntddk.h and wdmsec.h
;现阶段我无法将这些更改为wdm.h
或ntifs.h
。
在深入研究之前,您是否有机会将对DefineDosDevice的呼叫转移到服务中?从服务调用它会将链接放在全局目录中,这将完全消除您的别名问题。
如果您不能做到这一点,我的第一个猜测是您没有处理其他所需的装载管理器IOCTL。我知道您在所有特定IOCTL上都有断点,但您的默认处理程序中有断点吗?通常这就是STATUS_INVALID_DEVICE_REQUEST的来源。