2010-05-13 6 views
2

Я написал программу, которая должна запросить API-интерфейс служб терминалов и распечатать некоторую информацию о состоянии сеансов, работающих в окне служб терминалов. Я использую функцию WTSQuerySessionInformation, чтобы сделать это, и он возвращает некоторые данные, но большая часть данных, кажется, отсутствует ... Кто-нибудь знает, почему?WTSQuerySessionInformation возвращает пустые строки

Вот моя программа:

void WTSGetString(HANDLE serverHandle, DWORD sessionid, WTS_INFO_CLASS command, wchar_t* commandStr) 
{ 
    DWORD bytesReturned = 0; 
    LPTSTR pData = NULL; 
    if (WTSQuerySessionInformation(serverHandle, sessionid, command, &pData, &bytesReturned)) 
    { 
     wprintf(L"\tWTSQuerySessionInformationW - session %d - %s returned \"%s\"\n", sessionid, commandStr, pData);  
    } 
    else 
    { 
     wprintf(L"\tWTSQuerySessionInformationW - session %d - %s failed - error=%d - ", sessionid, commandStr, GetLastError()); 
     printLastError(NULL, GetLastError()); 
    } 
    WTSFreeMemory(pData); 
} 


void ExtractFromWTS(HANDLE serverHandle, DWORD sessionid) 
{ 

    WTSGetString(serverHandle, sessionid, WTSInitialProgram, L"WTSInitialProgram"); 
    WTSGetString(serverHandle, sessionid, WTSApplicationName, L"WTSApplicationName"); 
    WTSGetString(serverHandle, sessionid, WTSWorkingDirectory, L"WTSWorkingDirectory"); 
    WTSGetString(serverHandle, sessionid, WTSOEMId, L"WTSOEMId"); 
    WTSGetString(serverHandle, sessionid, WTSSessionId, L"WTSSessionId"); 
    WTSGetString(serverHandle, sessionid, WTSUserName, L"WTSUserName"); 
    WTSGetString(serverHandle, sessionid, WTSWinStationName, L"WTSWinStationName"); 
    WTSGetString(serverHandle, sessionid, WTSDomainName, L"WTSDomainName"); 
    WTSGetString(serverHandle, sessionid, WTSConnectState, L"WTSConnectState"); 
    WTSGetString(serverHandle, sessionid, WTSClientBuildNumber, L"WTSClientBuildNumber"); 
    WTSGetString(serverHandle, sessionid, WTSClientName, L"WTSClientName"); 
    WTSGetString(serverHandle, sessionid, WTSClientDirectory, L"WTSClientDirectory"); 
    WTSGetString(serverHandle, sessionid, WTSClientProductId, L"WTSClientProductId"); 
    WTSGetString(serverHandle, sessionid, WTSClientHardwareId, L"WTSClientHardwareId"); 
    WTSGetString(serverHandle, sessionid, WTSClientAddress, L"WTSClientAddress"); 
    WTSGetString(serverHandle, sessionid, WTSClientDisplay, L"WTSClientDisplay"); 
    WTSGetString(serverHandle, sessionid, WTSClientProtocolType, L"WTSClientProtocolType"); 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    PWTS_SESSION_INFOW ppSessionInfo = 0; 
    DWORD pCount; 
    if(!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &ppSessionInfo, &pCount)) 
    { 
     printLastError(L"WTSEnumerateSessions", GetLastError()); 
     return 1; 
    } 

    wprintf(L"%d WTS sessions found on host\n", pCount); 

    for (unsigned int i=0; i<pCount; i++) 
    { 
     wprintf(L"> session=%d, stationName = %s\n", ppSessionInfo[i].SessionId, ppSessionInfo[i].pWinStationName); 
     ExtractFromWTS(WTS_CURRENT_SERVER_HANDLE, ppSessionInfo[i].SessionId); 
     LPWSTR sessionstr = new wchar_t[200]; 
     wsprintf(sessionstr, L"%d", ppSessionInfo[i].SessionId);  
    } 

    return 0; 
} 

И вот результат:

C:\Users\Administrator\Desktop>ObtainWTSStartShell.exe empserver1 
4 WTS sessions found on host 
> session=0, stationName = Services 
     WTSQuerySessionInformationW - session 0 - WTSInitialProgram failed - error=87 - The paramete 
r is incorrect. 

     WTSQuerySessionInformationW - session 0 - WTSApplicationName failed - error=87 - The paramet 
