RtlQueryModuleInformation

The RtlQueryModuleInformation function produces an array of one or another sort of structure for each of the loaded kernel-mode modules.

Declaration

NTSTATUS 
RtlQueryModuleInformation (
    ULONG *InformationLength, 
    ULONG SizePerModule, 
    PVOID InformationBuffer);

Names and types for the arguments in the preceding declaration are confected for this article, Microsoft’s being unknown.

Parameters

The InformationLength argument provides the address of a variable that may matter for both input and output. On input, the variable provides the size, in bytes, of the buffer that is to receive the module information. This size is ignored if no buffer is provided, i.e., if InformationBuffer is NULL. On output, the variable 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).

The SizePerModule argument selects the type of information that is sought. It is specifically the size, in bytes, of the structure that the function is to produce for each loaded module. The supported structures are RTL_MODULE_BASIC_INFO and RTL_MODULE_EXTENDED_INFO.

The InformationBuffer argument provides the address of the buffer that is to receive information about the loaded modules. This argument can be NULL to mean that there is no buffer (and the module information is not wanted but the size is).

Return Value

The function returns STATUS_SUCCESS if successful, else a negative error code.

Of particular importance are the cases in which module information might be provided but is too large for the given buffer, including because there is no buffer. If InformationBuffer is NULL, then because the caller did not ask for module information and is not denied anything that was asked for, the function succeeds. If InformationBuffer is not NULL, the caller asked for module information which the function cannot deliver, and the function therefore fails, returning STATUS_BUFFER_TOO_SMALL. Either way, a size that would have sufficed will have been set into the variable at the address given by InformationLength.

Be aware that a size that would have sufficed on one call to the function need not still suffice on another, no matter how soon. This is not just the usual theoretical point, but a practical one: kernel-mode modules get loaded and unloaded, such that a change in their number between calls is, if not actually likely, then at least unsurprising.

Availability

The RtlQueryModuleInformation is exported by name from both the kernel and NTDLL in version 6.0 and higher. A function with the same name is exported by name from NTDLL in version 3.10 only, but it is very different and is left for another time.

Documentation Status

The RtlQueryModuleInformation is not documented.

Behaviour

If SizePerModule is not the size of either supported structure, the function fails, returning STATUS_INVALID_PARAMETER_2. If the InformationBuffer is not suitably aligned for the supported structures, the function fails, returning STATUS_INVALID_PARAMETER_3.

The function extracts the desired module information from more detailed data that it obtains through the SystemModuleInformation case of ZwQuerySystemInformation, first with a minimal buffer on the stack. If no information buffer is provided, the function calls ZwQuerySystemInformation just the once, to learn how many modules are loaded and to calculate how large an information buffer the caller would have sufficed for successful extraction. More typically, the function calls ZwQuerySystemInformation again but with a dynamically allocated buffer, repeating with larger buffers until the called function succeeds. Failure of the called function for any reason other than needing a larger buffer is failure for RtlQueryModuleInformation. If the function fails to get an indicated amount of memory for this buffer, it fails, returning STATUS_INSUFFICIENT_RESOURCES.

When ZwQuerySystemInformation succeeds, the function learns how many modules are loaded and how much module information it might put in the given buffer. If the given buffer is large enough, the function extracts the wanted information. Otherwise it fails, returning STATUS_BUFFER_TOO_SMALL. Either way, the variable at InformationLength receives the size.