Не удается заставить службу Windows правильно вызывать дочерний процесс в Windows Server 2012 - PullRequest
0 голосов
/ 05 июня 2019

Следующая функция, которую я написал, должна вызываться службой Windows, чтобы запустить дочерний процесс (как пользователь), чтобы дочерний процесс мог взаимодействовать с пользователем, то есть иметь пользовательский интерфейс. Он отлично работает на рабочем столе Windows, но не работает должным образом на Windows Server 2012. Пользовательский интерфейс не отображается (даже не в окне консоли), и горячая клавиша, которую мы регистрируем для удаления службы, также не работает.

Следующий код:

void WINAPI Run(DWORD dwTargetSessionId, int desktop, LPTSTR lpszCmdLine)
{
    wprintf(_T("Run client start"));

    if (hPrevAppProcess != NULL)
    {
        TerminateProcess(hPrevAppProcess, 0);
        WaitForSingleObject(hPrevAppProcess, INFINITE);
    }


    HANDLE hToken = 0;
    WTS_SESSION_INFO *si;
    DWORD cnt = 0;
    WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &si, &cnt);
    for (int i = 0; i < (int)cnt; i++)
    {
        if (si[i].SessionId == 0)continue;
        wprintf(_T("Trying session id %i (%s) user admin token"), si[i].SessionId, si[i].pWinStationName);
        HANDLE userToken;
        if (WTSQueryUserToken(si[i].SessionId, &userToken))
        {
            wprintf(_T("WTSQueryUserToken succeced"));
            TOKEN_LINKED_TOKEN admin;
            DWORD len;
            if (GetTokenInformation(userToken, TokenLinkedToken, &admin, sizeof(TOKEN_LINKED_TOKEN), &len))
            {
                wprintf(_T("Success using user admin token"));
                hToken = admin.LinkedToken;
                break;
            }
            else
                wprintf(L"GetTokenInformation() failed");

            CloseHandle(userToken);
        }
        else
        {
            DWORD error = GetLastError();
            if (error)
            {
                LPVOID lpMsgBuf;
                DWORD bufLen = FormatMessage(
                    FORMAT_MESSAGE_ALLOCATE_BUFFER |
                    FORMAT_MESSAGE_FROM_SYSTEM |
                    FORMAT_MESSAGE_IGNORE_INSERTS,
                    NULL,
                    error,
                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                    (LPTSTR)&lpMsgBuf,
                    0, NULL);
                utils::WriteLogFile(L"Error '%s'\n", lpMsgBuf);
            }
        }

    }
    if (hToken == 0)
    {
        HANDLE systemToken;
        OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &systemToken);
        DuplicateTokenEx(systemToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hToken);
        CloseHandle(systemToken);
        int i;
        for (i = 0; i < (int)cnt; i++)
        {
            if (si[i].SessionId == 0)continue;
            if (SetTokenInformation(hToken, TokenSessionId, &si[i].SessionId, sizeof(DWORD)))
            {
                wprintf(_T("Success using system token with set user session id %i"), si[i].SessionId);
                break;
            }
        }
        if (i == cnt)
            wprintf(_T("No success to get user admin token nor system token with set user session id"));
    }
    WTSFreeMemory(si);


    STARTUPINFO startupInfo = {};
    startupInfo.cb = sizeof(STARTUPINFO);

    startupInfo.lpDesktop = _T("winsta0\\default");

    LPVOID pEnv = NULL;
    CreateEnvironmentBlock(&pEnv, hToken, TRUE);

    PROCESS_INFORMATION processInfo = {};
    PROCESS_INFORMATION processInfo32 = {};

    TCHAR szCurModule[MAX_PATH] = { 0 };
    GetModuleFileName(NULL, szCurModule, MAX_PATH);

    BOOL bRes = FALSE;

    std::wstring commandLine;
    commandLine.reserve(1024);

    commandLine += L"\"";
    commandLine += szCurModule;
    commandLine += L"\" \"";
    commandLine += SERVICE_COMMAND_LUNCHER;
    commandLine += L"\"";

    wprintf(_T("launch SG_WinService with CreateProcessAsUser ...  %s"), commandLine.c_str());

    bRes = CreateProcessAsUserW(hToken, NULL, &commandLine[0], NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS |
        CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | CREATE_DEFAULT_ERROR_MODE, pEnv,
        NULL, &startupInfo, &processInfo);

    if (bRes == FALSE)
    {
        DWORD   dwLastError = ::GetLastError();
        TCHAR   lpBuffer[256] = _T("?");
        if (dwLastError != 0)    // Don't want to see a "operation done successfully" error ;-)
            ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,                 // It´s a system error
                NULL,                                      // No string to be formatted needed
                dwLastError,                               // Hey Windows: Please explain this error!
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),  // Do it in the standard language
                lpBuffer,              // Put the message here
                255,                     // Number of bytes to store the message
                NULL);
        (_T("CreateProcessAsUser(SG_WinService) failed - Error : %s (%i)"), lpBuffer, dwLastError);
    }
    else
    {
        wprintf(_T("CreateProcessAsUser(SG_WinService) success. New process ID: %i"), processInfo.dwProcessId);
    }
}

возвращает следующий вывод:

05.06.2019 04:25 5856: Попытка идентификатора администратора сеанса 1 (Консоль) пользователя

05.06.2019 04:25 5856: Попытка идентификатора администратора 2 сеанса (RDP-Tcp # 27) для пользователя admin

05.06.2019 04:25 5856: Попытка идентификатора сеанса 65536 (RDP-Tcp) токен администратора пользователя

05.06.2019 04:25 5856: Успешное использование системного токена с установленным идентификатором сеанса пользователя 1

05.06.2019 04:25 5856: запустить SG_WinService с CreateProcessAsUser ... "C: \ myservice \ SG_WinService.exe" "ServiceIsLuncher"

05.06.2019 04:25 5856: CreateProcessAsUser (SG_WinService) успешно завершен. ID нового процесса: 5580

Обновление: После добавления вызова GetLastError () я получаю:

09.06.2019 04:55 6008: пробный сеанс с идентификатором 1, токен администратора пользователя

09.06.2019 04:55 6008: Ошибка 'Была сделана попытка сослаться на несуществующий токен.

09.06.2019 04:55 6008: Попытка идентификатора администратора 3 сеанса пользователя

09.06.2019 04:55 6008: Попытка идентификатора сеанса 65536 токена администратора пользователя

09.06.2019 04:55 6008: Ошибка 'Система не может найти указанный файл.

09.06.2019 04:55 6008: Успешное использование системного токена с установленным идентификатором сеанса пользователя 1

09.06.2019 04:55 6008: запустить SG_WinService с CreateProcessAsUser ...

"C: \ Users \ Администратор \ Desktop \ src \ SpyfiWebApp \ SG_WinService.exe" "ServiceIsLuncher"

09.06.2019 04:55 6008: CreateProcessAsUser (SG_WinService) успешно завершен. ID нового процесса: 7536

Таким образом, вместо запуска дочернего процесса в сеансе 1, он запускается как "SYSTEM".

...