démarrage d'un processus surélevé UAC à partir d'un service non interactif (win32 / .net/powershell)

j'utilise un service Windows de thrid party qui gère certaines tâches d'automatisation en exécutant des scripts et des exécutables en utilisant CreateProcessAsUser(). Je suis en train de rencontrer des problèmes sur Windows Server 2008 en raison de L'UAC et de la façon dont L'élévation de LUA est gérée à travers L'API.

le service fonctionne comme un système local et n'a pas activé" interagir avec le bureau". Les processus sont exécutés en tant qu'utilisateurs dans le groupe des administrateurs, mais pas dans le compte administrateur (qui est exempté de nombreuses UAC). restriction.) Tous les paramètres par défaut UAC en place.

je peux passer des commandes arbitraires ou du code powershell au service, mais je ne peux pas sembler "sortir" du processus Non élevé et non interactif qui est déclenché par le service.

le nœud du problème semble être que la seule option (publique) de L'API pour lancer un processus surélevé est Shellexécute () avec le verbe 'runas', mais pour autant que je puisse dire que cela ne peut pas être appelé à partir d'un service non interactif ou vous obtenez des erreurs telles que "Cette opération nécessite une station windows interactive".

la seule solution que j'ai trouvée est mentionnée ici: http://www.eggheadcafe.com/software/aspnet/29620442/how-to-proper-use-sendinp.aspx

sous Vista, le officiel documentés pour élever un processus est seulement en utilisant le shell API ShellExecute(Ex) (non disponible en français) CreateProcess ou CreateProcessAsUser). Votre demande doit donc appeler Shellexécute (Ex) pour lancer un helper Elevé pour appeler SendInput. En outre, en raison de la Session 0 isolement, un service ne peut utiliser CreateProcessAsUser ou CreateProcessWithLogonW(ne peut pas utiliser Shellexécute (Ex)) pour préciser bureau interactif.

..Je pense qu'il n'y a pas de moyen direct pour frayer un processus élevé à partir d'un service windows. Nous ne pouvons que la première utilisation CreateProcessAsUser ou CreateProcessWithLogonW pour frayer un processus non élevé dans l'utilisateur session (Bureau interactif). Puis dans le processus non élevé, il peut utiliser ShellExecute(Ex) pour frayer un taux élevé de processus pour la vraie tâche.

pour faire cela à partir du code.net/powershell, il semble que je devrais faire quelques trucs élaborés P/Invoke pour appeler CreateProcessAsUser ou CreateProcessWithLogonW depuis le système. Net.Diagnostic.Processstinfo n'a pas d'équivalent de lpDesktop que je pourrais définir à "winsta0default". Et je ne sais pas si LocalSystem a le droit D'appeler CreateProcessAsUser ou CreateProcessWithLogonW.

j'ai aussi regardé http://blogs.msdn.com/alejacma/archive/2007/12/20/how-to-call-createprocesswithlogonw-createprocessasuser-in-net.aspx et Processus.Commencez avec des références différentes avec UAC sur

sur la base de tout cela, j'en arrive à la conclusion qu'il n'y a pas de façon simple de faire cela. Ai-je raté quelque chose? Ce n'est pas vraiment sembler comme il devrait être si dur. C'est comme si UAC n'avait jamais été conçu pour traiter les cas d'utilisation non interactive.

et si Quelqu'un de Microsoft finit par lire ceci, j'ai remarqué que la façon dont ShellExecute gère l'élévation en interne est en appelant au service D'information D'Application (AIS). Pourquoi cet appel à AIS n'est-il pas disponible via une API Win32 ou .NET? http://msdn.microsoft.com/en-us/library/bb756945.aspx

Désolé, qui a couru un peu long. Merci pour toutes les idées.

14
demandé sur Community 2010-03-11 19:11:40

2 réponses

