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/)
-   -   CommandLines der Prozesse unter Windows 64 Bit ermitteln? (https://www.delphipraxis.net/181736-commandlines-der-prozesse-unter-windows-64-bit-ermitteln.html)

Delphi-Laie 5. Sep 2014 17:41

CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Hallo Delphifreunde!

Kennt Ihr eine einfache und stabile Möglichkeit, die CommandLines aller (oder zumindest der meisten) Prozesse anhand deren Prozeß-IDs unter 64 Bit zu ermitteln? Debugrechte sind natürlich vorausgesetzt und erfolgreich angefordert, zumal das Compilat natürlich auch 64 Bit hat (mit XE2 erstellt).

Ich fand im Internet zwei recht ähnliche Delphi-Lösungen, die beide auf der kombinierten Anwendung der NTQueryProcessInformation- und ReadProcessMemory-Funktion beruhen und unter Windows 32 Bit wie gewünscht funktionieren (Abrufen der Process Basic Information). Unter Windows 7 64 Bit funktionert es jedoch nicht, nicht mal mit dem eigenen Prozeß (Prozeß-ID des eigenen Programmes). Zwar konnte ich mich ein wenig vorarbeiten (Integerwerte auf 64 Bit erweitert), doch bis zum erfolgreichen Ermitteln der Kommandozeile reicht es nie, an irgendeinem der wiederholten ReadProcessMemory-Aufrufe scheitert es regelmäßig. Natürlich lasse ich mir GetLastError ausgeben, doch für mehr als dem "Aufbohren" der Bitanzahl der Integerwerte reichten die Meldungen mir nicht.

Ehe ich hier beide Zwischenergebnisse ausgieße, einfach die Fragen:

1. Ist das Ermitteln der Kommandozeilen unter Windows 64 Bit überhaupt möglich, insbesondere mit den genannten API-Funktionen?
2. Gibt es ggf. eine recht simple Variante zur Ermittlung der jeweiligen Kommandozeile, die stabil und bitanzahlunabhängig funktioniert?

Ich vermute, daß der Process Environment Block (PEB) unter 64 Bit grundsätzlich anders gestaltet ist (s. http://stackoverflow.com/questions/5...extern-process ) und daß das der Hauptgrund ist, warum man nicht einfach für 32 und 64 Bit weitgehend gleiche Quelltexte nehmen kann.

Vielen Dank im voraus für Eure Aufmerksamkeit!

Delphi-Laie

jaenicke 5. Sep 2014 21:02

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Du kannst einfach die Spalte CommandLine aus der WMI Klasse Win32_Process nutzen:
http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx
Anders machen das andere Tools auch meistens nicht.

Delphi-Laie 7. Sep 2014 17:35

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Hallo Sebastian, besten Dank für Deine Antwort!

WMI erfordert, soweit ich mich schlaugelesen habe, auf NTx das Laufen des Windows-Verwaltungsinstrumentations-Dienstes (WinMgmt.exe). Daher sympathisiere ich nicht so sehr mit dieser Lösung.

Für alle, die es interessiert, hier die beiden Funktionen, die als 32-Bit-Compilate für 32-Bit-Prozesse funktionieren (die Integervariablen müssen dann auf 32 Bit reduziert werden). Bei 64 Bit scheitert es immer an irgendeinem der wiederholten ReadProcessMemory-Aufrufe.
Delphi-Quellcode:

implementation

NtQueryInformationProcess:function(ProcessHandle:THandle;ProcessInformationClass:UInt64{DWORD};ProcessInformation:Pointer;ProcessInformationLength:ULONG;ReturnLength:PULONG):LongInt;stdcall=nil;

type UNICODESTRING=record
  Length,MaximumLength:UInt64;//Word;
  Buffer:PWideChar;
  end;

type PROCESS_BASIC_INFORMATION=packed record
  ExitStatus:{U}Int64;//DWORD;
  PebBaseAddress:Pointer;
  AffinityMask,BasePriority,UniqueProcessId,InheritedUniquePID:{U}Int64;//DWORD;
  end;

  function getcommandline1(PID:dword):string;
  label 0;
   var
    PBI:PROCESS_BASIC_INFORMATION;
    CommandLine:UNICODESTRING;
    lib:THandle;
    ReturnLength:NativeUInt;//Cardinal;
  begin
  hProcess:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,false,pe.th32ProcessID);
  if hProcess<>invalid_handle_value then
    begin
    lib:=Loadlibrary('ntdll.dll');
    if lib<>0 then
      begin
      NtQueryInformationProcess:=GetProcAddress(lib,'NtQueryInformationProcess');
      if (NtQueryInformationProcess(hProcess,0{=>ProcessBasicInformation},@PBI,sizeof(PBI),@ReturnLength)=0{STATUS_SUCCESS}) {and (ReturnLength=SizeOf(PBI))} then
        begin
        if not ReadProcessMemory(hProcess,Pointer({U}Int64(PBI.PEBBaseAddress)+OffsetProcessParametersx32),@rtlUserProcAddress,sizeof(Pointer),ReturnLength) then
          begin
          result:='1. '+SysErrorMessage(GetLastError);
          goto 0
          end;
        if not ReadProcessMemory(hProcess,Pointer({U}Int64(rtlUserProcAddress)+OffsetCommandLinex32),@CommandLine,sizeof(CommandLine),ReturnLength) then
          begin
          result:='2. '+SysErrorMessage(GetLastError);
          goto 0
          end;
        SetLength(CommandLineContents,CommandLine.length);
        if not ReadProcessMemory(hProcess,CommandLine.Buffer,@CommandLineContents[1],CommandLine.Length,ReturnLength) then
          begin
          result:='3. '+SysErrorMessage(GetLastError);
          goto 0
          end;
        result:=WideCharLenToString(PWideChar(CommandLineContents),CommandLine.length div 2);
        end else result:='NTQueryInformationProcess gescheitert: '+SysErrorMessage(GetLastError);
     
      0:Freelibrary(lib)
      end;
    CloseHandle(hProcess)
    end
  end;

  function getcommandline2(PID:dword):string;
  label 0;
  var ProcessHandle:THandle;
  rtlUserProcAddress,PMBAddress:Pointer;
  command_line:UnicodeString;
  command_line_contents:WideString;
  ReturnLength:NativeUInt;//Cardinal;

    function GetPEBAddress(inhandle:THandle):pointer;
    var pbi:PROCESS_BASIC_INFORMATION;
    MyHandle:THandle;
    myFunc:procedure(ProcessHandle:THandle;
                     ProcessInformationClass:DWord;
                     ProcessInformation:Pointer;
                     ProcessInformationLength:DWord;
                     ReturnLength:Pointer);stdcall;
    begin
    MyHandle:=LoadLibrary('NTDLL.DLL');
    if MyHandle<>0 then
      begin
      myfunc:=GetProcAddress(myHandle,'NtQueryInformationProcess');
      if @myfunc<>nil then MyFunc(inhandle,0{=>ProcessBasicInformation},@pbi,sizeof(pbi),nil);
      FreeLibrary(Myhandle)
      end;
    Result:=pbi.PEBBaseAddress
    end;

  begin
  ProcessHandle:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ,false,PID);
  if ProcessHandle<>invalid_handle_value then
    begin
    PMBAddress:=GetPEBAddress(ProcessHandle);
    if not ReadProcessMemory(ProcessHandle,Pointer(int64(PMBAddress)+OffsetProcessParametersx32),@rtlUserProcAddress,sizeof(Pointer),ReturnLength) then
      begin
      result:='1. '+SysErrorMessage(GetLastError);
      goto 0
      end;
  if not ReadProcessMemory(ProcessHandle,Pointer(Longint(rtlUserProcAddress)+OffsetCommandLinex32),@command_line,sizeof(command_line),ReturnLength) then
      begin
      result:='2. '+SysErrorMessage(GetLastError);
      goto 0
      end;
    SetLength(Command_Line_Contents,command_line.length);ReadProcessMemory(ProcessHandle,command_Line.Buffer,@command_Line_contents[1],command_line.length,ReturnLength);
    Result:=WideCharLenToString(PWideChar(command_Line_Contents),command_line.length div 2);
   
    0:CloseHandle(ProcessHandle)
    end else result:='Kein gültiges Prozeßhandle '+SysErrorMessage(GetLastError);
  end;

