- INT 2Eh Interrupt Gate
- Calling Into ntdll.dll
- Calling NtQuerySystemInformation()
- Enumerating Processes and Threads
- Putting the Pieces Together
- Sample Code Archive
- References
Calling NtQuerySystemInformation()
Want some sample code? OKout of the various subfunctions offered by NtQuerySystemInformation(), I have chosen the one that returns a process/thread list. Retrieving this list is a common problem that system programmers have to face, and this is also one of the few examples in which Windows NT 2000 and NT 4.0 behave differently. Actually, the specifications of NtQuerySystemInformation() and NtSetSystemInformation() have remained remarkably stable during the last major NT upgrade, except that more subfunctions were added. To my knowledge, only two of the NT4 subfunctions were changed significantly in Windows 2000, and one of them is the SystemProcessInformation subfunction we will examine now. In Windows 2000, the process structure it returns contains an additional member. Unfortunately, it is not located at the end, where it could have been safely ignored, so you have to check the operating system version before accessing the returned data.
Listing 2 shows the prototypes of NtQuerySystemInformation() and NtSetSystemInformation(). NtQuerySystemInformation() behaves similarly to other NtQuery*() functions, such as the semidocumented NtQueryInformationProcess() function. These functions usually require a zero-based Information Class parameter that selects the subfunction to be called. In Listing 2, this is the SystemInformationClass argument. SystemInformation is a pointer to a buffer allocated by the application that will receive the requested system data, and SystemInformationLength specifies its length. The format of the buffer varies dramatically, depending on the specified info class. On return, the optional ReturnLength argument indicates how many bytes were copied to the buffer. Unfortunately, several NtQuerySystemInformation() subfunctions return variable-length data and don't tell you the required buffer size in case of an overflow, so you will usually have to implement a trial-and-error loop to find out the correct size.
Listing 2 NtQuerySystemInformation() and NtSetSystemInformation()
NTSTATUS NTAPI NtQuerySystemInformation (IN SYSTEMINFOCLASS SystemInformationClass, OUT PVOID SystemInformation, IN DWORD SystemInformationLength, OUT PDWORD ReturnLength OPTIONAL); NTSTATUS NTAPI NtSetSystemInformation (IN SYSTEMINFOCLASS SystemInformationClass, IN PVOID SystemInformation, IN DWORD SystemInformationLength);
In Listing 3, the system information classes available on Windows 2000 and NT 4.0 are defined. Please note the comment info classes specific to Windows 2000 that heads the subfunction numbers not available on NT 4.0. The info class we will use in the forthcoming example is named SystemProcessInformation (#5). Many NtQuerySystemInformation() subfunctions are merely wrappers around other internal ntoskrnl.exe functions; and in the case of SystemProcessInformation, the base function is ExpGetProcessInformation().
Listing 3 Available System Information Classes
typedef enum _SYSTEMINFOCLASS { SystemBasicInformation, // 0x002C SystemProcessorInformation, // 0x000C SystemPerformanceInformation, // 0x0138 SystemTimeInformation, // 0x0020 SystemPathInformation, // not implemented SystemProcessInformation, // 0x00F8+ per process SystemCallInformation, // 0x0018 + (n * 0x0004) SystemConfigurationInformation, // 0x0018 SystemProcessorCounters, // 0x0030 per cpu SystemGlobalFlag, // 0x0004 SystemInfo10, // not implemented SystemModuleInformation, // 0x0004 + (n * 0x011C) SystemLockInformation, // 0x0004 + (n * 0x0024) SystemInfo13, // not implemented SystemPagedPoolInformation, // checked build only SystemNonPagedPoolInformation, // checked build only SystemHandleInformation, // 0x0004 + (n * 0x0010) SystemObjectInformation, // 0x0038+ + (n * 0x0030+) SystemPagefileInformation, // 0x0018+ per page file SystemInstemulInformation, // 0x0088 SystemInfo20, // invalid info class SystemCacheInformation, // 0x0024 SystemPoolTagInformation, // 0x0004 + (n * 0x001C) SystemProcessorStatistics, // 0x0000, or 0x0018 per cpu SystemDpcInformation, // 0x0014 SystemMemoryUsageInformation1, // checked build only SystemLoadImage, // 0x0018, set mode only SystemUnloadImage, // 0x0004, set mode only SystemTimeAdjustmentInformation, // 0x000C, 0x0008 writeable SystemMemoryUsageInformation2, // checked build only SystemInfo30, // checked build only SystemInfo31, // checked build only SystemCrashDumpInformation, // 0x0004 SystemExceptionInformation, // 0x0010 SystemCrashDumpStateInformation, // 0x0008 SystemDebuggerInformation, // 0x0002 SystemThreadSwitchInformation, // 0x0030 SystemRegistryQuotaInformation, // 0x000C SystemLoadDriver, // 0x0008, set mode only SystemPrioritySeparationInformation,// 0x0004, set mode only SystemInfo40, // not implemented SystemInfo41, // not implemented SystemInfo42, // invalid info class SystemInfo43, // invalid info class SystemTimeZoneInformation, // 0x00AC SystemLookasideInformation, // n * 0x0020 // info classes specific to Windows 2000 // WTS = Windows Terminal Server SystemSetTimeSlipEvent, // set mode only SystemCreateSession, // WTS, set mode only SystemDeleteSession, // WTS, set mode only SystemInfo49, // invalid info class SystemRangeStartInformation, // 0x0004 SystemVerifierInformation, // 0x0068 SystemAddVerifier, // set mode only SystemSessionProcessesInformation, // WTS } SYSTEMINFOCLASS, *PSYSTEMINFOCLASS;
SystemProcessInformation is one of the NtQuerySystemInformation() subfunctions that return variable length data. The required buffer size depends on the number of processes and threads currently running. The data is returned in a single monolithic memory block, comprising a list of structuresone per process. Each process structure contains an array of fixed-length thread structures. Because the length of each process structure varies with the number of threads the corresponding process hosts, they are linked by a member that indicates how many bytes need to be skipped to get to the next list item. This scheme applies to several other NtQuerySystemInformation() subfunctions as well, except for some rare cases in which the link member specifies an absolute offset rather than a relative one.