2011-11-29 52 views
4

我有这个问题发生过一次,我仍然不知道如何解决它。我有一个Windows服务,当服务运行时,它首先需要模拟登录用户(活动用户)加载保存在用户应用程序数据文件夹中的一些路径和设置。我使用的代码在每次有新用户登录到Windows时都能很好地工作,除非服务得到错误模拟的地方,并且模拟了系统会话而不是实际的会话。正如我所说,这只发生过一次,但我无法真正说出原因。WTSGetActiveConsoleSessionId返回系统会话

这是怎么了检查什么活动会话并冒充是如何完成的:

首先在服务调用

WTSGetActiveConsoleSessionId(); 

然后检查检测登录事件是查询的活动会话ID如果会话是活动的,通过调用WTSQuerySessionInformation(连接的),如下所示:

WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected; 
WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL; 

DWORD bytes_returned = 0; 
if (::WTSQuerySessionInformation(
    WTS_CURRENT_SERVER_HANDLE, 
    session_id, 
    WTSConnectState, 
    reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state), 
    &bytes_returned)) 
{ 
     ASSERT(bytes_returned == sizeof(*ptr_wts_connect_state)); 
     wts_connect_state = *ptr_wts_connect_state; 
     ::WTSFreeMemory(ptr_wts_connect_state); 
     return (WTSActive == wts_connect_state); 
} 

其中SESSION_ID是会话ID由WTSG返回etActiveConsoleSessionId()。

然后我查询使用用户令牌WTSQueryUserToken

那么如果成功的服务调用GetTokenInformation如下:

DWORD neededSize = 0; 
    HANDLE *realToken = new HANDLE; 
    if(GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize)) 
    { 
     CloseHandle(hImpersonationToken); 
     hImpersonationToken = *realToken; 
    } 

其中hImpersonationToken是GetTokenInformation

如果所有检索到的令牌上面的成功就叫

DuplicateTokenEx(hImpersonationToken, 
           0, 
           NULL, 
           SecurityImpersonation, 
           TokenPrimary, 
           phUserToken); 

     CloseHandle(hImpersonationToken); 

,如果它成功,那么它与检索到的令牌

ImpersonateLoggedOnUser(phUserToken); 

我的服务模拟写入日志文件,并根据记录所有以前调用在成功的情况又冒充服后加载的系统配置文件,而不是的用户。

现在这个问题发生了一次,当我重新启动我的机器,但我甚至不再重现它,我一直在努力数周。

我不确定系统配置文件会话如何成为活动会话。我只是想知道如果我在那里做错了什么,不知道我在查询会话信息时是否使用了错误的信息类。

还想知道是否有可能确定查询的会话是否实际上是系统会话之前模拟与返回的令牌才可以再次重试模拟?

正如我所说的,所有提到的调用都有他们的返回对象和代码在移动到下一步之前被检查,所以他们没有来自调用的任何错误,因为它不应该继续模拟,但它做到了:(

希望得到任何帮助可能...谢谢。

回答

4

WTSGetActiveConsoleSessionId()从服务运行,并根据Windows版本在其上运行时,实际上可能会返回0。

执行所需操作的方法是枚举所有会话找到连接的会话(会话0断开连接),然后模拟该会话的用户。下面的代码在我的盒子上运行良好。

//Function to run a process as active user from windows service 
void ImpersonateActiveUserAndRun(WCHAR* path, WCHAR* args) 
{ 
    DWORD session_id = -1; 
    DWORD session_count = 0; 

    WTS_SESSION_INFOA *pSession = NULL; 


    if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &session_count)) 
    { 
     //log success 
    } 
    else 
    { 
     //log error 
     return; 
    } 

    for (int i = 0; i < session_count; i++) 
    { 
     session_id = pSession[i].SessionId; 

     WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected; 
     WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL; 

     DWORD bytes_returned = 0; 
     if (::WTSQuerySessionInformation(
      WTS_CURRENT_SERVER_HANDLE, 
      session_id, 
      WTSConnectState, 
      reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state), 
      &bytes_returned)) 
     { 
      wts_connect_state = *ptr_wts_connect_state; 
      ::WTSFreeMemory(ptr_wts_connect_state); 
      if (wts_connect_state != WTSActive) continue; 
     } 
     else 
     { 
      //log error 
      continue; 
     } 

     HANDLE hImpersonationToken; 

     if (!WTSQueryUserToken(session_id, &hImpersonationToken)) 
     { 
      //log error 
      continue; 
     } 


     //Get real token from impersonation token 
     DWORD neededSize1 = 0; 
     HANDLE *realToken = new HANDLE; 
     if (GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize1)) 
     { 
      CloseHandle(hImpersonationToken); 
      hImpersonationToken = *realToken; 
     } 
     else 
     { 
      //log error 
      continue; 
     } 


     HANDLE hUserToken; 

     if (!DuplicateTokenEx(hImpersonationToken, 
      //0, 
      //MAXIMUM_ALLOWED, 
      TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | MAXIMUM_ALLOWED, 
      NULL, 
      SecurityImpersonation, 
      TokenPrimary, 
      &hUserToken)) 
     { 
      //log error 
      continue; 
     } 

     // Get user name of this process 
     //LPTSTR pUserName = NULL; 
     WCHAR* pUserName; 
     DWORD user_name_len = 0; 

     if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSUserName, &pUserName, &user_name_len)) 
     { 
      //log username contained in pUserName WCHAR string 
     } 

     //Free memory       
     if (pUserName) WTSFreeMemory(pUserName); 

     ImpersonateLoggedOnUser(hUserToken); 

     STARTUPINFOW StartupInfo; 
     GetStartupInfoW(&StartupInfo); 
     StartupInfo.cb = sizeof(STARTUPINFOW); 
     //StartupInfo.lpDesktop = "winsta0\\default"; 

     PROCESS_INFORMATION processInfo; 

     SECURITY_ATTRIBUTES Security1; 
     Security1.nLength = sizeof SECURITY_ATTRIBUTES; 

     SECURITY_ATTRIBUTES Security2; 
     Security2.nLength = sizeof SECURITY_ATTRIBUTES; 

     void* lpEnvironment = NULL; 

     // Get all necessary environment variables of logged in user 
     // to pass them to the new process 
     BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE); 
     if (!resultEnv) 
     { 
      //log error 
      continue; 
     } 

     WCHAR PP[1024]; //path and parameters 
     ZeroMemory(PP, 1024 * sizeof WCHAR); 
     wcscpy(PP, path); 
     wcscat(PP, L" "); 
     wcscat(PP, args); 

     // Start the process on behalf of the current user 
     BOOL result = CreateProcessAsUserW(hUserToken, 
      NULL, 
      PP, 
      //&Security1, 
      //&Security2, 
      NULL, 
      NULL, 
      FALSE, 
      NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, 
      //lpEnvironment, 
      NULL, 
      //"C:\\ProgramData\\some_dir", 
      NULL, 
      &StartupInfo, 
      &processInfo); 

     if (!result) 
     { 
      //log error 
     } 
     else 
     { 
      //log success 
     } 

     DestroyEnvironmentBlock(lpEnvironment); 

     CloseHandle(hImpersonationToken); 
     CloseHandle(hUserToken); 
     CloseHandle(realToken); 

     RevertToSelf(); 
    } 

    WTSFreeMemory(pSession); 
}