CURRENT WORK ITEM - PREVIEW ONLY

ZwQuerySystemInformation

This function gets a wide range of system properties.

Specially noteworthy is that this function in its user-mode form, NtQuerySystemInformation, is occasionally the target of malware, not just to use it but to hook it, the idea being to mislead other software about the malware’s presence. See particularly the cases where this function returns information about the running processes, loaded modules and opened handles.

Declaration

NTSTATUS 
ZwQuerySystemInformation (
    SYSTEM_INFORMATION_CLASS SystemInformationClass, 
    PVOID SystemInformation, 
    ULONG SystemInformationLength, 
    ULONG *ReturnLength);

Parameters

The SystemInformationClass argument tells what sort of information is sought. There are very many supported values.

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. For some information classes, the function expects input from the buffer (too or instead). For some information classes, the SystemInformationLength argument can be 0 and the SystemInformation argument is then ignored.

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 produced or is available.

Return Value

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 unreliable since it looks not to be uniformly intended. Moreover, pending expansion of this article to account in detail for variations between Windows versions, it is as well to note that before version 6.0 the return of an expected size is unreliable even when the error code is STATUS_INFO_LENGTH_MISMATCH. (Roughly, the expected size tends to be returned for information classes for which the output can vary in size, but tends not to be for information classes whose output is a fixed-size structure.)

The function appears to be free to use the information buffer however it wants while it works towards its result. The understanding throughout these notes is that calling this function leaves the information buffer with undefined contents except for however many bytes the function declares as its output on success.

Beware that the preceding paragraphs attempt only to describe what seems intended in general for the parameters and return value. Cases exist which do not exactly conform. This likely means that the inferred description is wrong or at least needs to be refined, but some cases seem so special that it seems reasonable to suspect that the defect is in the implementation. For instance, after the function’s success for the information class SystemSessionProcessInformation (0x35), the size in the variable at ReturnLength can be vastly greater than the size that was given for SystemInformationLength.

Availability

The ZwQuerySystemInformation and NtQuerySystemInformation functions were originally for the kernel’s user-mode interface only. For this purpose, they are ancient, being exported by name from NTDLL in version 3.51 and higher. In user mode, the functions are aliases for a stub that transfers execution to the NtQuerySystemInformation implementation in kernel mode such that the execution is recognised as originating in user mode.

Availability in kernel mode wasn’t long in coming: ZwQuerySystemInformation is exported by name from the kernel in version 4.0 and higher; NtQuerySystemInformation in version 5.0 and higher. In kernel mode, ZwQuerySystemInformation is also a stub that transfers execution to the NtQuerySystemInformation implementation but such that the execution is recognised as originating in kernel mode.

Documentation Status

As NtQuerySystemInformation only, and only then as exported from NTDLL, this function got documented at roughly the time of Microsoft’s settlement compliance in 2002. It is declared in WINTERNL.H from the Software Development Kit (SDK). The definition given there for the SYSTEM_INFORMATION_CLASS enumeration names a handful of the very many values that are acceptable to the function.

After a few years, certainly by 2007, this documentation of NtQuerySystemInformation was joined by slightly different documentation of ZwQuerySystemInformation, still only as exported from NTDLL. This documentation nowadays states plainly that the function “is no longer available for use as of Windows 8.”

Though NtQuerySystemInformation is mentioned in a comment in NTDDK.H from as long ago as the Device Driver Kit (DDK) for Windows NT 3.51, no header from a DDK or Windows Driver Kit (WDK) declares the function under either name until ZwQuerySystemInformation is declared in the ZWAPI.H that seems to have been first published, possibly by oversight, in a WDK for Windows 10.

Behaviour

The following implementation notes are from inspection of the kernel from the original release of Windows 10 only. They may some day get revised to account for earlier versions. Meanwhile, where anything is added about earlier versions, take it not as an attempt at comprehensiveness but as a bonus from my being unable to resist a trip down memory lane or at least a quick look into the history.

Immediate Failure

Information classes SystemLogicalProcessorAndGroupInformation (0x6B) and SystemNodeDistanceInformation (0x79) are completely invalid for this function and cause its immediate failure, returning STATUS_INVALID_INFO_CLASS. Arguments other than SystemInformationClass are irrelevant. These information classes need ZwQuerySystemInformationEx instead.

User-Mode Defences

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, which typically returns STATUS_DATATYPE_MISALIGNMENT or STATUS_ACCESS_VIOLATION (showing in kernel mode as raised but handled exceptions).

Information Buffer

If an information buffer is given, meaning here that SystemInformationLength is non-zero, then its address SystemInformation must have 4-byte alignment (in general) and the whole buffer must be in user-mode address space and be writable (at its first byte and also for a byte at each page boundary that is inside the buffer). For some information classes, the alignment requirement is effectively waived by requiring only 1-byte alignment:

The x64 builds make an extra case of SystemLocksInformation (0x0C), which requires 8-byte alignment.

Return Length

If a variable is given by address in the ReturnLength argument for learning how much information is or could be produced, then the address must be in user-mode address space and the variable must be writable.

Valid Information Classes

The large table below lists the information classes that ZwQuerySystemInformation does not dismiss as invalid (after the preceding defences). For all others, the function fails, returning STATUS_INVALID_INFO_CLASS. A few, however, do little or nothing except to return some other error such as STATUS_NOT_IMPLEMENTED or STATUS_NOT_SUPPORTED. (Signs exist that some of these may be implemented non-trivially in debug builds, which are outside the scope of these notes.)

The versions that are presently shown for each information class are just from a cursory look for the upper limit that the function applies in different builds. This suffices for a rough idea of the history but not for much more. A version’s appearance for an information class doesn’t mean that the information class is implemented non-trivially, let alone usefully, in that version, just that the function’s switch statement for information classes does not in this version immediately reject this information class.

Names of the information classes and of the related structures and of their members are from symbol files for various high-level user-mode modules such as URLMON.DLL. No symbol files for the kernel or NTDLL, i.e., where the function is implemented or through where all user-mode calls to the function must pass, have relevant type information in any known Windows release.

