Re: Getting command line of another process

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance




You should never assume the address of the _PEB (the structure that includes _RTL_PROCESS_PARAMETERS) to be a certain value. It can vary.

The only guaranty threads have if that NtCurrentTeb() returns the address of their_TEB which. in turn, contains a pointer to _PEB. NtCurrentTeb() is just a macro, since_TEB is pointed by gs segment on 64bit systems and fs segment on 32bit systems. On Itanium it is easier since it is the value in register r13. Back on x86, even if you are able to get the value of fs/gs from another process, this will take you nowhere since the entry on GDT is probably different.

This, of course, assuming that you already had enough Integrity Level to OpenProcess in the first place...

Injecting the thread is probably your best bet :)


"BT" <BT@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in message news:05B3FA00-ED8E-4143-B18B-C833A9D13C3A@xxxxxxxxxxxxxxxx
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 :




.



Relevant Pages

  • 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
    ... It seems to be very complicated code just to retrieve the command line of a process. ... static public bool RetrieveUserModeProcessString(IntPtr HandleProcess, IntPtr PageBaseAddress, UInt32 UnicodeStringOffset, out string Result) ... UInt32 UnicodeStringSize = 8; ... pStringContent = Marshal.AllocCoTaskMemStringLength); ...
    (microsoft.public.win32.programmer.kernel)
  • VirtualAllocEx returns a bad pointer in some processes
    ... (ByVal hWnd As IntPtr, _ ... (ByVal hWndParent As IntPtr, _ ... ByVal lParam As String) As Integer ... Dim aihWnds As ArrayList ...
    (microsoft.public.vc.mfc)