CURRENT WORK ITEM - PREVIEW ONLY

SECTION_IMAGE_INFORMATION

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.

Layout

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.