Numeric Value Symbolic Name Versions
0x00 SystemBasicInformation 3.51 and higher
0x01 SystemProcessorInformation 3.51 and higher
0x02 SystemPerformanceInformation 3.51 and higher
0x03 SystemTimeOfDayInformation 3.51 and higher
0x04 SystemPathInformation 3.51 and higher
0x05 SystemProcessInformation 3.51 and higher
0x06 SystemCallCountInformation 3.51 and higher
0x07 SystemDeviceInformation 3.51 and higher
0x08 SystemProcessorPerformanceInformation 3.51 and higher
0x09 SystemFlagsInformation 3.51 and higher
0x0A SystemCallTimeInformation 3.51 and higher
0x0B SystemModuleInformation 3.51 and higher
0x0C SystemLocksInformation 3.51 and higher
0x0D SystemStackTraceInformation 3.51 and higher
0x0E SystemPagedPoolInformation 3.51 and higher
0x0F SystemNonPagedPoolInformation 3.51 and higher
0x10 SystemHandleInformation 3.51 and higher
0x11 SystemObjectInformation 3.51 and higher
0x12 SystemPageFileInformation 3.51 and higher
0x13 SystemVdmInstemulInformation 3.51 and higher
0x15 SystemFileCacheInformation 3.51 and higher
0x16 SystemPoolTagInformation 3.51 and higher
0x17 SystemInterruptInformation 3.51 and higher
0x18 SystemDpcBehaviorInformation 3.51 and higher
0x19 SystemFullMemoryInformation 3.51 and higher
0x1C SystemTimeAdjustmentInformation 3.51 and higher
0x1D SystemSummaryMemoryInformation 3.51 and higher
0x1F SystemPerformanceTraceInformation 3.51 and higher
0x21 SystemExceptionInformation 3.51 and higher
0x23 SystemKernelDebuggerInformation 3.51 and higher
0x24 SystemContextSwitchInformation 3.51 and higher
0x25 SystemRegistryQuotaInformation 3.51 and higher
0x2A SystemProcessorIdleInformation 4.0 and higher
0x2B SystemLegacyDriverInformation 4.0 and higher
0x2C SystemCurrentTimeZoneInformation 4.0 and higher
0x2D SystemLookasideInformation 4.0 and higher
0x32 SystemRangeStartInformation 5.0 and higher
0x33 SystemVerifierInformation 5.0 and higher
0x35 SystemSessionProcessInformation 5.0 and higher
0x37 SystemNumaProcessorMap 5.0 from Windows 2000 SP4, and higher
0x38 SystemPrefetcherInformation 5.1 and higher
0x39 SystemExtendedProcessInformation 5.1 and higher
0x3A SystemRecommendedSharedDataAlignment 5.1 and higher
0x3B SystemComPlusPackage 5.1 and higher
0x3C SystemNumaAvailableMemory 5.1 and higher
0x3D SystemProcessorPowerInformation 5.1 and higher
0x3E SystemEmulationBasicInformation 5.1 and higher
0x3F SystemEmulationProcessorInformation 5.1 and higher
0x40 SystemExtendedHandleInformation 5.1 and higher
0x41 SystemLostDelayedWriteInformation 5.1 and higher
0x42 SystemBigPoolInformation 5.1 from Windows XP SP2, and higher
0x43 SystemSessionPoolTagInformation 5.1 from Windows XP SP2, and higher
0x44 SystemSessionMappedViewInformation 5.1 from Windows XP SP2, and higher
0x45 SystemHotpatchInformation 5.1 from Windows XP SP2, and higher
0x46 SystemObjectSecurityMode 5.1 from Windows XP SP2, and higher
0x48 SystemWatchdogTimerInformation 5.1 from Windows XP SP3, and higher
0x49 SystemLogicalProcessorInformation 5.1 from Windows XP SP3, and higher
0x4C SystemFirmwareTableInformation 5.2 from Windows Server 2003 SP1, and higher
0x4D SystemModuleInformationEx 5.2 from Windows Server 2003 SP1, and higher
0x4F SystemSuperfetchInformation 5.2 from Windows Server 2003 SP1, and higher
0x50 SystemMemoryListInformation 5.2 from Windows Server 2003 SP1, and higher
0x51 SystemFileCacheInformationEx 5.2 from Windows Server 2003 SP1, and higher
0x53 SystemProcessorIdleCycleTimeInformation 6.0 and higher
0x56 SystemRefTraceInformation 6.0 and higher
0x57 SystemSpecialPoolInformation 6.0 and higher
0x58 SystemProcessIdInformation 6.0 and higher
0x5A SystemBootEnvironmentInformation 6.0 and higher
0x5B SystemHypervisorInformation 6.0 and higher
0x5C SystemVerifierInformationEx 6.0 and higher
0x5F SystemCoverageInformation 6.0 and higher
0x60 SystemPrefetchPatchInformation 6.0 and higher
0x62 SystemSystemPartitionInformation 6.0 and higher
0x63 SystemSystemDiskInformation 6.0 and higher
0x64 SystemProcessorPerformanceDistribution 6.0 and higher
0x65 SystemNumaProximityNodeInformation 6.0 and higher
0x66 SystemDynamicTimeZoneInformation 6.0 and higher
0x67 SystemCodeIntegrityInformation 6.0 and higher
0x69 SystemProcessorBrandString 6.0 from Windows Vista SP1, and higher
0x6A SystemVirtualAddressInformation 6.0 from Windows Vista SP1, and higher
0x6C SystemProcessorCycleTimeInformation 6.1 and higher
0x6D SystemStoreInformation 6.1 and higher
0x70 SystemVhdBootInformation 6.1 and higher
0x71 SystemCpuQuotaInformation 6.1 and higher
0x72 SystemNativeBasicInformation 6.1 and higher
0x73 SystemErrorPortTimeouts 6.1 and higher
0x74 SystemLowPriorityIoInformation 6.1 and higher
0x75 SystemBootEntropyInformation 6.1 and higher
0x76 SystemVerifierCountersInformation 6.1 and higher
0x77 SystemPagedPoolInformationEx 6.1 and higher
0x78 SystemSystemPtesInformationEx 6.1 and higher
0x7A SystemAcpiAuditInformation 6.1 and higher
0x7B SystemBasicPerformanceInformation 6.1 and higher
0x7C SystemQueryPerformanceCounterInformation 6.1 from Windows 7 SP1, and higher
0x7D SystemSessionBigPoolInformation 6.2 and higher
0x7E SystemBootGraphicsInformation 6.2 and higher
0x80 SystemBadPageInformation 6.2 and higher
0x85 SystemPlatformBinaryInformation 6.2 and higher
0x86 SystemPolicyInformation 6.2 and higher
0x87 SystemHypervisorProcessorCountInformation 6.2 and higher
0x88 SystemDeviceDataInformation 6.2 and higher
0x89 SystemDeviceDataEnumerationInformation 6.2 and higher
0x8A SystemMemoryTopologyInformation 6.2 and higher
0x8B SystemMemoryChannelInformation 6.2 and higher
0x8C SystemBootLogoInformation 6.2 and higher
0x8D SystemProcessorPerformanceInformationEx 6.2 and higher
0x8F SystemSecureBootPolicyInformation 6.2 and higher
0x90 SystemPageFileInformationEx 6.2 and higher
0x91 SystemSecureBootInformation 6.2 and higher
0x93 SystemPortableWorkspaceEfiLauncherInformation 6.2 and higher
0x94 SystemFullProcessInformation 6.2 and higher
0x95 SystemKernelDebuggerInformationEx 6.3 and higher
0x96 SystemBootMetadataInformation 6.3 and higher
0x97 SystemSoftRebootInformation 6.3 and higher
0x99 SystemOfflineDumpConfigInformation 6.3 and higher
0x9A SystemProcessorFeaturesInformation 6.3 and higher
0x9C SystemEdidInformation 6.3 and higher
0x9D SystemManufacturingInformation 10.0 and higher
0x9E SystemEnergyEstimationConfigInformation 10.0 and higher
0x9F SystemHypervisorDetailInformation 10.0 and higher
0xA0 SystemProcessorCycleStatsInformation 10.0 and higher
0xA2 SystemTrustedPlatformModuleInformation 10.0 and higher
0xA3 SystemKernelDebuggerFlags 10.0 and higher
0xA4 SystemCodeIntegrityPolicyInformation 10.0 and higher
0xA5 SystemIsolatedUserModeInformation 10.0 and higher
0xA6 SystemHardwareSecurityTestInterfaceResultsInformation 10.0 and higher
0xA7 SystemSingleModuleInformation 10.0 and higher
0xA9 SystemDmaProtectionInformation 10.0 and higher
0xAB SystemSecureBootPolicyFullInformation 10.0 and higher
0xAC SystemCodeIntegrityPolicyFullInformation 10.0 and higher
0xAD SystemAffinitizedInterruptProcessorInformation 10.0 and higher
0xAE SystemRootSiloInformation 10.0 and higher
0xAF SystemCpuSetInformation 10.0 and higher

All remaining behaviour varies with the information class.

Almost all information classes are associated with a structure that is at least the start of what the function produces as its output or expects as input. Mostly, the structure has no other purpose. Rather than have a separate page for each information class and then another for the corresponding structure, the remainder of this page gives for each information class a brief description of the general behaviour, and then the meaning of whatever the function puts in the structure or inteprets in it is taken up, if at all, in the separate documentation of the structure.

Before proceeding to the information classes one by one, it is as well to note some general points.

Exception Handling

Except if noted explicitly below, the function never 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.

Restricted Callers

Some information classes are sensitive in that the corresponding information may contain kernel-mode addresses. Plainly, this is not an accidental leakage: it’s intended for user-mode processes that exist for diagnostics and instrumentation. But relatively few user-mode processes have that purpose, none should be trusted more than can’t be avoided, and some are deliberately up to no good. Revealing a kernel-mode address to a malicious user-mode caller is arguably not itself a security vulnerability, but it may help the latter’s success at attacking some other vulnerability. For version 6.3, the Windows kernel introduced the notion of a restricted caller that is not to be given kernel-mode addresses. When this function executes for a user-mode request from a restricted caller, it fails for some information classes rather than produce any information, and for some others it edits kernel-mode addresses out of whatever information is produced.

What counts as a restricted caller depends on the Windows version. Originally, a restricted caller is specifically a low-integrity process. In detail, a process has low integrity if an integrity level cannot be obtained for the process’s primary token or if the integrity level is less than SECURITY_MANDATORY_MEDIUM_RID (0x2000). Windows 10 has a wider restriction that is essentially the same as implemented for the RtlIsSandboxedToken function: a user-mode caller is restricted unless it can pass an access check for READ_CONTROL rights to securable objects that have medium integrity.

Synchronisation

The information to be produced for some information classes comes from enumerating items whose existence, state and relationships during ordinary execution are subject to instant change. The different types of item provide differently for synchronisation. Describing these in each case is too much for these notes at present, but some general caution seems in order.

Even without complications from synchronisation, the enumeration is sometimes of tens of thousands of items and can therefore take enough time in total to affect how frequently the information can usefully be polled. Because of synchronisation, however, much of this time can have measureable effects not just on the program that calls the function but on multi-tasking performance in general and thus on other people’s software.