Bernhard Geyer 7. Sep 2014 18:04

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1271465)
WMI erfordert, soweit ich mich schlaugelesen habe, auf NTx das Laufen des Windows-Verwaltungsinstrumentations-Dienstes (WinMgmt.exe). Daher sympathisiere ich nicht so sehr mit dieser Lösung.

Und was stört genau daraun? Ich denke bei 99,99% der Windows-Rechner wird dieser Dienst laufen. Bei den restlichen 0,01% werden eh andere Probleme haben als dein Programm auszuführen.

jaenicke 7. Sep 2014 18:42

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1271465)
WMI erfordert, soweit ich mich schlaugelesen habe, auf NTx das Laufen des Windows-Verwaltungsinstrumentations-Dienstes (WinMgmt.exe). Daher sympathisiere ich nicht so sehr mit dieser Lösung.

Deine Lösung bewirkt ggf., dass dein Programm als Virus eingestuft wird. Zudem funktioniert sie nicht mit Adminprozessen, wenn sie ohne Adminrechte gestartet ist, die Lösung via WMI schon.

WMI ist ein Grundbestandteil von Windows, ohne läuft nicht einmal die Windows Firewall...

Delphi-Laie 7. Sep 2014 20:36

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Das Anfordern maximaler Privilegien, das ich schrieb, setzt natürlich Administrationsrechte voraus, das ist mir klar.

