The Product Suite

Windows comes in an ever-increasing variety of editions. A long-standing identifier is the product suite, which is most familiar to Windows programmers as the wSuiteMask member of the OSVERSIONINFOEX structure that is filled by the user-mode function GetVersionEx. Kernel-mode programmers have easy access to the product suite through the very similar function RtlGetVersion. Both functions pick the product suite from the SuiteMask member (at offset 0x02D0) of the KUSER_SHARED_DATA structure that the kernel makes addressable at 0x7FFE0000 in kernel mode and 0xFFDF0000 in user mode. The kernel’s own record of the product suite can be read more obscurely through ExVerifySuite.

The product suite is a combination of bit flags. It is first determined from the following registry value:

Key HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ProductOptions
Value ProductSuite
Type REG_MULTI_SZ

Each string in the data, if it is recognised, corresponds to one bit in the suite mask:

Small Business VER_SUITE_SMALLBUSINESS (0x0001)
Enterprise VER_SUITE_ENTERPRISE (0x0002)
BackOffice VER_SUITE_BACKOFFICE (0x0004)
CommunicationServer VER_SUITE_COMMUNICATIONS (0x0008)
Terminal Server VER_SUITE_TERMINAL (0x0010)
Small Business(Restricted) VER_SUITE_SMALLBUSINESS_RESTRICTED (0x0020)
EmbeddedNT VER_SUITE_EMBEDDEDNT (0x0040)
DataCenter VER_SUITE_DATACENTER (0x0080)
Personal VER_SUITE_PERSONAL (0x0200)
Blade VER_SUITE_BLADE (0x0400)
Embedded(Restricted) VER_SUITE_EMBEDDED_RESTRICTED (0x0800)
Security Appliance VER_SUITE_SECURITY_APPLIANCE (0x1000)
Storage Server VER_SUITE_STORAGE_SERVER (0x2000)
Compute Server VER_SUITE_COMPUTE_SERVER (0x4000)

Strings that are not in the list are ignored. Note that VER_SUITE_SINGLEUSERTS (0x0100) is not learnt this way.

The kernel interprets the ProductSuite value during phase 0 of initialisation. However, the suite mask that is obtained this way is not entirely believed. If the license value Kernel-ProductInfo is present and has 4 bytes of REG_DWORD data, then the suite mask is reappraised. The effective outcome is that the following are never combined:

Instead, one (at most) is selected from the Kernel-ProductInfo:

Kernel-ProductInfo Suite
0x01 (PRODUCT_ULTIMATE)
0x04 (PRODUCT_ENTERPRISE)
0x06 (PRODUCT_BUSINESS)
0x07 (PRODUCT_STANDARD_SERVER)
0x0D (PRODUCT_STANDARD_SERVER_CORE)
0x10 (PRODUCT_BUSINESS_N)
0x12 (PRODUCT_CLUSTER_SERVER)
0x13 (PRODUCT_HOME_SERVER)
0x18 (PRODUCT_SERVER_FOR_SMALLBUSINESS)
none
0x02 (PRODUCT_HOME_BASIC)
0x03 (PRODUCT_HOME_PREMIUM)
0x05 (PRODUCT_HOME_BASIC_N)
0x0B (PRODUCT_STARTER)
VER_SUITE_PERSONAL
0x08 (PRODUCT_DATACENTER_SERVER)
0x0C (PRODUCT_DATACENTER_SERVER_CORE)
VER_SUITE_DATACENTER
0x09 (PRODUCT_SMALLBUSINESS_SERVER)
0x19 (PRODUCT_SMALLBUSINESS_SERVER_PREMIUM)
VER_SUITE_SMALLBUSINESS
0x0A (PRODUCT_ENTERPRISE_SERVER)
0x0E (PRODUCT_ENTERPRISE_SERVER_CORE)
0x0F (PRODUCT_ENTERPRISE_SERVER_IA64)
VER_SUITE_ENTERPRISE
0x11 (PRODUCT_WEB_SERVER) VER_SUITE_BLADE
0x14 (PRODUCT_STORAGE_EXPRESS_SERVER)
0x15 (PRODUCT_STORAGE_STANDARD_SERVER)
0x16 (PRODUCT_STORAGE_WORKGROUP_SERVER)
0x17 (PRODUCT_STORAGE_ENTERPRISE_SERVER)
VER_SUITE_STORAGE_SERVER

In phase 2 of initialisation, the kernel forces VER_SUITE_TERMINAL to be set always, and also sets VER_SUITE_SINGLEUSERTS (0x0100) unless the following registry value has non-zero data:

Key HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server
Value TSAppCompat

The value is surely meant to have REG_DWORD data, and is documented as such (in the Microsoft Knowledge Base article Examining the Terminal Server Key in HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control), with 0 for a Remote Administration Server and 1 for an Application Server. However, the kernel actually only checks that the value has data of any sort with at least one non-zero byte in its first four.

This completes the identification of the product suite. The kernel saves it as bit flags in the shared user data and also writes it as multi-string data for the ProductSuite value. Of course, this will ordinarily mean writing the same data back to the registry as was read earlier. The REG_MULTI_SZ strings are always written in the order listed above. Failure to write the ProductSuite value is fatal to Windows, causing the bug check SYSTEM_LICENSE_VIOLATION (0x9A).

Applicability

This note is derived from inspection of the kernel version 6.0.6000.16386 from the original Windows Vista.