In the simplest but most comprehensive synchronisation, the function locks all other access to all instances of whatever is being enumerated. For the whole of the enumeration, while the function retrieves information about each item and follows links between items, no other access is possible to any of the items. In some (few) cases, this means the function holds a spin lock, with one processor at DISPATCH_LEVEL, for an unusually long time. Measurements in a debugger easily produce times of the order of 10ms, to compare with long-standing advice in the WDK that “no routine should hold a spin lock for longer than 25 microseconds.”

Where synchronisation is more sophisticated, access to the items being enumerated is subject to multiple levels of synchronisation such that the function’s retrieval of information about one item does not prevent others’ access to other items that have been enumerated already or may soon be. This has an implication that seems not much remarked upon, though perhaps not for being obvious. The information that this function produces from enumerating a given type of item is not a snapshot of the state of all such items at any one time or during any one interval. It ordinarily is a self-consistent snapshot of the state of each item each at some time, but at different times for different items. For instance, that two processes appear in the results from SystemProcessInformation (0x05) does not mean that these two processes ever coexisted.

Locked Memory

Somewhat related to synchronisation—indeed, sometimes demanded by the particular means of synchronisation—is that the function may, for the whole duration of the enumeration, both lock the supplied information buffer into physical memory and map it into system address space. In all such cases, the function trusts that the SystemInformationLength is reasonable. The whole information buffer is locked and mapped, even if this is vastly more than turns out to be needed. When executing for a user-mode request, the function locks and maps even if the information buffer is vastly more than the user-mode caller would be able to lock without having increased its working set, and even if the user-mode caller would not have been permitted to increase its working set for lack of the necessary privilege.

Shorthands

Many information classes have 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.

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.

Fixed Information

In the simplest cases that are well described by a shorthand the information buffer is to receive some fixed-size structure. In the very simplest, the information buffer must provide exactly this structure.

Shorthand: The information buffer must provide exactly an X for the function to fill.
Meaning: If the SystemInformationLength is not an exact fit for an X, the function sets the return length to the size of an X 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.
Example: SystemBasicInformation (0x00)

Only a little different is that the function tolerates a caller who provides more space than necessary.

Shorthand: The information buffer must provide at least an X for the function to fill.
Meaning: If the SystemInformationLength is too small for an X, the function sets the return length to the size of an X 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.
Example: SystemProcessorInformation (0x01)

These shorthands are in many cases the whole of the handling: nothing is checked other than the SystemInformationLength; and nothing can go wrong with filling in the structure. Where this is not true, variations are described under the heading Preliminaries, for applying in advance of checking the SystemInformationLength, else Retrieval.

Variable Information

Inevitably, the information classes for which the information can vary in size from one call to another each have very different requirements of the SystemInformationLength and interpretations of what length they should indicate via ReturnLength if the information buffer is too small. Two broad categories may lend themselves to shorthands: the information is an array of fixed-size structures; or the information is a fixed-size header whose last member begins an array of fixed-size structures.

Descriptions of information classes that produce variable-size information are mostly in this faded colour to signify that they are even more just a draft than is everything else on this page. Only after the descriptions are all at least drafted is it easy to see what repeats and what thus might be condensed.

Where a description below states that the information buffer is to receive some fixed-size structure A whose B array has some fixed-size structure C for each D, the following is implied as the whole behaviour. The function enumerates the D, writing to the information buffer as it goes. If an error occurs while enumerating, the function fails. For this purpose, it is not an error to find that the information buffer is too small. Without writing more to the information buffer, the function continues the enumeration to determine how much information might be produced were the buffer large enough. When the enumeration completes, the function sets the return length to this total, and fails, returning STATUS_INFO_LENGTH_MISMATCH. If enumeration completes such that the information buffer has all the information, the function sets the return length to this same total, and returns STATUS_SUCCESS. The oldest example is SystemModuleInformation (0x0B).

SystemBasicInformation (0x00)

The information buffer must provide exactly a SYSTEM_BASIC_INFORMATION structure for the function to fill.

SystemProcessorInformation (0x01)

The information buffer must provide at least a SYSTEM_PROCESSOR_INFORMATION structure for the function to fill.

SystemPerformanceInformation (0x02)

The information buffer must provide at least enough for the function to fill a SYSTEM_PERFORMANCE_INFORMATION structure up to and including its SystemCalls member. If the SystemInformationLength is too small for the partial structure, the function sets the return length to the size of the full structure and returns STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills in as much of the whole structure as fits, sets the return length to however many bytes are written to the buffer, and returns STATUS_SUCCESS.

In case it’s not clear: when given this information class, the function can succeed without having produced all the possible information and without indicating how much it could have produced.

SystemTimeOfDayInformation (0x03)

This information class is unusual in requiring that the information buffer provides no more than the fixed-size SYSTEM_TIMEOFDAY_INFORMATION structure. If given a bigger buffer, the function sets the return length to the size of the expected structure, and returns STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills in as much of the whole structure as fits, sets the return length to however many bytes are written to the buffer, and returns STATUS_SUCCESS.

In case it’s not clear: when given this information class but no information buffer, the function succeeds!

In case it’s not clear: when given this information class, the function can succeed without having produced all the possible information and without indicating how much it could have produced.

SystemPathInformation (0x04)

This information class is only trivially valid. The function returns STATUS_NOT_IMPLEMENTED.

Even as early as version 3.51, i.e., the first 32-bit kernel that is known to this study, the function breaks to the debugger with the message “EX: SystemPathInformation now available via SharedUserData” before failing. Does this information class pre-date 32-bit Windows?

SystemProcessInformation (0x05)

The information buffer is to receive a collection of irregularly spaced SYSTEM_PROCESS_INFORMATION structures, one per process. The spacing is irregular because each such structure can be followed by varying numbers of other fixed-size structures and by variable-size data too: an array of SYSTEM_THREAD_INFORMATION structures, one for each of the process’s threads; a SYSTEM_PROCESS_INFORMATION_EXTENSION structure; and the process’s name.

The least requirement for describing even one process, with no threads and no name, is a SYSTEM_PROCESS_INFORMATION and SYSTEM_PROCESS_INFORMATION_EXTENSION together. If given less for the information buffer but without having been asked for a return length, the function fails immediately, returning STATUS_INFO_LENGTH_MISMATCH.

Ordinarily, however, the function proceeds to enumerate processes until some error occurs that must be returned. The function writes to the information buffer while enumerating, for as long as space remains for each whole item. If the function has an item to add that will not fit, then if no return length was asked for, the function fails, returning STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function continues the enumeration but without writing more to the information buffer. The intention is still to return STATUS_INFO_LENGTH_MISMATCH if no other error occurs, but with the return length showing how much data the enumeration would have produced had the buffer been big enough. Note that the size thus reported need not suffice when the function is next called. This is not just the usual theoretical point, but a practical one: the number of processes and threads not only can change between calls but is highly likely to.

If the enumeration completes without error and without exhausting the buffer, the function sets the return length to however many bytes it put in the buffer, and succeeds.

SystemCallCountInformation (0x06)

This information class is only trivially valid. The function returns STATUS_NOT_SUPPORTED.

In older versions that support this information class, the information buffer must provide at least a SYSTEM_CALL_COUNT_INFORMATION for the function to fill.

SystemDeviceInformation (0x07)

The information buffer must provide exactly a SYSTEM_DEVICE_INFORMATION structure for the function to fill.

SystemProcessorPerformanceInformation (0x08)

The information buffer is to receive an array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION structures, one for each active processor in the current 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 copies to the buffer as many whole structures from the full array as fit, sets the return length to the size of what has been put in the buffer, and succeeds.

In case it’s not clear: when given this information class, the function can succeed without having produced all the possible information and without indicating how much it could have produced.

SystemFlagsInformation (0x09)

The information buffer must provide exactly a SYSTEM_FLAGS_INFORMATION structure for the function to fill.

SystemCallTimeInformation (0x0A)

This information class is only trivially valid. The function returns STATUS_NOT_IMPLEMENTED.

This information class is rejected even as early as version 3.51. Does it predate 32-bit Windows or was it planned for 32-bit Windows but never implemented? Microsoft has published symbol files that define a SYSTEM_CALL_TIME_INFORMATION structure, which would be curiously named if not to support this information class.

SystemModuleInformation (0x0B)

If executing for a user-mode request from a restricted caller, the function fails, returning STATUS_ACCESS_DENIED.

The information buffer is to receive an RTL_PROCESS_MODULES structure whose Modules array has an RTL_PROCESS_MODULE_INFORMATION for each module.

