Geoff Chappell - Software Analyst
CURRENT WORK ITEM - PREVIEW ONLY
The SECTION_IMAGE_INFORMATION is a structure that the Memory Manager keeps about an executable image that backs a section. It was originally nested into the SEGMENT structure and is still built in the same pool allocation. Windows 2000 changed it to be merely pointed to from the SEGMENT. Starting with Windows Vista, this SECTION_IMAGE_INFORMATION is itself nested into an MI_SECTION_IMAGE_INFORMATION as a member named ExportedImageInformation (presumably for explicit differentiation from the MI_EXTRA_IMAGE_INFORMATION that follows as a member named InternalImageInformation).
Though the SECTION_IMAGE_INFORMATION has always been implemented as bookkeeping for the SEGMENT, it has for just as long been exposed through interfaces. Copies are fetched from the SEGMENT for two interfaces that are callable from user mode.
The lower-level of these interfaces is the NtQuerySection and ZwQuerySection functions. Though the latter is not a kernel export until version 3.50 (and the former never is), both are exported from NTDLL (the latter as an alias of the former) right from the start. As with many similar functions, this one’s output is selected by an information class. Successful output for the information class SectionImageInformation is a (possibly adjusted) copy of the SECTION_IMAGE_INFORMATION from the queried section’s SEGMENT.
A higher-level interface is RtlCreateUserProcess. This too is an ancient export from NTDLL. The caller provides space for an RTL_USER_PROCESS_INFORMATION structure that the function fills in if it succeeds at creating the process and its initial thread. This is in some sense an elaboration of the even higher-level PROCESS_INFORMATION that is a similar provision for the CreateProcess function. Lke the documented PROCESS_INFORMATION, the undocumented RTL_USER_PROCESS_INFORMATION contains not just the handles and IDs of the process and thread. What’s extra is that it also has a SECTION_IMAGE_INFORMATION that is copied from the SEGMENT for the image section.
The SECTION_IMAGE_INFORMATION is 0x30 and 0x40 bytes in 32-bit and 64-bit Windows, respectively, in all known versions at least to the 2004 release of Windows 10. Names and definitions in the table that follows are from type information in Microsoft’s symbol files for the kernel starting with Windows 2000 SP3. Type information for two earlier versions is known from statically linked libraries named GDISRVL.LIB and SHELL32.LIB which Microsoft distributed with the Device Driver Kit (DDK) for Windows NT 3.51 and 4.0, respectively. What’s known for other versions is something of a guess from inspecting binaries for continuity with later versions.
Offset (x86) | Offset (x64) | Definition | Versions |
---|---|---|---|
0x00 | 0x00 |
PVOID TransferAddress; |
all |
0x04 | 0x08 |
ULONG ZeroBits; |
all |
0x08 | 0x10 |
ULONG_PTR MaximumStackSize; |
all |
0x0C | 0x18 |
ULONG_PTR CommittedStackSize; |
all |
0x10 | 0x20 |
ULONG SubSystemType; |
all |
0x14 |
union { struct { USHORT SubSystemMajorVersion; USHORT SubSystemMinorVersion; }; ULONG SubSystemVersion; }; |
3.10 to 3.50 | |
0x24 |
union { struct { USHORT SubSystemMinorVersion; USHORT SubSystemMajorVersion; }; ULONG SubSystemVersion; }; |
3.51 and higher | |
0x18 | 0x28 |
ULONG GpValue; |
3.10 to 6.3 |
union { struct { USHORT MajorOperatingSystemVersion; USHORT MinorOperatingSystemVersion; }; ULONG OperatingSystemVersion; }; |
10.0 and higher | ||
0x1C | 0x2C |
USHORT ImageCharacteristics; |
all |
0x1E | 0x2E |
USHORT DllCharacteristics; |
all |
0x20 | 0x30 |
USHORT Machine; |
all |
0x22 | 0x32 |
BOOLEAN ImageContainsCode; |
4.0 and higher |
0x22 (3.10 to 3.51); 0x23 |
USHORT Spare1; |
3.10 to 3.51 | |
0x33 |
UCHAR Spare1; |
4.0 to 5.2 | |
union { UCHAR ImageFlags; struct { /* changing bit fields, follow link */ }; }; |
6.0 and higher | ||
0x24 | 0x34 |
ULONG LoaderFlags; |
all |
0x28 | 0x38 |
ULONG ImageFileSize; |
late 5.2 and higher |
0x28 (3.10 to early 5.2); 0x2C |
ULONG Reserved [2]; |
3.10 to early 5.2 | |
0x3C |
ULONG Reserved [1]; |
late 5.2 only | |
ULONG CheckSum; |
6.0 and higher |
The GpValue and LoaderFlags members are known to be defined as early as version 3.51, but use in earlier versions has not yet been found (not that any effort has been put into looking).
Exactly what definition Microsoft started with for the subsystem version number may never be known. The essential point is that the order of major and minor version numbers changed. The IMAGE_OPTIONAL_HEADER from which the version numbers are obtained has all three of its pairs of major and minor versions ordered as major then minor. When the implementation in versions 3.10 and 3.50 composes a 32-bit version number from the header’s MajorSubsystemVersion and MinorSubsystemVersion, it keeps the minor as the more significant. Later versions transfer the major and minor version numbers separately but reverse the order. Curiously, for the MajorOperatingSystemVersion and MinorOperatingSystemVersion, which are not saved until version 10.0, the header’s order is retained.
The ImageContainsCode if the header shows a non-zero SizeOfCode or a non-zero AddressOfEntryPoint.