Reputation: 12296
I need to intercept certain signal in a windows service, and then find all explorer.exe
processes and restart them.
So far it works fine if only one user is logged into the system and the service is in "foreground" mode, e.g - started as process for the current user. Explorer is killed and restarted just fine. However if there are multiple users - the explorer
is killed but started only for the current user.
Moreover, as a service - there is a different user that owns the service itself, and while killing explorer works fine - it can't be started most of the time, and if starts - it is started for the service user only.
With some digging in Win32 API it seems possible to use something like CreateProcessWithLogonW()
- but that requires knowing user's credentials.
Is there any way to restart / send some signal to explorer so it will know that it needs to restart / re-read SRP rules?
UPD: just for the reference if someone is looking for the hints:
Upvotes: 0
Views: 1126
Reputation: 33754
if you run from service you in most case (if service not special restricted) will have SE_TCB_NAME
privilege. as result you can call WTSQueryUserToken
for obtain the primary access token of the logged-on user specified by the session ID. the explorer run exactly with this token. and you can use CreateProcessAsUserW
for start explorer again with this token (again i assume your service not restricted and have SE_ASSIGNPRIMARYTOKEN_NAME
privilege.). so you can enumerate all user terminal sessions with WTSEnumerateSessionsW
function, got token for every session, found explorer in session and restart it.
but here question how found explorer process(es). of course we can do this by short file name. enumerate all processes. but i think more reliable way will be call GetShellWindow
and then GetWindowThreadProcessId
. but we can not do this direct from service. this need do exactly from user session(s). so possible solution - first launch self exe in every terminal session, with special command line as marker, and then already from session call GetShellWindow
and restart explorer with simply CreateProcessW
call
WCHAR ExeName[MAX_PATH];
PROCESS_INFORMATION pi;
STARTUPINFO si = { sizeof(si) };
static const WCHAR tagCmdLine[] = L"|";
if (wcscmp(GetCommandLineW(), tagCmdLine))
{
GetModuleFileNameW(0, ExeName, _countof(ExeName));
if (GetLastError() == NOERROR)
{
ULONG Count;
PWTS_SESSION_INFO pSessionInfo;
if (WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &Count))
{
if (Count)
{
pSessionInfo += Count;
do
{
HANDLE hToken;
if (WTSQueryUserToken((--pSessionInfo)->SessionId, &hToken))
{
PVOID lpEnvironment;
if (CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE))
{
if (CreateProcessAsUserW(hToken, ExeName, const_cast<PWSTR>(tagCmdLine),
0, 0, 0, CREATE_UNICODE_ENVIRONMENT, lpEnvironment, 0, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
DestroyEnvironmentBlock(lpEnvironment);
}
CloseHandle(hToken);
}
} while (--Count);
}
WTSFreeMemory(pSessionInfo);
}
}
}
else
{
if (HWND hwnd = GetShellWindow())
{
ULONG dwProcessId, dwThreadId;
if (dwThreadId = GetWindowThreadProcessId(hwnd, &dwProcessId))
{
if (HANDLE hProcess = OpenProcess(PROCESS_TERMINATE|SYNCHRONIZE|
PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcessId))
{
ULONG cch = _countof(ExeName);
if (QueryFullProcessImageNameW(hProcess, 0, ExeName, &cch))
{
PostThreadMessageW(dwThreadId, WM_QUIT, 0, 0);
if (WaitForSingleObject(hProcess, 1000) == WAIT_OBJECT_0 ||
TerminateProcess(hProcess, 0) ||
RtlGetLastNtStatus() == STATUS_PROCESS_IS_TERMINATING)
{
if (CreateProcessW(ExeName, 0, 0, 0, 0, 0, 0, 0, &si, &pi))
{
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
}
}
CloseHandle(hProcess);
}
}
}
ExitProcess(0);
Upvotes: 1