Over in the PowerBASIC forums there was a program posted that showed how to get the product key that was used to install Windows. I thought it was interesting, but it didn't work correctly on 64-bit Windows and included some rather funky inline assembly. For anyone interested, I wrote an ANSI C version of it that should be easy to port, works correctly and is a lot easier to understand (I think). I based the algorithm used to actually decode the key value stored in the registry on some Pascal code (Google is our friend). I didn't think posting a C program on the PowerBASIC forums would be appropriate, so I thought I'd share here. I've tested it with both 32-bit and 64-bit builds, ANSI and Unicode.
//
// This is an ANSI C console-based example that provides a function that
// will return the Windows product key that was used to install this
// copy of Windows.
//
// The algorithm for decoding the product key is based on a Pascal program
// written by Chuck DeLong at http://www.chuckdelong.us/MSProdKey.html
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <conio.h>
#define WINNT_CURRENT_VERSION _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion")
#define KEY_VALUE_NAME _T("DigitalProductId")
#define KEY_VALUE_SIZE 164
#define KEY_PRODUCT_SIZE 15
#define KEY_STRING_SIZE 30
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
///////////////////////////////////////////////////////////////////////////////
//
// GetWindowsProduct key returns the product key that was used to install
// this copy of Windows. Note that the same key is used multiple times when
// Windows is pre-installed by an OEM, so it is not recommended that you
// use this value to uniquely identify a particular system.
//
// The lpszProductKey parameter is a pointer to a string that will contain
// the product key; it cannot be NULL, and it must be large enough to store
// the complete value.
//
// The nMaxLength parameter specifies the maximum number of characters
// that can be copied into the lpszProductKey string. The minimum string
// length is 30 characters, otherwise this function will fail.
INT WINAPI GetWindowsProductKey(LPTSTR lpszProductKey, INT nMaxLength)
{
LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
BOOL bIsWow64 = FALSE;
HKEY hKey = NULL;
REGSAM samDesired = KEY_QUERY_VALUE;
BYTE keyData[KEY_VALUE_SIZE] = { 0, };
BYTE keyProduct[KEY_PRODUCT_SIZE] = { 0, };
TCHAR szBuffer[KEY_STRING_SIZE] = { 0, };
DWORD dwType = 0;
DWORD dwSize = KEY_VALUE_SIZE;
INT nLength = 0;
INT nCounter = 0;
INT nIndex;
LONG lResult;
const TCHAR keyChars[] = {
'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M',
'P', 'Q', 'R', 'T', 'V', 'W', 'X', 'Y',
'2', '3', '4', '6', '7', '8', '9',
'\0'
};
if (lpszProductKey != NULL)
*lpszProductKey = 0;
else
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if (nMaxLength < KEY_STRING_SIZE)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(_T("kernel32")), "IsWow64Process");
if (fnIsWow64Process != NULL)
fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
if (bIsWow64)
samDesired |= KEY_WOW64_64KEY;
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINNT_CURRENT_VERSION, REG_OPTION_NON_VOLATILE, samDesired, &hKey);
if (lResult != ERROR_SUCCESS)
return 0;
lResult = RegQueryValueEx(hKey, KEY_VALUE_NAME, NULL, &dwType, keyData, &dwSize);
if (lResult != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return 0;
}
CopyMemory(keyProduct, &keyData[52], KEY_PRODUCT_SIZE);
RegCloseKey(hKey);
for(nCounter = 24; nCounter >= 0; nCounter--)
{
INT nValue = 0;
for (nIndex = 14; nIndex >= 0; nIndex--)
{
nValue = (nValue * 256) ^ keyProduct[nIndex];
keyProduct[nIndex] = nValue / 24;
nValue %= 24;
}
szBuffer[nLength++] = keyChars[nValue];
if (nCounter > 0 && (nCounter % 5) == 0)
szBuffer[nLength++] = _T('-');
}
for (nIndex = nLength; nIndex > 0; nIndex--)
*lpszProductKey++ = szBuffer[nIndex - 1];
return nLength;
}
int _tmain(int argc, TCHAR* argv[])
{
TCHAR szProductKey[KEY_STRING_SIZE] = _T("");
if (GetWindowsProductKey(szProductKey, KEY_STRING_SIZE) != 0)
_tprintf(_T("Your Windows product key is %s\n"), szProductKey);
else
_tprintf(_T("Unable to access your product key (error 0x%lx)\n"), GetLastError());
_tprintf(_T("Press any key to exit..."));
_getch();
return 0;
}
Here is another one in PowerBASIC, should be good for 95 up to Seven 32/64.
Get Window product id (http://pages.videotron.com/lyra/PowerBASIC/GetWindowProductId.html)
Pierre