Ich bin jetzt auch inzwischen soweit (also breitgeschlagen), daß ich mich mit WMI näher und mich mit den beiden o.g. auf 64 Bit "aufgebohrten" Funktionen nicht mehr beschäftigen werde. Nochmals danke für diesen Anstoß!

Unter Windows 2000 und XP ist der Instrumentationsdienst für mich ein Fremdkörper und gehört zu denen, die ich deaktiviere, und fahre damit immer recht gut (der Router "firewallt" ja ohnehin). Bei neueren Windows, und mir geht es ja um 64 Bit, ließ ich ihn bisher in Ruhe, wird ja dann auch in die svchost.exe verpackt.

Zacherl 9. Sep 2014 07:24

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Ursache des Problems ist folgende:
Zitat:

Zitat von http://winprogger.com/getmodulefilenameex-enumprocessmodulesex-failures-in-wow64/
PEB of the process is obviously found in PebBaseAddress. However the PEB of a 64-bit process lies at a 64-bit address and since PROCESS_BASIC_INFORMATION for 32-bit applications only has space for 32-bit pointer, how can the 64Bit PEB address be returned to a 32-bit application ? If the 64-bit PEB had no high bits set, then technically the 64-bit PEB address could fit into 32-bits without losing any of the address bits. wow64 solves this problem simply by setting PebBaseAddress to NULL in all cases.

Now, wow64 translation is needed in this case since the 64-bit structure members would have to be downsized to fit in 32-bit PROCESS_BASIC_INFORMATION structure. [32-bit PROCESS_BASIC_INFORMATION is 24 bytes where as 64-bit PROCESS_BASIC_INFORMATION is 48 bytes]

Since NtQueryInformationProcess returns success despite this loss of PEB data in the wow64 translation layer, GetModuleFileNameEx in 32-bit process eventually ends up attempting to read invalid memory in the opened process, when it calls ReadProcessMemory (or more specifically NtReadVirtualMemory) with offsets from NULL PEB returned. This causes error 299 (ERROR_PARTIAL_COPY).

Ich weiß nicht genau, ab welcher Version von Windows diese Funktionen implementiert wurden, aber schau dir mal NtWow64QueryInformationProcess64 und NtWow64ReadVirtualMemory64 aus der ntdll.dll an.

Delphi-Laie 9. Sep 2014 12:14

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Ich staune immer wieder, was manche Genies im Internet aufzustöbern imstande sind.

Vielen Dank, Zacherl!

Zacherl 9. Sep 2014 12:27

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1271815)
Ich staune immer wieder, was manche Genies im Internet aufzustöbern imstande sind.

Hatte mich vor einiger Zeit mal mit dem Thema beschäftigt, deshalb wusste ich wonach ich suchen musste (ERROR_PARTIAL_COPY) :D Hier gibts übrigens Prototypen zu den genannten Funktionen und auch etwas fertigen Code zum Auslesen des PEBs zwecks Modul Enumeration.

Delphi-Laie 14. Sep 2014 15:44

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Hallo Zacherl, nur allein das Nachvollziehen das von Dir verlinkten Beispielprogrammes ist ein nachmittagsfüllendes Programm, das leider bisher im Versuch steckenblieb. Es scheitert an den Units, die für das Programm benötigt werden. Bis zur NcxTypes.pas konnte ich alle Units besorgen (JEDI bzw. letztere, die NcxTypes von Luckies Internetseite). Die beiden Units NcxNtDef.pas und NcxNtTeb.pas konnte ich nicht auftreiben.

Darf ich Dich deshalb fragen, ob Du das Beispielprogramm selbst einmal zum Laufen brachtest, und, falls ja, woher Du die beiden letztgenannten Units bezogst?

Danke und Gruß

Delphi-Laie

Zacherl 14. Sep 2014 16:29

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1272540)
Darf ich Dich deshalb fragen, ob Du das Beispielprogramm selbst einmal zum Laufen brachtest, und, falls ja, woher Du die beiden letztgenannten Units bezogst?

