Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Anwendung aus Dienst heraus starten (https://www.delphipraxis.net/184721-anwendung-aus-dienst-heraus-starten.html)

Captnemo 16. Apr 2015 18:40

Anwendung aus Dienst heraus starten
 
Hi,

ich weiß, das Thema gab es hier schon öfter, aber eine Lösung habe ich bisher nicht gefunden (oder übersehen).

Ich will aus einem Dienst heraus eine Anwendung starten. Mach ich zur Zeit mit ShellExecute was soweit auch funktioniert.

Der Prozess wird zwar gestartet, aber das Window erscheint nicht. Und es scheint auch so, als dass der gestartete Prozess auch nichts macht (wobei ich das noch mal prüfen müsste).

Der Prozess wird natürlich unter dem Konto gestartet, unter dem auch der Dienst läuft. Aber auch wenn ich das auf das Userkonto ändere ändert das nichts an dem Verhalten, außer, dass jetzt die Anwendung auch unter dem Userkonto gestartet wird, aber weiterhin ohne sichtbares Fenster.

Gibt es eine Möglichkeit die Anwendung so zu starten (muß ja nicht mit Shellexecute sein), das das Fenster genauso erscheint, als hätte ich es manuell gestartet?

Der schöne Günther 16. Apr 2015 19:06

AW: Anwendung aus Dienst heraus starten
 
Ist das nicht dieses Häkchen "Datenaustausch zwischen Dienst und Desktop zulassen"? in services.msc?

Bernhard Geyer 16. Apr 2015 19:08

AW: Anwendung aus Dienst heraus starten
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1298060)
Ist das nicht dieses Häkchen "Datenaustausch zwischen Dienst und Desktop zulassen"? in services.msc?

Nicht mehr in supporteden OS-Versionen. Die letzte Version bei der die Checkbox funktionierte war XP.

Captnemo 16. Apr 2015 19:18

AW: Anwendung aus Dienst heraus starten
 
Den Haken gibt's auch nicht mehr....leider.

Bin grad mit einer Batchdatei am testen, aber so richtig klappt das auch nicht. Ich könnt mir natürlich ein kleines Programm in die TBNA legen, welches das dann sicherlich zuverlässig erledigt. Aber ich hatte gehofft noch eine andere (bessere) Lösung zu finden.

Der schöne Günther 16. Apr 2015 19:22

AW: Anwendung aus Dienst heraus starten
 
Also ich weiß nicht, ob es jetzt wirklich ein Dienst sein muss, und ob er nun im Konto SYSTEM laufen soll oder im Benutzerkonto. Gehen tut das schon. Ich habe es bislang aber nur so gemacht dass eine Anwendung auf dem SYSTEM-Konto läuft und die Anwendung dann auf dem Desktop des grade lokal angemeldeten Benutzers aufmacht.


Sieht bei mir so aus:

Delphi-Quellcode:
interface

type
   /// <summary>
   ///     Startet einen Prozess in der Session des grade angemeldeten Users
   /// </summary>
   /// <remarks>
   ///     <para>Muss von einer Anwendung im Kontext von <c>SYSTEM</c> aufgerufen
   ///    werden</para><para>Benötigt Windows Vista oder höher</para>
   ///    <para>Ich habe keine Ahnung wie sich das bei RPD verhält</para>
   /// </remarks>
   TLocalProcessLauncher = class
      protected
         /// <remarks>
         ///     Das zurückgegebene <c>THandle</c> muss, wenn es nicht mehr
         ///    benötigt wird, mit <c>WinApi.Windows.CloseHandle(..)</c>
         ///    geschlossen werden
         /// </remarks>
         /// <summary>
         ///     Liefert das <i>Client Access Token</i> um mittels
         ///    <c>CreateProcessAsUser(..)</c> einen Prozess im Kontext
         ///    der lokal angemeldeten Session starten zu können
         /// </summary>
         /// <exception cref="EOSError" />
         class function createSessionToken(): THandle;

      public
         /// <exception cref="EOSError" />
         class procedure launchProcess(
            const   absolutePath:   String;
            const   arguments:      String   =   ''
         );

   end platform;
und

Delphi-Quellcode:
implementation

uses
  System.IOUtils,
  Winapi.Windows, System.SysUtils;


class function TLocalProcessLauncher.createSessionToken(): THandle;
const
   SE_DEBUG_NAME = 'SeDebugPrivilege';
   desiredAccess: DWORD =
      TOKEN_ADJUST_PRIVILEGES or
      TOKEN_QUERY or
      TOKEN_DUPLICATE or
      TOKEN_ASSIGN_PRIMARY or
      TOKEN_ADJUST_SESSIONID or
      TOKEN_READ or
      TOKEN_WRITE;
