tags:

views:

2892

answers:

5

I need to be able to list the command line arguments (if any) passed to other running processes. I have the PIDs already of the running processes on the system, so basically I need to determine the arguments passed to process with given PID XXX.

I'm working on a core piece of a Python module for managing processes. The code is written as a Python extension in C and will be wrapped by a higher level Python library. The goal of this project is to avoid dependency on third party libs such as the pywin32 extensions, or on ugly hacks like calling 'ps' or taskkill on the command line, so I'm looking for a way to do this in C code.

I've Googled this around and found some brief suggestions of using CreateRemoteThread() to inject myself into the other process, then run GetCommandLine() but I was hoping someone might have some working code samples and/or better suggestions.

UPDATE: I've found full working demo code and a solution using NtQueryProcessInformation on CodeProject: http://www.codeproject.com/KB/threads/GetNtProcessInfo.aspx - It's not ideal since it's "unsupported" to cull the information directly from the NTDLL structures but I'll live with it. Thanks to all for the suggestions.

UPDATE 2: I managed through more Googling to dig up a C version that does not use C++ code, and is a little more direct/concisely pointed toward this problem. See http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/ for details.

Thanks!

A: 

If you aren't the parent of these processes, then this is not possible using documented functions :( Now, if you're the parent, you can do your CreateRemoteThread trick, but otherwise you will almost certainly get Access Denied unless your app has admin rights.

Paul Betts
I've got code in the module now that will get SeDebug rights if possible, so if they're an Admin user we should have the privileges needed right?
Jay
+3  A: 

The cached solution: http://74.125.45.132/search?q=cache:-wPkE2PbsGwJ:windowsxp.mvps.org/listproc.htm+running+process+command+line&hl=es&ct=clnk&cd=1&gl=ar&client=firefox-a

in CMD
WMIC /OUTPUT:C:\ProcessList.txt PROCESS get Caption,Commandline,Processid

or

WMIC /OUTPUT:C:\ProcessList.txt path win32_process get Caption,Processid,Commandline

Also: http://mail.python.org/pipermail/python-win32/2007-December/006498.html

http://tgolden.sc.sabren.com/python/wmi_cookbook.html#running_processes 
seems to do the trick:

import wmi
c = wmi.WMI ()
for process in c.Win32_Process ():
  print process.CommandLine
Ironicnet
Thanks for the suggestions, however, I'd really prefer not to call external processes. The wmi module referenced also requires another third party module on top of the pywin32 extensions, which we don't want to require the user to have either.
Jay
You can call WMI from C via its COM interface, though it won't be the most elegant code ever.
Rob Walker
@Rob - this is true...that'd be some serious overhead for this seemingly simple task, but it's starting to look like I don't have many options.
Jay
+2  A: 

The WMI approach mentioned in another response is probably the most reliable way of doing this. Looking through MSDN, I spotted what looks like another possible approach; it's documented, but its not clear whether it's fully supported. In MSDN's language, it--

may be altered or unavailable in future versions of Windows...

In any case, provided that your process has the right permissions, you should be able to call NtQueryProcessInformation with a ProcessInformationClass of ProcessBasicInformation. In the returned PROCESS_BASIC_INFORMATION structure, you should get back a pointer to the target process's process execution block (as field PebBaseAddress). The ProcessParameters field of the PEB will give you a pointer to an RTL_USER_PROCESS_PARAMETERS structure. The CommandLine field of that structure will be a UNICODE_STRING structure. (Be careful not too make too many assumptions about the string; there are no guarantees that it will be NULL-terminated, and it's not clear whether or not you'll need to strip off the name of the executed application from the beginning of the command line.)

I haven't tried this approach--and as I mentioned above, it seems a bit... iffy (read: non-portable)--but it might be worth a try. Best of luck...

Reuben
I saw this and felt the same as you - it seemed shaky, but the CodeProject demo I found works great even on Vista so I'm going to go with this anyway. See the CodeProject link for working code.
Jay
+4  A: 

To answer my own question, I finally found a CodeProject solution that does exactly what I'm looking for:

http://www.codeproject.com/KB/threads/GetNtProcessInfo.aspx

As @Reuben already pointed out, you can use NtQueryProcessInformation to retrieve this information. Unfortuantely it's not a recommended approach, but given the only other solution seems to be to incur the overhead of a WMI query, I think we'll take this approach for now.

Note that this seems to not work if using code compiled from 32bit Windows on a 64bit Windows OS, but since our modules are compiled from source on the target that should be OK for our purposes. I'd rather use this existing code and should it break in Windows 7 or a later date, we can look again at using WMI. Thanks for the responses!

UPDATE: A more concise and C only (as opposed to C++) version of the same technique is illustrated here:

http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/

Jay
+3  A: 

I expect to get voted up for my answer!

wj32
Why not link to your code or even add a little answer/descriptive text and I can upvote that?
Jay
Look at my username. Look at the accepted solution below. :)http://wj32.wordpress.com/2009/01/24/howto-get-the-command-line-of-processes/
wj32
I saw...I figured if you post an answer I can make that the accepted answer instead of my own, rather than upvote just this post :-)
Jay
CBB. Doesn't matter.
wj32