Leider nein :( Welche Deklarationen fehlen denn ohne die beiden Units? Vielleicht kann man die Klassen aus anderen Quellen rekonstruieren.

Delphi-Laie 14. Sep 2014 17:02

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Zacherl (Beitrag 1272545)
Welche Deklarationen fehlen denn ohne die beiden Units? Vielleicht kann man die Klassen aus anderen Quellen rekonstruieren.

Danke für Deine Hilfsbereitschaft!

Ohne die beiden letztgenannten Units geht es in der Zeile

Delphi-Quellcode:
function GetPeb32(ph : THandle; var PEB : TPeb32):Boolean;


los, dort findet der Compilter den Typ TPeb32 nicht, dito weiter unten mit TPeb64.

Weiter geht es mit
Delphi-Quellcode:
Function PEB32ProcName(ph : THandle; Base:boolean):String;

var PEB        : TPeb32;
  LdrData      : TPebLdrData32;
  LdrModule    : TLdrDataTableEntry32;
dort findet er den 2. und 3. Typ der var-Listung nicht.

Die paar anderen Kleckermeldungen gehen anscheinend darauf zurück, daß diese Typen unbekannt sind.

Nochmals besten Dank und viele Grüße

Delphi-Laie

jaenicke 14. Sep 2014 17:37

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Du findest Nicos Units hier:
http://www.bendlins.de/nico/delphi/NcxWOW64.zip

// EDIT:
Ich habe die Datei mal angehängt, da das laut Lizenz erlaubt ist.

Delphi-Laie 14. Sep 2014 17:47

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Sebastian, Du bist ein Schatz! Ich suchte direkt nach den Unit-Dateinamen und war damit natürlich nicht erfolgreich.

Nochmals besten Dank Euch beiden!

jaenicke 14. Sep 2014 18:54

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1272555)
Ich suchte direkt nach den Unit-Dateinamen und war damit natürlich nicht erfolgreich.

Habe ich auch:
Bei Google suchenNcxNtDef
erstes Ergebnis, ganz unten:
http://www.ic0de.org/archive/index.php/t-10798.html
;-)

Delphi-Laie 14. Sep 2014 19:58

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Wie auch immer, ich kam bei der Suche jedenfalls nicht bis zum gewünschten Ziele.

Ich staune immer wieder, wie viele im Internet veröffentlichte Quelltexte mir Probleme bereiten, hier das von Zacherl verlinkte Beispielprogramm.

Hier meine Erfahrungen mit XE2:

1. Die Compilerdirektive {$IFDEF CPU64} erzeugte merkwürdige Fehler im {$Else}-Zweig (nachdem die 32-Bit-Compilierung fehlerfrei klappte!). Alle durch {$IFDEF WIN64} ersetzt, danach schien XE2 verstanden zu haben, was gemeint ist, denn es flutschte darauhin durch die 64-Bit-Abteilungen.

2. Einige wenige Typumwandlungen von Pointer nach einen Integertyp oder umgekehrt waren noch nötig. Dann war endlich auch das erste 64-Bit-Compilat erzeugt.

3. Programmstart: Der Prozedureinsprungspunkt einer der beiden Funktionen wurde nicht gefunden. Das wundert mich nicht, denn durch den Dependency Walker wußte ich schon, daß in der gewöhnlichen ntdll.dll die Funktionen NtWow64QueryInformationProcess64 und NtWow64ReadVirtualMemory64 gar nicht enthalten sind. Also explizit die ntdll.dll im syswow64-Pfad angegeben. Dann wurden die Funktionen gefunden, weil diese Fehlermeldung entfiel, dafür gab es aber auch wieder gleich zum Programmstart eine andere Fehlermeldung, nämlich daß die Anwendung nicht korrekt gestartet werden kann (inkl. einer Binäradresse). Das gleiche Verhalten hatte ich auch schon mit meinem ursprünglichen Programm, das die Kommandozeile unter 64 Bit abzufragen versuchte.

Von PEB unter 64 Bit lasse ich nunmehr definitiv ab und werde mich deshalb nun der WMI-Lösung meiner ursprünglichen Frage zuwenden.

Nochmals danke Euch beiden für Eure Hilfsbereitschaft und Geduld mit mir!

jaenicke 14. Sep 2014 21:17

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1272565)
Das wundert mich nicht, denn durch den Dependency Walker wußte ich schon, daß in der gewöhnlichen ntdll.dll die Funktionen NtWow64QueryInformationProcess64 und NtWow64ReadVirtualMemory64 gar nicht enthalten sind. Also explizit die ntdll.dll im syswow64-Pfad angegeben.

Das kann nicht funktionieren, denn die DLL unter SysWOW64 ist eine 32-Bit DLL. In einem 64-Bit Prozess kann diese nicht funktionieren.

Eigentlich sind die Funktionen auch dafür gedacht, dass du aus einem 32-Bit Programm auf die Informationen eines 64-Bit Programms zugreifen kannst.

