About Terminal Server, Citrix, Delphi and other stuff
Hello, my name is Danila Galimov and i will write here sometimes ![]()
My first post is about communications between Terminal Server sessions and Terminal Server service process (termsrv.exe/dll). Terminal Server service needs to communicate with each session for many tasks, such as sending window message, getting message reply and so on. So, on init, Terminal Server creates a SmSsWinStationApiPort port in global namespace and runs a few WinStationLpcThread threads, which are listening on port and are used to process port messages. When csrss.exe is started, it parses its command line, which usually looks like:
%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=4096,4096,1024 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16
and loads the required dlls (winsrv.dll in our case). Initialization of winsrv.dll creates a thread, which connects to SmSsWinStationApiPort port and does the loop for processing Terminal Server messages until it receives WinStationTerminate message.
We’ll try to fool Terminal Server and send some messages to the port directly. At first, we need to connect to the port. A structure of 3 DWORDS is used to for connection:
Let’s do the connection:
ConnectionStructure : TConnecttionStructure;
begin
RtlInitUnicodeString(@PortName, ‘\SmSsWinStationApiPort’);
ConnectionDataLength := SizeOf(ConnectionStructure);
with ConnectionStructure do
begin
dwVersion := VERSION_1;
DWORD2 := 0; // is it a parameter, does it mean something?
end;
ZeroMemory(@SequrityQOS, SizeOf(SequrityQOS));
NtCheck(‘Connecting to port \SmSsWinStationApiPort’, NtConnectPort(@PortHandle, @PortName, @SequrityQOS, nil, nil, nil, @ConnectionStructure, @ConnectionDataLength));
try
if ConnectionDataLength = SizeOf(ConnectionStructure) then
NTCheck(‘Connecting to port \SmSsWinStationApiPort error code’, ConnectionStructure.ErrorCode);
finally
CloseHandle(PortHandle);
end;
end;
Now we’re connected. We need to prepare and send a message. Each message (after standard PORT_MESSAGE header) has common header:
For creating idle winstation, 2 fields are added to this message: WinstationName, which is optional, and OutSessionId, which returns, on success, id of recently created winstation. So the whole structure will look like this:
So now we can send this message and check for the results:
ApiNumber := API_NUMBER_WinStationInternalCreate;
DoRequireReply := True;
CallAndCheckResult(PortHandle, CreateIdleWinstationMessage.Base);
Writeln(Format(‘Session id %d has been created’, [OutSessionId]));
end;
end;
Disconnect and Reset (logoff messages) are very simple: just target session id is added to the structure.
That’s all! Now we can just add command line parameters parsing features, and it’s ready for usage!
As only system is allowed to access SmSsWinStationApiPort port, we need to run our program as system. You can use RunAsSys program for that propose.
Unfortunately, in windows vista/2008 the Terminal Server internal functions have been changed, so this program (IdleWinsta) does not work on vista.
IdleWinsta.zip (282)Related posts:
Active Directory Altiris bug Citrix Dell Delphi Exchange Exchange2003 Exchange2010 Hewlett-Packard HP iOS Jailbreak Java LinkedIn Linux MSI MySQL Navigation Objects Office Outlook Passat PowerPoint PowerShell referall was returned RNS315 RNS510 SasLibEx script slow Terminal Server ThinApp TSAdmin TSAdminEx VBS VCDS Vista VMWare Volkswagen Windows PE WLAN Wordpress WTSWaitSystemEvent wts_event_flush
WP Cumulus Flash tag cloud by Roy Tanck requires Flash Player 9 or better.
One Response for "Terminal Server Internals"
[...] Yes, I was told that more is to come. So dig into the first article Terminal Service Internals. [...]
Leave a reply