SystemLocksInformation (0x0C)

The information buffer is to receive an RTL_PROCESS_LOCKS structure whose Locks array has an RTL_PROCESS_LOCK_INFORMATION for each lock. Before the function sets about producing this information, There are two variations from this shorthand:

With these preliminaries out of the way, the information class is handled as implied by the shorthand.

The locks in question are what kernel-mode programmers know as system resources, each implemented as an ERESOURCE structure (declared in WDM.H). Beware that there can be very many locks. Expect tens of thousands even on a computer that has only just started. Beware also that their number not only can change between calls to the function but is highly likely to—indeed, almost always will.

SystemStackTraceInformation (0x0D)

The information buffer is to receive an RTL_PROCESS_BACKTRACES structure whose BackTraces array has an RTL_PROCESS_BACKTRACE_INFORMATION for each stack. There are several variations from this shorthand.

With these preliminaries out of the way, the information class is handled as implied by the shorthand.

SystemPagedPoolInformation (0x0E)

This information class is only trivially valid. The function sets the return length to zero and returns STATUS_NOT_IMPLEMENTED.

Some very old versions do not reject this information class immediately, but instead check for a minimum expectation and then have a subroutine complain of being not implemented. The expectation appears to be that the information buffer is to receive a SYSTEM_POOL_INFORMATION structure whose Entries member has a SYSTEM_POOL_ENTRY for each pool entry, allocated or not. Perhaps this information class was implemented non-trivially in debug builds.

SystemNonPagedPoolInformation (0x0F)

This information class is only trivially valid. The function sets the return length to zero and returns STATUS_NOT_IMPLEMENTED.

Some very old versions do not reject this information class immediately, but instead check for a minimum expectation and then have a subroutine complain of being not implemented. The expectation appears to be that the information buffer is to receive a SYSTEM_POOL_INFORMATION structure whose Entries member has a SYSTEM_POOL_ENTRY for each pool entry, allocated or not. Perhaps this information class was implemented non-trivially in debug builds.

SystemHandleInformation (0x10)

The information buffer is to receive a SYSTEM_HANDLE_INFORMATION structure whose Handles array has a SYSTEM_HANDLE_TABLE_ENTRY_INFO for each handle. If the buffer is too small even for the formally defined structure, with its capacity for describing one handle, the function sets the return length to the size of the formal structure, and fails, returning STATUS_INFO_LENGTH_MISMATCH. The function also returns STATUS_INFO_LENGTH_MISMATCH if the buffer is large enough for describing one handle but not large enough to receive the whole array. In this case, the function sets the return length to the size that would be needed for the full description. Beware that there can be very many handles and that their number not only can change between calls to the function but is highly likely to.

The information buffer must be pointer-aligned. If it is not, the function fails, returning STATUS_DATATYPE_MISALIGNMENT.

If executing for a user-mode request from a restricted caller, the function fails, returning STATUS_ACCESS_DENIED.

SystemObjectInformation (0x11)

The information buffer is to receive a collection of irregularly spaced SYSTEM_OBJECTTYPE_INFORMATION structures, one for each type of object. Each of these can be followed by some number of SYSTEM_OBJECT_INFORMATION structures, one for each object of the corresponding type. These too are irregularly spaced because each can be followed by the object’s name. If the buffer is too small even for one SYSTEM_OBJECTTYPE_INFORMATION, the function sets the return length to show this minimal expectation, and fails, returning STATUS_INFO_LENGTH_MISMATCH.

If executing for a user-mode request from a restricted caller, the function fails, returning STATUS_ACCESS_DENIED.

SystemPageFileInformation (0x12)

The information buffer is to receive a collection of irregularly spaced SYSTEM_PAGEFILE_INFORMATION structures, one for each paging file (not counting swap files and virtual stores). If the buffer is too small even for the first of these structures, the function sets the return length to show this minimal expectation, and fails, returning STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills the buffer with as many structures and other data as fits, and sets the return length to the size of what has been put in the buffer.

SystemVdmInstemulInformation (0x13)

In 64-bit Windows, which has no Virtual DOS Machine (VDM) support, this information class is only trivially valid. The function sets the return length to zero and returns STATUS_NOT_IMPLEMENTED.

In 32-bit Windows, the information buffer must provide at least a SYSTEM_VDM_INSTEMUL_INFORMATION structure for the function to fill.

SystemFileCacheInformation (0x15)

In 64-bit Windows, the information buffer must provide at least a SYSTEM_FILECACHE_INFORMATION structure for the function to fill.

The 32-bit Windows implementation allows a smaller information buffer, to account for an original definition that reached only to the PageFaultCount member. If the information buffer is not large enough for the original structure, the function sets the return length to this smaller requirement, and returns STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills in either the partial structure or the whole structure, if the latter fits, sets the return length to however many bytes were written to the buffer, and returns STATUS_SUCCESS.

SystemPoolTagInformation (0x16)

The information buffer is to receive a SYSTEM_POOLTAG_INFORMATION structure whose TagInfo array has a SYSTEM_POOLTAG for each tag. If the buffer is too small even for the formally defined structure, with its capacity for describing one tag, the function sets the return length to the size of the formal structure, and fails, returning STATUS_INFO_LENGTH_MISMATCH.

SystemInterruptInformation (0x17)

The information buffer is to receive an array of SYSTEM_INTERRUPT_INFORMATION structures, one for each active processor in the current processor group. 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_INFO_LENGTH_MISMATCH.

SystemDpcBehaviorInformation (0x18)

The information buffer must provide exactly a SYSTEM_DPC_BEHAVIOR_INFORMATION structure for the function to fill.

SystemFullMemoryInformation (0x19)

This information class is only trivially valid. The function returns STATUS_NOT_IMPLEMENTED.

SystemTimeAdjustmentInformation (0x1C)

The information buffer must provide exactly a SYSTEM_QUERY_TIME_ADJUST_INFORMATION structure for the function to fill.

SystemSummaryMemoryInformation (0x1D)

This information class is only trivially valid. The function returns STATUS_NOT_IMPLEMENTED.

SystemPerformanceTraceInformation (0x1F)

This information class is the oldest for which the information buffer not only receives output but provides input. Moreover, the input begins with a secondary information class that subdivides the behaviour. If the information buffer is too small to provide this EVENT_TRACE_INFORMATION_CLASS as input, the function returns STATUS_INVALID_PARAMETER.

SystemExceptionInformation (0x21)

The information buffer must provide at least a SYSTEM_EXCEPTION_INFORMATION structure for the function to fill.

SystemKernelDebuggerInformation (0x23)

The information buffer must provide at least a SYSTEM_KERNEL_DEBUGGER_INFORMATION structure for the function to fill.

SystemContextSwitchInformation (0x24)

The information buffer must provide at least a SYSTEM_CONTEXT_SWITCH_INFORMATION structure for the function to fill.

SystemRegistryQuotaInformation (0x25)

The information buffer must provide at least a SYSTEM_REGISTRY_QUOTA_INFORMATION structure for the function to fill.

SystemProcessorIdleInformation (0x2A)

The information buffer is to receive an array of SYSTEM_PROCESSOR_IDLE_INFORMATION structures, one for each active processor in the current processor group. 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_INFO_LENGTH_MISMATCH.

SystemLegacyDriverInformation (0x2B)

The information buffer is to receive a fixed-size SYSTEM_LEGACY_DRIVER_INFORMATION structure and a variable-size string. If the information buffer is too small even for the fixed-size structure, the function sets the return length to show the minimal expectation, and fails, returning STATUS_INFO_LENGTH_MISMATCH. If it’s too small for all that the function would copy, the function sets the return length to show what it could produce, and fails, returning STATUS_BUFFER_OVERFLOW.

SystemCurrentTimeZoneInformation (0x2C)

The information buffer must provide at least an RTL_TIME_ZONE_INFORMATION structure for the function to fill.

SystemLookasideInformation (0x2D)

The information buffer is to receive an array of SYSTEM_LOOKASIDE_INFORMATION structures, one for each lookaside list in four sets. Broadly, these sets are:

  1. per-processor pool lookaside lists that help with small pool allocations;
  2. per-processor and shared system lookaside lists dedicated to management of memory for particular system structures;
  3. general lookaside lists for non-paged allocations, as when initialised through ExInitializeNPagedLookasideList;
  4. general lookaside lists for paged allocations, as when initialised through ExInitializePagedLookasideList.