Zacherl 14. Sep 2014 22:46

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Das Problem mit den fehlenden Imports kann ich auch nicht nachvollziehen. Habe mal ein bisschen rumgespielt:
Delphi-Quellcode:
const
  {$IFDEF WIN32}
  OFFSET_PROCESSPARAMETERS     = $10;
  OFFSET_COMMANDLINE           = $40;
  {$ELSE}
  OFFSET_PROCESSPARAMETERS     = $20;
  OFFSET_COMMANDLINE           = $70;
  {$ENDIF}
  OFFSET_PROCESSPARAMETERSWOW64 = $20;
  OFFSET_COMMANDLINEWOW64       = $70;

function GetProcessCommandLineFromPEB(hProcess: THandle): String;
var
  Status: NTSTATUS;
  ReturnLength: UInt64;
  ProcessInfo: TProcessBasicInformation;
  ProcessParametersPointer: NativeUInt;
  CommandLine: TUnicodeString;
  {$IFDEF WIN32}
  IsWow64: BOOL;
  Wow64ProcessInfo: TWow64ProcessBasicInformation64;
  Wow64CommandLine: TWow64UnicodeString64;
  Wow64ProcessParametersPointer: UInt64;
  {$ENDIF}
begin
  Result := 'ERROR';
  {$IFDEF WIN32}
  if (not IsWow64Process(hProcess, IsWow64)) then
  begin
    RaiseLastOSError;
  end;
  if (not IsWow64) then
  begin
    // Query PEB base address
    Status := NtWow64QueryInformationProcess64(hProcess, ProcessBasicInformation,
      @Wow64ProcessInfo, SizeOf(Wow64ProcessInfo), @ReturnLength);
    if ((not NT_SUCCESS(Status)) or (ReturnLength <> SizeOf(Wow64ProcessInfo))) then
    begin
      RaiseLastOSError(RtlNtStatusToDosError(Status));
    end;
    // Read the ProcessParameters pointer
    Status := NtWow64ReadVirtualMemory64(hProcess, Wow64ProcessInfo.PebBaseAddress +
      OFFSET_PROCESSPARAMETERSWOW64, @Wow64ProcessParametersPointer,
      SizeOf(Wow64ProcessParametersPointer), @ReturnLength);
    if ((not NT_SUCCESS(Status)) or (ReturnLength <> SizeOf(Wow64ProcessParametersPointer))) then
    begin
      RaiseLastOSError(RtlNtStatusToDosError(Status));
    end;
    // Read the CommandLine UNICODE_STRING
    Status := NtWow64ReadVirtualMemory64(hProcess, Wow64ProcessParametersPointer +
      OFFSET_COMMANDLINEWOW64, @Wow64CommandLine, SizeOf(Wow64CommandLine), @ReturnLength);
    if ((not NT_SUCCESS(Status)) or (ReturnLength <> SizeOf(Wow64CommandLine))) then
    begin
      RaiseLastOSError(RtlNtStatusToDosError(Status));
    end;
    // Read the actual commandline
    SetLength(Result, Wow64CommandLine.Length div SizeOf(Result[1]));
    Status := NtWow64ReadVirtualMemory64(hProcess, Wow64CommandLine.Buffer,
      @Result[1], Wow64CommandLine.Length, @ReturnLength);
    if ((not NT_SUCCESS(Status)) or (ReturnLength <> Wow64CommandLine.Length)) then
    begin
      RaiseLastOSError(RtlNtStatusToDosError(Status));
    end;
    Exit;
  end;
  {$ENDIF}
  // Query PEB base address
  Status := NtQueryInformationProcess(hProcess, ProcessBasicInformation,
    @ProcessInfo, SizeOf(ProcessInfo), @ReturnLength);
  if ((not NT_SUCCESS(Status)) or (ReturnLength <> SizeOf(ProcessInfo))) then
  begin
    RaiseLastOSError(RtlNtStatusToDosError(Status));
  end;
  // Read the ProcessParameters pointer
  Status := NtReadVirtualMemory(hProcess, Pointer(NativeUInt(ProcessInfo.PebBaseAddress) +
    OFFSET_PROCESSPARAMETERS), @ProcessParametersPointer, SizeOf(ProcessParametersPointer),
    @ReturnLength);
  if ((not NT_SUCCESS(Status)) or (ReturnLength <> SizeOf(ProcessParametersPointer))) then
  begin
    RaiseLastOSError(RtlNtStatusToDosError(Status));
  end;
  // Read the CommandLine UNICODE_STRING
  Status := NtReadVirtualMemory(hProcess, Pointer(NativeUInt(ProcessParametersPointer) +
    OFFSET_COMMANDLINE), @CommandLine, SizeOf(CommandLine), @ReturnLength);
  if ((not NT_SUCCESS(Status)) or (ReturnLength <> SizeOf(CommandLine))) then
  begin
    RaiseLastOSError(RtlNtStatusToDosError(Status));
  end;
  // Read the actual commandline
  SetLength(Result, CommandLine.Length div SizeOf(Result[1]));
  Status := NtReadVirtualMemory(hProcess, CommandLine.Buffer, @Result[1], CommandLine.Length,
    @ReturnLength);
  if ((not NT_SUCCESS(Status)) or (ReturnLength <> CommandLine.Length)) then
  begin
    RaiseLastOSError(RtlNtStatusToDosError(Status));
  end;
