Delphi 获取进程命令行参数方法

适合D2007 x86版本

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit2: TEdit;
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  USHORT = Word;

  UNICODE_STRING = packed record
    Length: USHORT;
    MaximumLength: USHORT;
    Buffer: PWideString;
  end;

  RTL_USER_PROCESS_PARAMETERS = packed record
    Reserved1: array[0..15] of Byte;
    Reserved2: array[0..9] of Pointer;
    ImagePathName: UNICODE_STRING;
    CommandLine: UNICODE_STRING;
  end;

  PRTL_USER_PROCESS_PARAMETERS = ^RTL_USER_PROCESS_PARAMETERS;

  PEB = packed record
    Reserved1: array[0..1] of Byte;
    BeingDebugged: ByteBool;
    Reserved2: Byte;
    Reserved3: array[0..1] of Pointer;
    Ldr: Pointer;
    ProcessParameters: PRTL_USER_PROCESS_PARAMETERS;
    Reserved4: array[0..103] of Byte;
    Reserved5: array[0..51] of Pointer;
  end;

  PPEB = ^PEB;
  PROCESS_BASIC_INFORMATION = packed record
    ExitStatus: DWORD;
    PebBaseAddress: PPEB;
    AffinityMask: DWORD;
    BasePriority: DWORD;
    uUniqueProcessId: ULong;
    uInheritedFromUniqueProcessId: ULong;
  end;

  TProcessBasicInformation = PROCESS_BASIC_INFORMATION;


function NtQueryInformationProcess(ProcessHandle: THandle;ProcessInformationClass: Byte;ProcessInformation: Pointer;
                                   ProcessInformationLength: ULONG;ReturnLength: PULONG): DWORD; stdcall; external 'ntdll.dll';

var
  Form1: TForm1;

implementation

{$R *.dfm}

//only match x86 not support x64 bit application
function GetProcessCmdLine(PID: Cardinal): string;
const
  ProcessBasicInformation = 0;
var
  h: THandle;
  pbi: TProcessBasicInformation;
  ret: Cardinal;
  r: Cardinal;
  ws: WideString;
  aPEB: PEB;
  ProcPar: RTL_USER_PROCESS_PARAMETERS;
begin
  Result := '';
  if PID = 0 then   PID := GetCurrentProcessID;
  try
    h := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
    if h = 0 then  Exit;
    try
      ret := NtQueryInformationProcess(h, ProcessBasicInformation, @pbi, SizeOf(pbi), @r);
      if ret = 0 then
        repeat
          if (not ReadProcessMemory(h, pbi.PebBaseAddress, @aPEB, SizeOf(aPEB), r)) or (r <> SizeOf(aPEB)) then
            break;
          if (not ReadProcessMemory(h, aPEB.ProcessParameters, @ProcPar, SizeOf(ProcPar), r)) or (r <> SizeOf(ProcPar)) then
            break;
          SetLength(ws, ProcPar.CommandLine.Length div 2);
          if (not ReadProcessMemory(h, ProcPar.CommandLine.Buffer, PWideChar(ws), ProcPar.CommandLine.Length, r)) or (r <> ProcPar.CommandLine.Length) then
            break;
          Result := ws;
        until True;
    finally
      CloseHandle(h);
    end;
  finally
  end;
end;

function EnableDebugPriv: Boolean;  //提升进程权限为DEBUG权限
var
  hToken: THandle;
  tp: TTokenPrivileges;
  rl: Cardinal;
begin
  Result := false;
  OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,hToken);
  if LookupPrivilegeValue(nil, 'SeDebugPrivilege', tp.Privileges[0].Luid) then
  begin
    tp.PrivilegeCount:=1;
    tp.Privileges[0].Attributes:= SE_PRIVILEGE_ENABLED;
    Result := AdjustTokenPrivileges(hToken, false, tp, SizeOf(tp), nil, rl);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  EnableDebugPriv;
  Memo1.Text:=GetProcessCmdLine(StrToInt(Edit2.Text));
end;

end.

效果如下图:

 

以下代码适合X64位进程(32位兼容)编译环境XE2

function GetProcessCmdLine64(PID: Cardinal): string;
var
  pbi : PROCESS_BASIC_INFORMATION64;
  pfnNtQueryInformationProcess : TNtQueryInformationProcess;
  pfnNtReadVirtualMemory : TNtReadVirtualMemory64;
  dwSize:DWORD;
  size:UINT64;
  iReturn:Integer;
  pAddrPEB:PVOID64;
  PEB:__PEB64;
  stBlock:_RTL_USER_PROCESS_PARAMETERS64;
  PathBuffer : PByte;
  hProcess:Cardinal;
  CmdLine:string;
begin
  Result := '';
  @pfnNtQueryInformationProcess := GetProcAddress(GetModuleHandle('ntdll.dll'),'NtWow64QueryInformationProcess64');
  @pfnNtReadVirtualMemory := GetProcAddress(GetModuleHandle('ntdll.dll'),'NtWow64ReadVirtualMemory64');

  hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);

  if ( Assigned(pfnNtQueryInformationProcess) ) then
  begin
    pAddrPEB := 0;
    iReturn := pfnNtQueryInformationProcess(hProcess,0,@pbi,sizeof(pbi),PULONG(@dwSize));
    pAddrPEB := pbi.PebBaseAddress;
    // NtQueryInformationProcess returns a negative value if it fails
    if (iReturn >= 0) then
    begin
      // 1. Find the Process Environment Block
      size := dwSize;
      if ( ERROR_SUCCESS <> pfnNtReadVirtualMemory(hProcess, pAddrPEB, @PEB, sizeof(PEB), PUINT64(@size)) ) then
      begin
        // Call GetLastError() if you need to know why
        Exit;
      end;
      // 2. From this PEB, get the address of the block containing
      // a pointer to the CmdLine
      if ( ERROR_SUCCESS <> pfnNtReadVirtualMemory(hProcess, PEB.ProcessParameters, @stBlock, sizeof(stBlock), PUINT64(@size))) then
      begin
        // Call GetLastError() if you need to know why
        Exit;
      end;
 {     // 3. Get the ImagePathName
      PathBuffer := GetMemory(stBlock.ImagePathName.MaximumLength);
      FillChar(PathBuffer^,stBlock.ImagePathName.MaximumLength,0);
      if ( ERROR_SUCCESS = pfnNtReadVirtualMemory(hProcess, stBlock.ImagePathName.Buffer, PVOID(PathBuffer), stBlock.ImagePathName.Length*sizeof(Char), PUINT64(@size))) then
      begin    // Call GetLastError() if you need to know why
        SetString(ImagePath,PChar(PathBuffer),stBlock.ImagePathName.Length div 2);
        Result := True;   }
      end;
      // 4. Get the CmdLine
     // FreeMemory(PathBuffer);
      PathBuffer := GetMemory(stBlock.CmdLine.MaximumLength);
      FillChar(PathBuffer^,stBlock.CmdLine.MaximumLength,0);
      if ( ERROR_SUCCESS = pfnNtReadVirtualMemory(hProcess, stBlock.CmdLine.Buffer, PVOID(PathBuffer), stBlock.CmdLine.Length*sizeof(Char), PUINT64(@size))) then
      begin    // Call GetLastError() if you need to know why
        SetString(CmdLine,PChar(PathBuffer),stBlock.CmdLine.Length div 2);
        Result := CmdLine;
      end;
      FreeMemory(PathBuffer);
    end;
  end;

效果:

posted @ 2022-10-04 00:14  IT情深  阅读(238)  评论(0编辑  收藏  举报