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 Ermitteln ob ein Programm oder Prozess ein Dienst ist (https://www.delphipraxis.net/69927-ermitteln-ob-ein-programm-oder-prozess-ein-dienst-ist.html)

Codewalker 22. Mai 2006 14:03


Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Hallo zusammen.

Weiß jemand, wie ich herausfinden kann, ob ein Programm (exe?) oder ein Prozess ein Dienst ist. Ich würde gerne einen Prozess bei beenden neu starten, jedoch muss man ja Programme über CreateProcess und Dienste im Systemkonto mit "net start dienstname" starten. Wie kann man diesen Unterschied automatisch ermitteln?

Angel4585 22. Mai 2006 14:21

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
du könntest versuchen den Dienst oder das Programm mit NET STOP vorher zu beenden, wenn die Meldung kommt der es kein installierter DIenst ist, ist es ein normales Programm.. kA ob des so funzt.

Olli 22. Mai 2006 14:31

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Herausbekommen kann man das mit Sicherheit garnicht richtig (es gibt nämlich auch EXE-Dateien, die sich als Zwitter verhalten). Es gibt aber gewisse Anhaltspunkte:

1. Ist der Elternprozeß SERVICES.EXE?
2. Läuft der Prozeß als SYSTEM?

Es gibt sicher noch mehr. Das Problem ist halt, daß man bei einer Zwitter-EXE es kaum generisch ermitteln kann.

Codewalker 22. Mai 2006 15:52

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Danke, ich werds damit mal versuchen...

Codewalker 26. Mai 2006 16:35

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Zitat:

Zitat von Angel4585
du könntest versuchen den Dienst oder das Programm mit NET STOP vorher zu beenden, wenn die Meldung kommt der es kein installierter DIenst ist, ist es ein normales Programm

Soweit so gut, ich habs mit dem Systemkonto, etc. versucht. Jetzt würde ich für den Zweifelsfall noch gern die Überprüfung mit NET STOP einbauen. Das sollte aber innerhalb meines Programms erfolgen, ohne dass dabei das Konsolenfenster geöffnet wird. Ist das möglich und wenn ja, wir kann ich das Ergebnis von NET STOP abfangen?

Olli 26. Mai 2006 16:59

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Das geht mit den entsprechenden API-Funktionen zum Starten und Stoppen. Anhaltspunkte findest du hier:
http://assarbad.info/en/stuff/tutorials/ntsvc/

Codewalker 13. Aug 2006 19:07

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Für die Forensuche - Die Lösung:

Hilfsfunktion:
Delphi-Quellcode:
function GetUserAndDomainFromPID(ProcessId: DWORD; var User, Domain: String): Boolean;
  { Hilfsfunktion. Ermittelt zu einer PID den Benutzerkontext und die Domäne }
var
  hToken:  THandle;
  cbBuf:   Cardinal;
  ptiUser: PTOKEN_USER;
  snu:     SID_NAME_USE;
  ProcessHandle: THandle;
  UserSize, DomainSize: DWORD;
  bSuccess: Boolean;
begin
  Result := False;
  ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION, False, ProcessId);
  if ProcessHandle <> 0 then
  begin
    if OpenProcessToken(ProcessHandle, TOKEN_QUERY, hToken) then
    begin
      bSuccess := GetTokenInformation(hToken, TokenUser, nil, 0, cbBuf);
      ptiUser := nil;
      while (Not bSuccess) And (GetLastError = ERROR_INSUFFICIENT_BUFFER) do
      begin
        ReallocMem(ptiUser, cbBuf);
        bSuccess := GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, cbBuf);
      end;
      CloseHandle(hToken);

      if Not bSuccess then
      begin
        Exit;
      end;

      UserSize  := 0;
      DomainSize := 0;
      LookupAccountSid(nil, ptiUser.User.Sid, nil, UserSize, nil, DomainSize, snu);
      if (UserSize <> 0) And (DomainSize <> 0) then
      begin
        SetLength(User, UserSize);
        SetLength(Domain, DomainSize);
        if LookupAccountSid(nil, ptiUser.User.Sid, PChar(User), UserSize, PChar(Domain),
          DomainSize, snu) then
        begin
          Result := True;
          User  := StrPas(PChar(User));
          Domain := StrPas(PChar(Domain));
        end;
      end;

      if bSuccess then
      begin
        FreeMem(ptiUser);
      end;
    end;
    CloseHandle(ProcessHandle);
  end;
end;
Eigentliche Funktion:

Delphi-Quellcode:
function IsServiceApp(AppName: String; PID: Integer; var ServiceName: String): Boolean;
{
Überprüft, ob ein Prozess mit der PID ein Dienst ist.
Bedingungen: - Benutzerkonto ist das Systemkonto
             - Service ist in der Registry eingetragen
}
var
  User, Domain: String;
  Reg: TRegistry;
  List: TStringList;
  I:   Integer;