end;
Zusätzlich brauchst du folgende Definitionen:
Delphi-Quellcode:
type
  NTSTATUS = LongInt;
  HANDLE  = THandle;

// Set struct alignment and enum size for C compatibility
{$IFDEF WIN32}
  {$A4}
{$ELSE}
  {$A8}
{$ENDIF}
{$Z4}
type
  TProcessInfoClass = (
    ProcessBasicInformation,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort,
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers,
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    ProcessDeviceMap,
    ProcessSessionInformation,
    ProcessForegroundInformation,
    ProcessWow64Information,
    ProcessImageFileName,
    ProcessLUIDDeviceMapsEnabled,
    ProcessBreakOnTermination,
    ProcessDebugObjectHandle,
    ProcessDebugFlags,
    ProcessHandleTracing,
    MaxProcessInfoClass);

type
  TProcessBasicInformation = record
    ExitStatus: Cardinal;
    PebBaseAddress: PVOID;
    AffinityMask: NativeUInt;
    BasePriority: NativeUInt;
    UniqueProcessId: NativeUInt;
    InheritedFromUniqueProcessId: NativeUInt;
  end;
{$IFDEF WIN32}
  TWow64ProcessBasicInformation64 = record
    ExitStatus: Cardinal;
    Pad1: DWord;
    PebBaseAddress: UInt64;
    AffinityMask: UInt64;
    BasePriority: Cardinal;
    Pad2: DWord;
    UniqueProcessId: UInt64;
    InheritedFromUniqueProcessId: UInt64;
  end;
{$ENDIF}

  TUnicodeString = record
    Length: USHORT;
    MaximumLength: USHORT;
    Buffer: Pointer;
  end;
{$IFDEF WIN32}
  TWow64UnicodeString64 = record
    Length: USHORT;
    MaximumLength: USHORT;
    Pad1: DWord;
    Buffer: UInt64;
  end;
{$ENDIF}

{$IFDEF WIN32}
function NtWow64QueryInformationProcess64(ProcessHandle: HANDLE;
  ProcessInformationClass: TProcessInfoClass; ProcessInformation: PVOID;
  ProcessInformationLength: ULONG; ReturnLength: PUInt64): NTSTATUS; stdcall; external 'ntdll.dll';
function NtWow64ReadVirtualMemory64(ProcessHandle: HANDLE; BaseAddress: UInt64; Buffer: Pointer;
  BufferLength: UInt64; ReturnLength: PUInt64): NTSTATUS; stdcall; external 'ntdll.dll';
{$ENDIF}

function NtQueryInformationProcess(ProcessHandle: HANDLE;
  ProcessInformationClass: TProcessInfoClass; ProcessInformation: PVOID;
  ProcessInformationLength: ULONG; ReturnLength: PULONG): NTSTATUS; stdcall; external 'ntdll.dll';
function NtReadVirtualMemory(ProcessHandle: HANDLE; BaseAddress : PVOID; Buffer: PVOID;
  BufferLength: ULONG; ReturnLength: PULONG): NTSTATUS; stdcall; external 'ntdll.dll';
function RtlNtStatusToDosError(Status: NTSTATUS): ULONG; stdcall; external 'ntdll.dll';

function NT_SUCCESS(Status: NTSTATUS): BOOL;
begin
  Result := Status >= 0;
end;
Und der Aufruf wäre z.b. so:
Delphi-Quellcode:
procedure TForm2.Button1Click(Sender: TObject);
var
  hProcess: THandle;
begin
  hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_OPERATION or PROCESS_VM_READ,
    false, 3000);
  if (hProcess <> 0) then
  try
    MessageBox(0, PChar(GetProcessCommandlineFromPEB(hProcess)), 'Info', MB_ICONINFORMATION);
  finally
    CloseHandle(hProcess);
  end;
end;

hoika 15. Sep 2014 07:27

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Hallo,

müssen das nicht packed records sein,
oder ist das Alignment in den Records irgendwie geändert worden?


Heiko

Zacherl 15. Sep 2014 09:08

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von hoika (Beitrag 1272589)
müssen das nicht packed records sein,
oder ist das Alignment in den Records irgendwie geändert worden?

