• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

Recovering the Windows product key

Started by Mike Stefanik, November 21, 2011, 04:00:00 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Mike Stefanik

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;
}
Mike Stefanik
sockettools.com

Pierre Bellisle

Here is another one in PowerBASIC, should be good for 95 up to Seven 32/64.

Get Window product id

Pierre