2010-06-18 22 views
7

Así que aquí está la primicia:Ejecución de un proceso en la pantalla de bienvenida de Windows 7

escribí una pequeña aplicación de C# hace un tiempo que muestra el nombre de host, dirección IP, fecha fotografiado, el estado de deshielo (usamos DeepFreeze), corriente dominio, y la fecha/hora actual, para mostrar en la pantalla de bienvenida de nuestras máquinas de laboratorio de Windows 7. Esto fue para reemplazar nuestro bloque de información anterior, que se configuró estáticamente en el inicio y en realidad el texto incrustado en el fondo, con algo un poco más dinámico y funcional. La aplicación utiliza un temporizador para actualizar la dirección IP, el estado de congelación profunda y el reloj cada segundo, y comprueba si un usuario ha iniciado sesión y se suicida cuando detecta dicha condición.

Si solo lo ejecutamos, a través de nuestro script de inicio (establecido a través de la política de grupo), mantiene abierta la secuencia de comandos y la máquina nunca llega al indicador de inicio de sesión. Si utilizamos algo así como los comandos start o cmd para iniciarlo en un shell/process separado, se ejecuta hasta que finalice el script de inicio, en cuyo momento Windows parece limpiar todos y cada uno de los procesos secundarios del script. Actualmente podemos evitarlo usando psexec -s -d -i -x para desactivarlo, lo que permite que persista después de que se complete el script de inicio, pero puede ser increíblemente lento, agregando entre 5 segundos y más de un minuto a nuestro tiempo de inicio.

Experimentamos con el uso de otra aplicación C# para iniciar el proceso, a través de la clase Process, utilizando llamadas WMI (Win32_Process y Win32_ProcessStartup) con varios indicadores de inicio, etc., pero todos terminan con el mismo resultado proceso de bloqueo de información siendo asesinado. Intenté volver a escribir la aplicación como un servicio, pero los servicios nunca fueron diseñados para interactuar con el escritorio, y mucho menos con la ventana de inicio de sesión, y hacer funcionar las cosas en el contexto correcto nunca pareció funcionar.

Entonces, para la pregunta: ¿Alguien tiene una buena manera de lograr esto? ¿Iniciar una tarea para que sea independiente del script de inicio y se ejecute en la parte superior de la pantalla de bienvenida?

Respuesta

9

Esto se puede hacer a través de una gran cantidad de llamadas a la API de Win32. Logré obtener un programa con una GUI en el escritorio de Winlogon (antes de que nadie lo pregunte, no es una GUI interactiva). Básicamente, debe ejecutar un proceso de cargador como SISTEMA, que generará el nuevo proceso. Como lo más probable es que desee que este proceso se ejecute al inicio, puede usar el programador de tareas para ejecutar el cargador como SISTEMA o puede usar un servicio para hacer lo mismo. Actualmente estoy usando un servicio, pero traté de usar el programador de tareas y funcionó bien.

Breve resumen:

  1. Grab el proceso Winlogon.exe (como proceso)
  2. Coge la muestra de winlogon usando OpenProcessToken utilizando el .handle del Proceso
  3. Crear un nuevo token y duplicar el token de winlogon al
  4. Elevar los privilegios del token
  5. Cree el proceso usando CreateProcessAsUser, asegurándose de configurar lpDesktop en "Winsta0 \ Winlogon" y utilizando el token que creado.

