I am trying to get another process commandline (on WinXP 32bit). I do the following:
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, ProcList.proc_id_as_numbers[i]);
BytesNeeded = sizeof(PROCESS_BASIC_INFORMATION);
ZwQueryInformationProcess(hProcess, ProcessBasicInformation, UserPool, sizeof(PROCESS_BASIC_INFORMATION), &BytesNeeded);
pbi = (PPROCESS_BASIC_INFORMATION)UserPool;
BytesNeeded = sizeof(PEB);
res = ZwReadVirtualMemory(hProcess, pbi->PebBaseAddress, UserPool, sizeof(PEB), &BytesNeeded);
/* zero value returned */
peb = (PPEB)UserPool;
BytesNeeded = sizeof(RTL_USER_PROCESS_PARAMETERS);
res = ZwReadVirtualMemory(hProcess, peb->ProcessParameters, UserPool, sizeof(RTL_USER_PROCESS_PARAMETERS), &BytesNeeded);
ProcParam = (PRTL_USER_PROCESS_PARAMETERS)UserPool;
After first call pbi.UniqueProcessID is correct. But after calling ZwReadVirtualMemory I get command line for my process, not requested one.
I also used ReadProcessMemore & NtQueryInformationProcess, but get the same result.
Can anybody help?
Here http://forum.sysinternals.com/get-commandline-of-running-processes_topic6510_page1.html is being said that this code works. Unfortunately, I do not have access to post on this forum to ask themselves.
Duplicate of How to query a running process for it's parameters list? (windows, C++) , so I'll just copy my answer from there over here:
You can't reliably get that information. There are various tricks to try and retrieve it, but there's no guarantee that the target process hasn't already mangled that section of memory. Raymond Chen discussed this awhile back on The Old New Thing.
It looks like ZwReadVirtualMemory is called only once. That is not enough. It has to be called for each level of pointer indirection. In other words when you retrieve a pointer it points to other process' address space. You cannot read it directly. You have to call ZwReadVirtualMemory again. For the case of those data structures ZwReadVirtualMemory has to be called 3 times: once to read PEB (that is what the code above does), once to read RTL_USER_PROCESS_PARAMETERS and once to read UNICODE_STRING's buffer. The following code fragment worked for me (error handling omitted for clarity and I used documented ReadProcessMemory API instead of ZwReadVirtualMemory):
Why we see see the command line of our own process? That is because processes are laid out in a similar way. Command line and PEB-related structures are likely to have the same addresses. So if you missed ReadProcessMemory you end up exactly with local process' command line.
I was trying to do this same thing using mingw & Qt. I ran into a problem with "undefined reference to CLSID_WbemLocator". After some research, it seems that the version of libwbemuuid.a which was included with my version of mingw only defined IID_IWbemLocator but not CLSID_WbemLocator.
I found that manually defining CLSID_WbemLocator works (although its probably not the "correct" way of doing things).
The final working code:
and in my Qt project file (.pro) I link to the following libraries:
You don't have to read the VM of the target process to do this. Just make sure you have the correct Process ID for the target process.
Once you have the process handle via
OpenProcess
, you can then use NtQueryInformationProcess to get detailed process info. Use the ProcessBasicInformation option to get the PEB of the process - this contains another structure pointer RTL_USER_PROCESS_PARAMETERS, through which you can get the command line.You need to be more disciplined with checking return codes. It may be that any of your
ZwReadVirtualMemory
calls yield an error code which points you into the right direction.In particular, the
ProcList.proc_id_as_numbers[i]
part suggests that you're executing this code in a loop. Chances are that theprocPeb.ProcessParameters
structure is still filled with the values of an earlier loop iteration - and since theZwReadVirtualMemory
call fails on your target process, you get to see the command line of whatever process was previously queried.