博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Delphi 获取进程路径及命令行参数

Posted on 2014-03-11 19:02  wlmbz  阅读(2230)  评论(0编辑  收藏  举报

Delphi 获取进程路径及命令行参数, 但有的进程获取时会报错,不知为啥

type
  PVOID64 = UINT64;

  _UNICODE_STRING = packed record
    Length : USHORT;
    MaximumLength : USHORT;
    Buffer : PWideChar;
  end;
  UNICODE_STRING = _UNICODE_STRING;
  PUNICODE_STRING =^_UNICODE_STRING;

  _UNICODE_STRING64 = packed record
    Length : USHORT;
    MaximumLength : USHORT;
    Fill : DWORD;
    Buffer : PVOID64;
  end;
  UNICODE_STRING64 = _UNICODE_STRING64;
  PUNICODE_STRING64 =^_UNICODE_STRING64;

  __PEB = packed record
    Filler : array [0..3] of DWORD;
    ProcessParameters : DWORD;
  end;

  __PEB64 = packed record
    Filler : array [0..3] of PVOID64;
    ProcessParameters : PVOID64;
  end;

  _CURDIR = packed record
    DosPath : UNICODE_STRING;
    Handle : THANDLE;
  end;

  _CURDIR64 = packed record
    DosPath : UNICODE_STRING64;
    Handle : PVOID64;
  end;

  _RTL_USER_PROCESS_PARAMETERS = packed record
    MaximumLength   :DWORD;
    Length          :DWORD;
    Flags           :DWORD;
    DebugFlags      :DWORD;
    ConsoleHandle   :THandle;
    ConsoleFlags    :DWORD;
    StandardInput   :THandle;
    StandardOutput  :THandle;
    StandardError   :THandle;
    //////////////////////////
    DosPath         :UNICODE_STRING;    //CurrentDirectory
    Handle          :THANDLE;
    //////////////////////////
    DllPath         :UNICODE_STRING;
    ImagePathName   :UNICODE_STRING;
    CmdLine         :UNICODE_STRING;
  end;

  _RTL_USER_PROCESS_PARAMETERS64 = record
    MaximumLength   :DWORD;
    Length          :DWORD;
    Flags           :DWORD;
    DebugFlags      :DWORD;
    ConsoleHandle   :PVOID64;
    ConsoleFlags    :DWORD;
    StandardInput   :PVOID64;
    StandardOutput  :PVOID64;
    StandardError   :PVOID64;
    //////////////////////////
    CurrentDirectory:_CURDIR64;
    //////////////////////////
    DllPath         :UNICODE_STRING64;
    ImagePathName   :UNICODE_STRING64;
    CmdLine         :UNICODE_STRING64;
  end;

  _PROCESS_BASIC_INFORMATION = packed record
    Reserved1       :PVOID;
    PebBaseAddress  :PVOID;
    Reserved2       :Array [0..1] of PVOID;
    UniqueProcessId :PVOID;
    Reserved3       :PVOID;
  end;
  PROCESS_BASIC_INFORMATION  =_PROCESS_BASIC_INFORMATION;
  PPROCESS_BASIC_INFORMATION =^_PROCESS_BASIC_INFORMATION;

  _PROCESS_BASIC_INFORMATION64 = packed record
    Reserved1       :PVOID64;
    PebBaseAddress  :PVOID64;
    Reserved2       :Array [0..1] of PVOID64;
    UniqueProcessId :PVOID64;
    Reserved3       :PVOID64;
  end;
  PROCESS_BASIC_INFORMATION64  =_PROCESS_BASIC_INFORMATION64;
  PPROCESS_BASIC_INFORMATION64 =^_PROCESS_BASIC_INFORMATION64;

  TNtQueryInformationProcess = function(a:THANDLE;b:UINT;c:PVOID;d:ULONG;e:PULONG):LONG; stdcall;
  TNtReadVirtualMemory = function(ProcessHandle:THANDLE; BaseAddress:PVOID; Buffer:PVOID; NumberOfBytesToRead:ULONG; NumberOfBytesReaded:PULONG):LONG; stdcall;
  TNtReadVirtualMemory64 = function(ProcessHandle:THANDLE; BaseAddress:PVOID64; Buffer:PVOID; NumberOfBytesToRead:UINT64; NumberOfBytesReaded:PUINT64):LONG; stdcall;
  TISWOW64PROCESS = function(hProcess:THANDLE; var Wow64Process:BOOL):BOOL; stdcall;

  function GetProcessImagePathAndCmdLine(hProcess:THandle; var ImagePath:string; var CmdLine:string):Boolean;


implementation


function GetProcessImagePathAndCmdLine32(hProcess:THandle; var ImagePath:string; var CmdLine:string):Boolean;
var
  pbi : PROCESS_BASIC_INFORMATION;
  pfnNtQueryInformationProcess : TNtQueryInformationProcess;
  pfnNtReadVirtualMemory : TNtReadVirtualMemory;
  dwSize:DWORD;
  size:SIZE_T;
  iReturn:Integer;
  pAddrPEB:PVOID;
  PEB:__PEB;
  stBlock:_RTL_USER_PROCESS_PARAMETERS;
  PathBuffer : PByte;
begin
  Result := False;
  @pfnNtQueryInformationProcess := GetProcAddress(GetModuleHandle('ntdll.dll'),'NtQueryInformationProcess');
  @pfnNtReadVirtualMemory := GetProcAddress(GetModuleHandle('ntdll.dll'),'NtReadVirtualMemory');

  if ( Assigned(pfnNtQueryInformationProcess) ) then
  begin
    pAddrPEB := nil;
    iReturn := pfnNtQueryInformationProcess(hProcess,0,@pbi,sizeof(pbi),@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), PULONG(@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, PVOID(PEB.ProcessParameters), @stBlock, sizeof(stBlock), PULONG(@size))) then
      begin
        // Call GetLastError() if you need to know why
        Exit;
      end;
      // 3. Get the ImagePathName
      if (stBlock.ImagePathName.MaximumLength <= 1024) then
      begin
        PathBuffer := GetMemory(stBlock.ImagePathName.MaximumLength);
        FillChar(PathBuffer^,stBlock.ImagePathName.MaximumLength,0);
        if (stBlock.ImagePathName.MaximumLength <= 1024) and ( ERROR_SUCCESS = pfnNtReadVirtualMemory(hProcess, PVOID(stBlock.ImagePathName.Buffer), PVOID(PathBuffer), stBlock.ImagePathName.Length*sizeof(Char), PULONG(@size))) then
        begin    // Call GetLastError() if you need to know why
          SetString(ImagePath,PChar(PathBuffer),stBlock.ImagePathName.Length div 2);
          Result := True;
        end;
        FreeMemory(PathBuffer);
      end;
        // 4. Get the CmdLine
      if (stBlock.CmdLine.MaximumLength <= 1024) then
      begin
        PathBuffer := GetMemory(stBlock.CmdLine.MaximumLength);
        FillChar(PathBuffer^,stBlock.CmdLine.MaximumLength,0);
        if ( ERROR_SUCCESS = pfnNtReadVirtualMemory(hProcess, PVOID(stBlock.CmdLine.Buffer), PVOID(PathBuffer), stBlock.CmdLine.Length*sizeof(Char), PULONG(@size))) then
        begin    // Call GetLastError() if you need to know why
          SetString(CmdLine,PChar(PathBuffer),stBlock.CmdLine.Length div 2);
          Result := True;
        end;
        FreeMemory(PathBuffer);
      end;
    end;
  end;
end;


function GetProcessImagePathAndCmdLine64(hProcess:THandle; var ImagePath:string; var CmdLine:string):Boolean;
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;
begin
  Result := False;
  @pfnNtQueryInformationProcess := GetProcAddress(GetModuleHandle('ntdll.dll'),'NtWow64QueryInformationProcess64');
  @pfnNtReadVirtualMemory := GetProcAddress(GetModuleHandle('ntdll.dll'),'NtWow64ReadVirtualMemory64');

  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 := True;
      end;
      FreeMemory(PathBuffer);
    end;
  end;
end;

function GetProcessImagePathAndCmdLine(hProcess:THandle; var ImagePath:string; var CmdLine:string):Boolean;
var
  fn:TISWOW64PROCESS;
begin
  Result := False;
  try
    fn := GetProcAddress(GetModuleHandle('kernel32'),'IsWow64Process');
    if Assigned(fn) then
    begin
      Result := GetProcessImagePathAndCmdLine64(hProcess,ImagePath,CmdLine);
    end else
    begin
      Result := GetProcessImagePathAndCmdLine32(hProcess,ImagePath,CmdLine);
    end;
  Except
  end;
end;