Código ejemplo:

 // grab the winlogon process 
     Process winLogon = null; 
     foreach (Process p in Process.GetProcesses()) { 
      if (p.ProcessName.Contains("winlogon")) { 
       winLogon = p; 
       break; 
      } 
     } 
     // grab the winlogon's token 
     IntPtr userToken = IntPtr.Zero; 
     if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, out userToken)) { 
      log("ERROR: OpenProcessToken returned false - " + Marshal.GetLastWin32Error()); 
     } 

     // create a new token 
     IntPtr newToken = IntPtr.Zero; 
     SECURITY_ATTRIBUTES tokenAttributes = new SECURITY_ATTRIBUTES(); 
     tokenAttributes.nLength = Marshal.SizeOf(tokenAttributes); 
     SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES(); 
     threadAttributes.nLength = Marshal.SizeOf(threadAttributes); 
     // duplicate the winlogon token to the new token 
     if (!DuplicateTokenEx(userToken, 0x10000000, ref tokenAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, 
      TOKEN_TYPE.TokenImpersonation, out newToken)) { 
      log("ERROR: DuplicateTokenEx returned false - " + Marshal.GetLastWin32Error()); 
     } 
     TOKEN_PRIVILEGES tokPrivs = new TOKEN_PRIVILEGES(); 
     tokPrivs.PrivilegeCount = 1; 
     LUID seDebugNameValue = new LUID(); 
     if (!LookupPrivilegeValue(null, SE_DEBUG_NAME, out seDebugNameValue)) { 
      log("ERROR: LookupPrivilegeValue returned false - " + Marshal.GetLastWin32Error()); 
     } 
     tokPrivs.Privileges = new LUID_AND_ATTRIBUTES[1]; 
     tokPrivs.Privileges[0].Luid = seDebugNameValue; 
     tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
     // escalate the new token's privileges 
     if (!AdjustTokenPrivileges(newToken, false, ref tokPrivs, 0, IntPtr.Zero, IntPtr.Zero)) { 
      log("ERROR: AdjustTokenPrivileges returned false - " + Marshal.GetLastWin32Error()); 
     } 
     PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); 
     STARTUPINFO si = new STARTUPINFO(); 
     si.cb = Marshal.SizeOf(si); 
     si.lpDesktop = "Winsta0\\Winlogon"; 
     // start the process using the new token 
     if (!CreateProcessAsUser(newToken, process, process, ref tokenAttributes, ref threadAttributes, 
      true, (uint)CreateProcessFlags.CREATE_NEW_CONSOLE | (uint)CreateProcessFlags.INHERIT_CALLER_PRIORITY, IntPtr.Zero, 
      logInfoDir, ref si, out pi)) { 
      log("ERROR: CreateProcessAsUser returned false - " + Marshal.GetLastWin32Error()); 
     } 

     Process _p = Process.GetProcessById(pi.dwProcessId); 
     if (_p != null) { 
      log("Process " + _p.Id + " Name " + _p.ProcessName); 
     } else { 
      log("Process not found"); 
     } 
+0

cómo darse cuenta de esto en Win XP? recibo un error de token no válido ... – MariusK

+0

@Fluxer El proceso de inicio de sesión de Windows XP es enormemente diferente al de Vista y superior. XP usó GINA, pero desde Vista hacia arriba, Microsoft reescribió la sección de inicio de sesión para usar CredentialProviders. Espero que esto ayude. –

+0

Recibo el error 1314 cuando trato de ejecutar CreateProcessAsUser. ¿Alguna sugerencia? string lpAppName = @ "D: \ SMU \ Computación ubicua 7390 \ Final Project \ Locker \ Locker \ bin \ Debug \ Locker.exe"; if (! CreateProcessAsUser (newToken, lpAppName, null, ref tokenAttributes, ref threadAttributes, true, (uint) CreateProcessFlags.CREATE_NEW_CONSOLE | (uint) CreateProcessFlags.INHERIT_CALLER_PRIORITY, IntPtr.Zero, null, ref si, out pi)) –

1

Creo que puedes hacerlo, pero es bastante complicado. Normalmente, las aplicaciones interactivas no se pueden ejecutar en la pantalla de bienvenida. En un nivel alto, tendrá que:

  • Crear un servicio de Windows que se inicia automáticamente
  • utilizar el servicio de Windows para crear otro proceso en el actual periodo de sesiones y de escritorio (usando los métodos de Win32 y WTSGetActiveConsoleSessionIdOpenInputDesktop)

Escribí una aplicación que puede interactuar un poco con la pantalla de inicio de sesión, pero no muestra ninguna interfaz de usuario. Probablemente se puede hacer, pero puede ser aún más complicado.

Nota: Descubrí que no pude obtener resultados de OpenInputDesktop de mi servicio de Windows. Tuve que realizar la llamada en el otro proceso y notificar al servicio para reiniciar el proceso en el escritorio correcto.

Espero que al menos pueda comenzar. ¡Buena suerte!

+0

Eso PSEXEC puede hacerlo me dice que su posible, es sólo una cuestión de imitar la forma en que está lanzando lo que supongo. Veré lo que sugirió y veré dónde me llega. – peelman

6

Este es uno de esos "Usted realmente necesita una buena razón para hacer esto" preguntas. Microsoft intenta bloquear las aplicaciones que se ejecutan en la pantalla de inicio: cada código de Windows que interactúa con la pantalla de inicio de sesión se revisa con mucho cuidado porque las consecuencias de seguridad de un error en el código que se ejecuta en la pantalla de inicio de sesión son calamitosas. incluso ligeramente, permitirá que el malware ingrese en la computadora.

