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.