er is incorrect. 

     WTSQuerySessionInformationW - session 0 - WTSWorkingDirectory returned "" 
     WTSQuerySessionInformationW - session 0 - WTSOEMId returned "" 
     WTSQuerySessionInformationW - session 0 - WTSSessionId returned "" 
     WTSQuerySessionInformationW - session 0 - WTSUserName returned "" 
     WTSQuerySessionInformationW - session 0 - WTSWinStationName returned "Services" 
     WTSQuerySessionInformationW - session 0 - WTSDomainName returned "" 
     WTSQuerySessionInformationW - session 0 - WTSConnectState returned "♦" 
     WTSQuerySessionInformationW - session 0 - WTSClientBuildNumber returned "" 
     WTSQuerySessionInformationW - session 0 - WTSClientName returned "" 
     WTSQuerySessionInformationW - session 0 - WTSClientDirectory returned "" 
     WTSQuerySessionInformationW - session 0 - WTSClientProductId returned "" 
     WTSQuerySessionInformationW - session 0 - WTSClientHardwareId returned "" 
     WTSQuerySessionInformationW - session 0 - WTSClientAddress returned "" 
     WTSQuerySessionInformationW - session 0 - WTSClientDisplay returned "" 
     WTSQuerySessionInformationW - session 0 - WTSClientProtocolType returned "" 
     GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2] 
     GetShellProcessName succeseded - explorer.exe 
> session=1, stationName = Console 
     WTSQuerySessionInformationW - session 1 - WTSInitialProgram returned "" 
     WTSQuerySessionInformationW - session 1 - WTSApplicationName returned "" 
     WTSQuerySessionInformationW - session 1 - WTSWorkingDirectory returned "" 
     WTSQuerySessionInformationW - session 1 - WTSOEMId returned "" 
     WTSQuerySessionInformationW - session 1 - WTSSessionId returned "☺" 
     WTSQuerySessionInformationW - session 1 - WTSUserName returned "" 
     WTSQuerySessionInformationW - session 1 - WTSWinStationName returned "Console" 
     WTSQuerySessionInformationW - session 1 - WTSDomainName returned "" 
     WTSQuerySessionInformationW - session 1 - WTSConnectState returned "☺" 
     WTSQuerySessionInformationW - session 1 - WTSClientBuildNumber returned "" 
     WTSQuerySessionInformationW - session 1 - WTSClientName returned "" 
     WTSQuerySessionInformationW - session 1 - WTSClientDirectory returned "" 
     WTSQuerySessionInformationW - session 1 - WTSClientProductId returned "" 
     WTSQuerySessionInformationW - session 1 - WTSClientHardwareId returned "" 
     WTSQuerySessionInformationW - session 1 - WTSClientAddress returned "" 
     WTSQuerySessionInformationW - session 1 - WTSClientDisplay returned "?" 
     WTSQuerySessionInformationW - session 1 - WTSClientProtocolType returned "" 
     GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2] 
     GetShellProcessName succeseded - explorer.exe 
> session=3, stationName = RDP-Tcp#0 
     WTSQuerySessionInformationW - session 3 - WTSInitialProgram returned "" 
     WTSQuerySessionInformationW - session 3 - WTSApplicationName returned "" 
     WTSQuerySessionInformationW - session 3 - WTSWorkingDirectory returned "" 
     WTSQuerySessionInformationW - session 3 - WTSOEMId returned "" 
     WTSQuerySessionInformationW - session 3 - WTSSessionId returned "♥" 
     WTSQuerySessionInformationW - session 3 - WTSUserName returned "Administrator" 
     WTSQuerySessionInformationW - session 3 - WTSWinStationName returned "RDP-Tcp#0" 
     WTSQuerySessionInformationW - session 3 - WTSDomainName returned "EMPSERVER1" 
     WTSQuerySessionInformationW - session 3 - WTSConnectState returned "" 
     WTSQuerySessionInformationW - session 3 - WTSClientBuildNumber returned "?" 
     WTSQuerySessionInformationW - session 3 - WTSClientName returned "APWADEV03" 
     WTSQuerySessionInformationW - session 3 - WTSClientDirectory returned "C:\Windows\System32\m 
stscax.dll" 
     WTSQuerySessionInformationW - session 3 - WTSClientProductId returned "☺" 
     WTSQuerySessionInformationW - session 3 - WTSClientHardwareId returned "" 
     WTSQuerySessionInformationW - session 3 - WTSClientAddress returned "☻" 
     WTSQuerySessionInformationW - session 3 - WTSClientDisplay returned "?" 
     WTSQuerySessionInformationW - session 3 - WTSClientProtocolType returned "☻" 
     GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2] 
     GetShellProcessName succeseded - explorer.exe 