¿Por qué quiere ejecutar su programa en la pantalla de inicio de sesión?Quizás haya una forma documentada de hacerlo que no sea tan arriesgada.

+0

Entiendo la paranoia de Microsoft, pero esta es una de esas cosas que me hacen odiar a Windows mucho más. Necesitamos información en la pantalla para una variedad de razones, la mayoría de las cuales son las nuestras. El programa en cuestión no recibe información del usuario, simplemente muestra información. Las probabilidades de que una aplicación de 14k C# sea un riesgo de seguridad no son un problema para nosotros, particularmente cuando tenemos 50,000 usuarios potenciales por máquina. – peelman

+1

¿Puede la información que desea mostrar que se ajuste en un cuadro de mensaje? Windows tiene un mecanismo para mostrar una cadena de texto en un cuadro de mensaje en el momento de inicio de sesión que puede hacer lo que desee. –

+0

Volviendo a mi publicación original, se trata de datos de la máquina para el personal de soporte y operaciones, por lo que no tienen que iniciar sesión en una máquina para verla. Es importante que sea información rápida, siempre disponible. OSX proporciona información similar en la ventana de inicio de sesión, lo que nos ahorra tener que hacer algo similar complicado allí. – peelman

5

traduje el código anterior en C++, si alguien más lo necesita ... Aviso hay referencias a partes de mi código, pero puede ayudar de todos modos:

static bool StartProcess(LPCTSTR lpApplicationPath) 
{ 
    CAutoGeneralHandle hWinlogonProcess = FindWinlogonProcess(); 
    if (hWinlogonProcess == INVALID_HANDLE_VALUE) 
    { 
     DU_OutputDebugStringff(L"ERROR: Can't find the 'winlogon' process"); 
     return false; 
    } 

    CAutoGeneralHandle hUserToken; 
    if (!OpenProcessToken(hWinlogonProcess, TOKEN_QUERY|TOKEN_IMPERSONATE|TOKEN_DUPLICATE, &hUserToken)) 
    { 
     DU_OutputDebugStringff(L"ERROR: OpenProcessToken returned false (error %u)", GetLastError()); 
     return false; 
    } 

    // Create a new token 
    SECURITY_ATTRIBUTES tokenAttributes = {0}; 
    tokenAttributes.nLength = sizeof tokenAttributes; 

    SECURITY_ATTRIBUTES threadAttributes = {0}; 
    threadAttributes.nLength = sizeof threadAttributes; 

    // Duplicate the winlogon token to the new token 
    CAutoGeneralHandle hNewToken; 
    if (!DuplicateTokenEx(hUserToken, 0x10000000, &tokenAttributes, 
      SECURITY_IMPERSONATION_LEVEL::SecurityImpersonation, 
      TOKEN_TYPE::TokenImpersonation, &hNewToken)) 
    { 
     DU_OutputDebugStringff(L"ERROR: DuplicateTokenEx returned false (error %u)", GetLastError()); 
     return false; 
    } 

    TOKEN_PRIVILEGES tokPrivs = {0}; 
    tokPrivs.PrivilegeCount = 1; 

    LUID seDebugNameValue = {0}; 
    if (!LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &seDebugNameValue)) 
    { 
     DU_OutputDebugStringff(L"ERROR: LookupPrivilegeValue returned false (error %u)", GetLastError()); 
     return false; 
    } 

    tokPrivs.Privileges[0].Luid = seDebugNameValue; 
    tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 

    // Escalate the new token's privileges 
    if (!AdjustTokenPrivileges(hNewToken, false, &tokPrivs, 0, nullptr, nullptr)) 
    { 
     DU_OutputDebugStringff(L"ERROR: AdjustTokenPrivileges returned false (error %u)", GetLastError()); 
     return false; 
    } 

    PROCESS_INFORMATION pi = {0}; 
    STARTUPINFO si = {0}; 
    si.cb = sizeof si; 
    si.lpDesktop = L"Winsta0\\Winlogon"; 

    // Start the process using the new token 
    if (!CreateProcessAsUser(hNewToken, lpApplicationPath, nullptr, &tokenAttributes, &threadAttributes, 
     true, CREATE_NEW_CONSOLE|INHERIT_CALLER_PRIORITY, nullptr, nullptr, &si, &pi)) 
    { 
     DU_OutputDebugStringff(L"ERROR: CreateProcessAsUser returned false (error %u)", GetLastError()); 
     return false; 
    } 

    return true; 
} 
Cuestiones relacionadas