begin
  Result := False;
  GetUserAndDomainFromPID(PID, User, Domain); // Ermittelt den Benutzerkontext
  if User = 'SYSTEM' then
  begin // Programm läuft im Systemkontext... (könnte ein Dienst sein)
    Reg := TRegistry.Create;
    List := TStringList.Create;

    Reg.RootKey := HKEY_LOCAL_MACHINE;
    Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Services\'); // Serviceliste öffnen
    Reg.GetKeyNames(List); // Alle Untereinträge auflisten
    for I := 0 to List.Count - 1 do
    begin
      Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Services\' + List[i]);
      if Reg.ValueExists('ImagePath')
      // Wenn zugehörige Startdatei angegeben... (sonst kann nicht zugeordnet werden über den Prozessnamen)
      then
      begin
        if LowerCase(ExtractFileNameFromSystemPath(Reg.ReadString('ImagePath'))) =
          LowerCase(AppName)
        // Wenn die Dienst-EXE = Prozess-EXE --> Prozess ist ein Dienst
        then
        begin
          Result     := True; // Prozess = Dienst
          ServiceName := List[i]; // Prozessnamen zurückgeben (z.B. "Spooler")
          Break; // Schleife verlassen
        end;
      end;
    end;
    List.Free;
    Reg.Free;
  end;
end;
Funktioniert bis jetzt ohne Probleme, bin aber für Diskussion offen :wink:

Olli 13. Aug 2006 19:57

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Zitat:

Zitat von Codewalker
Funktioniert bis jetzt ohne Probleme, bin aber für Diskussion offen :wink:

<homermäßig>Naaaain :mrgreen:</homermäßig>

1. Punkt: was passiert, wenn einmal der Service-Schlüssel aaa und einmal zzz, beidemale mit dem gleichen ImagePath existieren? Hat ja niemand gesagt, daß man von einer EXE nur eine Instanz als Service laufen lassen kann.
2. Punkt: ImagePath kann auch Parameter enthalten, nicht nur Pfade. Abgesehen davon kann es mal eine Umgebungsvariable und einmal schon "expandierte" Pfade enthalten.
3. Punkt: Warum sollte ein normales Programm nicht auch als SYSTEM laufen können?
4. Punkt: Zuguterletzt Stichwort MSDN-Library durchsuchenImpersonation

Anderes ließe sich noch anführen. So richtig kann man es eben doch nicht rausbekommen. Der Prozeßbaum (Suche nach "svchost") wäre noch eine Alternative, aber auch nicht 100% sicher - schließlich kann ein Dienst auch einen "normalen" Prozeß starten.

Codewalker 14. Aug 2006 13:31

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
okay, okay. 1:0 für Dich, verdammt gute Argumente :wink: . Aber ich hab einen Vorschlag, es zu ändern:

Zitat:

Zitat von Olli
1. Punkt: was passiert, wenn einmal der Service-Schlüssel aaa und einmal zzz, beidemale mit dem gleichen ImagePath existieren? Hat ja niemand gesagt, daß man von einer EXE nur eine Instanz als Service laufen lassen kann.

Okay, aber für die reine Erkennung, ob es ein Dienst ist, tut es da ja auch. Dann kann ich halt nur nicht mit Sicherheit den Dienstnamen ermitteln. Dn könnte man ja in solchen Zweifelsfällen auf einen leeren String setzen bzw. als StringList beide Werte zurückgeben. Außerdem darf die Schleife dann bei einem Fund nicht automatisch abgebrochen werden.

Zitat:

Zitat von Olli
2. Punkt: ImagePath kann auch Parameter enthalten, nicht nur Pfade. Abgesehen davon kann es mal eine Umgebungsvariable und einmal schon "expandierte" Pfade enthalten.

Okay, das lässt sich aber auch noch machen. ExtractFileNameFromSystemPath habe ich selbst geschrieben um Pfad wie %systemdir% und ähnliche aufzulösen. Kann ich bei Gelegenheit gerne posten (hab ich grad nicht zur Hand).

Das könnte man über die Module ermitteln. Bei einem normalen Programm ist das Modul 0 immer das Programm selber. Bei einem Dienst dürfte das doch dann nicht der Fall sein. Siehe auch hier Link am Ende des ersten Posts

Zitat:

Zitat von Olli
4. Punkt: Zuguterletzt Stichwort MSDN-Library durchsuchenImpersonation

Was meinst du damit? :gruebel:

Zitat:

Zitat von Olli
Der Prozeßbaum (Suche nach "svchost") wäre noch eine Alternative, aber auch nicht 100% sicher

Und das sagt mir auch nicht viel.... :gruebel:

Olli 14. Aug 2006 13:53

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Zitat:

Zitat von Codewalker
Okay, aber für die reine Erkennung, ob es ein Dienst ist, tut es da ja auch. Dann kann ich halt nur nicht mit Sicherheit den Dienstnamen ermitteln. Dn könnte man ja in solchen Zweifelsfällen auf einen leeren String setzen bzw. als StringList beide Werte zurückgeben. Außerdem darf die Schleife dann bei einem Fund nicht automatisch abgebrochen werden.

Sicher.

Zitat:

Zitat von Codewalker
Okay, das lässt sich aber auch noch machen. ExtractFileNameFromSystemPath habe ich selbst geschrieben um Pfad wie %systemdir% und ähnliche aufzulösen. Kann ich bei Gelegenheit gerne posten (hab ich grad nicht zur Hand).

Hmm.

Zitat:

Zitat von Codewalker
Das könnte man über die Module ermitteln. Bei einem normalen Programm ist das Modul 0 immer das Programm selber. Bei einem Dienst dürfte das doch dann nicht der Fall sein. Siehe auch hier Link am Ende des ersten Posts

Das müßtest du mir nochmal erklären, wenn es geht.

Zitat:

Zitat von Codewalker
Was meinst du damit? :gruebel:

Ein Thread innerhalb eines Dienstes muß nicht als SYSTEM laufen, auch wenn der Dienst als SYSTEM gestartet wurde. Ergo kann das Token falsch sein, oder schlimmer, du kannst möglicherweise garnicht die Rechte haben um auf Ressourcen zuzugreifen, die du im obigen Code ansprichst.

Zitat:

Zitat von Codewalker
Und das sagt mir auch nicht viel.... :gruebel:

Daß einige Prozesse einen Elternprozeß haben ist dir klar? Für Dienste gibt es normalerweise einen einzigen Elternprozeß (services.exe) unter dem dann andere laufen (svchost.exe für DLL-Services usw.).

Codewalker 14. Aug 2006 14:04

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Zitat:

Zitat von Olli
Das müßtest du mir nochmal erklären, wenn es geht.

Delphi-Quellcode:
function GetExecutableFromPID(dwProcessID: DWord): String;
var
  FSnapshotHandle: THandle;
  FModuleEntry32: TModuleEntry32;
begin
  Result := '';
  begin
    FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessID);
    FModuleEntry32.dwSize := Sizeof(FModuleEntry32);
    Module32First(FSnapshotHandle, FModuleEntry32);
    if FileExists(FModuleEntry32.szExePath) = True then
      Result := FModuleEntry32.szExePath
    else
      Result := '';
    CloseHandle(FSnapshotHandle);
  end;
end;
Ich wollte den Pfad zu einem Prozess ermitteln, um diesen z.B. neu starten zu können. In einem Forum (ich meine DP, bin mir aber nicht sicher) habe ich dann den Tipp gefunden, dass man zu die geöffneten Module auslesen kann. Das erste Modul ist dann immer die Prozessdatei selbst, da diese immer als erste geöffnet werden muss, bevor weitere Module geladen werden können. Bei einem Dienst steht in dort jedoch Speichermüll. So hat man ein weiteres Indiz, ob es sich um einen Dienst handelt.

Zitat:

Zitat von Olli
Ein Thread innerhalb eines Dienstes muß nicht als SYSTEM laufen, auch wenn der Dienst als SYSTEM gestartet wurde. Ergo kann das Token falsch sein, oder schlimmer, du kannst möglicherweise garnicht die Rechte haben um auf Ressourcen zuzugreifen, die du im obigen Code ansprichst.

Zitat:

Zitat von Olli
Daß einige Prozesse einen Elternprozeß haben ist dir klar? Für Dienste gibt es normalerweise einen einzigen Elternprozeß (services.exe) unter dem dann andere laufen (svchost.exe für DLL-Services usw.).

Wie kann ich denn diesen "Elternprozess" ermitteln? Kannst du das ein wenig ausführlicher beschreiben, da endet mein Wissen :oops:

NicoDE 14. Aug 2006 17:45

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Zitat:

Zitat von Codewalker
Weiß jemand, wie ich herausfinden kann, ob ein Programm (exe?) oder ein Prozess ein Dienst ist.

Wenn du die nötigen Rechte hast und das Betriebssystem mindestens Windows 2000 ist, dann mit MSDN-Library durchsuchenEnumServicesStatusEx (in den Strukturen steht u.a. die ID des jeweiligen Prozesses).

