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;