Delphi Pages Forums

Delphi Pages Forums (
-   General (
-   -   Get the param string of an exe (

kate 12-10-2006 10:29 AM

Get the param string of an exe
Is there a way to get the param string of another executable. I mean, assuming an executable named 'runman.exe' is executed with parameter such as 'runman.exe -a -b -l'. I want to get the '-a -b -l' that is attached to the runman.exe, when this executable run.

I hope I have explained this correctly.

Thank you.

Jasser 12-10-2006 10:32 AM

RE: Get the param string of an exe
Is it a Delphi program?

Abdulaziz Jasser

kate 12-10-2006 07:09 PM

RE: What type of executables are they
I have three exe to monitor. Two are two dos command line programs (borrowed from and another is a delphi exe. Hope this gives you more infor.

Are there differences in monitoring dos(command line), delphi or C++ executables?


digitiger 12-11-2006 04:54 AM

RE: What type of executables are they
May I request you to clarify your problem in bit more details. Also do you have the source of the applications which you are monitoring and can you modify those applications a bit so that you can establish a systamatic communication between the executables?

MerijnB 12-11-2006 11:52 PM

RE: Get the param string of an exe
I know there are a few ways to achieve this, but it isn't easy though.

You can try to create a thread in the other process (CreateRemoteThread()). This won't work for the DOS programs, but then again, are you sure these aren't just console applications?. In this thread you can call GetCommandLine() from within the other application. Then you'll need to do some more calls to get the string into your application. I don't know if DEP will prevent you from doing this nowadays though.

Other way could be to make a hook, I don't know exactly how this works but afaik you should be able to get some info this way.

If you've read this post and have no idea what I'm saying, it might be a good idea to just drop it, because this isn't easy :)

Kovachev 12-12-2006 06:54 AM

RE: Get the param string of an exe
The only way I found some times ago when I was dealing with such a problem was code injection + remote code execution.
It is very simple to do that. The following code is tested on win NT, 2000 and XP with 32bit executables and it could retrieve the command line even on windows system processes. The code is tested for memory leaks and it seems to be safe.


program CmdLineDump;
{$IMAGEBASE $13140000}

  Windows, SysUtils, TLHelp32;

  SE_DEBUG_NAME = 'SeDebugPrivilege' ;
  NL = #10 + #13; // new line + carrier return

  // GCLW abbreviation stands for GetCommandLineW
  // windows API located in kernel32.dll
  tGCLW = function(): PWideChar; stdcall;

  // The data structure to be injected in remote process
  // it contains the pointer to GCLW API and the pointer
  // for the result buffer.
  PInjectData = ^TInjectData;
  TInjectData = record
    pGCLW: Pointer;
    Buff: Pointer;

// The code to be injected and executed in
// the remote process
function InjectedCode(Param: PInjectData): LongWord; stdcall;
  Param^.Buff := tGCLW(Param^.pGCLW);

  for Result := 0 to 512 do
    if PWideChar(Param^.Buff)[Result] = #0 then Break;

// Code injection routine
procedure InjectToTarget(hProcess: THandle; EntryPoint: Pointer; CodeSize: Integer);
  InitData: TInjectData;
  InitDataAddr, WriteAddr: Pointer;
  ThreadHandle: THandle;
  BytesWritten, TheadID: DWORD;

  CmdLineLength: LongWord;
  CmdLineBuff: PWideChar;
  CmdLineSize: LongWord;
  // Get the address there GCLW API is loaded in memory
  InitData.pGCLW := GetProcAddress(LoadLibrary('kernel32.dll'), 'GetCommandLineW');

  // Allocate memory in the memory space of the remote process
// and copy InitData there
  InitDataAddr := VirtualAllocEx(hProcess, nil, SizeOf(InitData), MEM_COMMIT, PAGE_READWRITE);
  if (InitDataAddr <> nil) then begin
    WriteProcessMemory(hProcess, InitDataAddr, (@InitData), SizeOf(InitData), BytesWritten);

  // Allocate memory for the injected function (injected code)
  // and copy it there
  WriteAddr := VirtualAllocEx(hProcess, nil, CodeSize, MEM_COMMIT, PAGE_READWRITE);
  if (WriteAddr <> nil) then begin
    WriteProcessMemory(hProcess, WriteAddr, EntryPoint, CodeSize, BytesWritten);

    // The following lines checks if we have written something
    // in the remote process and if yes it executes
    // our code and waits for result
    // then copies back the InitData from remote memory
    // to be able to retrive the command line
    // and finally frees the allocated memory
    if BytesWritten = CodeSize then begin
      ThreadHandle := CreateRemoteThread(hProcess, nil, 0, WriteAddr, InitDataAddr, 0, TheadID);
      WaitForSingleObject(ThreadHandle, INFINITE);
      GetExitCodeThread(ThreadHandle, CmdLineLength);

      CmdLineSize := SizeOf(WideChar)*(CmdLineLength+1);
      GetMem(CmdLineBuff, CmdLineSize);

      ReadProcessMemory(hProcess, InitDataAddr, (@InitData), SizeOf(InitData), BytesWritten);
      ReadProcessMemory(hProcess, InitData.Buff, CmdLineBuff, CmdLineSize, BytesWritten);
      Writeln('Commend line (',CmdLineLength,') = ',WideString(CmdLineBuff));

      VirtualFreeEx(hProcess, WriteAddr, 0, MEM_RELEASE);

  VirtualFreeEx(hProcess, InitDataAddr,  0, MEM_RELEASE);

// This routine asks the system for DebugPrivileges for
// our program so it could "debug" other programs
// i.e. reasd/write to their memory and so on ...
procedure GetDebugPrivileges;
  hToken: THandle;
  tkp: TTokenPrivileges;
  retval: dword;
  if not OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then begin
    Writeln('ERROR! OPT() failed, GLE()='+IntToStr(GetLastError())+' SeDebugPrivilege is not available.');
    Readln; Exit;

  if not LookupPrivilegeValue(nil, SE_DEBUG_NAME, tkp.Privileges[0].Luid) then begin
    Writeln('ERROR! LPV() failed, GLE()='+IntToStr(GetLastError())+' SeDebugPrivilege is not available.');
    Readln; Exit;

  tkp.PrivilegeCount := 1;
  tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;

  if not AdjustTokenPrivileges(hToken, false, tkp, 0, nil, retval) then begin
    Writeln('ERROR! ATP() failed, GLE()='+IntToStr(GetLastError())+' SeDebugPrivilege is not available.');
    Readln; Exit;


  ProcessHandle: THandle;
  PID: Cardinal;

// This routine retrieves all running process and returns
// their process id (PID)
procedure EnumerateProcesses;
  H: THandle;
  R: Boolean;
  PE: TProcessEntry32;
  Writeln(Format('%6s | %s', ['PID', 'Process']));

  H := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if H <> INVALID_HANDLE_VALUE then begin
    PE.dwSize := SizeOf(PE);
    R := Process32First(H, PE);
    while R do begin
      Writeln(Format('%6d | %s', [PE.th32ProcessID, PE.szExeFile]));
      R := Process32Next(H, PE);
  end else begin
    Writeln('ERROR! CT32S() failed, GLE()='+IntToStr(GetLastError())+'.');
    Readln; Exit;

  Writeln('| Process enumeration and code injection |');
  Writeln('|          2004, St. Kovachev          |');

  if ParamCount = 0 then begin
    Writeln('Usage :');
    Writeln('To get process command line: CmdLineDump.exe [pid]');
    Writeln('To view proceses list: CmdLineDump.exe -list');
    Writeln; Exit;

  if LowerCase(ParamStr(1)) = '-list' then begin
    Writeln; Exit;

  Write('Get debuger privileges . . . ');

  PID := StrToInt(ParamStr(1));

  Writeln(Format('Injecting code @ process %d . . .', [PID]));
  ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
  if ProcessHandle = INVALID_HANDLE_VALUE then begin
    Writeln(Format('ERROR! OP(%d) failed, GLE()=%d', [PID, GetLastError()]));
    Readln; Exit;
  InjectToTarget(ProcessHandle, @InjectedCode, 1000);


St. Kovachev <>

MerijnB 12-12-2006 07:00 AM

RE: Get the param string of an exe
nice piece of code, but as I suspected, this won't work due to DEP (anymore).

kate 12-12-2006 10:09 AM

Credits goes to Kovachev - sorry
Just click the wrong person which should be credited!

MerijnB 12-12-2006 11:30 AM

RE: Credits goes to Kovachev - sorry
kate, if you got Kovachev's solution working be aware that it probably won't work on windows XP SP2 and up.

Kovachev 12-12-2006 12:45 PM

RE: Credits goes to Kovachev - sorry
It was tested to work on XP SP2 (with almost all hotfixes). As you probably know DEP is CPU dependent so the solution may probably work even on Vista ("running" on old CPU), but I have no time to test it. I will test it on DEP enabled CPU in the weekend.

St. Kovachev <>

All times are GMT. The time now is 07:15 PM.

Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2019, vBulletin Solutions, Inc.