// Includes and Namespaces #include "KMSPID.h" #pragma region Structs // HostType and OSBuild static const struct KMSHostOS { WORD Type; WORD Build; } HostOS[] = { { 55041, 7601 }, // Windows Server 2008 R2 SP1 { 5426, 9200 }, // Windows Server 2012 { 6401, 9600 }, // Windows Server 2012 R2 }; // GroupID and PIDRange static const struct PKEYCONFIG { WORD GroupID; DWORD RangeMin; DWORD RangeMax; } pkeyconfig[] = { { 206, 152000000, 152999999 }, // Windows Server 2012 KMS Host pkeyconfig, actual max is 191999999 { 206, 271000000, 271999999 }, // Windows Server 2012 R2 KMS Host pkeyconfig, actual max is 310999999 { 96, 199000000, 201999999 }, // Office2010 KMS Host pkeyconfig, actual max is 217999999 { 206, 234000000, 234999999 }, // Office2013 KMS Host pkeyconfig, actual max is 255999999 }; #pragma endregion #pragma region Defines // Defines static const GUID APP_ID_WINDOWS = {0x55C92734, 0xD682, 0x4D71, {0x98, 0x3E, 0xD6, 0xEC, 0x3F, 0x16, 0x05, 0x9F}}; static const GUID APP_ID_OFFICE14 = {0x59A52881, 0xA989, 0x479D, {0xAF, 0x46, 0xF2, 0x75, 0xC6, 0x37, 0x06, 0x63}}; static const GUID APP_ID_OFFICE15 = {0x0FF1CE15, 0xA989, 0x479D, {0xAF, 0x46, 0xF2, 0x75, 0xC6, 0x37, 0x06, 0x63}}; #define HOST_SERVER2008R2 0 #define HOST_SERVER2012 1 #define HOST_SERVER2012R2 2 #define PKEYCONFIG_SERVER2012_CSVLK 0 #define PKEYCONFIG_SERVER2012R2_CSVLK 1 #define PKEYCONFIG_OFFICE2010_CSVLK 2 #define PKEYCONFIG_OFFICE2013_CSVLK 3 // Minimum possible activation date for each Microsoft products (in UTC seconds) #define MinDateServer2008R2 ((time_t)1297875600LL) // Available on February 16, 2011 through TechNet or MSDN #define MinDateServer2012 ((time_t)1346778000LL) // Available on September 4, 2012 through TechNet or MSDN #define MinDateOffice2013 ((time_t)1351098000LL) // Available on October 24, 2012 through TechNet or MSDN #define MinDateServer2012R2 ((time_t)1382029200LL) // Available on October 17, 2013 through TechNet or MSDN // Macros #define countof( array ) ( sizeof( array )/sizeof( array[0] ) ) #pragma endregion using namespace std; // Get GroupID and PIDRange for the specified AppID and KMS Protocol Version static const PKEYCONFIG *GetKMSHostPkeyConfig(REQUEST* const Request) { if (Request->ApplicationId == APP_ID_WINDOWS) return (Request->MajorVer == 6 ? &pkeyconfig[PKEYCONFIG_SERVER2012R2_CSVLK] : &pkeyconfig[PKEYCONFIG_SERVER2012_CSVLK]); if (Request->ApplicationId == APP_ID_OFFICE15) return &pkeyconfig[PKEYCONFIG_OFFICE2013_CSVLK]; if (Request->ApplicationId == APP_ID_OFFICE14) return &pkeyconfig[PKEYCONFIG_OFFICE2010_CSVLK]; return &pkeyconfig[PKEYCONFIG_SERVER2012_CSVLK]; } // Calculate Minimum Possible Date of KMS Host static const time_t GetMinKMSHostBuildDate(int HostIndex, REQUEST* const Request) { // Request is KMS V6 or Server 2012 R2 Build # is used if (Request->MajorVer == 6 || HostIndex == HOST_SERVER2012R2) return MinDateServer2012R2; // Request is Office 2013 (Both V4 and V5) if (Request->ApplicationId == APP_ID_OFFICE15) return MinDateOffice2013; // Request is KMS V5 or Server 2012 Build # is used if (Request->MajorVer == 5 || HostIndex == HOST_SERVER2012) return MinDateServer2012; // Otherwise, Request is KMS V4 (Office 2010/Vista/7) and Server 2008 R2 Build # is used return MinDateServer2008R2; } // Random Number Generator BOOL GetRandomBytes(BYTE *RandomBuffer, DWORD RandomBufferLength) { BOOL success = FALSE; HCRYPTPROV hProv = NULL; success = CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT) && CryptGenRandom(hProv, RandomBufferLength, RandomBuffer); if (hProv) CryptReleaseContext(hProv, 0); return success; } void CreateKMSPID(WCHAR* const KMSPID, REQUEST* const Request) { // Random Number Buffer DWORD RandomNumber[4]; GetRandomBytes((BYTE *)RandomNumber, sizeof(RandomNumber)); // Choose KMS HostOS int HostIndex = RandomNumber[0] % countof(HostOS); const KMSHostOS *host = &HostOS[HostIndex]; // Set Product Specific Base pkeyconfig (use Windows if unknown product) const PKEYCONFIG *config = GetKMSHostPkeyConfig(Request); // Generate Random ID int RandomID = config->RangeMin + RandomNumber[1] % (config->RangeMax - config->RangeMin); // Generate Part 5: License Channel (00=Retail, 01=Retail, 02=OEM, 03=Volume(GVLK,MAK)) - always 03 DWORD LicenseChannel = 3; // Generate Part 6: Language - use system default language DWORD LanguageCode = GetSystemDefaultLCID(); // Get Product Specific Minimum Activation Date time_t MinDate = GetMinKMSHostBuildDate(HostIndex, Request); // Get Maximum Possible Value of Activation Date time_t MaxDate = time(NULL) - 86400; // limit latest activation date to yesterday // Generate Random Date between MinDate and MaxDate time_t RandomDate = ((ULONG64 *)RandomNumber)[1] & 0x7FFFFFFFFFFFFFFFULL; time_t GeneratedDate = MinDate + RandomDate % (MaxDate - MinDate); struct tm Date; localtime_s(&Date, &GeneratedDate); StringCchPrintfW(KMSPID, PID_BUFFER_SIZE, L"%05u-%05u-%03u-%06u-%02u-%u-%04u.0000-%03d%04d", host->Type, config->GroupID, RandomID / 1000000, RandomID % 1000000, LicenseChannel, LanguageCode, host->Build, Date.tm_yday+1, Date.tm_year+1900); } // Get Application Specific KMS PID from the Registry (KMS Server Service Only) void GetKMSPID(WCHAR* const KMSPID, REQUEST* const Request) { // Open Registry Key HKEY hKey; DWORD bufferSize = 256; WCHAR buffer[256] = {0}; // Get ClientAppID as String WCHAR ClientAppID[GUID_BUFFER_SIZE]; StringCchPrintfW(ClientAppID, GUID_BUFFER_SIZE, L"%08X-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X", Request->ApplicationId.Data1, Request->ApplicationId.Data2, Request->ApplicationId.Data3, Request->ApplicationId.Data4[0], Request->ApplicationId.Data4[1], Request->ApplicationId.Data4[2], Request->ApplicationId.Data4[3], Request->ApplicationId.Data4[4], Request->ApplicationId.Data4[5], Request->ApplicationId.Data4[6], Request->ApplicationId.Data4[7]); if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\KMSServerService\\Parameters\\KMSPID"), NULL, KEY_READ, &hKey) == ERROR_SUCCESS) { // Get Registry Value if (RegQueryValueExW(hKey, ClientAppID, NULL, NULL, (LPBYTE)buffer, &bufferSize) == ERROR_SUCCESS) { if (regex_match(buffer, wregex(L"^([0-9]{5})-([0-9]{5})-([0-9]{3})-([0-9]{6})-([0-9]{2})-([0-9]{4,5})-([0-9]{4}).([0-9]{4})-([0-9]{7})$"))) { // Close Registry Key RegCloseKey(hKey); // Apply Setting StringCchCopyW(KMSPID, PID_BUFFER_SIZE, buffer); } } // Close Registry Key RegCloseKey(hKey); } else { // Return Empty KMSPID StringCchCopyW(KMSPID, PID_BUFFER_SIZE, L""); } }