Finer resolution of the lookaside lists that can be enumerated would necessarily be a separate article (or articles). For present purposes it must suffice to know that there typically exist very many lookaside lists: easily in the thousands. The function fills the buffer with as many whole structures as there are lists to describe and which fit. It then sets the return length to show how much has been put there, and succeeds.

In case it’s not clear: when given this information class but no information buffer, the function succeeds!

In case it’s not clear: when given this information class, the function can succeed without having produced all the possible information and without indicating how much it could have produced.

Buffering

Except when succeeding trivially because the information buffer is too small for even one structure, the function expects to write at least something into the information buffer. So that enumerating the lookaside lists does not itself cause allocations from and frees to lookaside lists because of paging I/O or exception handling, the function locks the information buffer into physical memory and maps it into system address space. Failure at this is failure for the function.

Synchronisation

The function does not synchronise its enumeration of either the pool or system lookaside lists with code that would initialise more such lists for a newly added processor. These lookaside lists are themselves in two double-linked lists, one for each set. Is it possible that addition of a processor could disturb a link just as it gets followed by this function for the enumeration?

The other sets of lookaside lists each have a corresponding spin lock which is held while any lookaside list of the same type is initialised or deleted. The function holds each lock in turn, thus running the current processor at DISPATCH_LEVEL while enumerating these sets.

SystemRangeStartInformation (0x32)

The information buffer must provide exactly a pointer for the function to set. If Microsoft has a structure for this, Microsoft’s name for it is not known.

The buffer receives a copy of the kernel’s MmSystemRangeStart variable. The kernel exports this variable in version 4.0 from Windows NT 4.0 SP3, and higher. It is declared in NTDDK.H as far back as the DDK for Windows 2000. Since this variable is exported from all known kernel versions that support SystemRangeStartInformation, this information class has little or no reason to exist except to help user-mode callers.

SystemVerifierInformation (0x33)

The information buffer is to receive a collection of irregularly spaced SYSTEM_VERIFIER_INFORMATION structures. If the buffer is too small even for the first of these structures, the function sets the return length to show this minimal expectation, and fails, returning STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills the buffer with as many structures and other data as it can generate and fit within the buffer, to a maximum of 10MB, and sets the return length to the size of what has been put in the buffer.

In case it’s not clear, when given this information class but no information buffer, the function may fail, telling of a minimum size that is required for the buffer, and then when given that size of buffer, the function may succeed but say it put nothing in the buffer.

SystemSessionProcessInformation (0x35)

The information buffer must provide at least a SYSTEM_SESSION_PROCESS_INFORMATION structure as input. Given less, the function sets the return length to the size of the structure, and fails, returning STATUS_INFO_LENGTH_MISMATCH.

As input, the structure provides a session ID and the address and size of a secondary information buffer for the function to use as if for SystemProcessInformation but refined to query just for processes in the given session. This secondary information buffer must have four-byte alignment, lie wholly in user-mode address space and be writable.

DETAILS IN PREPARATION

For this information class, the size returned via ReturnLength need not be the amount of information that has been or might have been put in the information buffer as described by SystemInformation and SystemInformationLength. The output value of the variable at ReturnLength may instead describe the secondary information buffer. Whether this is by design or oversight is unclear. Oversight seems more plausible, however. See especially that it is inconsistent with the annotations on Microsoft’s one published declaration of the function (in ZWAPI.H from the WDK for Windows 10).

SystemNumaProcessorMap (0x37)

The information buffer is to receive as much of a SYSTEM_NUMA_INFORMATION structure as there are nodes to describe. If the buffer is too small for the function to fill in at least the HighestNodeNumber at the structure’s start, then the function sets the return length to that member’s size, and fails, returning STATUS_INFO_LENGTH_MISMATCH. If the buffer is too small for even one GROUP_AFFINITY in the ActiveProcessorsGroupAffinity array, the function sets the HighestNodeNumber in the buffer, sets the return length to that member’s size and declares success. Otherwise, it fills as many GROUP_AFFINITY structures as there are nodes to describe and which fit in the buffer, and sets the return length to the size of what has been put in the buffer.

SystemPrefetcherInformation (0x38)

If executing for a user-mode request, the caller must have SeProfileSingleProcessPrivilege. Without it, the function fails, returning STATUS_ACCESS_DENIED.

The information buffer must provide exactly a SUPERFETCH_INFORMATION structure as input. This is not certainly Microsoft’s name for the structure as expected for this information class. It is, however, Microsoft’s name for a structure that has the same layout and which is known to be correct for the information class SystemSuperfetchInformation.

The first dword must be 0x01 and the second 0x6B756843, else the function fails, returning STATUS_INVALID_PARAMETER. If the third dword is not a valid Prefetcher information class, the function fails, returning STATUS_INVALID_INFO_CLASS. The valid cases are beyond the present scope of this review.

SystemExtendedProcessInformation (0x39)

The information buffer is to receive a collection of irregularly spaced SYSTEM_PROCESS_INFORMATION structures, one per process. The spacing is irregular because each such structure can be followed by varying numbers of other fixed-size structures and by variable-size data too: an array of SYSTEM_EXTENDED_THREAD_INFORMATION structures, one for each of the process’s threads; a SYSTEM_PROCESS_INFORMATION_EXTENSION structure; and the process’s name.

The least requirement for describing even one process, with no threads and no name, is a SYSTEM_PROCESS_INFORMATION and SYSTEM_PROCESS_INFORMATION_EXTENSION together. If given less for the information buffer but without having been asked for a return length, the function fails immediately, returning STATUS_INFO_LENGTH_MISMATCH.

Ordinarily, however, the function proceeds to enumerate processes until some error occurs that must be returned. The function writes to the information buffer while enumerating, for as long as space remains for each whole item. If the function has an item to add that will not fit, then if no return length was asked for, the function fails, returning STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function continues the enumeration but without writing more to the information buffer. The intention is still to return STATUS_INFO_LENGTH_MISMATCH if no other error occurs, but with the return length showing how much data the enumeration would have produced had the buffer been big enough. Note that the size thus reported need not suffice when the function is next called. This is not just the usual theoretical point, but a practical one: the number of processes and threads not only can change between calls but is highly likely to.

If the enumeration completes without error and without exhausting the buffer, the function sets the return length to however many bytes it put in the buffer, and succeeds.

SystemRecommendedSharedDataAlignment (0x3A)

The information buffer must provide at least a ULONG for the function to set. If this is dressed as a structure, Microsoft’s name for it is not known.

What the buffer receives is simply the result of the documented kernel function KeGetRecommendedSharedDataAlignment. This is the size of the largest cache line of any processor, which the kernel will have determined from initialising its Second-Level Cache Support for successive processors.

SystemComPlusPackage (0x3B)

The information buffer must provide exactly a ULONG for the function to set. If this is dressed as a structure, Microsoft’s name for it is not known.

The buffer receives a copy of the ComPlusPackage from the KUSER_SHARED_DATA except that if what’s there is (still) 0xFFFFFFFF, the kernel first clears it to 0 and then tries to load it from the registry:

Key: HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework
Value: Enable64Bit

Failure to read the data for any reason other than absence of the key or value is failure for the function, which returns the error from the registry operation. If the key or value is not found or if the data is not a dword of REG_DWORD data, the result of this and future queries is zero.

Microsoft documents one meaningful value: COMPLUS_ENABLE_64BIT (1). The documented KERNEL32 function GetComPlusPackageInstallStatus ordinarily reads from the KUSER_SHARED_DATA, presumably for efficiency, but queries via SystemComPlusPackage if the cached value is 0xFFFFFFFF. Though Microsoft documents the KERNEL32 function only for Windows Vista and higher, it is exported as early as version 5.1. What it can mean to have the 64-bit Common Language Runtime installed in version 5.1 is unclear but immaterial: for what looks to be the lack of a break statement, all builds of version 5.1 fill the information buffer for SystemComPlusPackage as if for SystemLostDelayedWriteInformation.

SystemNumaAvailableMemory (0x3C)

The information buffer is to receive as much of a SYSTEM_NUMA_INFORMATION structure as there are nodes to describe. If the buffer is too small for the function to fill in at least the HighestNodeNumber at the structure’s start, then the function sets the return length to that member’s size, and fails, returning STATUS_INFO_LENGTH_MISMATCH. If the buffer is too small for even one ULONGLONG in the AvailableMemory array, the function sets the HighestNodeNumber in the buffer, sets the return length to that member’s size and declares success. Otherwise, it fills as many array members as there are nodes to describe and which fit in the buffer and sets the return length to the size of what has been put in the buffer.

SystemProcessorPowerInformation (0x3D)

The information buffer is to receive an array of SYSTEM_PROCESSOR_POWER_INFORMATION structures, one for each active processor in the current processor group. 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_INFO_LENGTH_MISMATCH.

