RunAsLoggedOnUser

Ich hatte neulich ein Problem während ich Software an Windows Vista anpassen musste. Wenn die Software per Online Update installiert wird, startet das Setup Programm nach der Installation die Software neu. Dummerweise lief die neu gestartete Software jetzt als Administrator. 🙁

Leider gibt es scheinbar kein API, um direkt ein Programm mit den Rechten der Windows Shell (Explorer.exe) in der aktuellen Logon Session zu starten. Mit der Funktion ShellExecute(~Ex) kann man über das Verb „runas“ zwar einen Prozess als Administrator starten, aber für das Ausführen von Software als User der Logon Session gibt es kein Verb. 😕

Die API Funktion CreateProcessAsUser kann man nicht benutzen, weil der aufrufende Thread das Privileg SE_ASSIGNPRIMARYTOKEN_NAME braucht. Dieses Privileg besitzen aber keine User Prozesse. Nur System Prozesse haben dieses Privileg. 👿

Was also tun?

Microsoft empfiehlt unter Windows Vista die Aufgabenplanung zu benutzen (Beispielcode gibt’s auf tweak-uac.com). Was aber tun, wenn man gar kein Vista hat? Ich selbst habe in meinen Windows 2000 und XP Installationen den Aufgabenplaner Dienst abgeschaltet.

Da man als Administrator läuft, hat man zwar nicht das Recht, CreateProcessAsUser zu benutzen, das können ja nur Dienste tun, aber man hat das Recht einen Dienst zu installieren, zu starten und zu deinstallieren! 💡

Ein Programm kann also folgendes tun:

  • Es besorgt sich die Terminal Server Session ID des Prozesses (ProcessIdToSessionId)
  • Es installiert einen Dienst, der als Kommandozeile die Session ID und den auszuführenden Befehl bekommt. Der Dienst ist das Programm selbst mit spezieller Kommandozeile.
  • Es startet den Dienst, also sich selbst, mit den Rechten des lokalen Systems
  • Der Dienst benutzt StartServiceCtrlDispatcher, RegisterServiceCtrlHandler und SetServiceStatus, um Windows einen realen Diest vorzuspielen.
  • Dann besorgt sich der Dienst den User Token des Shell Prozesses der angegebenen Terminal Server Session
  • Der Dienst benutzt CreateProcessAsUser (was das System ja darf), um den Prozess als Shell User auszuführen. 😀
  • Der Dienst löscht sich selbst

Eine Demo dieser Technik die unter Windows 2000, XP, 2003, Terminal Server und Vista läuft und die (halbwegs dokumentierten) VC6 Quellen gibt’s hier. 🙂

RunAsLoggedOnUser Demo Screenshot

Der Quelltext darf ohne Einschränkung benutzt werden. Ich habe Teile davon selbst von Microsoft Beispielen oder von frei verfügbaren Quellen abgeleitet und hoffentlich keine Lizenzrechte verletzt. 😉 Das Icon ist von foood’s „iCandy Junior“.

7 Reaktionen zu “RunAsLoggedOnUser”

  1. Sven

    Alternativ kann man auch auch ein kleines Bootstrapper-Programm starten, welches dann das Setup-Programm mit erhöhten Rechten aufruft und auf dessen Beendigung wartet. Das anschließend zu startende Programm wird dann vom Bootstrapper gestartet und läuft mit einfachen Rechten. 😉

  2. Kay

    @Sven: Einfach kann jeder 😛 …und das schlägt fehl, wenn der Benutzer den Setup Bootstrap schon „Als Administrator“ ausführt.

    Ich benutze die Token-Klau-Technik u.A. auch in einem Dienst, der für jeden Nutzer ein Tray-Symbol darstellt, über das man den Dienst verwalten kann.

  3. Sven

    Der Bootstrapper wird ja bei Dir direkt aus der Anwendung gestartet (sofern ich es richtig verstanden habe), was schon dafür sorgt, dass er mit den Rechten der Anwendung läuft. Bei meinen Setup-SFXen klappt das ganze jedenfalls wunderbar.

  4. Kay

    Bei Deinen SFXen funktioniert alles prima… solange man nicht mit der rechten Maustate drauf klickt und „Ausführen als“ [Admin] wählt. Dann wird z.B. SpeedCommander als Admin gestartet. Da Dein SFX aber selbst ein „RunAs“ macht, wird keiner auf so blöde Ideen kommen. 🙂

    Die RunAsLoggedOnUser Demo soll nur zeigen, wie man als Admin einen Prozess mit Shell Rechten in der aktuellen Sitzung startet. Ich habe der Einfachheit wegen immer RunAsLoggedOnUser.exe neu gestartet. Das „Wollen sie als anderer Benutzer laufen“ ist nur zum einfachen Umschalten des RunAsLoggedOnUser Bentutzer für die Demo eingebaut. Das sollte kein Bootstrap sein.

    Der eigentliche Dienst wird vollständig über Zeile 408
    „static bool g_ExitProcessIfService = ExitProcessIfService();“ in RunAsLib.cpp vor dem Aufruf von WinMain gehandhabt.
    Deshalb ist RunAsLib sehr einfach zu benutzen.

  5. Olaf Hess

    Hallo Herr Bruns,

    die Klimmzüge können Sie sich vielleicht sparen. Unter
    http://msdn2.microsoft.com/en-us/library/ms972827.aspx
    findet sich ein Artikel „Browsing the Web and Reading E-mail Safely as an Administrator“ der beschreibt, wie man mit den mit XP eingeführten Funktionen „SaferCreateLevel“ sowie „SaferComputeTokenFromLevel“ einem Admin-Token die Rechte nimmt.

    MfG
    Olaf Hess

  6. Thomas Maierhofer

    Hallo ich hab gerade diesen Eintrag gefunden. Wir entwickeln gerade einen Setup Bootstrapper der von RunAsLoggedOnUser profitieren könnte.
    Das Projekt: http://www.codeplex.com/MseItSetupBootstrap/
    Wenn das jemand braucht, bitte einen Feature Request stellen.

    Gruß Tom

  7. Delphi CreateProcessAsUser ERROR_PRIVILEGE_NOT_HELD - Seite 2 - Delphi-PRAXiS

    […] […]

Einen Kommentar schreiben

Time limit is exhausted. Please reload the CAPTCHA.