How to request an executable process for a parameter list? (windows, C ++)

For this Windows process, I want to know what command line options it was running with. Windows Task Manager can show this, for example.

Thank you in advance!

+5
c ++ winapi
source share
4 answers

Assuming you know the process identifier, use OpenProcess to access it (this requires an elevated privilege, as indicated in the docs). Then use NtQueryInformationProcess to get detailed information about the process. Use the ProcessBasicInformation option to get the process PEB - this contains another structure pointer through which you can run the command line.

+6
source share

Well, you can insert the dll into the address space of the external process, and then call GetCommandLine .

+2
source share

You cannot reliably obtain this information. There are various tricks to try to get it, but there is no guarantee that the target process has not yet looked for this section of memory. Raymond Chen discussed this a while ago at The Old New Thing .

+2
source share

Remote thread insert:

You use remote stream injection, call GetCommandLine() , then return the IPC result. This may work most of the time on Windows XP, but on Windows Vista or later, it does not work on systems and services. This is because CreateRemoteThread only works with processes in the same session identifier as the caller β€” in Windows Vista, services, and other system processes runs in session 0, while user programs run in higher sessions. The best and safest way is to read the structure present in every Windows process.

PEB structure:

The Process Environment Block (PEB) is typically stored in high areas of the process memory, above 0x7ff00000 . These regions also contain flow medium blocks (TEBs). The PEB address is different for almost every process, so you cannot just use a hard-coded constant.

 #include <windows.h> #include <stdio.h> #include "Winternl.h" typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)( HANDLE ProcessHandle, DWORD ProcessInformationClass, PVOID ProcessInformation, DWORD ProcessInformationLength, PDWORD ReturnLength ); PVOID GetPebAddress(HANDLE ProcessHandle) { _NtQueryInformationProcess NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); PROCESS_BASIC_INFORMATION pbi; NtQueryInformationProcess(ProcessHandle, 0, &pbi, sizeof(pbi), NULL); return pbi.PebBaseAddress; } int wmain(int argc, WCHAR *argv[]) { int pid; HANDLE processHandle; PVOID pebAddress; PVOID rtlUserProcParamsAddress; UNICODE_STRING commandLine; WCHAR *commandLineContents; if (argc < 2) { printf("Usage: getprocesscommandline [pid]\n"); return 1; } pid = _wtoi(argv[1]); if ((processHandle = OpenProcess( PROCESS_QUERY_INFORMATION | /* required for NtQueryInformationProcess */ PROCESS_VM_READ, /* required for ReadProcessMemory */ FALSE, pid)) == 0) { printf("Could not open process!\n"); return GetLastError(); } pebAddress = GetPebAddress(processHandle); /* get the address of ProcessParameters */ if (!ReadProcessMemory(processHandle, &(((_PEB*) pebAddress)->ProcessParameters), &rtlUserProcParamsAddress, sizeof(PVOID), NULL)) { printf("Could not read the address of ProcessParameters!\n"); return GetLastError(); } /* read the CommandLine UNICODE_STRING structure */ if (!ReadProcessMemory(processHandle, &(((_RTL_USER_PROCESS_PARAMETERS*) rtlUserProcParamsAddress)->CommandLine), &commandLine, sizeof(commandLine), NULL)) { printf("Could not read CommandLine!\n"); return GetLastError(); } /* allocate memory to hold the command line */ commandLineContents = (WCHAR *)malloc(commandLine.Length); /* read the command line */ if (!ReadProcessMemory(processHandle, commandLine.Buffer, commandLineContents, commandLine.Length, NULL)) { printf("Could not read the command line string!\n"); return GetLastError(); } /* print it */ /* the length specifier is in characters, but commandLine.Length is in bytes */ /* a WCHAR is 2 bytes */ printf("%.*S\n", commandLine.Length / 2, commandLineContents); CloseHandle(processHandle); free(commandLineContents); return 0; } 

For more information, see Get a process command line.

EDIT (additional information):

The first author said:

CreateRemoteThread only works with processes in the same session identifier as the caller β€” in Windows Vista, services and other system processes run in session 0, while user programs run in higher sessions. The best and safest way is to read the structure present in every Windows process.

This is the same with OpenProcess , you cannot open a process that is a service or process, open SYSTEM or LOCAL SERVICE or NETWORK SERVICE if you run your program as a user (even as an administrator).

If your program is a service, it is probably already started by the local system account, so no problem. But if not, then the solution should start it using PSEXEC :

  • Download PSEXEC and unzip it to a folder.
  • Open the elevated CMD prompt as an administrator.
  • Go to the folder where you unzipped PSEXEC.EXE
  • Launch: PSEXEC -i -s -d CMD
  • A new CMD prompt opens.
  • Enter the following in a new CMD invitation to prove who you are: WHOAMI

You should see that you are SYSTEM, now you can run your program and view the command line for all processes.

+2
source share

All Articles