2011-11-29 249 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); 
}