"RemoteCmdLine" Example 


We have two variations of the "RemoteCmdLine" Example. The first one is using the low level functions CopyFunction, AllocMemEx/FreeMemEx and CreateRemoteThreadEx, while the second one is using the higher level function RemoteExecute.

The second variation can also be found in the "Demo" folder on your harddisk.

Here come the first variation using the low level functions:

// demonstrate how to use CopyFunction, AllocMemEx and CreateRemoteThread to
// execute a function in the context of another process

// this demo shows us the command line of the explorer, which normally is not
// possible when using normal win32 APIs

program RemoteCmdLine;

uses Windows, madRemote;

// this is our thread function, which will be copied to and then executed in the
// context of any desired process
function GetCmdLineThread(buffer: pchar) : dword; stdcall;
var cl : pchar;
  // first let's get the command line of the current process
  cl := GetCommandLine;

  // now let's copy the characters to the specified buffer
  // we can't use StrPCopy, because that's not available in other processes
  // we use "result" as the loop variable, so the length of the copied
  // command line is automatically the exit code of the thread
  for result := 0 to MAX_PATH - 1 do begin
    buffer[result] := cl[result];
    if buffer[result] = #0 then

// this function can give us the command line of any specified 32bit process
function GetProcessCmdLine(processHandle: dword) : string;
var th, tid    : dword;
    entryPoint : pointer;
    buffer     : pointer;
    params     : pointer;
    len        : dword;
  // first of all we copy the function to the specified process
  entryPoint := CopyFunction(@GetCmdLineThread, processHandle, false, @buffer);

  // now we allocate a temporare buffer in the context of the specified process
  params := AllocMemEx(MAX_PATH, processHandle);

  // finally we create the remote thread and enter the entryPoint of the
  // copied fuction and the temporare buffer as the parameter
  // both addresses are valid in the context of the destination process
  th := CreateRemoteThreadEx(processHandle, nil, 0, entryPoint, params, 0, tid);

  // let's wait until the remote thread has done it's work
  WaitForSingleObject(th, INFINITE);

  // the exit code of the remote thread is the length of the command line
  GetExitCodeThread(th, len);
  SetLength(result, len);

  // finally let's fill the result string from the temporare buffer
  ReadProcessMemory(processHandle, params, pointer(result), len, len);

  // never forget to close handles

  // also don't forget to free whatever we allocated in the other process
  FreeMemEx(params, processHandle);
  FreeMemEx(buffer, processHandle);

// now we demonstrate the functionality by showing the explorer's command line
var wnd, pid, ph : dword;
  // first we ask the taskbar's window handle and the corresponding process ID
  wnd := FindWindow('Shell_TrayWnd', '');
  GetWindowThreadProcessID(wnd, @pid);

  // then we open the process, which is the explorer, of course
  ph := OpenProcess(PROCESS_ALL_ACCESS, false, pid);

  // and finally show it's command line
  MessageBox(0, pchar('"' + GetProcessCmdLine(ph) + '"'),
             'explorer''s command line...', MB_ICONINFORMATION);

  // again: don't forget to close the handles

The second variation is in some parts identical to the first one. Only the function "GetProcessCmdLine" differs. There the 2nd variation uses the higher level function RemoteExecute:

function GetProcessCmdLine(processHandle: dword) : string;
var arrCh : array [0..MAX_PATH - 1] of char;
    len   : dword;
  // we simply execute "GetCmdLineThread" in the context of the target process
  if RemoteExecute(processHandle, @RemoteGetCmdLine, len, @arrCh, MAX_PATH) then
    // if this succeeds, "arrCh" will contain the command line and
    // the function result "len" will contain the length of the command line
    SetString(result, arrCh, len)
    result := '';