“The Back-End Service Model“

Salve a tutti!

Spero abbiate scaricato in tanti l’applicazione di esempio e l’abbiate provata. Non è nulla di eccezionale, ma vuole mostrare la strada per creare una applicazione client-server, dove il server è un servizio che gira in Sessione 0 e il client è una applicazione user mode. Questo è il cosiddetto “Back-End Service Model“.

 

Come funziona il servizio.

Il servizio è un banalissimo servizio Windows realizzato in VB.Net. All’avvio, crea una pipe con un nome random, e salva il nome in una chiave di registry predefinita, cosicchè quando i client verranno avviati, potranno andare a leggere il nome della pipe nel registry e potranno collegarsi a quella. Questa è solo una misura di sicurezza per evitare attacchi DOS (Denial of Service), a cui la vostra applicazione potrebbe essere soggetta, dato che avere un servizio che gira come Local System e che esegue qualunque comando/applicazione, potrebbe consentire un veloce EOP (“escalation of privilege”) ad un qualunque malaware che vi prenda di mira. Ovviamente potete migliorare moltissimo questa fase, creando un protocollo di handshaking complicato e cryptato a piacimento.

Tenete sempre presente che qualora andaste a portare in produzione un’applicazione del genere, il rischio esiste, quindi dovete fare tutto il possibile per mitigare questa possibilità.

Il thread principale del servizio in ascolto sulla pipe, quando riceve una chiamata da un client, ottiene il nome dello user e crea un nuovo thread che altro non fa che aprire una nuova pipe su cui da ora in poi andranno avanti le comunicazioni. La vecchia comunicazione viene interrotta e il server può rimettesi in ascolto per una nuova connessione. Al client viene inviato il nome della nuova pipe creata.

Il client a questo punto tenterà di connettersi alla nuova pipe e se ci riesce il servizio gli invia indietro una stringa di controllo “START:” che significa che il client è connesso e può iniziare ad inviare comandi.

Come vedete il resto del thread è molto semplicemente una grande Select Case dove si analizza il contenuto del comando ricevuto e si agisce di conseguenza, richiamando la funzione specifica.

Oltre a questo, prima dell’avvio del pipe server, ho aggiunto la creazione di una form, che serve per gestire gli eventi relativi alle sesisoni.

La WTSRegisterSessionNotificationEx e la WTSUnRegisterSessionNotificationEx prevedono espressamente di utilizzare un window handle per gestire i messaggi di tipo WM_WTSSESSION_CHANGE, che sono elencati in questa enumerazione:

Public Enum WTS_SESSIONCHANGE_EVENT
    WTS_CONSOLE_CONNECT = 1
    WTS_CONSOLE_DISCONNECT
    WTS_REMOTE_CONNECT
    WTS_REMOTE_DISCONNECT
    WTS_SESSION_LOGON
    WTS_SESSION_LOGOFF
    WTS_SESSION_LOCK
    WTS_SESSION_UNLOCK
    WTS_SESSION_REMOTE_CONTROL
End Enum

In questo modo, potremo sapere sempre quando accade un evento di quelli sopra elencati, ed eventualmente mantenere una lista in memoria dove, avremo elencati numero sessione e ultimo evento ricevuto, così da  poter sapere sempre in che stato si trova la sessione.. Locked o unlocked, collegata alla console o ad una sessione remota, ecc.. questo è l’unico modo per tenere traccia del fatto che una sesisone sia lockata o meno ad esempio.

Per evitare che la finestra si chiudesse immediatamente dato che siamo in Sessione 0 e il sistema si rende conto che questa finestra non serve a nulla, ho implementato un trucchetto, creando un thread di attesa.. bruttissima come soluzione, ma funzionale..

 

Conclusioni.

Quindi, riassumendo, abbiamo visto come il servizio può essere migliorato e di molto.. ad esempio implementando della sicurezza intorno alla creazione della pipe e/o cifrando il protocollo di comunicazione. Anche la creazione di una lista che mi dica sempre lo stato delle sessioni può essere una bella cosa.

 

Alla prossima!

Mario Raccagni
Senior Support Engineer
Platform Development Support Team