SystemEmulationBasicInformation (0x3E)

The information buffer must provide exactly a SYSTEM_BASIC_INFORMATION structure for the function to fill.

SystemEmulationProcessorInformation (0x3F)

The information buffer must provide at least a SYSTEM_PROCESSOR_INFORMATION structure for the function to fill.

SystemExtendedHandleInformation (0x40)

The information buffer is to receive a SYSTEM_HANDLE_INFORMATION_EX structure whose Handles array has a SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX for each handle. If the buffer is too small even for the formally defined structure, with its capacity for describing one handle, the function sets the return length to the size of the formal structure, and fails, returning STATUS_INFO_LENGTH_MISMATCH.

The information buffer must be pointer-aligned. If it is not, the function fails, returning STATUS_DATATYPE_MISALIGNMENT.

If executing for a user-mode request from a restricted caller, the function fails, returning STATUS_ACCESS_DENIED.

SystemLostDelayedWriteInformation (0x41)

The information buffer must provide at least a ULONG for the function to set. If this is dressed as a structure, Microsoft’s name for it is not known.

What the buffer receives is the total of the per-processor CcLostDelayedWrites counters, one per KPRCB.

SystemBigPoolInformation (0x42)

The information buffer is to receive a SYSTEM_BIGPOOL_INFORMATION structure whose AllocatedInfo array has a SYSTEM_BIGPOOL_ENTRY for each allocation. If the buffer is too small even for the formally defined structure, with its capacity for describing one allocation, the function sets the return length to the size of the formal structure, and fails, returning STATUS_INFO_LENGTH_MISMATCH.

SystemSessionPoolTagInformation (0x43)

TO BE DONE

SystemSessionMappedViewInformation (0x44)

The information buffer must provide at least a SYSTEM_SESSION_MAPPED_VIEW_INFORMATION structure for both input and output. Given less, the function sets the return length to the size of the structure, and fails, returning STATUS_INFO_LENGTH_MISMATCH.

As input, the structure provides a session ID. This can be 0xFFFFFFFF to mean all sessions.

For output, the information buffer is to receive an array of these structures. If the information buffer does not have 8-byte alignment, the function fails, returning STATUS_DATATYPE_MISALIGNMENT.

SystemHotpatchInformation (0x45)

This information class is only trivially valid. The function sets the return length to zero and returns STATUS_NOT_SUPPORTED.

SystemObjectSecurityMode (0x46)

The information buffer must provide exactly a 32-bit integer for the function to set. If Microsoft has a structure for this, Microsoft’s name for it is not known.

What the buffer receives is a copy of an internal variable that the kernel initialises from the registry but does not otherwise use:

Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager
Value: ObjectSecurityMode
Type: REG_DWORD
Default: 1

The kernel merely holds the value for callers of this function, presumably so that their interpretation of it at different times cannot be made inconsistent by changes to the registry value. (Changes take effect only after Windows restarts.) A known interpretation is by BASESRV.DLL for setting the access that Everyone (S-1-1-0) is allowed to the per-session \Session\id\BaseNamedObjects and \Session\id\BaseNamedObjects\Restricted directories in the object namespace. Protection is stronger when the mode is non-zero, for Everyone is permitted only DIRECTORY_QUERY and DIRECTORY_TRAVERSE instead of also getting DIRECTORY_CREATE_OBJECT, DIRECTORY_CREATE_SUBDIRECTORY and READ_CONTROL.

SystemWatchdogTimerInformation (0x48)

This information class is only trivially valid. The function returns STATUS_NOT_SUPPORTED.

SystemLogicalProcessorInformation (0x49)

The information buffer is to receive an array of SYSTEM_LOGICAL_PROCESSOR_INFORMATION structures, one for each active processor in processor group 0. (The structure is declared in WDM.H and WINNT.H, for kernel-mode and user-mode programming, respectively.)

SystemFirmwareTableInformation (0x4C)

TO BE DONE

SystemModuleInformationEx (0x4D)

TO BE DONE

SystemSuperfetchInformation (0x4F)

TO BE DONE

SystemMemoryListInformation (0x50)

TO BE DONE

SystemFileCacheInformationEx (0x51)

In 64-bit Windows, the information buffer must provide at least a SYSTEM_FILECACHE_INFORMATION structure for the function to fill.

The 32-bit Windows implementation allows a smaller information buffer, to account for an original definition that reached only to the PageFaultCount member. If the information buffer is too small for the original structure, the function sets the return length to this smaller requirement, and returns STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills in either the partial structure or the whole structure, if the latter fits, sets the return length to however many bytes were written to the buffer, and returns STATUS_SUCCESS.

SystemProcessorIdleCycleTimeInformation (0x53)

The information buffer is to receive an array of SYSTEM_PROCESSOR_IDLE_CYCLE_TIME structures, one for each active processor in the current 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).

SystemRefTraceInformation (0x56)

TO BE DONE

SystemSpecialPoolInformation (0x57)

The information buffer must provide exactly a SYSTEM_SPECIAL_POOL_INFORMATION structure for the function to fill.

SystemProcessIdInformation (0x58)

The information buffer must provide exactly a SYSTEM_PROCESS_ID_INFORMATION structure for both input and output.

The essence of the function is to get the full image name of a process, given the process ID. The structure must provide as input both the ProcessId and the address and size of a buffer that is to receive  the name. A UNICODE_STRING named ImageName describes the buffer with the usual interpretations. The address and size are in Buffer and MaximumLength, respectively, and Length tells how many bytes hold meaningful content. If the buffer is already in use, i.e., Length is not zero, or if its capacity is not a whole number of Unicode characters, i.e., MaximumLength is not a multiple of two, then the function returns STATUS_INVALID_PARAMETER. If executing for a user-mode request and MaximumLength is non-zero, the buffer must be word-aligned and must lie wholly in user-mode address space. Failure at these defences causes the function to return STATUS_DATATYPE_MISALIGNMENT or STATUS_ACCESS_VIOLATION (as raised but handled exceptions).

If no process can be found for the given ProcessId or if whatever is found is not in the current silo, the function returns STATUS_INVALID_CID.

If the process’s image name (meaning what the EPROCESS has in its SeAuditProcessCreationInfo) is too large for the given buffer, the function returns STATUS_INFO_LENGTH_MISMATCH, having set the MaximumLength to the size required and the return length to the size of the input structure.

Ordinarily, the function copies the image name to the given Buffer, updates Length and MaximumLength to fit the new content, sets the return length to the size of the input structure, and succeeds. One variation is that the process may have no image name, as with the system process. In such a case, there is nothing to copy and the function instead clears MaximumLength to 0 and Buffer to NULL.

Note the absence of any check for privilege or access rights. The information class SystemProcessIdInformation lets user-mode callers of NtQuerySystemInformation get the names of processes that they cannot open.

SystemBootEnvironmentInformation (0x5A)

The information buffer must provide at least a SYSTEM_BOOT_ENVIRONMENT_INFORMATION structure up to and including its FirmwareType member. If the information buffer is too small for the partial structure, the function sets the return length to the size of the full structure and returns STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills in either the partial structure or the whole structure, if the latter fits, sets the return length to however many bytes were written to the buffer, and returns STATUS_SUCCESS.

SystemHypervisorInformation (0x5B)

This information class is for kernel-mode use only. If executing for a user-mode request, the function fails, returning STATUS_ACCESS_DENIED.

The information buffer must provide exactly a SYSTEM_HYPERVISOR_QUERY_INFORMATION structure for the function to fill.

SystemVerifierInformationEx (0x5C)

The information buffer must provide exactly a SYSTEM_VERIFIER_INFORMATION_EX structure for the function to fill.

SystemCoverageInformation (0x5F)

TO BE DONE

SystemPrefetchPatchInformation (0x60)

This information class is only trivially valid. The function returns STATUS_NOT_IMPLEMENTED.

In older versions whose x64 builds support this information class, the information buffer must supply at least a SYSTEM_PREFETCH_PATCH_INFORMATION structure for the function to fill.

SystemSystemPartitionInformation (0x62)

TO BE DONE

SystemSystemDiskInformation (0x63)

TO BE DONE

SystemProcessorPerformanceDistribution (0x64)

TO BE DONE

SystemNumaProximityNodeInformation (0x65)

The information buffer must provide at least a SYSTEM_NUMA_PROXIMITY_MAP structure for both input and output.

SystemDynamicTimeZoneInformation (0x66)

The information buffer must provide at least an RTL_DYNAMIC_TIME_ZONE_INFORMATION structure for the function to fill.

