You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从SYSTEM权限进程可靠获取登录用户名/SID?适配Win10/11全版本

SYSTEM权限应用以当前登录用户启动程序的可靠方案及API兼容性说明

核心结论

WTSQuerySessionInformationW 在Win10/11所有版本(包括家庭版)中均可正常工作,无需依赖远程桌面服务运行。微软文档的描述侧重远程桌面会话主机(RD Session Host)场景,但该API完全支持本地交互式会话的信息查询,家庭版只是不支持作为RD会话主机提供远程服务,本地会话的WTS相关API调用不受限制。

具体实现步骤

  • 获取活跃交互式会话ID
    使用WTSGetActiveConsoleSessionId()获取当前用户登录的控制台会话ID,该API全Windows版本通用,且不受远程桌面服务状态影响:

    DWORD sessionId = WTSGetActiveConsoleSessionId();
    
  • 查询会话用户信息
    传入获取到的会话ID,调用WTSQuerySessionInformationW获取用户名和域名:

    LPWSTR pUserName = nullptr;
    DWORD dwUserNameLen = 0;
    LPWSTR pDomainName = nullptr;
    DWORD dwDomainNameLen = 0;
    
    if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, &pUserName, &dwUserNameLen) &&
        WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSDomainName, &pDomainName, &dwDomainNameLen))
    {
        // 后续处理用户名与域名
    }
    
    // 释放API分配的内存
    if (pUserName) WTSFreeMemory(pUserName);
    if (pDomainName) WTSFreeMemory(pDomainName);
    
  • 转换用户名到SID
    通过LookupAccountNameW结合域名和用户名获取用户SID:

    PSID pSid = nullptr;
    DWORD dwSidSize = 0;
    LPWSTR pReferencedDomainName = nullptr;
    DWORD dwReferencedDomainNameSize = 0;
    SID_NAME_USE sidType;
    
    // 先获取所需内存大小
    LookupAccountNameW(nullptr, pUserName, nullptr, &dwSidSize, nullptr, &dwReferencedDomainNameSize, &sidType);
    pSid = (PSID)LocalAlloc(LPTR, dwSidSize);
    pReferencedDomainName = (LPWSTR)LocalAlloc(LPTR, dwReferencedDomainNameSize * sizeof(WCHAR));
    
    if (LookupAccountNameW(nullptr, pUserName, pSid, &dwSidSize, pReferencedDomainName, &dwReferencedDomainNameSize, &sidType))
    {
        // SID获取成功,可用于后续令牌操作
    }
    
    // 释放分配的资源
    if (pSid) LocalFree(pSid);
    if (pReferencedDomainName) LocalFree(pReferencedDomainName);
    
  • 创建用户令牌并启动目标程序
    通过WTSQueryUserToken获取用户主令牌,复制后用CreateProcessAsUserW启动浏览器或邮件客户端,需指定用户桌面确保可见:

    HANDLE hUserToken = nullptr;
    if (WTSQueryUserToken(sessionId, &hUserToken))
    {
        HANDLE hDuplicateToken = nullptr;
        if (DuplicateTokenEx(hUserToken, MAXIMUM_ALLOWED, nullptr, SecurityIdentification, TokenPrimary, &hDuplicateToken))
        {
            STARTUPINFOW si = { sizeof(si) };
            PROCESS_INFORMATION pi = { 0 };
            si.lpDesktop = L"WinSta0\\Default"; // 指定用户可见桌面
    
            // 示例:启动Edge浏览器
            if (CreateProcessAsUserW(hDuplicateToken, L"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe", nullptr, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi))
            {
                CloseHandle(pi.hThread);
                CloseHandle(pi.hProcess);
            }
    
            CloseHandle(hDuplicateToken);
        }
    
        CloseHandle(hUserToken);
    }
    

关键注意事项

  • 会话ID准确性:优先使用WTSGetActiveConsoleSessionId()而非WTS_CURRENT_SESSION,SYSTEM权限下WTS_CURRENT_SESSION可能指向Session 0系统会话,无法获取登录用户信息。
  • 桌面指定:启动进程时必须指定WinSta0\\Default桌面,否则进程会在Session 0的不可见后台运行,用户无法交互。
  • 资源释放:所有通过WTS或LocalAlloc分配的资源必须手动释放,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Scott Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 08:55:20