2

After doing some research and looking at the source code of ProcessHacker, it seems the way to obtain conhost.exe's process id is to use NtQuerySystemInformation.

I wrote the following little program for testing purposes but, it isn't working and I don't see why.

{$APPTYPE CONSOLE}

{$TYPEDADDRESS ON}

program _QueryInformationProcess_ProcessConsoleHostProcess;

uses
  Windows,
  sysutils
  ;

{$ifdef VER90}
type
  ptrint  = longint;
  ptruint = DWORD;

const
  DELETE                   = $00010000;
  READ_CONTROL             = $00020000;
  WRITE_DAC                = $00040000;
  WRITE_OWNER              = $00080000;
  SYNCHRONIZE              = $00100000;

  STANDARD_RIGHTS_REQUIRED = $000F0000;

  STANDARD_RIGHTS_READ     = READ_CONTROL;
  STANDARD_RIGHTS_WRITE    = READ_CONTROL;
  STANDARD_RIGHTS_EXECUTE  = READ_CONTROL;

  STANDARD_RIGHTS_ALL      = $001F0000;
  SPECIFIC_RIGHTS_ALL      = $0000FFFF;

  PROCESS_ALL_ACCESS        = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $FFF;
{$endif}

const
  ntdll = 'ntdll.dll';

  { process information class(es) used in QueryInformationProcess             }