SystemCodeIntegrityInformation (0x67)

This information class is handled outside the kernel, by a callback that the kernel learns from CI.DLL via the CiInitialize function. If the callback is not yet known, this function fails, setting the return length to zero and returning STATUS_UNSUCCESSFUL.

The information buffer must provide exactly a SYSTEM_CODEINTEGRITY_INFORMATION structure for both input to and output from the CI callback function. (This structure is nowadays documented by Microsoft, apparently in full.)

As input, the structure provides only its Length member, which must hold the structure’s size, presumably to allow for expansion in future without having to define a new information class.

SystemProcessorBrandString (0x69)

TO BE DONE

SystemVirtualAddressInformation (0x6A)

The information buffer must provide at least an array of six SYSTEM_VA_LIST_INFORMATION structures for the function to fill.

SystemProcessorCycleTimeInformation (0x6C)

The information buffer is to receive an array of SYSTEM_PROCESSOR_CYCLE_TIME structures, one for each active processor in the current 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).

SystemStoreInformation (0x6D)

The information buffer must provide exactly some structure for both input and output. Microsoft’s name for this structure is not known. The structure is 0x10 or 0x18 bytes in 32-bit and 64-bit Windows, respectively.

On input, the first dword must be 1, else the function fails, returning STATUS_INVALID_PARAMETER. A second dword provides a store information class. For values other than 2, 5, 8, 13 and 16, a user-mode caller must have SeProfileSingleProcessPrivilege, else the function fails, returning STATUS_ACCESS_DENIED. The valid store information classes are 2, 5, 8, 13, 15 and 16. Given anything else, the function fails, returning STATUS_INVALID_INFO_CLASS.

The third and fourth members of the input structure are the address and size of a secondary buffer which is to receive the function’s output. This output varies with the store information class. The meaning of each store information class is presently beyond the scope of these notes.

SystemVhdBootInformation (0x70)

The information buffer is to receive a SYSTEM_VHD_BOOT_INFORMATION structure whose OsVhdParentVolume array is a null-terminated Unicode string to be followed by another null-terminated Unicode string. If the information buffer is too small for the total, the function sets the return length to the total and returns STATUS_BUFFER_TOO_SMALL.

SystemCpuQuotaInformation (0x71)

The information buffer is to receive a PS_CPU_QUOTA_QUERY_INFORMATION structure whose SessionInformation array has a PS_CPU_QUOTA_QUERY_ENTRY for each session.

Preliminaries

This information class depends on DFSS to be enabled by a registry configuration (details of which are presently beyond the scope of this note). If it is not, the function fails, returning STATUS_QUOTA_NOT_ENABLED.

If executing for a user-mode request, the caller must have SeIncreaseQuotaPrivilege. Without it, the function fails, returning STATUS_PRIVILEGE_NOT_HELD.

Length

The function allows that SystemInformationLength can be zero. Otherwise, the information buffer must provide at least for fixed-size part of the structure, i.e., up to but not including the SessionInformation array, and the excess must provide exactly a whole number of PS_CPU_QUOTA_QUERY_ENTRY structures that the function might fill. If either expectation is not met, the function returns STATUS_INFO_LENGTH_MISMATCH but without having set the return length.

Enumeration

The function enumerates sessions. Details are beyond the scope of this note. For each that has a scheduling group, the function fills the next PS_CPU_QUOTA_QUERY_ENTRY in the array, if space remains. When enumeration is complete, the function sets the SessionCount in the PS_CPU_QUOTA_QUERY_INFORMATION, again if space is sufficient. If space does not suffice for all the available information, the function sets the return length to match what it might have put in the buffer, and returns STATUS_BUFFER_TOO_SMALL. If space did suffice, the function sets the return length to match what it did put in the buffer, and returns STATUS_SUCCESS.

SystemNativeBasicInformation (0x72)

The information buffer must provide exactly a SYSTEM_BASIC_INFORMATION structure for the function to fill.

It is not known why this information class exists separately from SystemBasicInformation. Perhaps the reason is nothing more than to make an explicit contrast with SystemEmulationBasicInformation.

SystemErrorPortTimeouts (0x73)

TO BE DONE

SystemLowPriorityIoInformation (0x74)

The information buffer must provide at least a SYSTEM_LOW_PRIORITY_IO_INFORMATION structure for the function to fill.

If the information buffer is too small, the function sets the return length to the expected size and returns STATUS_BUFFER_TOO_SMALL.

SystemBootEntropyInformation (0x75)

The information buffer must provide exactly a BOOT_ENTROPY_NT_RESULT structure for the function to fill.

This information class is for kernel-mode use only. If executing for a user-mode request, the function fails, returning STATUS_ACCESS_DENIED. Even in kernel mode, the boot entropy information can be successfully queried at most once, and no later than phase 1 of the kernel’s initialisation. The intended error code for a call that is too late is STATUS_UNSUCCESSFUL.

SystemVerifierCountersInformation (0x76)

The information buffer is to receive a collection of irregularly spaced SYSTEM_VERIFIER_COUNTERS_INFORMATION structures. If the buffer is too small even for the first of these structures, the function sets the return length to show this minimal expectation, and fails, returning STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills the buffer with as many structures and other data as fits, to a maximum of 10MB, and sets the return length to the size of what has been put in the buffer.

SystemPagedPoolInformationEx (0x77)

In 64-bit Windows, the information buffer must provide at least a SYSTEM_FILECACHE_INFORMATION structure for the function to fill.

The 32-bit Windows implementation allows a smaller information buffer, to account for an original definition that reached only to the PageFaultCount member. If the information buffer is too small for the original structure, the function sets the return length to this smaller requirement, and returns STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills in either the partial structure or the whole structure, if the latter fits, sets the return length to however many bytes were written to the buffer, and returns STATUS_SUCCESS.

SystemSystemPtesInformationEx (0x78)

In 64-bit Windows, the information buffer must provide at least a SYSTEM_FILECACHE_INFORMATION structure for the function to fill.

The 32-bit Windows implementation allows a smaller information buffer, to account for an original definition that reached only to the PageFaultCount member. If the information buffer is too small for the original structure, the function sets the return length to this smaller requirement, and returns STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills in either the partial structure or the whole structure, if the latter fits, sets the return length to however many bytes were written to the buffer, and returns STATUS_SUCCESS.

SystemAcpiAuditInformation (0x7A)

The information buffer must provide exactly a SYSTEM_ACPI_AUDIT_INFORMATION structure for the function to fill.

SystemBasicPerformanceInformation (0x7B)

The information buffer must provide exactly a SYSTEM_BASIC_PERFORMANCE_INFORMATION structure for the function to fill.

SystemQueryPerformanceCounterInformation (0x7C)

The information buffer must provide at least a SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION structure for both input and output.

The Version member is expected as input. If the information buffer is not at least large enough to provide this member, the function sets the return length to the size of the expected structure and fails, returning STATUS_INFO_LENGTH_MISMATCH. If the Version member is not 1 on input, the function fails, returning STATUS_NOT_SUPPORTED. Apparently, the SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION as presently defined is only for version 1. The information buffer must provide at least this structure for the function to fill.

SystemSessionBigPoolInformation (0x7D)

TO BE DONE

SystemBootGraphicsInformation (0x7E)

The information buffer must provide exactly a SYSTEM_BOOT_GRAPHICS_INFORMATION structure for the function to fill.

SystemBadPageInformation (0x80)

TO BE DONE

SystemPlatformBinaryInformation (0x85)

TO BE DONE

SystemPolicyInformation (0x86)

The information buffer must provide exactly a SYSTEM_POLICY_INFORMATION structure for both input and output. Details are presently beyond the scope of this article.

SystemHypervisorProcessorCountInformation (0x87)

The information buffer must provide at least a SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION structure for the function to fill.

SystemDeviceDataInformation (0x88)

The information buffer must provide exactly a SYSTEM_DEVICE_DATA_INFORMATION structure for both input and output.

If SystemInformationLength is correct but SystemInformation is NULL, the function returns STATUS_INFO_LENGTH_MISMATCH but without setting the return length. The information buffer must have 4-byte alignment and lie wholly in user-mode address space (even if the request originated in kernel mode).

SystemDeviceDataEnumerationInformation (0x89)

The information buffer must provide exactly a SYSTEM_DEVICE_DATA_INFORMATION structure for both input and output.

If SystemInformationLength is correct but SystemInformation is NULL, the function returns STATUS_INFO_LENGTH_MISMATCH but without setting the return length. The information buffer must have 4-byte alignment and lie wholly in user-mode address space (even if the request originated in kernel mode).

