Geoff Chappell - Software Analyst
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).
This note is derived from inspection of the kernel version 6.0.6000.16386 from the original Windows Vista.