Delphi Pages Forums  

Go Back   Delphi Pages Forums > Delphi Forum > General

Lost Password?

Reply
 
Thread Tools Display Modes
  #1  
Old 12-10-2006, 10:29 AM
kate kate is offline
Senior Member
 
Join Date: Feb 2001
Posts: 356
Default Get the param string of an exe

Hi,
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.
Reply With Quote
  #2  
Old 12-10-2006, 10:32 AM
Jasser Jasser is offline
Moderator
 
Join Date: Jan 2005
Location: Saudi Arabia
Posts: 5,060
Default RE: Get the param string of an exe

Is it a Delphi program?

Regards,
Abdulaziz Jasser
Reply With Quote
  #3  
Old 12-10-2006, 07:09 PM
kate kate is offline
Senior Member
 
Join Date: Feb 2001
Posts: 356
Default RE: What type of executables are they

Hi,
I have three exe to monitor. Two are two dos command line programs (borrowed from sourceforge.net) and another is a delphi exe. Hope this gives you more infor.

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

Thanks
Reply With Quote
  #4  
Old 12-11-2006, 04:54 AM
digitiger digitiger is offline
Senior Member
 
Join Date: Jan 2001
Posts: 716
Default 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?
Reply With Quote
  #5  
Old 12-11-2006, 11:52 PM
MerijnB MerijnB is offline
Senior Member
 
Join Date: Mar 2001
Posts: 452
Default 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
Reply With Quote
  #6  
Old 12-12-2006, 06:54 AM
Kovachev Kovachev is offline
Member
 
Join Date: Mar 2001
Posts: 33
Default 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.


Code:
program CmdLineDump;
{$APPTYPE CONSOLE}
{$IMAGEBASE $13140000}

uses
  Windows, SysUtils, TLHelp32;

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

type
  // 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;
  end;

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

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

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

  CmdLineLength: LongWord;
  CmdLineBuff: PWideChar;
  CmdLineSize: LongWord;
begin
  // 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);
  end;

  // 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);
    end;
  end;

  VirtualFreeEx(hProcess, InitDataAddr,  0, MEM_RELEASE);
end;

// 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;
var
  hToken: THandle;
  tkp: TTokenPrivileges;
  retval: dword;
begin
  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;
  end;

  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;
  end;

  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;
  end;

  CloseHandle(hToken);
end;

var
  ProcessHandle: THandle;
  PID: Cardinal;

// This routine retrieves all running process and returns
// their process id (PID)
procedure EnumerateProcesses;
var
  H: THandle;
  R: Boolean;
  PE: TProcessEntry32;
begin
  Writeln;
  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;
    CloseHandle(H);
  end else begin
    Writeln('ERROR! CT32S() failed, GLE()='+IntToStr(GetLastError())+'.');
    Readln; Exit;
  end;
  Writeln;
end;

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

  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;
  end;

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

  Write('Get debuger privileges . . . ');
  GetDebugPrivileges;
  Writeln('done!'+NL);

  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;
  end;
  InjectToTarget(ProcessHandle, @InjectedCode, 1000);
  CloseHandle(ProcessHandle);

  Writeln;
end.
St. Kovachev
Reply With Quote
  #7  
Old 12-12-2006, 07:00 AM
MerijnB MerijnB is offline
Senior Member
 
Join Date: Mar 2001
Posts: 452
Default RE: Get the param string of an exe

nice piece of code, but as I suspected, this won't work due to DEP (anymore).
Reply With Quote
  #8  
Old 12-12-2006, 10:09 AM
kate kate is offline
Senior Member
 
Join Date: Feb 2001
Posts: 356
Default Credits goes to Kovachev - sorry

Just click the wrong person which should be credited!
Reply With Quote
  #9  
Old 12-12-2006, 11:30 AM
MerijnB MerijnB is offline
Senior Member
 
Join Date: Mar 2001
Posts: 452
Default 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.
Reply With Quote
  #10  
Old 12-12-2006, 12:45 PM
Kovachev Kovachev is offline
Member
 
Join Date: Mar 2001
Posts: 33
Default 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
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On

Forum Jump


All times are GMT. The time now is 01:23 AM.


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