【问题标题】:Run process from other user从其他用户运行进程
【发布时间】:2015-02-23 11:02:53
【问题描述】:

我正在尝试从以本地管理员帐户运行的 Windows 服务执行进程。这台机器是 Windows 7,它使用Remote Desktop/Terminal Service APIs

WTSQueryUserToken 上的代码失败,错误代码 = 5。

首先我尝试从当前线程获取令牌,然后调用SetPrivilege 来启用SE_DEBUG_NAMESE_TCB_NAME 权限。然后调用WTSQueryUserToken,但得到错误5。

只是为了澄清: 当服务在本地系统(localSystem)下时,即使不需要调用SetPrivilege,这段代码也能完美运行。现在的问题是我需要将服务移动到本地管理员用户下运行!!!

知道我错过了什么吗?


代码:

BOOL  T_Ex_RunProgram (DWORD sessionId, LPCWSTR targetPath)
{
#ifdef DEBUG
    if(g_pLog)
    {
         g_pLog->Format ("T_Ex_RunProgram: sessionId = %d, targetPath = \"%S\"\n", sessionId, targetPath);
    }
#endif
    HANDLE htoken;

    if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &htoken))
    {
        if (GetLastError() == ERROR_NO_TOKEN)
        {
            if (!ImpersonateSelf(SecurityImpersonation))
            {
                 DWORD dwErr = GetLastError();
#ifdef DEBUG
                    if(g_pLog)
                    {
                        g_pLog->Format ("ImpersonateSelf::RunProgram: dwErr = %d\n", dwErr);
                    }
#endif
                SetLastError(dwErr);
                return FALSE;
            }

            if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &htoken))
            {
                 DWORD dwErr = GetLastError();
#ifdef DEBUG
                    if(g_pLog)
                    {
                        g_pLog->Format ("OpenThreadToken::RunProgram: dwErr = %d\n", dwErr);
                    }
#endif
                SetLastError(dwErr);
                return FALSE;
            }
        }
        else{
                 DWORD dwErr = GetLastError();
#ifdef DEBUG
                    if(g_pLog)
                    {
                        g_pLog->Format ("OpenThreadToken::RunProgram: GetLastError return unexpected dwErr = %d\n", dwErr);
                    }
#endif
                SetLastError(dwErr);
                return FALSE;
            }
     }
#ifdef DEBUG
    if(g_pLog)
    {
        g_pLog->Format ("Before SetPrivilege(SE_DEBUG_NAME)::RunProgram\n");
    }
#endif
    // enable SeDebugPrivilege
    if(!SetPrivilege(htoken, SE_DEBUG_NAME, TRUE))
    {
        // close token handle
        CloseHandle(htoken);

        DWORD dwErr = GetLastError();
#ifdef DEBUG
        if(g_pLog)
        {
            g_pLog->Format ("SetPrivilege::RunProgram((SE_DEBUG_NAME): dwErr = %d\n", dwErr);
        }
#endif
        SetLastError(dwErr);
        return FALSE;
    }

#ifdef DEBUG
    if(g_pLog)
    {
        g_pLog->Format ("Before SetPrivilege(SE_TCB_NAME)::RunProgram\n");
    }
#endif
    // enable SeDebugPrivilege
    if(!SetPrivilege(htoken, SE_TCB_NAME, TRUE))
    {
        // close token handle
        CloseHandle(htoken);

        DWORD dwErr = GetLastError();
#ifdef DEBUG
        if(g_pLog)
        {
            g_pLog->Format ("SetPrivilege(SE_TCB_NAME)::RunProgram: dwErr = %d\n", dwErr);
        }
#endif
        SetLastError(dwErr);
        return FALSE;
    }

    BOOL b = WTSQueryUserToken (sessionId, &htoken);
    if (!b)
    {
        DWORD dwErr = GetLastError();
#ifdef DEBUG
    if(g_pLog)
    {
        g_pLog->Format ("T_Ex_RunProgram: WTSQueryUserToken failed. dwErr = %d\n", dwErr);
    }
#endif
        SetLastError(dwErr);
        return FALSE;
    }


    LPWSTR userName, userName1;
    DWORD userNameLength;
    b = WTSQuerySessionInformationW (WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, &userName, &userNameLength);
    if (b)
    {
        userName1 = _wcsdup (userName);
        WTSFreeMemory (userName);
    }
    else
    {
        DWORD dwErr = GetLastError();
    #ifdef DEBUG
        if(g_pLog)
        {
            g_pLog->Format ("T_Ex_RunProgram: WTSQuerySessionInformation failed: dwErr = %d\n", dwErr);
        }
    #endif
        SetLastError(dwErr);
        return FALSE;
    }
    b = RunProgramWithToken (htoken, userName1, targetPath,sessionId);
    DWORD dwreturnErr = GetLastError();


#ifdef DEBUG
    if(g_pLog)
    {
        g_pLog->Format ("Before SetPrivilege(SE_DEBUG_NAME,FALSE)::RunProgram\n");
    }
#endif
    // enable SeDebugPrivilege
    if(!SetPrivilege(htoken, SE_DEBUG_NAME, FALSE))
    {
        // close token handle
        CloseHandle(htoken);

        DWORD dwErr = GetLastError();
#ifdef DEBUG
        if(g_pLog)
        {
            g_pLog->Format ("SetPrivilege::RunProgram((SE_DEBUG_NAME,FALSE): dwErr = %d\n", dwErr);
        }
#endif
        SetLastError(dwErr);
    }

