c-如何与NT装载管理器接口以分配驱动器号



我正在尝试替换一些遗留的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.
);

那么,归结到一些问题:

  1. 我是否正确地为装载管理器创建了消息?MakeDeviceIoRequest调用基本上封装了IoCallDriver,我有理由相信这不是问题所在
  2. 我用CreateDevice做什么有问题吗?我之所以这么问,是因为我读了这篇博客文章,其中暗示了一些关于设备名称、FDO和PDO的内容,我真的不太理解
  3. 如果我看起来太深入了,有没有机会澄清我对这一切是如何运作的理解

注意:我有一些限制。我在上面构建的代码是相当遗留的,所以我包含了ntddk.h and wdmsec.h;现阶段我无法将这些更改为wdm.hntifs.h

在深入研究之前,您是否有机会将对DefineDosDevice的呼叫转移到服务中?从服务调用它会将链接放在全局目录中,这将完全消除您的别名问题。

如果您不能做到这一点,我的第一个猜测是您没有处理其他所需的装载管理器IOCTL。我知道您在所有特定IOCTL上都有断点,但您的默认处理程序中有断点吗?通常这就是STATUS_INVALID_DEVICE_REQUEST的来源。

最新更新