以提升的权限运行时如何正确检测网络驱动器

Posted

技术标签:

【中文标题】以提升的权限运行时如何正确检测网络驱动器【英文标题】:How to correctly detect Network drive when running with elevated privileges 【发布时间】:2017-03-13 15:36:31 【问题描述】:

我正在开发一个需要正确检测 Windows 上所有使用过的驱动器号的应用程序。我为此使用了GetLogicalDrives() 函数。此功能工作得很好,除非用户以提升的权限启动我的应用程序(即,使用属于“管理员”组的帐户登录的用户并通过选择“以管理员身份运行”选项启动我的应用程序)。在这种情况下,GetLogicalDrives() 无法检测到机器上映射的网络驱动器。

问题的根本原因似乎是在这种情况下 Windows 并行运行 2 个用户会话。我的应用程序在“提升权限”会话中运行,而驱动器在“非提升”会话中映射:

https://support.microsoft.com/en-us/help/3035277/mapped-drives-are-not-available-from-an-elevated-prompt-when-uac-is-configured-to-prompt-for-credentials-in-windows

是否有针对此问题的任何程序化解决方法?我试图在“非提升”会话中重新启动我的应用程序,但不知道如何(或者是否可能)。我已经尝试过使用受限令牌重新启动我的应用程序(使用CreateRestrictedTokenDISABLE_MAX_PRIVILEGE 选项),希望Windows 会以某种方式发现它现在可以在“非提升”会话中重新启动我的应用程序,但确实如此不工作。

【问题讨论】:

您能解释一下为什么需要知道映射的驱动器号吗? 我需要映射一个新的驱动器号,并作为其中的一部分,试图找出已经映射的驱动器号。在我描述的上述场景中,我的应用程序未能检测到已映射的驱动器号(例如,“D”),并且实际上成功地将新驱动器映射到它(“D”)。问题是它不会出现在 Explorer 中,我想它会在未提升权限的用户会话中运行。 您希望您的程序(正在运行提升)映射驱动器,以便它显示在非提升进程中?充其量是很难的(我当然不知道怎么做)。在注册表中设置EnabledLinkedConnections(根据您发布的链接)是一个选项吗?它会一次解决你所有的问题。 你可能想看看这个问题***.com/questions/42762595/… for relaunch my application in the "non-elevated" session - 需要在驱动器映射的特定登录会话中重新启动。 CreateRestrictedToken 这里没有帮助,因为它没有更改令牌中的登录会话。需要从此登录会话中打开一些令牌并在调用CreateProcessAsUserW 中使用它 【参考方案1】:

为此,您可以使用链接令牌临时模拟 - 所以获取自己的链接令牌,如果它存在,将其设置为线程,调用 GetLogicalDrives() 并返回处理令牌(链接令牌有 SECURITY_IMPERSONATION_LEVEL == @ 987654324@ 因此它可以使用非常有限

#define BOOL_TO_ERR(b) ((b) ? NOERROR : GetLastError())

ULONG GetLogicalDrivesEx(PULONG pDrives)

    HANDLE hToken;

    ULONG err = BOOL_TO_ERR(OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken));

    if (err != NOERROR)
    
        return err;
    

    union 
        TOKEN_ELEVATION_TYPE tet;
        TOKEN_LINKED_TOKEN tlt;
    ;

    ULONG rcb;

    err = BOOL_TO_ERR(GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &rcb));

    if (err == NOERROR)
    
        if (tet == TokenElevationTypeFull)
        
            err = BOOL_TO_ERR(GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb));

            if (err == NOERROR)
            
                if (NOERROR == (err = BOOL_TO_ERR(SetThreadToken(0, tlt.LinkedToken))))
                
                    err = (rcb = GetLogicalDrives()) ? NOERROR : GetLastError();
                    SetThreadToken(0, 0);
                

                CloseHandle(tlt.LinkedToken);
            
        
        else
        
            err = (rcb = GetLogicalDrives()) ? NOERROR : GetLastError();
        
    

    *pDrives = rcb;
    return err;


void test()

    ULONG Drives, Drives0 = GetLogicalDrives();
    GetLogicalDrivesEx(&Drives);
    WCHAR sz[32];
    swprintf(sz, L"%08x %08x", Drives0, Drives);
    MessageBoxW(0, sz, L"", MB_OK);


如果没有错误(GetLogicalDrivesEx 返回 NOERRORDrives 是未提升会话的逻辑驱动器,当 Drives0 - 用于提升(如果您当然以提升身份运行)

【讨论】:

非常感谢,RbMm。

以上是关于以提升的权限运行时如何正确检测网络驱动器的主要内容,如果未能解决你的问题,请参考以下文章

关于映射网络驱动器时,用户名和密码输入错误的问题。

批处理:从映射的网络驱动器以管理员身份运行

无法在以管理员身份运行的 PowerShell 中访问网络驱动器

win10电脑显示未检测到正确的网络适配器,不可以联网

如何使用 PHP 和 IIS 7 访问映射网络驱动器中的文件

映射网络驱动器是啥