Bug Check 0x9A

The SYSTEM_LICENSE_VIOLATION bug check reports
a fatal error in validating the license to use Windows.

Bug Check Code:

SYSTEM_LICENSE_VIOLATION

1st Argument:

case

2nd Argument:

status code or number of bytes or 0, depending on case

3rd Argument:

sub-case or 0

4th Argument:

0

Some two dozen different causes are indicated by the first argument. For most,
the second argument is a status code. Some have sub-cases indicated by the third
argument. The fourth argument is always zero.

To understand all this bug check’s cases, it helps to know the kernel’s algorithm
for license validation. Windows Vista has two distinct approaches. One is inherited
from earlier versions and is here referred to as license protection. The other involves
the new scheme of named license values and is here referred to as tamper detection.

License Protection

For license protection, relevant registry values are monitored for changes, most
such changes are signalled as license violations, and all changes are undone by
rewriting the value.

Whatever may be suggested by this bug check’s symbolic name or stated explicitly
in Microsoft’s documentation, an occurrence of bug check 0x9A for license protection
does not mean that the license for using Windows has been found to be violated.
The bug check means only that the kernel ran into a problem while trying to detect
a violation and protect the license. Though the most likely reason is very plausibly
that a user has damaged relevant registry keys or values while attempting to violate
the license, the violation is not of itself what bug check 0x9A reports.

In particular, when the detection proceeds without error and actually does find
that the relevant registry values have changed in a way that violates the license,
the kernel does not respond with any bug check, let alone with this one. What it
does instead is to raise a so-called hard error. The visible outcome is not a stopped
system, just an entry in the System event log, with the stern text:

Application popup: Windows - License Violation : The system has detected tampering with your
registered product type. This is a violation of your software license. Tampering with product type
is not permitted.

Incidentally, lawyers may want to consider that the presence of such an entry
in the System log is not immediately good evidence that the system detected a license
violation. It can be produced by any kernel-mode component, such as a driver, simply
by calling the (admittedly undocumented) function ExRaiseHardError
and giving STATUS_LICENSE_VIOLATION (0xC000026A) as
the status code.

Initialisation

License protection is prepared at the beginning of phase 2 of system initialisation.
Ordinarily, the failure of any operation for initialising license protection causes
bug check 0x9A. In Setup mode, most failures are not fatal but just cause the kernel
to proceed no further with protecting the license.

The Setup Key

Though license protection is much reduced in Setup mode, the kernel must be certain
that it is in Setup mode. The determination is from the registry values
SetupType and SystemSetupInProgress
in the HKEY_LOCAL_MACHINE\System\Setup key. The kernel
assumes that each value has at least 4 bytes of data. The kernel interprets 1 and
4 for SetupType as meaning that Windows is in Setup
mode, and 1 for SystemSetupInProgress as meaning that
system setup is in progress.

The kernel must not only open the Setup key but also
reference it as an object. The only purpose to this is to protect the key from being
deleted. (The kernel’s code for deleting a registry key explictly checks that the
object to be deleted is not this one that the kernel has kept referenced for license
protection.) If Setup mode is detected from the subsequent reading of
SetupType, the kernel dereferences the object.

In WinPE mode, checking these values in the Setup
key is as far as the kernel proceeds with license protection. (WinPE mode is known
from phase 1, if MININT is in the boot options.) That
it proceeds even this far seems useless and is presumably vestigial: earlier versions
will have done something non-trivial, namely to protect the
SystemPrefix value in the Setup
key.

The ProductOptions Key

The essential registry values for differentiating the various editions of a Windows
version are ProductType and ProductSuite in the registry
key HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ProductOptions.

In Setup mode, failure to open the ProductOptions
key causes the kernel to abandon license protection.

Except in Setup mode, the kernel must not only open the
ProductOptions key but also reference it as an object. The only purpose to
this is to protect the key from being deleted. (The kernel’s code for deleting a
registry key explictly checks that the object to be deleted is not this one that
the kernel has kept referenced for license validation.)

In Windows Vista, the product type and product suite are determined only in part
from the ProductType and ProductSuite
values. A value named ProductPolicy (also in the
ProductOptions key) provides for an essentially arbitrary
number of named license values. One of these, Kernel-ProductInfo,
is checked in phase 0 of initialisation and may override what was read from
ProductType and ProductSuite.
If the product type has been re-determined from Kernel-ProductInfo,
then in phase 2 unless in Setup mode, the kernel rewrites both values, whether or
not they are changed. It then proceeds as if for earlier versions, which involves
re-reading what it has just written.

The general idea to protecting the ProductType
and ProductSuite values is to read them now, save
their original data, and then watch the ProductOptions
key for changes, so that any attempt to change these values can be undone by rewriting
the original data. It seems that the ProductType is
mandatory for the scheme but the ProductSuite is merely
desirable. However, there are quirks. If the kernel cannot obtain memory for the
ProductType value’s original data, it abandons license
protection. In Setup mode, failure to read the ProductType
also causes the kernel to abandon license protection. The
ProductSuite value gets protected only if it has more than four bytes of
data. For some reason, obtaining memory in which to hold this data is vital, but
failure to read the data is not. In Setup mode, failure to read the
ProductSuite causes the kernel to abandon license
protection.

Having saved the original data for these two values, the kernel registers a work
queue item that is to execute as a change-notify callback for the
ProductOptions key. The action taken should this work
queue item ever execute is discussed below. In Setup mode, failure to register the
callback causes the kernel to abandon license protection.

The LicenseInfoSuites Key

More registry values for licensing are supported through the
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LicenseInfoSuites
key. Even the presence of this key is merely optional. If the key cannot be opened,
the initialisation of license protection is complete.

The LicenseInfoSuites key may have subkeys, each
treated here as representing some sort of suite.
Each of these subkeys may have yet more subkeys, each treated here as representing
some sort of suite product. (These terms are from
Microsoft’s documentation of the bug check. The LicenseInfoSuites
key and its subkeys seem otherwise to be undocumented.)

The kernel’s only interest in the keys for the suites and suite products is the
ConcurrentLimit value.

TO BE DONE

Changes in the ProductOptions Key

During initialisation, the kernel registers a work queue item which is to execute
if changes are detected in the ProductOptions key. Of
course, not all changes in that key suggest a license violation, just changes to
the ProductType value and only then if not in Setup
mode. A change of ProductType to
LanmanNT or ServerNT from
anything other than WinNT is not treated as a license
violation. Any other change, including if implied by failure to read the value,
is.

TO BE DONE

Changes in a LicenseInfoSuites Subkey

TO BE DONE

Tamper Detection

TO BE DONE

Approximately every hour, the kernel resynchronises system time with the real-time
clock. (This resynchronisation is performed at other times, too, particularly after
events that may have stopped the handling of timer interrupts, as when execution
breaks to a kernel-mode debugger.) This hourly update is also an opportunity for
license validation. Unless system setup is in progress, the kernel checks that the
license data has not been tampered with and that the license has not expired its
evaluation period (as specified by the Kernel-ExpirationDate
license value).

Bug Check Parameters

In the table that follows, the several cases in which the 3rd argument takes
values that Microsoft does not document for this bug check are highlighted
yellow.