> session=65536, stationName = RDP-Tcp 
     WTSQuerySessionInformationW - session 65536 - WTSInitialProgram returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSApplicationName returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSWorkingDirectory returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSOEMId returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSSessionId returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSUserName returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSWinStationName returned "RDP-Tcp" 
     WTSQuerySessionInformationW - session 65536 - WTSDomainName returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSConnectState returned "♠" 
     WTSQuerySessionInformationW - session 65536 - WTSClientBuildNumber returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSClientName returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSClientDirectory returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSClientProductId returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSClientHardwareId returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSClientAddress returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSClientDisplay returned "" 
     WTSQuerySessionInformationW - session 65536 - WTSClientProtocolType returned "" 
     GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2] 
     GetShellProcessName succeseded - explorer.exe 

Как вы можете видеть, некоторые из данных выглядит действительно, но не все ....

ответ

2

Хм, кажется, что это нормально для этих полей быть пустыми в терминальных службах/сеансе RDP. Этот API был первоначально API Citrix, и для большинства этих функций WTS существует эквивалент WF. Похоже, вы получаете гораздо больше данных из моей программы при работе на сервере Citrix/IDA, который, как представляется, реализует этот сеансовый API гораздо более полно. Сказав это, я также видел больше полей, заполняемых при использовании MS Remote App. Однако по существу моя программа работала ...

0

Я думаю, что WTSQuerySessionInformation нуждается в том, чтобы вы сначала получили привилегии для правильного возврата всех данных?

+0

Я думаю, что может быть в случае, если вы работаете на удаленный сервер ... но я бегала эту программу локально (т.е. в пределах терминала Службы сеанса, и я не считаю, что какие-либо разрешения необходимы. – Benj

+0

Не разрешено. Я имею в виду привилегии приложения Windows, которые необходимо явно получить из кода. См. Здесь: http://msdn.microsoft.com/en-us/library /bb530716(VS.85).aspx Если это то, о чем вы говорите, я прошу прощения. –

2

Несмотря на то, что WTSQuerySessionInformation принимает LPTSTR для хранения возвращаемых данных, данные не всегда являются строкой. Попытка напечатать что-то, что не является строкой, не будет работать очень хорошо в большинстве случаев. Тот факт, что вы видите пустые/мусорные строки, означает, что иногда буфер, на который указывает LPTSTR, начинается с «\ 0», если он читается как строка, которую printf будет печатать как пустую строку.

Вместо этого попробуйте распечатать каждый символ строки в представлении HEX. Проведите через каждый символ в строке (от 0 до байтReturned-1) и напечатайте его как hex. Это даст вам лучшее представление о том, что находится в буфере LPTSTR.

0

Я никогда не мог получить ничего, кроме текущего материала сеанса.

int _tmain(int argc, _TCHAR* argv[]) 
    { 

     // if(!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &ppSessionInfo, &pCount)) 
     // { 
     ////The stuff coming back from WTSEnumerateSessions in ppSessionInfo doesn't seem to be useful. 

     if (GetSystemMetrics(SM_REMOTESESSION) == 0) 
     { 
      //it ain't remote. give up. 
      return 1; 
     } 

     DWORD bytesReturned = 0; 
     LPTSTR pData = NULL; 
     WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSSessionId, &pData, &bytesReturned); 
     DWORD sessionId = pData[0]; /*for lookin' at in the debugger*/ 
     wprintf(L"%d WTS session where you will see stuff. CURRENT_SESSION\n", pData[0]); 

     ExtractFromWTS(WTS_CURRENT_SERVER_HANDLE, pData[0]); 
     LPWSTR sessionstr = new wchar_t[200]; 
     wsprintf(sessionstr, L"%d", pData[0]);  

     getchar(); 
     return 0; 
    } 
0

Одно из решений, которое мы нашли, это. База информации реестра:

enter image description here

Вы запрос удаленного реестра под HKLM \ Software \ Citrx \ Ика \ сессии для всех ключей реестра (которые сеансовые идентификаторы). Затем вы читаете значение valueNameName из каждого подключаемого ключа. После этого вы сопоставляете идентификатор сеанса из WTSQuerySessionInformation с именем ключа реестра, и все готово.

Часть кода PowerShell PoC будет выглядеть следующим образом:

$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', 'YOURSERVER') 
$RegKey = $Reg.OpenSubKey("SOFTWARE\\Citrix\\ICA\\Session") 
foreach ($sessionId in $RegKey.GetSubKeyNames()) 
{ 
    $sessionKey = $RegKey.OpenSubKey($sessionId + "\\Connection") 
    if ($sessionKey -ne $null) 
    { 
     $sessionKey.GetValue("PublishedName") 
     $sessionKey.Close() 
    } 
}  
$RegKey.Close() 
$Reg.Close()