var
   sessionID:      DWORD;
   serviceToken:   THandle;
   userToken:      THandle;
   tokenPriv:      TTokenPrivileges;
   luid:         TLargeInteger; //wtf?
begin
   sessionID := WTSGetActiveConsoleSessionId();

   Win32Check(
      OpenProcessToken(
         GetCurrentProcess(),
         desiredAccess,
         serviceToken
      )
   );
   try
      Win32Check( LookupPrivilegeValue(nil, SE_DEBUG_NAME, luid) );
      tokenPriv.PrivilegeCount := 1;
      tokenPriv.Privileges[0].Luid := luid;
      tokenPriv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;

      Win32Check(
         DuplicateTokenEx(
            serviceToken,
            MAXIMUM_ALLOWED,
            nil,
            WinApi.Windows.SecurityIdentification,
            WinApi.Windows.TokenPrimary,
            userToken
         )
      );

      Win32Check( SetTokenInformation(userToken, TokenSessionId, @sessionID, SizeOf(sessionID)) );
   finally
      CloseHandle(serviceToken);
    end;

   Result := userToken;
end;

class procedure TLocalProcessLauncher.launchProcess(const absolutePath, arguments: String);
var
   token:   THandle;
   args:   PChar;

   startupInfo:   TStartupInfo;
   processInfo:   TProcessInformation;
begin
   if arguments.IsEmpty() then args := nil else args := PChar(arguments);

   token := createSessionToken();
   try
      startupInfo := Default(TStartupInfo);
      startupInfo.cb := SizeOf(TStartupInfo);
        startupInfo.lpDesktop := 'winsta0\Default';

      Win32Check(
         CreateProcessAsUser(
            token,
            PChar(absolutePath),
            args,
            nil,
            nil,
            false,
            NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE,
            nil,
            nil,
            startupInfo,
            processInfo
         )
      );

   finally
      CloseHandle(token);
   end;
end;
Man sollte sich aber bewusst sein was das für ein gewaltiges Sicherheitsrisiko ist. Ich habe dafür auch keinen praktischen Anwendungsfall und das nur mal aus Spaß gemacht...

Luckie 16. Apr 2015 19:30

AW: Anwendung aus Dienst heraus starten
 
Das kann mit ShellExecute nicht funktionieren. Dienste laufen in einer anderen Windowstation. Siehe hier: http://michael-puff.de/Programmierun...Stations.shtml

Der schöne Günther 16. Apr 2015 19:38

AW: Anwendung aus Dienst heraus starten
 
Aber wenn er sagt dass sein Service im Kontext des aktuellen Benutzers läuft? Dann unterscheidet er sich doch eigentlich gar nicht von einer normalen Anwendung die der Benutzer gestartet hätte, oder? Warum sollte ShellExecute dann nicht klappen?

Grade kurz ausprobiert, es klappt tatsächlich nicht. Aber warum?

Luckie 16. Apr 2015 19:52

AW: Anwendung aus Dienst heraus starten
 
Ein Dienst läuft unter dem System Konto, welches in einer anderen WindowsStation läuft.

Der schöne Günther 16. Apr 2015 20:02

AW: Anwendung aus Dienst heraus starten
 
Das habe ich verstanden, aber ein Dienst kann doch ebenso gut in einem anderen Kõnto laufen, unter anderem das des grade angemeldeten Benutzers.

Luckie 16. Apr 2015 20:06

AW: Anwendung aus Dienst heraus starten
 
Dann ist es kein Dienst. Dann ist es ein Programm, was einfach beim Anmelden des Benutzers gestartet (Stichwort Autostart) wird und beim Abmelden wieder beendet. Ein Dienst hat ja gerade die Besonderheit, dass er unter dem System Konto läuft und so erweiterte Berechtigungen hat. Zum Beispiel um Updates installieren zu können.

Er könnte mit CreateProcessAsUser aus dem Dienst heraus ein Programm starten, was im Kontext des Benutzers läuft. Dazu braucht es aber dessen Anmeldedaten.

Captnemo 16. Apr 2015 20:42

AW: Anwendung aus Dienst heraus starten
 
