Search
Close this search box.

Recover your XP product key from the registry using C#

Ever needed to reinstall your PC and could not recover your product key from that ‘safe storage’ you were supposed to use? It is no secret that if your system is still running you can recover the key from the system registry where it is encoded in a REG_BINARY value.

You can download a free utility that recovers the XP product key (and the MS Office product key if its installed):

You can even recover it online here:

  • Windows XP Key Decrypter Tool

but if you’re paranoid, maybe these applications are actually stealing your product key, so you want to do this yourself with your own code, right?  The only bit of code I could find that can recover product keys is here:

which provides a working Delphi source-code listing. I only required to find the XP product key, so after hacking the code, I produced a working C# version (works with .NET 1.1 and 2.0) shown below. I allowed place-holders for other product keys but the code may have to be further modified to work correctly.

Windows XP KeyFinder Listing

using System;
using System.Collections;
using Microsoft.Win32;

namespace MSKeyFinder {
  public class KeyDecoder {
    public enum Key { XP, Office10, Office11 }
    ;
    public static byte[] GetRegistryDigitalProductId(Key key) {
      byte[] digitalProductId = null;
      RegistryKey registry = null;
      switch (key) {
        // Open the XP subkey readonly.
        case Key.XP:
          registry = Registry.LocalMachine.OpenSubKey(
              @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false);
          break;
        // Open the Office 10 subkey readonly.
        case Key.Office10:
          // TODO: Open the registry key.
          break;
        // Open the Office 11 subkey readonly.
        case Key.Office11:
          // TODO: Open the registry key.
          break;
      }
      if (registry != null) {
        // TODO: For other products, key name maybe different.
        digitalProductId = registry.GetValue("DigitalProductId") as byte[];
        registry.Close();
      }
      return digitalProductId;
    }
    public 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.
      char[] digits = new char[] {
        '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.
      char[] decodedChars = new char[decodeLength];
      // Extract byte 52 to 67 inclusive.
      ArrayList 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);
    }
  }
}

Once you realize how the product keys are encoded, a search through the registry for the values starting with DigitalProductId indicates that many more product keys may be encoded this way.

PLEASE NOTE: All code listed here is provided as-is, with no guarantees what so ever. Use of this code does not require a license and no copyright on the code exists or is implied. You are free to use the code as you see fit, for any commercial or non-commercial use.

This article is part of the GWB Archives. Original Author: Willem Fourie

Related Posts