Запуск процесса в сеансе пользователя из службы - PullRequest
13 голосов
/ 27 июня 2010

В Windows Vista / 7/2008 / 2008R2 возможно ли вообще запустить процесс в сеансе пользователя из службы? В частности, локальный сеанс будет наиболее полезным.

Все, что я читал, похоже, говорит, что это невозможно, но я решил спросить здесь, прежде чем полностью сдаться.

Я пишу в VB.NET, но приму предложения во всем.

Ответы [ 5 ]

21 голосов
/ 27 июня 2010

Это действительно возможно. Основная проблема, с которой вы столкнулись, заключается в том, что Windows должна рассматриваться как сервер терминалов, а сеанс пользователей - как удаленный сеанс. Ваша служба должна иметь возможность запускать процесс, который выполняется в удаленном сеансе и принадлежит пользователю.

Кстати, если вы напишите службу, работающую под Windows XP, которая не добавлена ​​в домен, и быстрое переключение пользователей активировано, у вас могут возникнуть такие же проблемы, чтобы запустить процесс при запуске на втором (третьем и и так далее) Рабочий стол зарегистрированных пользователей.

Я надеюсь, что у вас есть токен пользователя, который вы получаете, например, в отношении подражания или у вас есть dwSessionId сессии. Если у вас его нет, вы можете попробовать использовать какую-либо функцию WTS (API служб удаленных рабочих столов http://msdn.microsoft.com/en-us/library/aa383464.aspx,, например WTSEnumerateProcesses или WTSGetActiveConsoleSessionId) или LSA-API, чтобы найти соответствующий сеанс пользователя (LsaEnumerateLogonSessions см http://msdn.microsoft.com/en-us/library/aa378275.aspx и LsaGetLogonSessionData см http://msdn.microsoft.com/en-us/library/aa378290.aspx) или ProcessIdToSessionId (см http://msdn.microsoft.com/en-us/library/aa382990.aspx).

Вы можете использовать функцию GetTokenInformation с параметром TokenSessionId (см. http://msdn.microsoft.com/en-us/library/aa446671.aspx) для получения идентификатора сеанса dwSessionId сеанса пользователя, если вам известен токен пользователя hClient.

BOOL bSuccess;
HANDLE hProcessToken = NULL, hNewProcessToken = NULL;
DWORD dwSessionId, cbReturnLength;

bSuccess = GetTokenInformation (hClient, TokenSessionId, &dwSessionId,
                                sizeof(DWORD), &cbReturnLength);
bSuccess = OpenProcessToken (GetCurrentProcess(), MAXIMUM_ALLOWED, &hProcessToken);
bSuccess = DuplicateTokenEx (hProcessToken, MAXIMUM_ALLOWED, NULL,
                             SecurityImpersonation,
                             TokenPrimary, &hNewProcessToken);
EnablePrivilege (SE_TCB_NAME);
bSuccess = SetTokenInformation (hNewProcessToken, TokenSessionId, &dwSessionId,
                                sizeof(DWORD));
bSuccess = CreateProcessAsUser (hNewProcessToken, NULL, szCommandToExecute, ...);

Этот код только схема. EnablePrivilege - это простая функция, используемая AdjustTokenPrivileges для включения привилегии SE_TCB_NAME (см. http://msdn.microsoft.com/en-us/library/aa446619.aspx в качестве шаблона). Важно, чтобы процесс, из которого вы запускаете процесс, имел привилегию TCB, но если ваша служба работает в локальной системе, у вас достаточно разрешений. Кстати, следующий фрагмент кода работает не только с учетной записью Local System, но и учетной записью должна обладать привилегией SE_TCB_NAME, чтобы иметь возможность переключать текущий сеанс сервера терминалов.

Еще одно замечание. В приведенном выше коде мы запускаем новый процесс с той же учетной записью, что и текущий процесс (например, Local System). Вы изменяете код для использования другой учетной записи, например токена пользователя hClient. Важно только иметь primary token. Если у вас есть токен олицетворения, вы можете преобразовать его в основной токен, как показано в коде выше.

В структуре STARTUPINFO, используемой в CreateProcessAsUser, следует использовать lpDesktop = WinSta0 \ Default ".

В зависимости от ваших требований также может потребоваться использовать CreateEnvironmentBlock для создания нового блока среды, который вы будете передавать новому процессу.

Рекомендую также прочитать Как обеспечить, чтобы окно процесса, запущенное Process.Start (ProcessStartInfo), было в фокусе всех форм? , где я опишу, как заставить процесс запускаться на переднем плане рабочий стол пользователя.

4 голосов
/ 30 января 2015

Если это поможет, я столкнулся с подобной проблемой, но хотел получить чистое решение PowerShell.

Я собрал кусочки с других сайтов и придумал следующее:

function Invoke-CommandInSession 
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [ScriptBlock] $expression
    )

    $commandLine = “powershell“

    ## Convert the command into an encoded command for PowerShell
    $commandBytes = [System.Text.Encoding]::Unicode.GetBytes($expression)
    $encodedCommand = [Convert]::ToBase64String($commandBytes)
    $args = “-Output XML -EncodedCommand $encodedCommand”


    $action = New-ScheduledTaskAction -Execute $commandLine -Argument $args
    $setting = New-ScheduledTaskSettingsSet -DeleteExpiredTaskAfter ([Timespan]::Zero)
    $trigger = New-ScheduledTaskTrigger -Once -At ((Get-Date) + ([Timespan]::FromSeconds(5)))
    $task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $setting
    Register-ScheduledTask "Invoke-CommandInSession - $([Guid]::NewGuid())" -InputObject $task
}

Да, это немного странно, но это работает - и самое главное, вы можете позвонить из ps remoting

3 голосов
/ 27 июня 2010

Это может быть сделано, но это не считается хорошей практикой для служб напрямую взаимодействовать с сеансами пользователей, поскольку это может создать серьезные дыры в безопасности.

http://support.microsoft.com/kb/327618

Лучше всего создать 2 программы, бэкэнд-сервис и программу пользовательского интерфейса клиентского интерфейса.Бэкэнд службы выполняется все время и предоставляет свои операции с использованием WCF (например).Клиентская программа может быть запущена при запуске сеанса пользователя.

3 голосов
/ 27 июня 2010

Да, используя CreateProcessAsUser , вы можете сделать это.В MSDN есть примеры статей, и есть несколько предостережений.

0 голосов
/ 08 июля 2016

Подрыв Vista UAC в 32- и 64-разрядных архитектурах

Предоставленный код предназначен для Vista, но работает и для Win7 и Win10

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...