Interaktívne spúšťanie programov z NT Služieb.

 

Najprv si povieme čo-to o spúšťaní programov z aplikácií.
V klasickej aplikácii môžeme iný program spustiť buď ako nový proces: CreateProcess, ako ShellExecute alebo, ako script v klauzuly system(), napríklad system("c:\\diallix.exe")

Jednotlivým inštanciám programu sa dá nastaviť zobrazenie - či majú byť spustené vo windows reŹime alebo v hide reŽime na pozadí, tak ako aj nastavenie (passovanie) argumentov a podobne.
Pri Službách NT to nie je také jednoduché. Narozdiel od klasických aplikáciách, ktoré sa spúšťjú pod desktopom užívateľa, služby NT systému bežia pod priradením System po nabootovaní systému. Pri snahe spustiť program, napríklad konzolovú aplikáciu interaktívne, teda dialógovo, dôjde k jej skrytiu na pozadí. Ako teda spustiť program v okne pod daným užívateľským kontom a desktopom?

Odpoveďou je CreateProcessAsUser. Na to, aby sme mohli vyvolať a spustiť program, potrebujeme ešte tieto funkcie, ktoré kooperujú : SetTokenInformation, DuplicateTokenEx, WTSGetActiveConsoleSessionId, WTSQueryUserToken, LookupPrivilegeValue.

Takže v skratke, potrebujeme napísať funkciu, korá spustí program s GUI v interaktívnom režíme.
Podrobnejší popis vyššie uvedených funkcií nájdete tu: https://www.codeproject.com/Articles/18367/Launch-your-application-in-Vista-under-the-local-s

Navrhovaná funkcia by mohla vypadať následovne:



#include "WinAPI.h" //https://www.netbot.sk/sk/14-blog-headers/31-winapi 
bool StartInteractiveProcess(::DWORD sessionId, char* programpath) { ::HANDLE hToken, hProcess, hPToken, hUserTokenDup; ::HDESK hdesk; ::HWINSTA hwinsta; ::HWINSTA hwinstaSave; ::PROCESS_INFORMATION pi; ::PSID pSid; ::STARTUPINFO si; bool bQueryUserToken;
this->hdesk = NULL; this->hwinsta = NULL; this->hwinstaSave = NULL; this->pSid = NULL;
this->bQueryUserToken = false;
sessionId = ::WTSGetActiveConsoleSessionId();
this->bQueryUserToken = ::WTSQueryUserToken(sessionId, &this->hToken);
::ZeroMemory(&this->si, sizeof(STARTUPINFO)); this->si.cb= sizeof(STARTUPINFO); this->si.lpDesktop = TEXT("winsta0\\default");
TOKEN_PRIVILEGES tp; LUID luid2;
::LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid2);
tp.PrivilegeCount = 1; tp.Privileges[0].Luid =luid2; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
::DuplicateTokenEx(this->hToken, MAXIMUM_ALLOWED,NULL, SecurityIdentification,
TokenPrimary, &this->hUserTokenDup);
::SetTokenInformation(this->hUserTokenDup, TokenSessionId, (void*)sessionId, sizeof(DWORD));
::CreateProcessAsUser(this->hUserTokenDup, NULL, this->CHAR_To_LPWSTR(programpath),
NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
::CloseHandle(this->hProcess); ::CloseHandle(this->hUserTokenDup); ::CloseHandle(this->hPToken);
return 0; }

 

 

 

 

 

 

 

 

-----------------------------------------------------------------

Celá funkcia je zakonpovaná do headeru WinAPI.h WinAPI.h


#include "WinAPI.h" //https://www.netbot.sk/sk/14-blog-headers/31-winapi

int _cdecl main (void) 
{
   ::Diall_WinApi::WinApi::GetInstance()->SystemIntegrity(::Diall_WinApi::Privilege::ENABLE);
::Diall_WinApi::WinApi::GetInstance()->StartInteractiveProcess(0,"c:\\diallix.net");

return 0; }