2010-05-13 416 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最初是一个Citrix API,并且有一个WF等价于这些WTS函数的大部分。在Citrix/IDA服务器上运行时,您似乎从我的程序中获得了更多的数据,这似乎更充分地实现了此会话API。话虽如此,使用MS Remote App时我也看到了更多的字段。然而,本质上我的程序正在工作......

0

我认为WTSQuerySessionInformation需要您首先获得特权才能正确返回所有数据?

+0

我认为,如果你对一个远程服务器上运行,可能是这样......但我是一个终端内本地运行这个程序(即服务会话,我不相信任何权限是必需的。 – Benj 2010-05-13 11:04:05

+0

不具有权限。我的意思是您需要从代码明确获取的Windows应用程序权限。请参阅:http://msdn.microsoft.com/en-us/library /bb530716(VS.85).aspx 如果这是你所指的,那么我很抱歉。 – 2010-05-13 11:15:28

2

尽管WTSQuerySessionInformation采用LPTSTR来保存返回的数据,但数据并不总是一个字符串。试图在大多数情况下打印不是字符串的东西不会很好。您看到空/垃圾字符串的事实意味着,如果作为字符串读取,LPTSTR指向的缓冲区有时以'\ 0'开头,该printf将作为空字符串打印。

请尝试打印出十六进制表示中字符串的每个字符。遍历字符串中的每个字符(0到bytesReturned-1)并将其打印为十六进制。这会让您更好地了解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 \伊卡\会话的远程注册表的所有注册表项(这是会话ID的)。然后你读他们从每个子键连接值发布的名称。之后,将WTSQuerySessionInformation的会话ID与注册表项名称进行匹配,然后完成。

一些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()