Win32 XP Key Recovery Utility

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:

  • Download XPKey Console Application,

and the VC source-code and project file here:

  • Download XPKey Source Code.

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.

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

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.