type
  PROCESSINFOCLASS =
  (
    {  0 }  ProcessBasicInformation,                      // q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION
    {  1 }  ProcessQuotaLimits,                           // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX
    {  2 }  ProcessIoCounters,                            // q: IO_COUNTERS
    {  3 }  ProcessVmCounters,                            // q: VM_COUNTERS, VM_COUNTERS_EX, VM_COUNTERS_EX2
    {  4 }  ProcessTimes,                                 // q: KERNEL_USER_TIMES
    {  5 }  ProcessBasePriority,                          // s: KPRIORITY
    {  6 }  ProcessRaisePriority,                         // s: ULONG
    {  7 }  ProcessDebugPort,                             // q: HANDLE
    {  8 }  ProcessExceptionPort,                         // s: HANDLE
    {  9 }  ProcessAccessToken,                           // s: PROCESS_ACCESS_TOKEN
    { 10 }  ProcessLdtInformation,                        // qs: PROCESS_LDT_INFORMATION                                                               // 10
    { 11 }  ProcessLdtSize,                               // s: PROCESS_LDT_SIZE
    { 12 }  ProcessDefaultHardErrorMode,                  // qs: ULONG
    { 13 }  ProcessIoPortHandlers,                        // (kernel-mode only)
    { 14 }  ProcessPooledUsageAndLimits,                  // q: POOLED_USAGE_AND_LIMITS
    { 15 }  ProcessWorkingSetWatch,                       // q: PROCESS_WS_WATCH_INFORMATION[]; s: void
    { 16 }  ProcessUserModeIOPL,
    { 17 }  ProcessEnableAlignmentFaultFixup,             // s: BOOLEAN
    { 18 }  ProcessPriorityClass,                         // qs: PROCESS_PRIORITY_CLASS
    { 19 }  ProcessWx86Information,
    { 20 }  ProcessHandleCount,                           // q: ULONG, PROCESS_HANDLE_INFORMATION                                                               // 20
    { 21 }  ProcessAffinityMask,                          // s: KAFFINITY
    { 22 }  ProcessPriorityBoost,                         // qs: ULONG
    { 23 }  ProcessDeviceMap,                             // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX
    { 24 }  ProcessSessionInformation,                    // q: PROCESS_SESSION_INFORMATION
    { 25 }  ProcessForegroundInformation,                 // s: PROCESS_FOREGROUND_BACKGROUND
    { 26 }  ProcessWow64Information,                      // q: ULONG_PTR
    { 27 }  ProcessImageFileName,                         // q: UNICODE_STRING
    { 28 }  ProcessLUIDDeviceMapsEnabled,                 // q: ULONG
    { 29 }  ProcessBreakOnTermination,                    // qs: ULONG
    { 30 }  ProcessDebugObjectHandle,                     // q: HANDLE                                                               // 30
    { 31 }  ProcessDebugFlags,                            // qs: ULONG
    { 32 }  ProcessHandleTracing,                         // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables
    { 33 }  ProcessIoPriority,                            // qs: IO_PRIORITY_HINT
    { 34 }  ProcessExecuteFlags,                          // qs: ULONG
    { 35 }  ProcessResourceManagement,
    { 36 }  ProcessCookie,                                // q: ULONG
    { 37 }  ProcessImageInformation,                      // q: SECTION_IMAGE_INFORMATION
    { 38 }  ProcessCycleTime,                             // q: PROCESS_CYCLE_TIME_INFORMATION                                                               // since VISTA
    { 39 }  ProcessPagePriority,                          // q: ULONG
    { 40 }  ProcessInstrumentationCallback,               // 40
    { 41 }  ProcessThreadStackAllocation,                 // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX
    { 42 }  ProcessWorkingSetWatchEx,                     // q: PROCESS_WS_WATCH_INFORMATION_EX[]
    { 43 }  ProcessImageFileNameWin32,                    // q: UNICODE_STRING
    { 44 }  ProcessImageFileMapping,                      // q: HANDLE (input)
    { 45 }  ProcessAffinityUpdateMode,                    // qs: PROCESS_AFFINITY_UPDATE_MODE
    { 46 }  ProcessMemoryAllocationMode,                  // qs: PROCESS_MEMORY_ALLOCATION_MODE
    { 47 }  ProcessGroupInformation,                      // q: USHORT[]
    { 48 }  ProcessTokenVirtualizationEnabled,            // s: ULONG
    { 49 }  ProcessConsoleHostProcess,                    // q: ULONG_PTR
    { 50 }  ProcessWindowInformation,                     // q: PROCESS_WINDOW_INFORMATION                                                               // 50
    { 51 }  ProcessHandleInformation,                     // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION                                                               // since WIN8
    { 52 }  ProcessMitigationPolicy,                      // s: PROCESS_MITIGATION_POLICY_INFORMATION
    { 53 }  ProcessDynamicFunctionTableInformation,
    { 54 }  ProcessHandleCheckingMode,
    { 55 }  ProcessKeepAliveCount,                        // q: PROCESS_KEEPALIVE_COUNT_INFORMATION
    { 56 }  ProcessRevokeFileHandles,                     // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION
    { 57 }  ProcessWorkingSetControl,                     // s: PROCESS_WORKING_SET_CONTROL
    { 58 }  ProcessHandleTable,                           // since WINBLUE
    { 59 }  ProcessCheckStackExtentsMode,
    { 60 }  ProcessCommandLineInformation,                // q: UNICODE_STRING                                                               // 60
    { 61 }  ProcessProtectionInformation,                 // q: PS_PROTECTION
    { 62 }  ProcessMemoryExhaustion,                      // PROCESS_MEMORY_EXHAUSTION_INFO                                                               // since THRESHOLD
    { 63 }  ProcessFaultInformation,                      // PROCESS_FAULT_INFORMATION
    { 64 }  ProcessTelemetryIdInformation,                // PROCESS_TELEMETRY_ID_INFORMATION
    { 65 }  ProcessCommitReleaseInformation,              // PROCESS_COMMIT_RELEASE_INFORMATION
    { 66 }  ProcessDefaultCpuSetsInformation,
    { 67 }  ProcessAllowedCpuSetsInformation,
    { 68 }  ProcessReserved1Information,
    { 69 }  ProcessReserved2Information,
    { 70 }  ProcessSubsystemProcess,                      // 70
    { 71 }  ProcessJobMemoryInformation,                  // PROCESS_JOB_MEMORY_INFO
    { 72 }  ProcessInPrivate,                             // since THRESHOLD2
    { 73 }  ProcessRaiseUMExceptionOnInvalidHandleClose,
    { 74 }  MaxProcessInfoClass
  );

type
  NTSTATUS                    = DWORD;

{-----------------------------------------------------------------------------}

function NtQueryInformationProcess(ProcessHandle            : THANDLE;
                                   ProcessInformationClass  : DWORD;
                                   ProcessInformation       : pointer;
                                   ProcessInformationLength : DWORD;
                                   ReturnLength             : PDWORD)
         : NTSTATUS; stdcall; external ntdll;

{-----------------------------------------------------------------------------}

procedure EndProgram(ExitCode : ptruint);
begin
  writeln('Exit code : ', ExitCode);
  writeln('Press <enter>/<return> to end this program.');

  readln;
end;

{-----------------------------------------------------------------------------}

var
  ProcessHandle      : THANDLE;

  ReturnLength       : DWORD;
  NtResult           : NTSTATUS;

  { upon success should contain the conhost.exe process id                    }

  ConsoleHostProcess : ptruint;

begin
  writeln;

  writeln('GetCurrentProcessId : ', GetCurrentProcessId()); { not conhost's   }

  // since we are dealing with our own process we can specify PROCESS_ALL_ACCESS

  ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS,
                               FALSE,
                               GetCurrentProcessId());

  if ProcessHandle = 0 then EndProgram(1);


  // use the process handle to obtain conhost.exe process id

  ReturnLength := 0;  { for good measure }
  NtResult     := 0;

  NtResult := NtQueryInformationProcess(ProcessHandle,
                                        DWORD(ProcessConsoleHostProcess),
                                        @ConsoleHostProcess,
                                        sizeof(ConsoleHostProcess),
                                        nil);
                                        //@ReturnLength);

  { returns 0xC0000003 STATUS_INVALID_INFO_CLASS                              }
  { [Invalid Parameter] The specified information class is not a valid        }
  { information class for the specified object.                               }

  writeln('NTSTATUS           : ', IntToHex(NtResult, 0));
  writeln('ReturnLength       : ', ReturnLength);

  writeln;
  writeln('Press <enter>/<result> to end this program.');
  readln;
end.

As is stated in the program comments, I get NTSTATUS - 0xC0000003 STATUS_INVALID_INFO_CLASS

which means:

[Invalid Parameter] The specified information class is not a valid information class for the specified object.

but, I don't see it, where is my mistake ?

Thank you for your help.

ScienceAmateur
  • 521
  • 4
  • 11
  • 2
    On a side note, you can and should use `GetCurrentProcess()` instead of `OpenProcess(GetCurrentProcessId())` – Remy Lebeau Apr 26 '19 at 02:37
  • @ Remy, yes, you're right. The reason the example uses GetCurrentProcessId is because I'm actually using that method with processes other than mine and, what I have is their process id. I was trying to make the example as close as possible to what I'm actually doing. – ScienceAmateur Apr 26 '19 at 03:06
  • Look at [documentation](https://learn.microsoft.com/en-us/windows/desktop/api/winternl/nf-winternl-ntqueryinformationprocess) under `Parameters, ProcessInformationClass` . `ProcessConsoleHostProcess` is not listed as a valid parameter. – Tom Brunberg Apr 26 '19 at 05:22
  • @ Tom, it's not documented. ProcessHacker and Process Explorer use it. – ScienceAmateur Apr 26 '19 at 05:46
  • Debug the working code and see where it diverges from your code – David Heffernan Apr 26 '19 at 05:55
  • @ David, I've been trying to do that. I cannot get ProcessHacker to compile anymore and I no longer have a debug version of the executable. Some update to VS2107 messed everything up. – ScienceAmateur Apr 26 '19 at 07:14
  • 1
    Yeah, you don't need to debug the entire program. Just extract the part that is of interest. – David Heffernan Apr 26 '19 at 07:21
  • this is `ProcessOwnerInformation` (49) declared in *ntddk.h*, what is windows version you use ? – RbMm Apr 26 '19 at 12:36
  • @ RbMm, sorry for the delay in responding to you. I got the definition from ProcessHacker's ntpsapi.h, specifically, the structure typedef enum _PROCESSINFOCLASS. Since that works for ProcessHacker, it should work for other programs too. – ScienceAmateur Apr 26 '19 at 21:11

1 Answers1

2

Seems that parameter ProcessConsoleHostProcess(49) is not support in 32-bit, and I can just get it work in 64-bit program. You could try to compile it with x64.

There are also reminders in the document

To maintain the compatibility of your application, it is better to use public functions mentioned in the description of the ProcessInformationClass parameter instead.

Or you could also get it in another way with Tool Help Functions. Here is the related sample.

Drake Wu
  • 6,927
  • 1
  • 7
  • 30