la façon "officielle" de briser l'isolement de session zero est d'utiliser une combinaison de L'API des services terminaux et de CreateProcessAsUser() lancer un processus dans la session d'un utilisateur. À mon ancien travail, nous l'avons fait, car nous avions besoin d'afficher un dialogue à l'utilisateur à partir d'un service avant d'installer une mise à jour téléchargée donc, je sais que cela fonctionne, sur WinXP, Win2K3, Vista, et Win7 au moins, mais je ne m'attends pas à ce que Win 2K8 serait trop différent. Fondamentalement, le processus se déroule comme suit:

  1. Appel WTSGetActiveConsoleSessionId() pour obtenir l'id de session de la console active (très important, car la session interactive est toujours de la session 1, même sur des systèmes client). Cette API renvoie également un -1 s'il n'y a pas d'utilisateur actif connecté dans la session interactive (c'est-à-dire connecté localement à la machine physique, au lieu d'utiliser RDP).
  2. passez l'id de session de l'appel API précédent à WTSQueryUserToken() pour ouvrir une jeton reprents l'utilisateur connecté à la console.
  3. Appel DuplicateTokenEx() pour convertir le jeton d'imitation (de WTSQueryUserToken) dans un jeton principal.
  4. Appel CreateEnvironmentBlock() pour créer un nouvel environnement pour le processus (optionnel, mais si vous ne le faites pas, le processus n'en aura pas).
  5. passer le jeton primaire de l'étape #3 dans un appel à CreateProccessAsUser(), ainsi que la ligne de commande pour l'exécutable. Si vous avez créé un bloc d'environnement à partir de l'étape #4, vous devez passer l' CREATE_UNICODE_ENVIRONMENT drapeau (toujours). Cela peut sembler idiot, mais L'API échoue horriblement si vous ne le faites pas (avec ERROR_INVALID_PARAMTER).
  6. Si vous avez créé un bloc d'environnement, alors vous devez appeler DestroyEnvironmentBlock, sinon vous générerez une fuite de mémoire. Le processus reçoit une copie séparée du bloc d'environnement lors de son lancement, de sorte que vous ne détruisez que des données locales.

Et le tour est joué! Windows fait de la magie interne, et vous voyez le lancement de l'application. Cependant, bien que cela lancera et processus interactif à partir d'un service, Je ne suis pas bien sûr, si elle va contourner UAC (mais ne me citez pas sur ce point). En d'autres termes, il ne peut pas être lancé comme un processus élevé à moins que le registre ou le manifeste interne dit de le faire, et même alors, vous pouvez toujours obtenir une invite UAC. Si le token que vous obtenez de l'étape #3 est un token restreint, vous pouvez être en mesure d'utiliser AdjustTokenPrivileges() pour restaurer le jeton élevé (complet), mais ne me cite pas là-dessus non plus. Cependant, comme indiqué dans les docs MSDN, veuillez noter qu'il n'est pas possible d ' "ajouter" des privilèges sur un jeton qui ne les avait pas déjà (par exemple, vous ne pouvez pas transformer un token utilisateur restreint en administrateur en utilisant AdjustTokenPrivileges; l'utilisateur sous-jacent devrait être un administrateur pour commencer avec).

il est techniquement possible de faire tout cela à partir de Win2K forward. Cependant, il n'est vraiment possible de commencer avec WinXP, car Win2K n'a pas le WTSGetActiveConsoleSessionId() et WTSQueryUserToken() API (avec WTSEnumerateProcesses() pour Win2K Pro). Vous pouvez utiliser le code 0 comme id de session (puisque C'est toujours le cas dans Win2K), et je suppose que vous pourrait être en mesure d'obtenir le jeton utilisateur en énumérant les processus en cours d'exécution et en dupliquant un de leurs jetons (il devrait être celui qui a la SID interactive présente). Peu importe, le CreateProcessAsUser() se comportera de la même façon lorsque vous passez un token utilisateur interactif, même si vous ne sélectionnez pas "interagir avec le bureau" dans les paramètres de service. Il est aussi plus sûr que de lancer directement depuis le service de toute façon, car le processus n'héritera pas du divin LocalSystem jeton d'accès.

Maintenant, Je Je ne sais pas si votre application tierce fait tout cela quand elle exécute le script/processus, mais si vous voulez le faire à partir d'un service, c'est comme ça (et avec Vista ou Win7, c'est la seule façon de surmonter l'isolement de la session 0).

16
répondu Javert93 2011-08-23 10:45:20

selon votre cas d'utilisation, vous pourriez faire ce que je fais. Je traque le processus winlogon pour la session active et voler son jeton. S'il n'y a pas de session active (API renvoyée -1), Utilisez 1 si WINVER >= 6 sinon 0. Il en résulte un système sur la session active.

1
répondu Joshua 2013-07-03 19:05:44