WTSQuerySessionInformation, возвращающая пустые строки
Я написал программу, которая должна запрашивать API служб терминалов и распечатывать некоторую информацию о состоянии сеансов, запущенных в окне служб терминалов. Я использую функцию 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
Как видите, некоторые данные выглядят достоверными, но не все....
5 ответов
Хм, ответ, по-видимому, заключается в том, что эти поля являются вполне обычными пустыми в сеансе служб терминалов /RDP. Этот API изначально был API-интерфейсом Citrix, и существует WF-эквивалент для большинства этих функций WTS. Похоже, вы получаете намного больше данных из моей программы при работе на сервере Citrix/IDA, который, по-видимому, реализует этот сеансовый API гораздо более полно. Сказав это, я также увидел больше полей, заполняемых при использовании MS Remote App. Однако по сути моя программа работала...
Хотя WTSQuerySessionInformation использует LPTSTR для хранения возвращаемых данных, данные не всегда являются строкой. Попытка напечатать что-то, что не является строкой, в большинстве случаев не будет работать очень хорошо. Тот факт, что вы видите пустые / мусорные строки, означает, что иногда буфер, на который указывает LPTSTR, начинается с '\0', если читается как строка, которую printf будет печатать как пустую строку.
Вместо этого попробуйте распечатать каждый символ строки в шестнадцатеричном представлении. Перебирайте каждый символ в строке (от 0 до bytesReturned-1) и печатайте его как шестнадцатеричный. Это даст вам лучшее представление о том, что находится в буфере LPTSTR.
Я никогда не был в состоянии получить что-либо кроме текущего материала сессии.
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;
}
Я думаю, что WTSQuerySessionInformation нуждается в вас, чтобы сначала получить привилегии, чтобы правильно вернуть все данные?
Мы нашли одно решение: База данных реестра:
Вы запрашиваете в удаленном реестре в HKLM\Software\Citrx\Ica\Session все ключи реестра (которые являются идентификаторами сеансов). Затем вы читаете, что они имеют значение "Имя_узла" для каждого подключа. После этого вы сопоставляете идентификатор сеанса из 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()