Geoff Chappell, Software Analyst
CURRENT WORK ITEM - PREVIEW ONLY
This function gets a wide range of system properties but allows for refining the query by specifying such things as a processor group.
NTSTATUS ZwQuerySystemInformationEx ( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID InputBuffer, ULONG InputBufferLength, PVOID SystemInformation, ULONG SystemInformationLength, ULONG *ReturnLength);
The SystemInformationClass argument tells what sort of information is sought. There are many supported values.
The InputBuffer and InputBufferLength arguments are respectively the address and size (in bytes) of a buffer that provides data to refine the query. What the function interprets in this buffer depends on the information class.
The SystemInformation and SystemInformationLength arguments are respectively the address and size (in bytes) of a buffer that receives the information. What the function puts into this buffer depends on the information class.
The ReturnLength argument is the address of a variable whose value on output tells how much information, in bytes, the successful function has put into the buffer or may tell how much the failed function might have put into the buffer (had the buffer been large enough). This argument can be NULL if the caller does not want to know how much information is available.
The function returns STATUS_SUCCESS if successful, else a negative error code.
Of particular importance are STATUS_INFO_LENGTH_MISMATCH and STATUS_BUFFER_TOO_SMALL, which are the function’s indications that the information buffer was given with the wrong size. A size that would have sufficed for a full return of available information will have been set into the variable, if any, that was specified through the ReturnLength argument.
A size may be returned via ReturnLength for other error codes, but this outcome is here treated as unintended since it looks unreliable.
The ZwQuerySystemInformationEx and NtQuerySystemInformationEx functions are exported by name from NTDLL in version 6.1 and higher. In user mode, the functions are aliases for a stub that transfers execution to the NtQuerySystemInformationEx implementation in kernel mode such that the execution is recognised as originating in user mode.
As named exports from the kernel, NtQuerySystemInformationEx also dates from version 6.1 but ZwQuerySystemInformationEx is exported only in version 6.3 and higher. In kernel mode, ZwQuerySystemInformationEx is also a stub that transfers execution to NtQuerySystemInformationEx but such that the execution is recognised as originating in kernel mode.
Under any name, this function is not documented. As ZwQuerySystemInformationEx only, it is declared in the ZWAPI.H that seems to have been first published in a Windows Driver Kit (WDK) for Windows 10.
The SYSTEM_INFORMATION_CLASS enumeration has a C-language definition in WINTERNL.H from the Software Development Kit (SDK), for use with the NtQuerySystemInformation function which is documented as an NTDLL export. The definition given there is plainly not what Microsoft itself uses but is instead a contrivance for the relative handful of cases that Microsoft discloses. Two of those cases, however, are acceptable to NtQuerySystemInformationEx.
The following implementation notes are from inspection of the kernel from the original release of Windows 10. They may some day get revised to account for earlier versions. Meanwhile, where anything is added about earlier versions, take it as a bonus from my being unable to resist at least a quick look into the history, not as an attempt at comprehensiveness.
The function exists only to get information that varies with some input specification. If InputBuffer is NULL or InputBufferLength is zero, the function fails, returning STATUS_INVALID_PARAMETER.
A table below lists the acceptable information classes. For all others the function fails, returning STATUS_INVALID_INFO_CLASS.
If executing for a user-mode request, the function has some general defensiveness about addresses passed as arguments. Failure at any of these defences is failure for the function, typically showing as a return of STATUS_DATATYPE_MISALIGNMENT or STATUS_ACCESS_VIOLATION (as raised but handled exceptions).
The input buffer must be word-aligned ordinarily but dword-aligned for information classes SystemLogicalProcessorAndGroupInformation (0x6B) and SystemCpuSetInformation (0xAF), and qword-aligned for SystemIsolatedUserModeInformation (0xA5). Of course, the whole of the input buffer must lie in user-mode address space.
If an information buffer is given, meaning here that SystemInformationLength is non-zero, then its address SystemInformation must have 4-byte alignment and must be in user-mode address space and must be writable (at its first byte and also for a byte at each page boundary that is inside the buffer).
If a variable is given by address in the ReturnLength argument for learning how much information is or could be produced, then this variable too must be in user-mode address space and be writable.
Except if noted explicitly below, the function never reads the InputBuffer or accesses the SystemInformation or writes to the variable at ReturnLength without preparing for exceptions. If executing for a user-mode request, the occurrence of an exception during such access is fatal for the function, which returns the exception code as its own result. If executing for a kernel-mode request, exceptions are handled only to continue as if unhandled, which will typically be fatal to Windows.
The following table lists the information classes that ZwQuerySystemInformationEx does not dismiss as invalid. For all others the function fails, returning STATUS_INVALID_INFO_CLASS.
Numeric Value | Symbolic Name |
---|---|
0x08 | SystemProcessorPerformanceInformation |
0x17 | SystemInterruptInformation |
0x2A | SystemProcessorIdleInformation |
0x3D | SystemProcessorPowerInformation |
0x49 | SystemLogicalProcessorInformation |
0x53 | SystemProcessorIdleCycleTimeInformation |
0x64 | SystemProcessorPerformanceDistribution |
0x6B | SystemLogicalProcessorAndGroupInformation |
0x6C | SystemProcessorCycleTimeInformation |
0x79 | SystemNodeDistanceInformation |
0x8D | SystemProcessorPerformanceInformationEx |
0xA0 | SystemProcessorCycleStatsInformation |
0xA5 | SystemIsolatedUserModeInformation |
0xAF | SystemCpuSetInformation |
All remaining behaviour varies with the information class, but many have some similar elements to their treatment. This allows some shorthands. Notably, where the descriptions below say simply that the function sets the return length, it’s left as understood that what gets set is the variable at the address given by ReturnLength if the latter is not NULL.
For each information class, the function expects a fixed-size parameter in the input buffer. The descriptions below leave as understood that if the input buffer is too small for the expected parameter, then the function fails, returning STATUS_INVALID_PARAMETER. For most information classes, the parameter is specifically the USHORT group number of the processor group for which information is wanted. If this group number is not smaller than the current count of active groups, then the function fails, returning STATUS_INVALID_PARAMETER.
For many information classes, the information buffer must either provide exactly a fixed-size structure for the function to fill or be at least large enough for this structure. If, the SystemInformationLength is not an exact fit or is too small, respectively, then the function sets the return length to the expected size and returns STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills in the structure, sets the return length to the size of that structure and returns STATUS_SUCCESS. Where the descriptions below simply state that the information buffer must provide exactly or at least some structure for the function to fill in, then this is the whole behaviour. The meaning of whatever the function puts in the structure is taken up, if at all, in the separate documentation of that structure.
Please understand that devising shorthands so that the behaviour can be described accurately without tedious repetition is a work in progress, surely requiring multiple passes, each susceptible to error. Take more care than would be usual even for draft material.
The input buffer must specify a processor group. The information buffer is to receive an array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION structures, one for each active processor in the specified processor group. If the information buffer is not an exact fit for one or more such structures, the function sets the return length to the size of the array it could produce, and fails, returning STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills the buffer with as many structures as fit, up to the number of processors, and sets the return length to the size of what has been put in the buffer. Even if this is not the whole array that the function could have put in the buffer, the function declares success.
TO BE DONE
TO BE DONE
TO BE DONE
The input buffer must specify a processor group. The information buffer is to receive an array of SYSTEM_LOGICAL_PROCESSOR_INFORMATION structures, one for each active processor in the specified processor group. (The structure is declared in WDM.H and WINNT.H, for kernel-mode and user-mode programming, respectively.)
For this information class, the function is the essence of the documented user-mode function GetLogicalProcessorInformation.
The input buffer must specify a processor group. The information buffer is to receive an array of SYSTEM_PROCESSOR_IDLE_CYCLE_TIME structures, one for each active processor in the specified processor group. If the information buffer is too small for even one such structure, the function sets the return length to the size of the array it could produce, and fails, returning STATUS_BUFFER_TOO_SMALL. Otherwise, the function fills the buffer with as many structures as fit, up to the number of processors, and sets the return length to the size of the whole array. If the buffer is too small for the whole array, the function fails, returning STATUS_INFO_LENGTH_MISMATCH (but with meaningful data in the buffer).
For this information class, the function is the essence of the documented user-mode function QueryIdleProcessorCycleTimeEx.
TO BE DONE
The input buffer must specify a LOGICAL_PROCESSOR_RELATIONSHIP. The information buffer is to receive an array of SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX structures, one for each logical processor that is known to the system. (The enumeration and the structure are defined in WDM.H and WINNT.H, for kernel-mode and user-mode programming, respectively.)
For this information class, the function is the essence of the documented user-mode function GetLogicalProcessorInformationEx.
The input buffer must specify a processor group. The information buffer is to receive an array of SYSTEM_PROCESSOR_CYCLE_TIME structures, one for each active processor in the specified processor group. If the information buffer is too small for even one such structure, the function sets the return length to the size of the array it could produce, and fails, returning STATUS_BUFFER_TOO_SMALL. Otherwise, the function fills the buffer with as many structures as fit, up to the number of processors, and sets the return length to the size of the whole array. If the buffer is too small for the whole array, the function fails, returning STATUS_INFO_LENGTH_MISMATCH (but with meaningful data in the buffer).
For this information class, the function is the essence of the documented user-mode function GetProcessorSystemCycleTime.
TO BE DONE
The input buffer must specify a processor group. The information buffer is to receive an array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX structures, one for each active processor in the specified processor group. If the information buffer is not an exact fit for one or more such structures, the function sets the return length to the size of the array it could produce, and fails, returning STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills the buffer with as many structures as fit, up to the number of processors, and sets the return length to the size of what has been put in the buffer. Even if this is not the whole array that the function could have put in the buffer, the function declares success.
TO BE DONE
TO BE DONE
The input buffer must provide a HANDLE for a target process. The data that this function produces in the information buffer will indicate which CPU sets are allocated to this process. This handle can be NULL if this indication is not wanted, i.e., to mean that there is no target process. Otherwise, failure to reference the target process for PROCESS_QUERY_LIMITED_INFORMATION access is failure for the function.
The information buffer is to receive an array of SYSTEM_CPU_SET_INFORMATION structures, one for each CPU set. (The structure is defined in WDM.H and WINNT.H, for kernel-mode and user-mode programming, respectively.) If the information buffer is not large enough for them all, the function sets the return length to the size of the array it could produce, and fails, returning STATUS_BUFFER_TOO_SMALL.
For this information class, the function is the essence of the documented user-mode function GetSystemCpuSetInformation.