Lanzar un proceso en la sesión del usuario desde un servicio

En Windows Vista / 7/2008 / 2008R2, ¿es posible iniciar un proceso en la sesión de un usuario desde un servicio? Específicamente, la sesión local sería más útil.

Todo lo que he estado leyendo parece decir que esto no es posible, pero pensé que lo haría antes de rendirme por completo.

Estoy codificando en VB.NET, pero tomaré sugerencias en cualquier cosa.

Es realmente posible. El problema principal que tiene es que Windows debe verse como un servidor de terminal y una sesión de usuarios como una sesión remota. Su servicio debería poder iniciar un proceso que se ejecuta en la sesión remota y le pertenece al usuario.

Por cierto, si escribe un servicio que se ejecuta en Windows XP que no se agrega a un dominio y se activa el cambio rápido de usuario, puede tener los mismos problemas para iniciar un proceso en ejecución en el segundo (tercero y así sucesivamente) usuario registrado escritorio

Espero que tengas un token de usuario, que recibes por ejemplo con respecto a la suplantación o tienes un dwSessionId de sesión. Si no lo tiene puede intentar usar alguna función WTS (API de Servicios de Escritorio Remoto http://msdn.microsoft.com/en-us/library/aa383464.aspx , por ejemplo WTSEnumerateProcesses o WTSGetActiveConsoleSessionId ) o LSA-API para averiguar la sesión de usuarios correspondiente ( LsaEnumerateLogonSessions consulte http://msdn.microsoft.com/en-us/library/aa378275.aspx y LsaGetLogonSessionData consulte http://msdn.microsoft.com/en-us/library/aa378290. aspx ) o ProcessIdToSessionId (vea http://msdn.microsoft.com/en-us/library/aa382990.aspx ).

Puede utilizar la función GetTokenInformation con el parámetro TokenSessionId (consulte http://msdn.microsoft.com/en-us/library/aa446671.aspx ) para recibir la sesión id dwSessionId de la sesión de usuarios si conoce el token hClient los usuarios.

 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, ...); 

Este código solo un esquema. EnablePrivilege es una función simple que utiliza AdjustTokenPrivileges para habilitar el privilegio SE_TCB_NAME (ver http://msdn.microsoft.com/en-us/library/aa446619.aspx como plantilla). Es importante que el proceso desde el cual se inicia un proceso tenga privilegio de TCB, pero si su servicio se ejecuta bajo el Sistema local, tiene suficientes permisos. Por cierto, el siguiente fragmento de código funciona no solo con la cuenta del sistema local, sino que la cuenta debe tener el privilegio SE_TCB_NAME para poder cambiar la sesión actual del servidor de la terminal.

Una observación más. En el código anterior, iniciamos un nuevo proceso con la misma cuenta que el proceso actual (por ejemplo, Sistema local). Cambia el cambio de un código para usar otra cuenta, por ejemplo, el token hClient los usuarios. Solo es importante tener un primary token . Si tienes un token de suplantación, puedes convertirlo al token primario exactamente como en el código anterior.

En la estructura STARTUPINFO utilizada en CreateProcessAsUser , debe usar lpDesktop = WinSta0 \ Default “.

Dependiendo de sus requisitos, también podría ser necesario utilizar CreateEnvironmentBlock para crear un nuevo bloque de entorno que pasará al nuevo proceso.

También le recomiendo que lea Cómo asegurarse de que la ventana de proceso iniciada por Process.Start (ProcessStartInfo) tiene el foco de todas las Formas? donde describo cómo forzar que el proceso se inicie en primer plano en el escritorio de los usuarios.

Si ayuda, me enfrenté a un problema similar, pero quería una solución pura de PowerShell.

Arreglé bits de otros sitios web y se me ocurrió esto:

 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 } 

Sí, es un poco raro, pero funciona, y lo más importante es que puedes llamarlo desde dentro.

Se puede hacer, pero no se considera una buena práctica para que los servicios interactúen directamente con las sesiones de los usuarios, ya que puede crear graves problemas de seguridad.

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

Un mejor enfoque es crear 2 progtwigs, un servicio de back-end y un progtwig de interfaz de usuario del cliente front-end. El backend de servicio se ejecuta todo el tiempo y expone sus operaciones usando WCF (por ejemplo). El progtwig cliente podría ejecutarse al inicio de la sesión de un usuario.

Sí, usando CreateProcessAsUser puedes hacer esto. MSDN tiene ejemplos de artículos, y hay algunas advertencias.

Subvertir Vista UAC en Arquitecturas de 32 y 64 bit

El código proporcionado está dirigido a Vista, pero también funciona en Win7 y Win10