SystemMemoryTopologyInformation (0x8A)

TO BE DONE

SystemMemoryChannelInformation (0x8B)

TO BE DONE

SystemBootLogoInformation (0x8C)

The information buffer is to receive a SYSTEM_BOOT_LOGO_INFORMATION structure and a variable-size bitmap for the boot logo.

If the information buffer is too small even for the formally defined structure but the function is not asked for a return length, the function fails, returning STATUS_INVALID_PARAMETER. If the information buffer is too small for the structure and bitmap, the function sets the return length to the total and returns STATUS_BUFFER_TOO_SMALL. Along the way, the function may fail for other reasons and return other errors, such as STATUS_UNSUCCESSFUL.

If the information buffer is large enough for the structure and bitmap, the function copies both to the buffer, sets the return length to the total, and succeeds.

SystemProcessorPerformanceInformationEx (0x8D)

The information buffer is to receive an array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX structures, one for each active processor in the current 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.

SystemSecureBootPolicyInformation (0x8F)

If Secure Boot is not enabled, the function can do nothing with this information class: it fails, returning STATUS_SECUREBOOT_NOT_ENABLED.

The information buffer must provide at least a SYSTEM_SECUREBOOT_POLICY_INFORMATION structure for the function to fill.

SystemPageFileInformationEx (0x90)

The information buffer is to receive a collection of irregularly spaced SYSTEM_PAGEFILE_INFORMATION_EX structures, one for each paging file (not counting swap files and virtual stores). If the buffer is too small even for the first of these structures, the function sets the return length to show this minimal expectation, and fails, returning STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function fills the buffer with as many structures and other data as fits, and sets the return length to the size of what has been put in the buffer.

SystemSecureBootInformation (0x91)

The information buffer must provide at least a SYSTEM_SECUREBOOT_INFORMATION structure for the function to fill.

Beware that the expected structure is naturally byte-aligned but the function’s user-mode defences for this information class require four-byte alignment.

SystemPortableWorkspaceEfiLauncherInformation (0x93)

TO BE DONE

SystemFullProcessInformation (0x94)

The information buffer is to receive a collection of irregularly spaced SYSTEM_PROCESS_INFORMATION structures, one per process. The spacing is irregular because each such structure can be followed by varying numbers of other fixed-size structures and by variable-size data too: an array of SYSTEM_EXTENDED_THREAD_INFORMATION structures, one for each of the process’s threads; a SYSTEM_PROCESS_INFORMATION_EXTENSION structure; and as many as four variable-size items including the user SID, the package name and application ID, and the process’s name.

Minimum

The least requirement for describing even one process, with no threads and no name, is a SYSTEM_PROCESS_INFORMATION and SYSTEM_PROCESS_INFORMATION_EXTENSION together. If given less for the information buffer but without having been asked for a return length, the function fails immediately, returning STATUS_INFO_LENGTH_MISMATCH.

Permissions

Unlike its ealier forms, SystemProcessInformation and SystemExtendedProcessInformation, this information class has access restrictions. First, it is available only for user-mode requests. If the function is instead executing for a kernel-mode request, it fails, returning STATUS_ACCESS_DENIED. A permitted user-mode caller (or group) can be configured in the registry:

Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows
Value: FullProcessInformationSID

The expected data is a SID in binary form. (The type is not checked. Any data is accepted provided there is not more of it than is possible for a SID, i.e., 0x44 bytes.) The SID designates the one user or group that is, along with all members of the Administrators group, permitted to use this information class. For all other user-mode callers, the function fails, returning STATUS_ACCESS_DENIED.

Enumeration

Ordinarily, however, the function proceeds to enumerate processes until some error occurs that must be returned. The function writes to the information buffer while enumerating, for as long as space remains for each whole item. If the function has an item to add that will not fit, then if no return length was asked for, the function fails, returning STATUS_INFO_LENGTH_MISMATCH. Otherwise, the function continues the enumeration but without writing more to the information buffer. The intention is still to return STATUS_INFO_LENGTH_MISMATCH if no other error occurs, but with the return length showing how much data the enumeration would have produced had the buffer been big enough. Note that the size thus reported need not suffice when the function is next called. This is not just the usual theoretical point, but a practical one: the number of processes and threads not only can change between calls but is highly likely to.

If the enumeration completes without error and without exhausting the buffer, the function sets the return length to however many bytes it put in the buffer, and succeeds.

SystemKernelDebuggerInformationEx (0x95)

The information buffer must provide at least a SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX structure for the function to fill.

Beware that the expected structure is naturally byte-aligned but the function’s user-mode defences for this information class require four-byte alignment.

SystemBootMetadataInformation (0x96)

TO BE DONE

SystemSoftRebootInformation (0x97)

TO BE DONE

SystemOfflineDumpConfigInformation (0x99)

TO BE DONE

SystemProcessorFeaturesInformation (0x9A)

TO BE DONE

SystemEdidInformation (0x9C)

The information buffer must provide exactly 0x80 bytes for the function to fill. If Microsoft has a structure for this, Microsoft’s name for it is not known.

What the buffer receives is a 128-byte Extended Display Identification Data (EDID), as defined by the Video Electronics Standards Association (VESA). Details of how the kernel gets the EDID from the loader (via the BgContext member of the LOADER_PARAMETER_EXTENSION) are beyond the scope of this article.

SystemManufacturingInformation (0x9D)

TO BE DONE

SystemEnergyEstimationConfigInformation (0x9E)

TO BE DONE

SystemHypervisorDetailInformation (0x9F)

The information buffer must provide exactly a SYSTEM_HYPERVISOR_DETAIL_INFORMATION structure for the function to fill, but with the variation that if the information buffer is not the expected size, the function sets the return length to zero and returns STATUS_INVALID_PARAMETER_1.

SystemProcessorCycleStatsInformation (0xA0)

TO BE DONE

SystemTrustedPlatformModuleInformation (0xA2)

TO BE DONE

SystemKernelDebuggerFlags (0xA3)

The information buffer must provide at least a BOOLEAN for the function to set. If this is dressed as a structure, Microsoft’s name for it is not known. What the buffer receives is simply the kernel’s record of whether to ignore user-mode exceptions.

SystemCodeIntegrityPolicyInformation (0xA4)

This information class is handled outside the kernel, by a callback that the kernel learns from CI.DLL via the CiInitialize function. If the callback is not yet known, this function fails, setting the return length to zero and returning STATUS_UNSUCCESSFUL.

The information buffer must provide exactly a SYSTEM_CODEINTEGRITYPOLICY_INFORMATION structure for the CI callback function to fill.

SystemIsolatedUserModeInformation (0xA5)

The information buffer must provide exactly a SYSTEM_ISOLATED_USER_MODE_INFORMATION structure for the function to fill.

SystemHardwareSecurityTestInterfaceResultsInformation (0xA6)

TO BE DONE

SystemSingleModuleInformation (0xA7)

TO BE DONE

SystemDmaProtectionInformation (0xA9)

TO BE DONE

SystemSecureBootPolicyFullInformation (0xAB)

If Secure Boot is not enabled, the function can do nothing with this information class: it fails, returning STATUS_SECUREBOOT_NOT_ENABLED.

The information buffer must provide at least enough for the function to fill a SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION structure with a variable-size Policy member at its end.

SystemCodeIntegrityPolicyFullInformation (0xAC)

This information class is handled outside the kernel, by a callback that the kernel learns from CI.DLL via the CiInitialize function. If the callback is not yet known, this function fails, setting the return length to zero and returning STATUS_UNSUCCESSFUL.

SystemAffinitizedInterruptProcessorInformation (0xAD)

If executing for a user-mode request, the function fails unless the caller has SeIncreaseBasePriorityPrivilege or is running as Local System or as a particular service that has not yet been identified.

The information buffer must provide exactly a KAFFINITY_EX structure for the function to fill. Each set bit in that structure’s Bitmap signifies that the corresponding processor has at least some interrupt steered to it for handling.

SystemRootSiloInformation (0xAE)

The information buffer is to receive a SYSTEM_ROOT_SILO_INFORMATION structure whose SiloIdList array has an identifier for each root silo, i.e., each silo that is not itself in a silo. If the buffer is too small even for the NumberOfSilos member, the function sets the return length to zero, and fails, returning STATUS_BUFFER_TOO_SMALL. The function also returns STATUS_BUFFER_TOO_SMALL if the buffer is not large enough for the whole array, however big that turns out to be. In this case too, here suspected of being coded defectively, the function sets the return length to zero. The only way the function sets the return length to anything but zero is if it succeeds.

SystemCpuSetInformation (0xAF)

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.