Also, es muss ein Dienst (TService) sein.
Aber er kann unter einem beliebigen Benutzerkonto ausgeführt werden.
Das sind die Vorgaben, an die ich mich halten muss (wenn's denn geht)

Aber warum es wenn der Dienst unter einem anderen Benutzer läuft kein Dienst mehr sein soll ist mir nicht klar. Ich kann doch in der Dienst-Konsole für einen Dienst explizit ein Benutzerkonto auswählen (Es gibt ja auch das Recht für Benutzerkonto "Als Dienst anmelden"). Das hat doch dann auch nichts mit Autostart zu tun.
Sprich: ich kann einen Dienst unter meinem Benutzerkonto starten, der auch weiter läuft wenn ich mich abmelde.

Das Programm kann ja auch gestartet werden, laut Taskmanager und es läuft auch unter den gleichen Benutzerkonto laut Taskmanager. Es scheint nur das Problem zu sein, dass das MainWindow sich nicht auf dem Desktop erzeugt.

Anmeldedaten brauch ich dafür eigentlich auch nicht, da diese ja schon in der Dienste-Konsole hinterlegt worden sind.

Luckie 16. Apr 2015 20:44

AW: Anwendung aus Dienst heraus starten
 
Erklär doch mal, was eigentlich der "Dienst" machen soll? Und warum es ein Dienst sein muss.

Captnemo 16. Apr 2015 20:51

AW: Anwendung aus Dienst heraus starten
 
Weil er per TCP Kommandos empfängt, und über die Kommandos dann andere Dienste starten bzw. Neustarten und auch Programme auf dem Desktop des angemeldeten Benutzers.
Programme natürlich nur, wenn ein Benutzer angemeldet ist, aber Dienste auf jeden Fall, auch wenn z.Zt. Kein Benutzer angemeldet ist.

Wenn's nicht geht, dann schreib ich mir halt noch was, das beim Logon des Users als Programm in der TBNA liegt und diese Aufgabe für Programme übernimmt. Ich dachte halt, das es eigentlich gehen sollte.

Stevie 16. Apr 2015 20:59

AW: Anwendung aus Dienst heraus starten
 
Das hier sollte eigentlich alles notwendige erklären:
http://blogs.msdn.com/b/winsdk/archi...and-later.aspx

Luckie 16. Apr 2015 23:17

AW: Anwendung aus Dienst heraus starten
 
Zitat:

The first thing you should do about it is that, don't do it.
Schon da sollte man sich überlegen, ob das gut ist, was man vor hat. Und da habe ich schon aufgehört zu lesen.

Also du hast einen Dienst der Anweisungen über das Netzwerk bekommt und die bestehen unter anderen darin andere Dienste zu starten oder für den angemeldeten Benutzer Programme?

OK, andere Dienste Starten sollte kein Problem sein.

Für den angemeldeten Benutzer schon. Denn für welchen angemeldeten Benutzer? Wenn ich aus dem Startmenü den Menüpunkt "Benutzer wechseln" auswähle, dann sind schon mal zwei oder mehr Benutzer angemeldet. Dann gibt es noch Terminal Sessions. Um es kurz zu machen, es gibt nicht DEN angemeldeten Benutzer.

Captnemo 17. Apr 2015 05:54

AW: Anwendung aus Dienst heraus starten
 
Ja, ihr habt recht. Nach dem Artikel von Stevie ist mir das auch klar, warum. Und die vielen Wiederholungen von den Wörten "Never, no, don't do this, usw" sagen ja auch aus, dass man es wohl tunlichst lassen sollte (aber immerhin auch das es mal theoretisch gehen könne ;) )

Und selbst wenn es doch hinbekommt ist ja zum einen am Sicherheitssystem komplett vorbei und zum anderen würde es bei kommenden Win-Generationen sicherlich wieder Probleme aufwerfen.

Deshalb werde ich mein ursprüngliches Vorhaben verwerfen. Das der Dienst per TCP-Kommando andere Dienste startet funktioniert schon wunderbar. Für das Starten der Programm werde ich den Dienst als Programm kompilieren, der über Autostart in der TBNA schlummert und eben das gleiche für die Programme übernimmt. Ich denke das ist auch eine ganz gute Lösung.

Zitat:

Zitat von Luckie (Beitrag 1298093)
Zitat:

The first thing you should do about it is that, don't do it.
Und da habe ich schon aufgehört zu lesen.

Ja, aber auch nur, weil du den Rest schon auswendig kannst :D
Ich fand ihn sehr informativ, und hab auch den Rest gelesen.

taveuni 17. Apr 2015 12:56

AW: Anwendung aus Dienst heraus starten
 
Es gibt sehr wohl Anwendungen in welchen es Sinn macht aus einem Dienst welcher unter dem Systemkonto läuft Anwendungen im User Kontext zu starten. Das machen unter anderem Remote Access Tools wie Teamviewer. Auch für benutzerspezifische Updates wird das gebraucht. Und: wo soll genau das Sicherheitsproblem in einem selbst erstellten Dienst sein?


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:23 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz