Willem's...

{rue if I mellow}

  Home  |   Contact  |   Syndication    |   Login
  24 Posts | 0 Stories | 93 Comments | 78 Trackbacks

News

Archives

Post Categories

Businessware Architects

Wednesday, May 31, 2006 #

Following my prior post:

I have had many requests to provide the same code in unmanaged C++ - so here goes:

// KeyDecoder.h
#pragma once
#ifndef byte
typedef unsigned char byte;
#endif // byte
class KeyDecoder
{
public:
  enum Key { XP, Office10, Office11 };
  static int DecodeProductKey(KeyDecoder::Key key, char* pDecodedKey);
protected:
  static byte* GetRegistryDigitalProductId(KeyDecoder::Key key);
  static char* DecodeProductKey(byte* digitalProductId);
};

and:

// KeyDecoder.cpp
#include "StdAfx.h"
#include "keydecoder.h"
int KeyDecoder::DecodeProductKey(KeyDecoder::Key key, char* pKey)
{
  byte* pEncodedPID = GetRegistryDigitalProductId(key);
  int keyLen = 0;
  if(pEncodedPID)
  {
    char* pDecodedPID = DecodeProductKey(pEncodedPID);
    if(pDecodedPID)
    {
      keyLen = (int)::strlen(pDecodedPID);
      if(pKey)
      {
        ::strcpy(pKey, pDecodedPID);
      }
      delete[] pDecodedPID;
    }
  }
  return keyLen + 1;
}
char* KeyDecoder::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[] = 
  {
    '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* pDecodedChars = new char[decodeLength + 1];
  ::memset(pDecodedChars, 0, decodeLength + 1); 
  // Extract byte 52 to 67 inclusive.
  byte hexPid[keyEndIndex - keyStartIndex + 1];
  for (int i = keyStartIndex; i <= keyEndIndex; i++)
  {
    hexPid[i - keyStartIndex] = digitalProductId[i];
  }
  for (int i = decodeLength - 1; i >= 0; i--)
  {
    // Every sixth char is a separator.
    if ((i + 1) % 6 == 0)
    {
      *(pDecodedChars + i) = '-';
    }
    else
    {
      // Do the actual decoding.
      int digitMapIndex = 0;
      for (int j = decodeStringLength - 1; j >= 0; j--)
      {
        int byteValue = (digitMapIndex << 8) | hexPid[j];
        hexPid[j] = (byte)(byteValue / 24);
        digitMapIndex = byteValue % 24;
        *(pDecodedChars + i) = digits[digitMapIndex];
      }
    }
  }
  return pDecodedChars;
}
byte* KeyDecoder::GetRegistryDigitalProductId(KeyDecoder::Key key)
{
  HKEY hKey = 0;
  LONG lResult = 0L;
  const char* pPIDName = "DigitalProductId";
  byte* pPID = 0;
  switch(key)
  {
    case KeyDecoder::Key::XP:
      lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
        "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
        0, KEY_QUERY_VALUE, &hKey);
      break;
    case KeyDecoder::Key::Office10:
      break;
    case KeyDecoder::Key::Office11:
      break;
  }
  if(lResult == ERROR_SUCCESS)
  {
    DWORD cbData = 0;
    DWORD dwType = 0;
    lResult = ::RegQueryValueEx(hKey, pPIDName, 0, &dwType, 0, &cbData);
    if(lResult == ERROR_SUCCESS)
    {
      pPID = new byte[cbData];
      lResult = ::RegQueryValueEx(hKey, pPIDName, 0, &dwType, pPID, &cbData);
      if(lResult != ERROR_SUCCESS)
      {
        delete[] pPID;
        pPID = 0;
      }
    }
  }
  if(hKey)
  {
    ::RegCloseKey(hKey);
  }
  return pPID;
}

This provides the same functionality as the C# code in the prior post.

XPKey is a standard Win32 console application that pops up a message box containing the decoded XP product key. It also copies the product key to the clipboard. You can download the executable here:

and the VC source-code and project file here:

The C++ application is provided for VS2003, but should convert without problems to VS2005. It uses only standard Win32 calls - no MFC/ATL/STL etc.