Delphi-PRAXiS
Seite 2 von 4     12 34      

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)

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}.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:09 Uhr.
Seite 2 von 4     12 34      

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