Get Windows 10 Product Key

AceInfinity

Emeritus, Contributor
Joined
Feb 21, 2012
Posts
1,728
Location
Canada
Here's some code that I wrote to grab and decrypt the Windows 10 product key from the registry.

Code:
[plain]#include <Windows.h>
#include <stdio.h>
#include <string.h>

#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define NT_SUCCESS(status) (((NTSTATUS)(status)) == STATUS_SUCCESS)

#define TD(func) T_##func
#define DynamicFunction(name, dll) TD(name) \
  name = (TD(name))GetProcAddress(GetModuleHandle(dll), #name)

#define REG_KEY_BUFFER_MAX (4096 * 2)
#define OBJ_CASE_INSENSITIVE 0x00000040

typedef enum _KEY_VALUE_INFORMATION_CLASS
{
  KeyValueBasicInformation = 0,
  KeyValueFullInformation,
  KeyValuePartialInformation,
  KeyValueFullInformationAlign64,
  KeyValuePartialInformationAlign64,
  MaxKeyValueInfoClass
} KEY_VALUE_INFORMATION_CLASS;

typedef struct _UNICODE_STRING
{
  USHORT Length;
  USHORT MaximumLength;
  PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_ATTRIBUTES
{
  ULONG Length;
  PVOID RootDirectory;
  PUNICODE_STRING ObjectName;
  ULONG Attributes;
  PVOID SecurityDescriptor;
  PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

typedef struct _KEY_VALUE_FULL_INFORMATION
{
  ULONG TitleIndex;
  ULONG Type;
  ULONG DataOffset;
  ULONG DataLength;
  ULONG NameLength;
  WCHAR Buffer[REG_KEY_BUFFER_MAX];
} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;

typedef NTSTATUS (NTAPI *TD(NtOpenKey))
  (
   PHANDLE KeyHandle,
   ACCESS_MASK DesiredAccess,
   POBJECT_ATTRIBUTES ObjectAttributes
  );

typedef NTSTATUS (NTAPI *TD(NtQueryValueKey))
  (
   HANDLE KeyHandle,
   PUNICODE_STRING ValueName,
   KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
   PVOID KeyValueInformation,
   ULONG Length,
   PULONG ResultLength
  );

BOOL __declspec(naked) WINAPI IsWow64(void)
{
  __asm
  {
    MOV EAX, FS:[0xC0] ; wow64cpu!X86SwitchTo64BitMode
    SHR EAX, 30
    RET
  }
}

#if UNICODE
#  define tstrlen wcslen
#else
#  define tstrlen strlen
#endif


BOOL OpenKeyForQuery(PHANDLE pKey, TCHAR *keyName)
{
  NTSTATUS status;

  HANDLE hKey;
  OBJECT_ATTRIBUTES objAttribs;
  DynamicFunction(NtOpenKey, TEXT("ntdll.dll"));
  UNICODE_STRING wKeyName;

  wKeyName.Buffer = keyName;
  wKeyName.Length = (USHORT)tstrlen(keyName) * sizeof(*keyName);

  objAttribs.Length = sizeof(OBJECT_ATTRIBUTES);
  objAttribs.RootDirectory = NULL;
  objAttribs.Attributes = OBJ_CASE_INSENSITIVE;
  objAttribs.ObjectName = &wKeyName;
  objAttribs.SecurityDescriptor = NULL;
  objAttribs.SecurityQualityOfService = NULL;

  ACCESS_MASK access = KEY_QUERY_VALUE;
  if (IsWow64()) access |= KEY_WOW64_64KEY;

  status = NtOpenKey(&hKey, access, &objAttribs);
  if (NT_SUCCESS(status))
  {
    *pKey = hKey;
    return TRUE;
  }
  printf("NtOpenKey() -> NTSTATUS: 0x%X\n", status); /* DEBUG */
  return FALSE;
}

BOOL QueryValueKey(HANDLE hKey, TCHAR *valueName, PVOID pResultBuffer, PULONG pResultBufferLen)
{
  NTSTATUS status;

  DynamicFunction(NtQueryValueKey, TEXT("ntdll.dll"));
  UNICODE_STRING wValueName;

  wValueName.Buffer = valueName;
  wValueName.Length = (USHORT)tstrlen(valueName) * sizeof(*valueName);

  status = NtQueryValueKey(hKey, &wValueName, KeyValueFullInformation, pResultBuffer, *pResultBufferLen, pResultBufferLen);
  if (NT_SUCCESS(status))
  {
    return TRUE;
  }
  printf("NtQueryValueKey() -> NTSTATUS: 0x%X\n", status); /* DEBUG */
  return FALSE;
}

#define KEY_OFFSET 52
#define KEY_SECTION_LEN 5
#define DIGITAL_PID_ENCRYPTED_LEN 24
#define DIGITAL_PID_DECRYPTED_LEN 14

BOOL DecodeDigitalPID(BYTE *binData, ULONG binDataLen, PBYTE *pResultKey)
{
  int i, j, n;
  const char *Base24 = "BCDFGHJKMPQRTVWXY2346789";
  const size_t Base24Len = strlen(Base24);
  BYTE buf[DIGITAL_PID_ENCRYPTED_LEN + 1] = { 0 };
  static BYTE key[DIGITAL_PID_ENCRYPTED_LEN + KEY_SECTION_LEN + 1] = { 0 };
  BYTE *digitalPID = binData + KEY_OFFSET;
  BOOL containsN = (digitalPID[DIGITAL_PID_DECRYPTED_LEN] >> 3) & 1;

  printf("\nDIGITAL PID:\n");
  for (i = 0; i <= DIGITAL_PID_DECRYPTED_LEN; ++i)
  {
    printf("0x%.2X ", digitalPID[i]);
  }
  puts("\n\n");

  digitalPID[DIGITAL_PID_DECRYPTED_LEN] &= 0xF7;
  for (i = DIGITAL_PID_ENCRYPTED_LEN; i >= 0; --i)
  {
    n = 0;
    for (j = DIGITAL_PID_DECRYPTED_LEN; j >= 0; --j)
    {
      n = (UINT16)(n << 8 ^ digitalPID[j]);
      digitalPID[j] = (BYTE)(n / Base24Len);
      n = (UINT16)(n % Base24Len);
    }
    buf[i] = Base24[n];
  }

  if (containsN)
  {
    n = 0;
    for (i = 0; i < DIGITAL_PID_ENCRYPTED_LEN; ++i)
    {
      if (*buf != Base24[i]) continue;
      n = i;
      break;
    }

    memcpy(key, buf + 1, n);
    memcpy(key + n, buf + n, DIGITAL_PID_ENCRYPTED_LEN - n + 1);
    key[n] = 'N';
  }
  else
  {
    memcpy(key, buf, DIGITAL_PID_ENCRYPTED_LEN);
  }

  if (pResultKey)
  {
    *pResultKey = key;
  }

  return TRUE;
}

int main(void)
{
  ULONG i;
  BOOL ret = FALSE;
  HANDLE hKey = NULL;

  KEY_VALUE_FULL_INFORMATION keyValueInfo;
  ULONG keyValueInfolen = sizeof(keyValueInfo);
  BYTE *binData = NULL;
  BYTE *pKey = NULL;

  ret = OpenKeyForQuery(&hKey, TEXT("\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\"));
  if (ret)
  {
    ret = QueryValueKey(hKey, TEXT("DigitalProductId"), (PVOID)&keyValueInfo, &keyValueInfolen);
    if (ret)
    {
      puts("DATA:");
      binData = (BYTE *)&keyValueInfo + keyValueInfo.DataOffset;
      for (i = 0; i < keyValueInfo.DataLength; ++i)
      {
        printf("0x%.2X ", binData[i]);
      }
      putchar('\n');

      ret = DecodeDigitalPID(binData, keyValueInfo.DataLength, &pKey);
      if (ret)
      {
        fputs("PRODUCT KEY: ", stdout);
        for (i = 0; i <= DIGITAL_PID_ENCRYPTED_LEN; ++i)
        {
          putchar(pKey[i]);
          if (i < DIGITAL_PID_ENCRYPTED_LEN && (i + 1) % 5 == 0) putchar('-');
        }
        putchar('\n');
      }
    }
    else
    {
      fprintf(stdout, "[!] Failed to query registry key value\n");
    }
  }
  else
  {
    fprintf(stdout, "[!] Failed to open registry key\n");
  }

  if (hKey) { CloseHandle(hKey); }
  return ret;
}
[/plain]

My initial problem was that this key doesn't exist under Wow64 if you're viewing the 32-bit version of the registry:
rOiiuSq.png


NTSTATUS 0xC0000034 = object name not found

So I needed to check for this condition and specify an additional access flag mask to specify that I want to read from the 64-bit registry.

Code:
[plain]ACCESS_MASK access = KEY_QUERY_VALUE;
if (IsWow64()) access |= KEY_WOW64_64KEY;[/plain]

Code can be cleaned up into a few more functions and perhaps better logging functionality for errors. This is to serve as a base.

lacCshy.png


:thumbsup2:
 
Last edited:
Very strange. It appears that the powershell script I was going off was no good as well. For this PC I'm on right now with the latest version of Windows 10 Enterprise installed I get a result: BBBBB-BBBBB-BBBBB-BBBBB-BBBBB

Which is the same result that the powershell script returns too. Something must have changed here. It is a multiple-activation license which is the only difference.
 
Last edited:

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top