Nein, ganz im Gegenteil DÜRFEN die Records sogar auf keinen Fall packed sein. So ziemlich jede Windows API Library, die ich kenne wird mit einem Struct Alignment von 4 (bzw. 8 Byte unter 64 Bit) kompiliert.
Hatte damit früher schon einigen Ärger, deshalb bin ich dazu übergegangen immer explizit {$A4/8} anzugeben, wenn ich irgendwelche Structs für die WinAPI deklariere.

Selbes Spiel mit den Enums. Delphi interpretiert (weiß nicht, ob das immer noch der Fall ist, aber früher war es so) Enums mit < 256 Elementen immer als Byte, wohingegen die meisten C/C++ Compiler Enums auf 4 Byte erweitern. Deshalb auch hier immer ein explizites {$Z4}.

Delphi-Laie 15. Sep 2014 13:11

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Allmählich scheint es so, als müßte wegen Überforderung ich aussteigen.

Sebastian, danke für die plausible Erklärung! Allerdings wundert es mich, daß im Delphi-Proramm CPU64-Compilierungsoptionen vorhanden waren. Welchen Sinn haben die, wenn kein 64-Bit-Windows vorgesehen ist? Die 64 Bit des Zentralprozessors sind doch außerdem für die Katz', wenn nur 32-Bit-Windows verwendet wird!

Wie gesagt, ich lasse jetzt lieber die Finger von PEB & Co., es gibt ja noch die andere Möglichkeit, die Kommandozeilen abzufragen.

Noch was zu komprimierten/gepackten oder unkomprimierten/ungepackten Records. Die Delphi-Hilfe suggeriert, daß dieses Schlüsselwort überflüssig, aber auch nicht schädlich sei, weil die Records ohnehin intern gepackt würden. Bei den weiter oben in dieser Diskussion aufgeführten Funktionen macht es aber sehr wohl einen Unterschied, ob man das "packed" verwendet oder wegläßt, wie ich durch die üblichen Experimente herausfand.

Zacherl, danke für Dein ausführliches Beispiel, das ich recht bald ausprobieren werde!

jaenicke 15. Sep 2014 15:04

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1272627)
Sebastian, danke für die plausible Erklärung! Allerdings wundert es mich, daß im Delphi-Proramm CPU64-Compilierungsoptionen vorhanden waren. Welchen Sinn haben die, wenn kein 64-Bit-Windows vorgesehen ist?

Die sollten verwendet werden, wenn ein 64-Bit Compiler verwendet wird. Welche du konkret meinst, sehe ich gerade nicht.

Zitat:

Zitat von Delphi-Laie (Beitrag 1272627)
Die 64 Bit des Zentralprozessors sind doch außerdem für die Katz', wenn nur 32-Bit-Windows verwendet wird!

Es gibt aber kaum noch neue 32-Bit CPUs. ;-)

Zitat:

Zitat von Delphi-Laie (Beitrag 1272627)
Noch was zu komprimierten/gepackten oder unkomprimierten/ungepackten Records. Die Delphi-Hilfe suggeriert, daß dieses Schlüsselwort überflüssig, aber auch nicht schädlich sei, weil die Records ohnehin intern gepackt würden.

Das verstehe ich aber deutlich anders:
http://docwiki.embarcadero.com/RADSt...turierte_Typen
Zitat:

Die Verwendung von packed wird nicht empfohlen, da es die Kompatibilität mit anderen Sprachen oder Plattformen verhindern kann, den Datenzugriff verlangsamt und sich bei Zeichen-Arrays auf die Typkompatibilität auswirkt.

Zacherl 15. Sep 2014 15:30

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1272627)
Zacherl, danke für Dein ausführliches Beispiel, das ich recht bald ausprobieren werde!

Funktioniert sowohl mit 32, als auch mit 64 Bit Prozessen. Wobei dein eigener Prozess ebenfalls ein 32 oder 64 Bit Kompilat sein kann. Müsste man lediglich noch modifizieren, wenn man es auf einem nicht-64-bit System starten will, welches die IsWow64Process API nicht kennt.

Delphi-Laie 15. Sep 2014 20:54

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zacherl, danke, ich bleibe dran, nur heute probiere ich es nicht mehr aus.

Sebastian, mal eben die Hilfe von Delphi 2.0 zu packed befragt:

"Das reservierte Wort packed gibt dem Compiler in einer strukturierten Typdeklaration an, daß die Datenspeicherung, selbst auf Kosten eines langsameren Zugriffs auf eine Komponente einer Variable dieses Typs, komprimiert werden soll.
Es hat jedoch in Delphi keine Auswirkung, weil das Packen der Daten automatisch erfolgt."