Olli 14. Aug 2006 18:17

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Das kommt davon, wenn man (== "ich") zu faul ist ins PSDK zu gucken :roll: :lol: :mrgreen: :zwinker:

Codewalker 15. Aug 2006 06:40

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Zitat:

Das kommt davon, wenn man (== "ich") zu faul ist ins PSDK zu gucken
Ich hab mir die Funktionen in der MSDN mal in Ruhe angesehen kann auch nur sagen: :wall: - Ich werd das mal umsetzen damit ich weiterhin so eine "Durch-die-Brust-ins-Auge"-Funktion nutzen muss, wenn das auch eleganter und besser geht.

NicoDE 15. Aug 2006 09:48

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Kleiner Tipp am Rande: Nimm gleich die Unicode-Variante (ich hab hier einen japanischen Systemdienst der von den meisten ANSI-Programmen nicht angesprochen werden kann).

Olli 16. Aug 2006 00:35

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Zitat:

Zitat von NicoDE
Kleiner Tipp am Rande: Nimm gleich die Unicode-Variante (ich hab hier einen japanischen Systemdienst der von den meisten ANSI-Programmen nicht angesprochen werden kann).

Dieses Problem hätten Sie sich mit einem C/C++ Compiler und #define _UNICODE erspart :stupid:

Harry M. 16. Aug 2006 00:46

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Ich habe jetzte nicht den ganzen Thread gelesen....
Aber möglich wäre zu Testen ob der Pfand des Programmes wo Du wissen möchstes ob es ein Dienst ist oder nicht in der Registry findest bei den Servicen.

Olli 16. Aug 2006 00:52

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Zitat:

Zitat von Harry M.
Ich habe jetzte nicht den ganzen Thread gelesen....
Aber möglich wäre zu Testen ob der Pfand des Programmes wo Du wissen möchstes ob es ein Dienst ist oder nicht in der Registry findest bei den Servicen.

Vergleiche mal folgende Pfade sinnvoll:

%SystemRoot%\System32\\drivers\etc\\..\..\kernel32 .dll

C:\Windows\System32\kernel32.dll

Diverse Funktionen ala GetFullPathName() könnten helfen, aber manches wird IMO nicht aufgelöst.

Dann hätten wir noch \SystemRoot\System32\kernel32.dll ... das ist der Object Manager Namespace ... was nu?

Und das ist ja nur die Spitze des Eisbergs, siehe oben. Registry ist nicht die korrekte Methode. Der Einzige, der weiß welcher Prozeß ein Service ist, ist der SCM.

Harry M. 16. Aug 2006 00:58

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Ja klar ServiceMgr auch wenn ich Registry geschrieben habe. Nur der mach auch nix weiter als dort nach den Infos zu suchen.

NicoDE 16. Aug 2006 09:42

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Zitat:

Zitat von Harry M.
Ich habe jetzte nicht den ganzen Thread gelesen...

Das solltest Du aber :)
Zitat:

Zitat von Harry M.
Aber möglich wäre zu Testen ob der Pfand des Programmes wo Du wissen möchstes ob es ein Dienst ist oder nicht in der Registry findest bei den Servicen.

Obwohl Äpfel und Birnen Obst sind, kann man beides nicht vergleichen. Es gibt einige Module, die in einem Image Dienst(e) und Anwendung vereinen.

ps: ganz davon abgesehen, dass Microsoft die Art der Speicherung jederzeit ändern könnte (unter Vista wurde bereits viel geändert - mit hart-codierten Pfaden kommt man da nicht weit)

Olli 16. Aug 2006 19:03

Re: Ermitteln ob ein Programm oder Prozess ein Dienst ist
 
Zitat:

Zitat von NicoDE
Zitat:

Zitat von Harry M.
Aber möglich wäre zu Testen ob der Pfand des Programmes wo Du wissen möchstes ob es ein Dienst ist oder nicht in der Registry findest bei den Servicen.

Obwohl Äpfel und Birnen Obst sind, kann man beides nicht vergleichen. Es gibt einige Module, die in einem Image Dienst(e) und Anwendung vereinen.

Jawollja:

CmdAsSys wird wie das Programm von dem es abgewandelt wurde (von K. Brown, Name fällt mir nicht ein), als normales Programm installiert, startet dann einen neuen Prozess mithilfe des SCM und beendet die erste Instanz. Die zweite Instanz (im Kontext des SCM) erzeugt dann die Konsole mit SYSTEM-Rechten. Es handelt sich also um eine Art "Zwitter".

Bei Diensten in DLLs wird's dann nochmal etwas knackiger. Aber das geht eh nur auf Systemen, die auch APIs zum Ermitteln der Eigenschaften anbieten, soweit ich das überschauen kann ...


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:24 Uhr.

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