#ifdef DEBUG
    if(g_pLog)
    {
        g_pLog->Format ("Before SetPrivilege(SE_TCB_NAME,FALSE)::RunProgram\n");
    }
#endif
    // enable SeDebugPrivilege
    if(!SetPrivilege(htoken, SE_TCB_NAME, FALSE))
    {
        // close token handle
        CloseHandle(htoken);

        DWORD dwErr = GetLastError();
#ifdef DEBUG
        if(g_pLog)
        {
            g_pLog->Format ("SetPrivilege(SE_TCB_NAME,FALSE)::RunProgram: dwErr = %d\n", dwErr);
        }
#endif
        SetLastError(dwErr);
    }

    free (userName1);
    CloseHandle (htoken);
    if (!b)
        SetLastError (dwreturnErr);
    return b;
}
 BOOL SetPrivilege( HANDLE hToken,          // access token handle
    LPCTSTR lpszPrivilege,  // name of privilege to enable/disable
    BOOL bEnablePrivilege   // to enable or disable privilege
    ) 
{
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if ( !LookupPrivilegeValue( 
            NULL,            // lookup privilege on local system
            lpszPrivilege,   // privilege to lookup 
            &luid ) )        // receives LUID of privilege
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError() ); 
        return FALSE; 
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.

    if ( !AdjustTokenPrivileges(
           hToken, 
           FALSE, 
           &tp, 
           sizeof(TOKEN_PRIVILEGES), 
           (PTOKEN_PRIVILEGES) NULL, 
           (PDWORD) NULL) )
    { 
          printf("AdjustTokenPrivileges error: %u\n", GetLastError() ); 
          return FALSE; 
    } 

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)

    {
          printf("The token does not have the specified privilege. \n");
          return FALSE;
    } 

    return TRUE;
}

【问题讨论】:

  • 通常,您只需要SE_DEBUG_NAMESE_TCB_NAME 之一。但您可能需要启用SE_ASSIGNPRIMARYTOKEN_NAME。那是让您替换主要进程令牌的那个,它是“用进程做任何你想做的事”这三位一体中的第三个。请参阅 MSDN 上的 Privilege Constants
  • 目标用户帐户可能需要一些登录权限。事件日志 (eventvwr) 应该为您提供更多信息和更多详细信息。另外,对于初学者,请参阅知识库文章How to set logon user rights by using the NTRights utility。它应该让您能够找到更多信息。
  • 另外,您使用的 Windows 版本是什么。这是服务器 2008 吗?终端服务在 XP 和 2003(以及可能的其他版本)中的行为略有不同,它可能有助于其他人为您提供帮助。
  • 您说的是“本地管理员帐户”。该帐户是否已启用(我认为默认情况下已禁用)。您可以根据 MSDN 博客尝试使用 LocalSystem 来尝试隔离问题吗?还有another blog 声明它需要SE_TCB_NAME。这对我来说似乎有点沉重,但在您可以测试减少权限之前使用它。
  • @Joseph: WTSQueryUserToken() 仅适用于 LocalSystem 帐户。 documentation 也这么说:“要成功调用此函数,调用应用程序必须在 LocalSystem 帐户的上下文中运行,并具有 SE_TCB_NAME 权限。”另一种获取会话用户令牌的方法是从会话中运行的进程中提取令牌,例如explorer.exe

标签: c winapi windows-7 terminal-services


【解决方案1】:

WTSQueryUserToken 上的代码失败,错误代码 = 5...知道我遗漏了什么吗?

我认为这篇 MSDN 文章可能对您有用:Launching an interactive process from Windows Service in Windows Vista and later。根据文章,您在使用WTSQueryUserToken时应该调用以下代码:

WTSQueryUserToken (WTSGetActiveConsoleSessionId (), &hToken);

然后使用在对CreateProcessAsUser 的调用中检索到的令牌。


在您使用TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY 拨打OpenThreadToken 时,您可能暂时将其增加到TOKEN_ALL_ACCESS 之类的值,直到您消除皱纹(如果您仍然需要拨打电话) )。请参阅 MSDN 上的 Access Rights for Access-Token Objects

【讨论】:

  • 我已经试过了,现在又试了,使用 WTSGetActiveConsoleSessionId() 和 TOKEN_ALL_ACCESS,还是 WTSQueryUserToken 返回错误 5!
  • 您可以使用任何用户登录的会话,它不必是“活动”会话(连接到物理键盘/鼠标/显示器的会话)。例如,当本地没有用户登录时,“活动”会话可能会显示WinLogon 桌面。但是您可以获取远程登录用户的用户令牌。
  • WTSGetActiveConsoleSessionId() 获取在本地控制台上处于活动状态的会话的 ID。这适用于快速用户切换,用户在物理控制台上来回切换,但这不适用于终端服务,用户未连接到控制台。因此,如果您允许远程登录机器,则不能单独依赖WTSGetActiveConsoleSessionId(),您可能必须使用WTSEnumerateSessions() 来查找与登录用户的活动会话。
  • 伙计们,sessionID id 不是问题,当服务在本地系统下时,此代码在没有 SetPrivilege 的情况下工作。现在的问题是我需要将服务移动到本地管理员用户下运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-29
  • 1970-01-01
  • 2021-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多