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;