Zugegeben, die Hilfen in Delphi 3 und 4 (mehr habe ich jetzt nicht zur Hand) schreiben beide schon wieder etwas anderes, aber nichts gegensätzliches.

jaenicke 15. Sep 2014 21:44

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1272670)
Sebastian, mal eben die Hilfe von Delphi 2.0 zu packed befragt:

Die Hilfe hat sich seit damals eben wie Delphi selbst auch weiterentwickelt.

Delphi-Laie 16. Sep 2014 13:13

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von jaenicke (Beitrag 1272680)
Die Hilfe hat sich seit damals eben wie Delphi selbst auch weiterentwickelt.

Sicher, aber die von mir zitierten Sätze sind ja nicht zufällig in die Delphi-Hilfe gelangt.

Zacherl, ein ganz dickes Dankeschön! Erster Test auf 64 Bit mit einem XE2-Compilat, auch 64 Bit, und es funktioniert, welch ein Glückshormonausstoß! Werde ich in mein Programm "Prozesse" integrieren, das nunmehr auch als 64-Bit-Compilate die Spalte "Commandlines" auszufüllen imstande sein wird.

Delphi-Laie 16. Sep 2014 14:55

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Noch als Ergänzung: Das 32-Bit-Compilat bricht schon bei seinem Start mit einer Fehlermeldung ab, soweit ich das überblicke, scheitert es mal wieder an der (statisch aufgerufenene) ntdll.dll, die die wow64-Funktionen nicht beinhaltet. Das ist jetzt aber nicht wichtig, denn wenn der 64-Bit-Strang funktioniert, ist das schon die entscheidende Hilfe und Problemlösung.

Zacherl 16. Sep 2014 15:21

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Zitat:

Zitat von Delphi-Laie (Beitrag 1272782)
Noch als Ergänzung: Das 32-Bit-Compilat bricht schon bei seinem Start mit einer Fehlermeldung ab, soweit ich das überblicke, scheitert es mal wieder an der (statisch aufgerufenene) ntdll.dll, die die wow64-Funktionen nicht beinhaltet.

Mhh das ist wirklich seltsam. Auf welcher Windows Version hast du das 32 Bit Kompilat denn getestet? Auf meinem Win8.1 64 Bit findet er die Imports ohne Probleme. "Theoretisch" sollte der Code auf allen 64 Bit Systemen lauffähig sein. Auf 32 Bit Plattformen wird im 32 Bit Kompilat die IsWow64Process API und die nativen Wow64 Imports fehlen.

Finde leider auch keine richtigen Infos darüber ab welcher Win Version die Wow64 APIs hinzugefügt wurden.

Edit: Da die APIs aber bereits in einem Blog Artikel von 2005 genannt werden, sollten sie ab Vista wohl vorhanden sein (natürlich nur bei der 64 Bit Version).

Delphi-Laie 16. Sep 2014 15:37

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Windows 7 64 Bit.

War auch nur eine Vermutung meinerseits, woran es liegen könnte. Mit dynamischer DLL-Einbindung könnte man den Fehler wohl genauer eingrenzen.

Edit: Kommando zurück, die Fehlermeldung erfolgt nicht beim Start, sondern beim Aufrufen der Clickprozedur, und zwar mit einer Exzeption der Klasse EOSError mit er Meldung "Ein Aufruf einer Betriebssystemfunktion ist fehlgeschlagen."

Ist wohl nicht wichtig.

Zacherl 16. Sep 2014 15:42

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Puh unter einem 64 Bit OS sollte das definitiv nicht passieren. Kannst ja mal einfach testweise ein delayed hinter die Imports der nativen Wow64 APIs schreiben und zusätzlich den ganzen Teil der im {$IFDEF WIN32} Block der Funktion steht mit einem
Delphi-Quellcode:
if Is64BitOS then
absichern.

Die Is64BitOS Funktion findest du hier:
http://stackoverflow.com/a/1634007/3140346

Delphi-Laie 16. Sep 2014 21:47

AW: CommandLines der Prozesse unter Windows 64 Bit ermitteln?
 
Laß es gut sein, Zacherl. Ich weiß nicht, was mein Computer vorhin hatte, jetzt klappt es auch mit 32 Bit.

Lediglich die Integration Deiner 64-Bit-Lösung in mein 64-Bit-Programm zickt noch, aber das werde ich auch schon noch hinbekommen, da bin ich optimistisch, denn mit Debugger und dem Vergleichen zweier Programme beim Debuggen findet man so ziemlich alles.

Dein Verdienst ist definitiv, die PEB-Variante für 64 Bit gefunden zu haben (ich fand für die 64 Bit im Internet nichts), das erspart mir das Eintauchen in die für mich noch fremde Welt des WMIs. Wie soll ich Dir nur dafür danken?


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:47 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