Re: Getting command line of another process



A similar, yet easier but also undocumented way to retrieve this information should be to use
NtQueryInformationProcess(..., ProcessBasicInformation, ...)
to get the process' PEB address and then use ReadProcessMemory to query the command line from RTL_USER_PROCESS_PARAMETERS referred to by the PEB.

--Johannes

BT wrote:
That's still the only way.

It seems to be very complicated code just to retrieve the command line of a process. Why the undocumented structure RTL_PROCESS_PARAMETERS is not accessible by documented API.

There is another way to retrieve command line, but it is undocumented and using it is discouraged (but can resolve your problem). This way does not work on Vista. The RTL_PROCESS_PARAMETERS structure is accessible in the VA space of the process at the address 0x0002:0000. Here is the C# :

public class CProcessHelper
{
//
// RTL_PROCESS_PARAMETERS (undocumented structure)
//
// Memory Address : 0x0002:0000
// + 0x038 ImagePathName : UNICODE_STRING
// + 0x040 CmdLine : UNICODE_STRING // + 0x078 DesktopName : UNICODE_STRING //

public static IntPtr RtlProcessParametersAddress = new IntPtr(0x00020000);
public static IntPtr RtlProcessParametersAddressNtVDM = new IntPtr(0x02010000);

public static UInt32 RtlProcessParameterImagePathnameOffset = 0x38;
public static UInt32 RtlProcessParameterCommandLineOffset = 0x40;
public static UInt32 RtlProcessParameterDesktopNameOffset = 0x78;

/// <summary>
/// Retrieve a process parameter into RTL_PROCESS_PARAMETERS page located at address 0x0002:0000
/// </summary>
/// <param name="HandleProcess">Handle of process with PROCESS_VM_READ access</param>
/// <param name="PageBaseAddress">Base address of RTL_PROCESS_PARAMETERS (normally 0x0002:0000)</param>
/// <param name="UnicodeStringOffset">Relative offset (from PageBaseAddress) where UNICODE_STRING structure is situated </param>
/// <param name="Result">String read</param>
/// <returns></returns>
static public bool RetrieveUserModeProcessString(IntPtr HandleProcess, IntPtr PageBaseAddress, UInt32 UnicodeStringOffset, out string Result)
{
UInt32 UnicodeStringSize = 8;
UInt32 UnicodeStringSizeRead;

IntPtr pUnicodeString = Marshal.AllocCoTaskMem((Int32)UnicodeStringSize);
IntPtr pUnicodeStringAddress;
UInt64 UnicodeStringAddress = (UInt64)(PageBaseAddress.ToInt64() + UnicodeStringOffset);

UInt64 StringAddress;
UInt32 StringLength;

IntPtr pStringContent = IntPtr.Zero;
IntPtr pStringAddress;

Result = null;

try
{
// Translate UNICODE_STRUCTURE offset into pointer
pUnicodeStringAddress = new IntPtr((Int64)UnicodeStringAddress);

// Read the UNICODE_STRING structure
if (CKernel32API.ReadProcessMemory(HandleProcess, pUnicodeStringAddress, pUnicodeString, UnicodeStringSize, out UnicodeStringSizeRead) == false)
return false;

// Check that all the structure has been read if (UnicodeStringSizeRead != UnicodeStringSize)
return false;

// Retrieve the length
StringLength = (UInt16)Marshal.ReadInt16(pUnicodeString);

// Null string ? Ok, all done
if (StringLength == 0) return true;

// heuristic should be use on the string length retrieved

// Adjust the length for an Unicode string terminated by '\0'
StringLength = (UInt32)((StringLength + 1) * 2);

// Allocate space for retrieve the string
pStringContent = Marshal.AllocCoTaskMem((Int32)StringLength);

// Read the string address
StringAddress = (UInt32)Marshal.ReadInt32(pUnicodeString, 4);

// Translate offset into pointer
// Two solutions : either a relative offset or a absolute address
if (StringAddress > (UInt64)PageBaseAddress.ToInt64()) pStringAddress = new IntPtr((Int64)StringAddress);
else pStringAddress = new IntPtr(PageBaseAddress.ToInt64() + (Int64) StringAddress);

// Read the string
if (CKernel32API.ReadProcessMemory(HandleProcess, pStringAddress, pStringContent, StringLength, out StringLength) == false)
return false;

// Retrieve the string in managed result
Result = Marshal.PtrToStringUni(pStringContent);
}
catch
{
return false;
}
finally
{
Marshal.FreeCoTaskMem(pUnicodeString);
if (pStringContent != IntPtr.Zero) Marshal.FreeCoTaskMem(pStringContent);
}

return true;
}











code where CKernel32API class just declare the dllimport :






--
Johannes Passing - http://int3.de/
.



Relevant Pages

  • Re: Getting command line of another process
    ... It seems to be very complicated code just to retrieve the command line of a ... HandleProcess, IntPtr PageBaseAddress, UInt32 UnicodeStringOffset, out string ... pUnicodeStringAddress, pUnicodeString, UnicodeStringSize, out ... pStringContent = Marshal.AllocCoTaskMemStringLength); ...
    (microsoft.public.win32.programmer.kernel)
  • Re: Getting command line of another process
    ... public static IntPtr RtlProcessParametersAddressNtVDM = new ... IntPtr pStringContent = IntPtr.Zero; ... pUnicodeStringAddress, pUnicodeString, UnicodeStringSize, out ... // Null string? ...
    (microsoft.public.win32.programmer.kernel)
  • Re: Getting command line of another process
    ... public static IntPtr RtlProcessParametersAddressNtVDM = new ... IntPtr pStringContent = IntPtr.Zero; ... pUnicodeStringAddress, pUnicodeString, UnicodeStringSize, out ... // Null string? ...
    (microsoft.public.win32.programmer.kernel)
  • Re: Getting command line of another process
    ... public static IntPtr RtlProcessParametersAddressNtVDM = new ... IntPtr pStringContent = IntPtr.Zero; ... pUnicodeStringAddress, pUnicodeString, UnicodeStringSize, out ... // Null string? ...
    (microsoft.public.win32.programmer.kernel)
  • Re: Getting command line of another process
    ... public static IntPtr RtlProcessParametersAddressNtVDM = new ... HandleProcess, IntPtr PageBaseAddress, UInt32 UnicodeStringOffset, out string ... IntPtr pStringContent = IntPtr.Zero; ... pUnicodeStringAddress, pUnicodeString, UnicodeStringSize, out ...
    (microsoft.public.win32.programmer.kernel)