All posts tagged windows key

Getting the Windows Key

Categories: .Net, C#, Console, WPF
Comments: No

In my last post I went over how to retrieve the Windows Product Activation information from Windows Vista / 7.0 / 2008. Today, we are going to do something on the same thread but very much more desirable. And that is retrieving the Windows Key information.

For as long as Windows has had a key, admins have been looking to be able to retrieve the Windows key information on the fly: especially when they need to do a re-install and lost their original media casing.

So, let’s get right to it with a console application.


static void Main(string[] args)
{
    string computername = Environment.MachineName;
    const RegistryHive registryRoot = RegistryHive.LocalMachine;
    const string sSubKeyName = @"SOFTWAREMicrosoftWindows NTCurrentVersion";
    const string sValueName = "DigitalProductId";
    string windowsKey = "";

    // Get product Id
    RegistryKey regoutput = RegistryKey.OpenRemoteBaseKey(
        registryRoot, computername, RegistryView.Default).
        OpenSubKey(sSubKeyName);

    // Convert to byte array
    byte[] digitalProductId;
    if (regoutput != null)
    {
        digitalProductId = regoutput.GetValue(sValueName) as byte[];

        // Get Windows Product Key
        windowsKey = (digitalProductId != null)
            ? DecodeProductKey(digitalProductId)
            : "The product key was not accessible";
    }

    else
    {
        windowsKey = "The product key was not accessible";
    }

    // Output 
    Console.WriteLine(windowsKey);
    Console.Read();
}

In this example, I am choosing my local machine as the target. The location of the value we want is located in the registry here:
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionDigitalProductId.

We then get the byte array representing the key and decode it with the below method.


/// <summary>
/// Decodes a Microsoft product key based on the provided digital product id.
/// </summary>
/// <param name="digitalProductId">The digital product id.</param>
/// <returns></returns>
private static string DecodeProductKey(byte[] digitalProductId)
{
    // Offset of first byte of encoded product key in 
    //  'DigitalProductIdxxx" REG_BINARY value. Offset = 34H.
    const int keyStartIndex = 52;

    // Offset of last byte of encoded product key in 
    //  'DigitalProductIdxxx" REG_BINARY value. Offset = 43H.
    const int keyEndIndex = keyStartIndex + 15;

    // Possible alpha-numeric characters in product key.
    var digits = new[]
            {
                'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R',
                'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9'
            };

    // Length of decoded product key
    const int decodeLength = 29;

    // Length of decoded product key in byte-form.
    // Each byte represents 2 chars.
    const int decodeStringLength = 15;

    // Array of containing the decoded product key.
    var decodedChars = new char[decodeLength];

    // Extract byte 52 to 67 inclusive.
    var hexPid = new ArrayList();
    for (int i = keyStartIndex; i <= keyEndIndex; i++)
    {
        hexPid.Add(digitalProductId[i]);
    }
    for (int i = decodeLength - 1; i >= 0; i--)
    {
        // Every sixth char is a separator.
        if ((i + 1) % 6 == 0)
        {
            decodedChars[i] = '-';
        }
        else
        {
            // Do the actual decoding.
            int digitMapIndex = 0;
            for (int j = decodeStringLength - 1; j >= 0; j--)
            {
                int byteValue = (digitMapIndex << 8) | (byte)hexPid[j];
                hexPid[j] = (byte)(byteValue / 24);
                digitMapIndex = byteValue % 24;
                decodedChars[i] = digits[digitMapIndex];
            }
        }
    }
    return new string(decodedChars);
}

Now, if you are running 64-bit Windows (and most of us are), you may be running into problems getting your byte array. Why is that? Well, the short answer is that it has to do with your Configuration Manager settings. The default platform target is x86: which does not have access to several 64-bit spaces including certain registry values.

You can change that by doing the following in Visual Studio:

  1. Open your Project Properties.
  2. Go to the Build tab.
  3. For each Configuration set the Platorm target to Any CPU.
  4. For Visual Studio 2012, make sure to uncheck Prefer 32-bit.

That’s all there is to it.

Until next time.