5

我有一个在本地系统帐户下运行的 Windows 服务,它使用 DefineDosDevice 函数创建 DOS 设备。该服务在 W2K8 远程桌面服务器上运行。如果设备是使用服务的凭据创建的,则它们是在 GLOBAL 设备命名空间中创建的,因此对所有用户可见。我需要仅对特定交互会话可见的设备。

我通过模拟我希望驱动器出现在其会话中的用户来实现这一点。这相当简单,只要会话 id 可用。这是我为说明问题而编写的一个简单的测试应用程序:

int _tmain(int argc, _TCHAR* argv[])
{
BOOL result = TRUE;

if(argc > 3 && !wcscmp(argv[2], L"/i"))
{
    HANDLE hToken = 0;
    DWORD dwSessionId = _wtoi(argv[3]);
    result = WTSQueryUserToken(dwSessionId, &hToken);
    if(result) result = ImpersonateLoggedOnUser(hToken);
}
if(result)
{
    LPTSTR drive = argv[1];
    DefineDosDevice(DDD_REMOVE_DEFINITION, drive, NULL);
    result = DefineDosDevice(0, drive, L"C:\\test");
}

if(!result)
{
    printf("Error: %d\n", GetLastError());
}
return 0;
}

为了测试这段代码,我创建了一个在 LocalSystem 帐户下启动命令 shell 的服务:

sc create test_svc binpath=“cmd /K start”类型=自己的类型=交互

此服务无法启动,但在它失败之前,它会生成一个在 LocalSystem 帐户下运行的命令 shell。

从 LocalSystem cmd.exe,我运行:

MySubst.exe x: /i 2

它调用 ImpersonateLoggedOnUser(),然后调用 DefineDosDevice()

从用户会话中运行的 cmd.exe,我运行:

MySubst.exe y:

在不调用 ImpersonateLoggedOnUser() 的情况下调用DefineDosDevice 。

这行得通。从 cmd.exe 我可以访问两个驱动器 X: 和 Y:。我可以从开始菜单启动 notepad.exe,然后查看 X: 和 Y: 驱动器。此外,如果我与其他用户创建新的终端服务会话,我看不到 X: 或 Y:。

但是,资源管理器仅在“所有计算机”下显示 Y:驱动器。Y:是通过在目标会话中运行的 cmd.exe 运行我的测试应用程序创建的驱动器,即未完成模拟。如果我从任务管理器重新启动 explorer.exe,X: 和 Y: 驱动器都会出现。

我还使用 SysInternals 的 WinObj.exe 来检查定义的 Win NT 设备。我看到的是:

- Sessions
    - 0
        - DosDevices
            00000000-000057607

(57607 是与我正在模拟的会话关联的登录会话的 ID)

“00000000-000057607”的内容为:

Global    SymbolicLink    \Global??
X:        SymbolicLink    \\??\C:\test
Y:        SymbolicLink    \\??\C:\test

根据 WinObj,这两个 dos 设备是相同的。它们属于同一个会话和登录会话。它们是指向同一个 NT 对象的符号链接。

怎么可能其中一个出现在资源管理器中而另一个没有。

4

1 回答 1

4

@arx 和 @HarryJohnston 很赚钱。如果我从与资源管理器相同的会话中的线程广播 WM_DEVICECHANGE 消息,则新驱动器将出现在我的电脑中。这是代码:

DWORD recipients = BSM_ALLDESKTOPS | BSM_APPLICATIONS;

DEV_BROADCAST_VOLUME msg;
ZeroMemory(&msg, sizeof(msg));
msg.dbcv_size = sizeof(msg);
msg.dbcv_devicetype = DBT_DEVTYP_VOLUME;
msg.dbcv_unitmask = 1 << ('X' - 'A');

long success = BroadcastSystemMessage(0, &recipients, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, (LPARAM)&msg);
于 2013-02-14T17:53:44.890 回答