| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149 |
- #ifndef CONFIG
- #define CONFIG "config.h"
- #endif // CONFIG
- #include CONFIG
- #ifndef _GNU_SOURCE
- #define _GNU_SOURCE
- #endif
- #ifndef _CRT_SECURE_NO_WARNINGS
- #define _CRT_SECURE_NO_WARNINGS
- #endif
- #include <stdio.h>
- #include <string.h>
- #include <stdint.h>
- #include <ctype.h>
- #include <time.h>
- #if !defined(_WIN32)
- #if !__ANDROID__
- #include <sys/shm.h>
- #endif // !__ANDROID__
- #include <sys/socket.h>
- #include <sys/ipc.h>
- #endif // !defined(_WIN32)
- #include "output.h"
- #include "crypto.h"
- #include "endian.h"
- #include "kms.h"
- #include "shared_globals.h"
- #include "helpers.h"
- #define FRIENDLY_NAME_WINDOWS "Windows"
- #define FRIENDLY_NAME_OFFICE2010 "Office 2010"
- #define FRIENDLY_NAME_OFFICE2013 "Office 2013+"
- #ifndef IS_LIBRARY
- #ifdef NO_LOG
- #define LOGTEXT(x) ""
- #else //!NO_LOG
- #define LOGTEXT(x) x
- #endif // !NO_LOG
- int32_t getProductIndex(const GUID* guid, const PVlmcsdData_t list, const int32_t count, char** name, char** ePid)
- {
- int i;
- for (i = count - 1; i >= 0; i--)
- {
- if (IsEqualGUID(guid, &list[i].Guid))
- {
- if (name) *name = list[i].Name;
- if (ePid) *ePid = KmsData->CsvlkData[list[i].EPidIndex].EPid;
- return i;
- }
- }
- if (name) *name = "Unknown";
- if (ePid) *ePid = KmsData->CsvlkData[EPID_INDEX_WINDOWS].EPid;
- return i;
- }
- #endif // IS_LIBRARY
- #ifndef NO_RANDOM_EPID
- static const uint16_t HostBuilds[] = { 6002, 7601, 9200, 9600, 14393, 17763 };
- // Valid language identifiers to be used in the ePID
- static const uint16_t LcidList[] = {
- 1078, 1052, 1025, 2049, 3073, 4097, 5121, 6145, 7169, 8193, 9217, 10241, 11265, 12289, 13313, 14337, 15361, 16385,
- 1067, 1068, 2092, 1069, 1059, 1093, 5146, 1026, 1027, 1028, 2052, 3076, 4100, 5124, 1050, 4122, 1029, 1030, 1125, 1043, 2067,
- 1033, 2057, 3081, 4105, 5129, 6153, 7177, 8201, 9225, 10249, 11273, 12297, 13321, 1061, 1080, 1065, 1035, 1036, 2060,
- 3084, 4108, 5132, 6156, 1079, 1110, 1031, 2055, 3079, 4103, 5127, 1032, 1095, 1037, 1081, 1038, 1039, 1057, 1040, 2064, 1041, 1099,
- 1087, 1111, 1042, 1088, 1062, 1063, 1071, 1086, 2110, 1100, 1082, 1153, 1102, 1104, 1044, 2068, 1045, 1046, 2070,
- 1094, 1131, 2155, 3179, 1048, 1049, 9275, 4155, 5179, 3131, 1083, 2107, 8251, 6203, 7227, 1103, 2074, 6170, 3098,
- 7194, 1051, 1060, 1034, 2058, 3082, 4106, 5130, 6154, 7178, 8202, 9226, 10250, 11274, 12298, 13322, 14346, 15370, 16394,
- 17418, 18442, 19466, 20490, 1089, 1053, 2077, 1114, 1097, 1092, 1098, 1054, 1074, 1058, 1056, 1091, 2115, 1066, 1106, 1076, 1077
- };
- uint16_t getPlatformId(uint16_t hostBuild)
- {
- if (hostBuild < 9000) return 55041;
- if (hostBuild <= 9500) return 5426;
- if (hostBuild <= 10000) return 6401;
- return 3612;
- }
- #ifdef _PEDANTIC
- uint16_t IsValidLcid(const uint16_t lcid)
- {
- uint16_t i;
- for (i = 0; i < vlmcsd_countof(LcidList); i++)
- {
- if (lcid == LcidList[i]) return lcid;
- }
- return 0;
- }
- uint16_t IsValidHostBuild(const uint16_t hostBuild)
- {
- const uint16_t *hostOS;
- for (hostOS = HostBuilds; hostOS < HostBuilds + vlmcsd_countof(HostBuilds); hostOS++)
- {
- if (hostBuild == *hostOS) return hostBuild;
- }
- return 0;
- }
- #endif // _PEDANTIC
- #endif // NO_RANDOM_EPID
- // Unix time is seconds from 1970-01-01. Should be 64 bits to avoid year 2038 overflow bug.
- // FILETIME is 100 nanoseconds from 1601-01-01. Must be 64 bits.
- void getUnixTimeAsFileTime(FILETIME *const ts)
- {
- const int64_t unixtime = (int64_t)time(NULL);
- int64_t *filetime = (int64_t*)ts;
- PUT_UA64LE(filetime, (unixtime + 11644473600LL) * 10000000LL);
- }
- __pure int64_t fileTimeToUnixTime(const FILETIME *const ts)
- {
- return GET_UA64LE(ts) / 10000000LL - 11644473600LL;
- }
- #ifndef NO_STRICT_MODES
- #ifndef NO_CLIENT_LIST
- static PClientList_t ClientLists;
- static BYTE ZeroGuid[16] = { 0 };
- #if !defined(_WIN32) && !defined(__CYGWIN__)
- pthread_mutex_t* mutex;
- #define mutex_size (((sizeof(pthread_mutex_t)+7)>>3)<<3)
- #else
- CRITICAL_SECTION* mutex;
- #define mutex_size (((sizeof(CRITICAL_SECTION)+7)>>3)<<3)
- #endif // _WIN32
- #ifndef USE_THREADS
- static int shmid_clients = -1;
- #endif // USE_THREADS
- #if !defined(_WIN32) && !defined(__CYGWIN__)
- #define lock_client_lists() pthread_mutex_lock(mutex)
- #define unlock_client_lists() pthread_mutex_unlock(mutex)
- #define mutex_t pthread_mutex_t
- #else
- #define lock_client_lists() EnterCriticalSection(mutex)
- #define unlock_client_lists() LeaveCriticalSection(mutex)
- #define mutex_t CRITICAL_SECTION
- #endif
- void CleanUpClientLists()
- {
- # ifndef USE_THREADS
- shmctl(shmid_clients, IPC_RMID, NULL);
- # endif // !USE_THREADS
- }
- void InitializeClientLists()
- {
- int_fast8_t i;
- int_fast16_t j;
- # ifndef USE_THREADS
- if (
- (shmid_clients = shmget(IPC_PRIVATE, sizeof(ClientList_t) * KmsData->AppItemCount + mutex_size, IPC_CREAT | 0600)) < 0 ||
- (mutex = (mutex_t*)shmat(shmid_clients, NULL, 0)) == (mutex_t*)-1
- )
- {
- int errno_save = errno;
- printerrorf("Warning: CMID lists disabled. Could not create shared memory: %s\n", vlmcsd_strerror(errno_save));
- if (shmid_clients >= 0) shmctl(shmid_clients, IPC_RMID, NULL);
- MaintainClients = FALSE;
- return;
- }
- ClientLists = (PClientList_t)((BYTE*)mutex + mutex_size);
- # if __CYGWIN__
- InitializeCriticalSection(mutex);
- # else // !__CYGWIN__
- pthread_mutexattr_t mutex_attr;
- pthread_mutexattr_init(&mutex_attr);
- pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
- pthread_mutex_init(mutex, &mutex_attr);
- # endif // !__CYGWIN__
- # else // USE_THREADS
- ClientLists = (PClientList_t)vlmcsd_malloc(sizeof(ClientList_t) * KmsData->AppItemCount);
- mutex = (mutex_t*)vlmcsd_malloc(sizeof(mutex_t));
- # if !_WIN32 && !__CYGWIN__
- pthread_mutex_init(mutex, NULL);
- # else //_WIN32 || __CYGWIN__
- InitializeCriticalSection(mutex);
- # endif //_WIN32 || __CYGWIN__
- # endif // USE_THREADS
- memset(ClientLists, 0, sizeof(ClientList_t) * KmsData->AppItemCount);
- if (!StartEmpty)
- {
- for (i = 0; i < KmsData->AppItemCount; i++)
- {
- const uint8_t maxCount = KmsData->AppItemList[i].NCountPolicy;
- ClientLists[i].CurrentCount = (maxCount >> 1) - 1;
- ClientLists[i].MaxCount = maxCount;
- for (j = 0; j < (maxCount >> 1) - 1; j++)
- {
- get16RandomBytes(&ClientLists[i].Guid[j]);
- }
- }
- }
- }
- #endif // NO_CLIENT_LIST
- #endif // !NO_STRICT_MODES
- #ifndef NO_RANDOM_EPID
- // formats an int with a fixed number of digits with leading zeros (helper for ePID generation)
- static char* itoc(char *const c, const int i, uint_fast8_t digits)
- {
- char formatString[8];
- if (digits > 9) digits = 0;
- strcpy(formatString, "%");
- if (digits)
- {
- formatString[1] = '0';
- formatString[2] = digits | 0x30;
- formatString[3] = 0;
- }
- strcat(formatString, "u");
- sprintf(c, formatString, i);
- return c;
- }
- static uint8_t getRandomServerType()
- {
- # if defined(USE_MSRPC) || defined(SIMPLE_RPC)
- return rand() % vlmcsd_countof(HostBuilds);
- # else // !defined(USE_MSRPC) && !defined(SIMPLE_RPC)
- if (!UseServerRpcBTFN)
- {
- // This isn't possible at all, e.g. KMS host on XP
- return rand() % (int)vlmcsd_countof(HostBuilds);
- }
- // return 9200/9600/14393/17763 if NDR64 is in use, otherwise 6002/7601
- if (UseServerRpcNDR64) return rand() % ((int)vlmcsd_countof(HostBuilds) - 2) + 2;
- return rand() % 2;
- # endif // !defined(USE_MSRPC) && !defined(SIMPLE_RPC)
- }
- /*
- * Generates a random ePID
- */
- static void generateRandomPid(const int index, char *const szPid, int16_t lang, uint16_t hostBuild)
- {
- char numberBuffer[12];
- if (!hostBuild)
- {
- hostBuild = HostBuilds[getRandomServerType()];
- }
- strcpy(szPid, itoc(numberBuffer, getPlatformId(hostBuild), 5));
- strcat(szPid, "-");
- //if (index > 3) index = 0;
- const PCsvlkData_t csvlkData = &KmsData->CsvlkData[index];
- strcat(szPid, itoc(numberBuffer, csvlkData->GroupId, 5));
- strcat(szPid, "-");
- const int keyId = (rand32() % (csvlkData->MaxKeyId - csvlkData->MinKeyId)) + csvlkData->MinKeyId;
- strcat(szPid, itoc(numberBuffer, keyId / 1000000, 3));
- strcat(szPid, "-");
- strcat(szPid, itoc(numberBuffer, keyId % 1000000, 6));
- strcat(szPid, "-03-");
- if (lang < 1) lang = LcidList[rand() % vlmcsd_countof(LcidList)];
- strcat(szPid, itoc(numberBuffer, lang, 0));
- strcat(szPid, "-");
- strcat(szPid, itoc(numberBuffer, hostBuild, 0));
- strcat(szPid, ".0000-");
- # define minTime ((time_t)1538490811) /* Release Date Win 2019 */
- time_t maxTime;
- time(&maxTime);
- # ifndef BUILD_TIME
- # define BUILD_TIME 1538922811
- # endif
- if (maxTime < (time_t)BUILD_TIME) // Just in case the system time is < 10/17/2013 1:00 pm
- maxTime = (time_t)BUILD_TIME;
- time_t kmsTime = (rand32() % (maxTime - minTime)) + minTime;
- struct tm *pidTime = gmtime(&kmsTime);
- strcat(szPid, itoc(numberBuffer, pidTime->tm_yday + 1, 3));
- strcat(szPid, itoc(numberBuffer, pidTime->tm_year + 1900, 4));
- }
- /*
- * Generates random ePIDs and stores them if not already read from ini file.
- * For use with randomization level 1
- */
- void randomPidInit()
- {
- uint32_t i;
- const int16_t lang = Lcid ? Lcid : LcidList[rand() % vlmcsd_countof(LcidList)];
- for (i = 0; i < KmsData->CsvlkCount; i++)
- {
- if (KmsResponseParameters[i].Epid) continue;
- char Epid[PID_BUFFER_SIZE];
- generateRandomPid(i, Epid, lang, HostBuild);
- KmsResponseParameters[i].Epid = (const char*)vlmcsd_strdup(Epid);
- #ifndef NO_LOG
- KmsResponseParameters[i].EpidSource = "randomized at program start";
- #endif // NO_LOG
- }
- }
- #endif // NO_RANDOM_EPID
- #ifndef NO_LOG
- static int32_t getProductIndexFromAllLists(const GUID* guid, char** productName)
- {
- return getProductIndex(guid, KmsData->AppItemList, KmsData->AppItemCount + KmsData->KmsItemCount + KmsData->SkuItemCount, productName, NULL);
- }
- /*
- * Logs a Request
- */
- static void logRequest(const REQUEST *const baseRequest)
- {
- #ifndef NO_VERBOSE_LOG
- if (logverbose)
- {
- logger("<<< Incoming KMS request\n");
- logRequestVerbose(baseRequest, &logger);
- return;
- }
- #endif // NO_VERBOSE_LOG
- char *productName;
- char clientname[64];
- int32_t index = getProductIndexFromAllLists(&baseRequest->ActID, &productName);
- if (index < 0) index = getProductIndexFromAllLists(&baseRequest->KMSID, &productName);
- if (index < 0) index = getProductIndexFromAllLists(&baseRequest->AppID, &productName);
- if (index < 0 || !strcasecmp(productName, "Unknown"))
- {
- productName = (char*)alloca(GUID_STRING_LENGTH + 1);
- uuid2StringLE(&baseRequest->ActID, productName);
- }
- ucs2_to_utf8(baseRequest->WorkstationName, clientname, 64, 64);
- logger("KMS v%i.%i request from %s for %s\n", LE16(baseRequest->MajorVer), LE16(baseRequest->MinorVer), clientname, productName);
- }
- #endif // NO_LOG
- /*
- * Converts a utf-8 ePID string to UCS-2 and writes it to a RESPONSE struct
- */
- #ifndef IS_LIBRARY
- static void getEpidFromString(RESPONSE *const Response, const char *const pid)
- {
- const size_t length = utf8_to_ucs2(Response->KmsPID, pid, PID_BUFFER_SIZE, PID_BUFFER_SIZE * 3);
- Response->PIDSize = LE32(((unsigned int)length + 1) << 1);
- }
- /*
- * get ePID from appropriate source
- */
- static void getEpid(RESPONSE *const baseResponse, const char** EpidSource, const int32_t index, BYTE *const HwId, const char* defaultEPid)
- {
- #if !defined(NO_RANDOM_EPID) || !defined(NO_CL_PIDS) || !defined(NO_INI_FILE)
- const char* pid;
- if (KmsResponseParameters[index].Epid == NULL)
- {
- #ifndef NO_RANDOM_EPID
- if (RandomizationLevel == 2)
- {
- char ePid[PID_BUFFER_SIZE];
- generateRandomPid(index, ePid, Lcid, HostBuild);
- pid = ePid;
- #ifndef NO_LOG
- *EpidSource = "randomized on every request";
- #endif // NO_LOG
- }
- else
- #endif // NO_RANDOM_EPID
- {
- pid = defaultEPid;
- #ifndef NO_LOG
- *EpidSource = "vlmcsd default";
- #endif // NO_LOG
- }
- }
- else
- {
- pid = KmsResponseParameters[index].Epid;
- if (HwId && KmsResponseParameters[index].HwId != NULL)
- memcpy(HwId, KmsResponseParameters[index].HwId, sizeof(((RESPONSE_V6 *)0)->HwId));
- #ifndef NO_LOG
- *EpidSource = KmsResponseParameters[index].EpidSource;
- #endif // NO_LOG
- }
- getEpidFromString(baseResponse, pid);
- #else // defined(NO_RANDOM_EPID) && defined(NO_CL_PIDS) && !defined(NO_INI_FILE)
- getEpidFromString(baseResponse, defaultEPid);
- # ifndef NO_LOG
- *EpidSource = "vlmcsd default";
- # endif // NO_LOG
- #endif // defined(NO_RANDOM_EPID) && defined(NO_CL_PIDS) && !defined(NO_INI_FILE)
- }
- #endif // IS_LIBRARY
- #if !defined(NO_LOG) && defined(_PEDANTIC)
- static BOOL CheckVersion4Uuid(const GUID *const guid, const char *const szGuidName)
- {
- if (LE16(guid->Data3) >> 12 != 4 || guid->Data4[0] >> 6 != 2)
- {
- logger("Warning: %s does not conform to version 4 UUID according to RFC 4122\n", szGuidName);
- return FALSE;
- }
- return TRUE;
- }
- static void CheckRequest(const REQUEST *const Request)
- {
- CheckVersion4Uuid(&Request->CMID, "Client machine ID");
- CheckVersion4Uuid(&Request->AppID, "Application ID");
- CheckVersion4Uuid(&Request->KMSID, "Server SKU ID");
- CheckVersion4Uuid(&Request->ActID, "Client SKU ID");
- if (LE32(Request->IsClientVM) > 1)
- logger("Warning: Virtual Machine field in request must be 0 or 1 but is %u\n", LE32(Request->IsClientVM));
- if (LE32(Request->LicenseStatus) > 6)
- logger("Warning: License status must be between 0 and 6 but is %u\n", LE32(Request->LicenseStatus));
- }
- #endif // !defined(NO_LOG) && defined(_PEDANTIC)
- #ifndef NO_LOG
- /*
- * Logs the Response
- */
- static void logResponse(const RESPONSE *const baseResponse, const BYTE *const hwId, const char *const EpidSource)
- {
- char utf8pid[PID_BUFFER_SIZE * 3];
- ucs2_to_utf8(baseResponse->KmsPID, utf8pid, PID_BUFFER_SIZE, PID_BUFFER_SIZE * 3);
- #ifndef NO_VERBOSE_LOG
- if (!logverbose)
- {
- #endif // NO_VERBOSE_LOG
- logger("Sending ePID (%s): %s\n", EpidSource, utf8pid);
- #ifndef NO_VERBOSE_LOG
- }
- else
- {
- logger(">>> Sending response, ePID source = %s\n", EpidSource);
- logResponseVerbose(utf8pid, hwId, baseResponse, &logger);
- }
- #endif // NO_VERBOSE_LOG
- }
- #endif
- #if __UCLIBC__ && !defined(NO_STRICT_MODES)
- long long int llabs(long long int j);
- #endif
- /*
- * Creates the unencrypted base response
- */
- #ifndef IS_LIBRARY
- static HRESULT __stdcall CreateResponseBaseCallback(const REQUEST *const baseRequest, RESPONSE *const baseResponse, BYTE *const hwId, const char* const ipstr_unused)
- {
- const char* EpidSource;
- #ifndef NO_LOG
- logRequest(baseRequest);
- #ifdef _PEDANTIC
- CheckRequest(baseRequest);
- #endif // _PEDANTIC
- #endif // NO_LOG
- char* ePid;
- const DWORD minClients = LE32(baseRequest->N_Policy);
- const DWORD required_clients = minClients < 1 ? 1 : minClients << 1;
- int32_t index = getProductIndex(&baseRequest->KMSID, KmsData->KmsItemList, KmsData->KmsItemCount, NULL, &ePid);
- # ifndef NO_STRICT_MODES
- if (required_clients > 2000)
- {
- # ifndef NO_LOG
- logger("Rejecting request with more than 1000 minimum clients (0x8007000D)\n");
- # endif
- return 0x8007000D;
- }
- if (CheckClientTime)
- {
- const time_t requestTime = (time_t)fileTimeToUnixTime(&baseRequest->ClientTime);
- if (llabs(requestTime - time(NULL)) > 60 * 60 * 4)
- {
- # ifndef NO_LOG
- logger("Client time differs more than 4 hours from system time (0xC004F06C)\n");
- # endif // !NO_LOG
- return 0xC004F06C;
- }
- }
- if (WhitelistingLevel & 2)
- {
- if (index >= 0 && (KmsData->KmsItemList[index].IsPreview || KmsData->KmsItemList[index].IsRetail))
- {
- # ifndef NO_LOG
- logger("Refusing retail or beta product (0xC004F042)\n");
- # endif // !NO_LOG
- return 0xC004F042;
- }
- }
- if ((WhitelistingLevel & 1) && index < 0)
- {
- # ifndef NO_LOG
- logger("Refusing unknown product (0xC004F042)\n");
- # endif // !NO_LOG
- return 0xC004F042;
- }
- # ifndef NO_CLIENT_LIST
- const int32_t appIndex = index < 0 ? 0 : KmsData->KmsItemList[index].AppIndex;
- # endif // NO_CLIENT_LIST
- # endif // !NO_STRICT_MODES
- const int32_t ePidIndex = index < 0 ? 0 : KmsData->KmsItemList[index].EPidIndex;
- # if !defined(NO_STRICT_MODES)
- if ((WhitelistingLevel & 1) && index >= 0 && !IsEqualGUID(&KmsData->AppItemList[KmsData->KmsItemList[index].AppIndex].Guid, &baseRequest->AppID))
- {
- # ifndef NO_LOG
- logger("Refusing product with incorrect Application ID (0xC004F042)\n");
- # endif // NO_LOG
- return 0xC004F042;
- }
- # ifndef NO_CLIENT_LIST
- if (MaintainClients)
- {
- lock_client_lists();
- int_fast16_t i;
- int_fast8_t isKnownClient = FALSE;
- if (required_clients > (DWORD)ClientLists[appIndex].MaxCount) ClientLists[appIndex].MaxCount = required_clients;
- for (i = 0; i < ClientLists[appIndex].MaxCount; i++)
- {
- if (IsEqualGUID(&ClientLists[appIndex].Guid[i], &baseRequest->CMID))
- {
- isKnownClient = TRUE;
- break;
- }
- }
- if (isKnownClient)
- {
- baseResponse->Count = LE32(ClientLists[appIndex].CurrentCount);
- }
- else
- {
- for (i = 0; i < ClientLists[appIndex].MaxCount; i++)
- {
- if (IsEqualGUID(ZeroGuid, &ClientLists[appIndex].Guid[i]))
- {
- if (ClientLists[appIndex].CurrentCount >= MAX_CLIENTS)
- {
- # ifndef NO_LOG
- logger("Rejecting more than 671 clients (0xC004D104)\n");
- # endif // !NO_LOG
- unlock_client_lists();
- return 0xC004D104;
- }
- baseResponse->Count = LE32(++ClientLists[appIndex].CurrentCount);
- memcpy(&ClientLists[appIndex].Guid[i], &baseRequest->CMID, sizeof(GUID));
- break;
- }
- }
- if (i >= ClientLists[appIndex].MaxCount)
- {
- memcpy(&ClientLists[appIndex].Guid[ClientLists[appIndex].CurrentPosition], &baseRequest->CMID, sizeof(GUID));
- ClientLists[appIndex].CurrentPosition = (ClientLists[appIndex].CurrentPosition + 1) % (ClientLists[appIndex].MaxCount > MAX_CLIENTS ? MAX_CLIENTS : ClientLists[appIndex].MaxCount);
- baseResponse->Count = LE32(ClientLists[appIndex].CurrentCount);
- }
- }
- unlock_client_lists();
- }
- else
- # endif // !NO_CLIENT_LIST
- # endif // !defined(NO_STRICT_MODES)
- {
- const uint8_t minimum_answer_clients = (uint8_t)KmsData->CsvlkData[ePidIndex].MinActiveClients;
- baseResponse->Count = LE32(required_clients > minimum_answer_clients ? required_clients : minimum_answer_clients);
- //if (LE32(baseRequest->N_Policy) > LE32(baseResponse->Count)) baseResponse->Count = LE32(LE32(baseRequest->N_Policy) << 1);
- }
- getEpid(baseResponse, &EpidSource, ePidIndex, hwId, ePid);
- baseResponse->Version = baseRequest->Version;
- memcpy(&baseResponse->CMID, &baseRequest->CMID, sizeof(GUID));
- memcpy(&baseResponse->ClientTime, &baseRequest->ClientTime, sizeof(FILETIME));
- baseResponse->VLActivationInterval = LE32(VLActivationInterval);
- baseResponse->VLRenewalInterval = LE32(VLRenewalInterval);
- #ifndef NO_LOG
- logResponse(baseResponse, hwId, EpidSource);
- #endif // NO_LOG
- return S_OK;
- }
- RequestCallback_t CreateResponseBase = &CreateResponseBaseCallback;
- #else // IS_LIBRARY
- RequestCallback_t CreateResponseBase = NULL;
- #endif // IS_LIBRARY
- ////TODO: Move to helpers.c
- void get16RandomBytes(void* ptr)
- {
- int i;
- for (i = 0; i < 4; i++) ((DWORD*)ptr)[i] = rand32();
- }
- /*
- * Creates v4 response
- */
- size_t CreateResponseV4(REQUEST_V4 *const request_v4, BYTE *const responseBuffer, const char* const ipstr)
- {
- RESPONSE_V4* Response = (RESPONSE_V4*)responseBuffer;
- HRESULT hResult;
- if (FAILED(hResult = CreateResponseBase(&request_v4->RequestBase, &Response->ResponseBase, NULL, ipstr))) return hResult;
- const DWORD pidSize = LE32(Response->ResponseBase.PIDSize);
- BYTE* postEpidPtr = responseBuffer + V4_PRE_EPID_SIZE + pidSize;
- memmove(postEpidPtr, &Response->ResponseBase.CMID, V4_POST_EPID_SIZE);
- const size_t encryptSize = V4_PRE_EPID_SIZE + V4_POST_EPID_SIZE + pidSize;
- AesCmacV4(responseBuffer, encryptSize, responseBuffer + encryptSize);
- return encryptSize + sizeof(Response->MAC);
- }
- /*
- // Workaround for buggy GCC 4.2/4.3
- #if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 4)
- __attribute__((noinline))
- #endif
- __pure static uint64_t TimestampInterval(void *ts)
- {
- return ( GET_UA64LE(ts) / TIME_C1 ) * TIME_C2 + TIME_C3;
- }*/
- /*
- * Creates the HMAC for v6
- */
- static int_fast8_t CreateV6Hmac(BYTE *const encrypt_start, const size_t encryptSize, int_fast8_t tolerance)
- {
- BYTE hash[32];
- const uint8_t halfHashSize = sizeof(hash) >> 1;
- BYTE *responseEnd = encrypt_start + encryptSize;
- // This is the time from the response
- FILETIME* ft = (FILETIME*)(responseEnd - V6_POST_EPID_SIZE + sizeof(((RESPONSE*)0)->CMID));
- // Generate a time slot that changes every 4.11 hours.
- // Request and repsonse time must match +/- 1 slot.
- // When generating a response tolerance must be 0.
- // If verifying the hash, try tolerance -1, 0 and +1. One of them must match.
- uint64_t timeSlot = LE64((GET_UA64LE(ft) / TIME_C1 * TIME_C2 + TIME_C3) + (tolerance * TIME_C1));
- // The time slot is hashed with SHA256 so it is not so obvious that it is time
- Sha256((BYTE*)&timeSlot, sizeof(timeSlot), hash);
- // The last 16 bytes of the hashed time slot are the actual HMAC key
- if (!Sha256Hmac
- (
- hash + halfHashSize, // Use last 16 bytes of SHA256 as HMAC key
- encrypt_start, // hash only the encrypted part of the v6 response
- (DWORD)(encryptSize - sizeof(((RESPONSE_V6*)0)->HMAC)), // encryptSize minus the HMAC itself
- hash // use same buffer for resulting hash where the key came from
- ))
- {
- return FALSE;
- }
- memcpy(responseEnd - sizeof(((RESPONSE_V6*)0)->HMAC), hash + halfHashSize, halfHashSize);
- return TRUE;
- }
- /*
- * Creates v5 or v6 response
- */
- size_t CreateResponseV6(REQUEST_V6 *restrict request_v6, BYTE *const responseBuffer, const char* const ipstr)
- {
- // The response will be created in a fixed sized struct to
- // avoid unaligned access macros and packed structs on RISC systems
- // which largely increase code size.
- //
- // The fixed sized struct with 64 WCHARs for the ePID will be converted
- // to a variable sized struct later and requires unaligned access macros.
- RESPONSE_V6* Response = (RESPONSE_V6*)responseBuffer;
- RESPONSE* baseResponse = &Response->ResponseBase;
- #ifdef _DEBUG
- // ReSharper disable once CppEntityNeverUsed
- RESPONSE_V6_DEBUG* xxx_unused = (RESPONSE_V6_DEBUG*)responseBuffer;
- #endif
- static const BYTE DefaultHwid[8] = { HWID };
- const int_fast8_t v6 = LE16(request_v6->MajorVer) > 5;
- AesCtx aesCtx;
- AesInitKey(&aesCtx, v6 ? AesKeyV6 : AesKeyV5, v6, AES_KEY_BYTES);
- AesDecryptCbc(&aesCtx, NULL, request_v6->IV, V6_DECRYPT_SIZE);
- // get random salt and SHA256 it
- get16RandomBytes(Response->RandomXoredIVs);
- Sha256(Response->RandomXoredIVs, sizeof(Response->RandomXoredIVs), Response->Hash);
- if (v6) // V6 specific stuff
- {
- // In v6 a random IV is generated
- Response->Version = request_v6->Version;
- get16RandomBytes(Response->IV);
- // pre-fill with default HwId (not required for v5)
- memcpy(Response->HwId, DefaultHwid, sizeof(Response->HwId));
- // Just copy decrypted request IV (using Null IV) here. Note this is identical
- // to XORing non-decrypted request and reponse IVs
- memcpy(Response->XoredIVs, request_v6->IV, sizeof(Response->XoredIVs));
- }
- else // V5 specific stuff
- {
- // In v5 IVs of request and response must be identical (MS client checks this)
- // The following memcpy copies Version and IVs at once
- memcpy(Response, request_v6, V6_UNENCRYPTED_SIZE);
- }
- // Xor Random bytes with decrypted request IV
- XorBlock(request_v6->IV, Response->RandomXoredIVs);
- // Get the base response
- HRESULT hResult;
- if (FAILED(hResult = CreateResponseBase(&request_v6->RequestBase, baseResponse, Response->HwId, ipstr))) return hResult;
- // Convert the fixed sized struct into variable sized
- const DWORD pidSize = LE32(baseResponse->PIDSize);
- BYTE* postEpidPtr = responseBuffer + V6_PRE_EPID_SIZE + pidSize;
- const size_t post_epid_size = v6 ? V6_POST_EPID_SIZE : V5_POST_EPID_SIZE;
- memmove(postEpidPtr, &baseResponse->CMID, post_epid_size);
- // number of bytes to encrypt
- size_t encryptSize =
- V6_PRE_EPID_SIZE
- - sizeof(Response->Version)
- + pidSize
- + post_epid_size;
- //AesDecryptBlock(&aesCtx, Response->IV);
- if (v6 && !CreateV6Hmac(Response->IV, encryptSize, 0)) return 0;
- // Padding auto handled by encryption func
- AesEncryptCbc(&aesCtx, NULL, Response->IV, &encryptSize);
- return encryptSize + sizeof(Response->Version);
- }
- // Create Hashed KMS Client Request Data for KMS Protocol Version 4
- BYTE *CreateRequestV4(size_t *size, const REQUEST* requestBase)
- {
- *size = sizeof(REQUEST_V4);
- // Build a proper KMS client request data
- BYTE *request = (BYTE *)vlmcsd_malloc(sizeof(REQUEST_V4));
- // Temporary Pointer for access to REQUEST_V4 structure
- REQUEST_V4 *request_v4 = (REQUEST_V4 *)request;
- // Set KMS Client Request Base
- memcpy(&request_v4->RequestBase, requestBase, sizeof(REQUEST));
- // Generate Hash Signature
- AesCmacV4(request, sizeof(REQUEST), request_v4->MAC);
- // Return Request Data
- return request;
- }
- // Create Encrypted KMS Client Request Data for KMS Protocol Version 6
- BYTE* CreateRequestV6(size_t *size, const REQUEST* requestBase)
- {
- *size = sizeof(REQUEST_V6);
- // Temporary Pointer for access to REQUEST_V5 structure
- REQUEST_V6 *request = (REQUEST_V6 *)vlmcsd_malloc(sizeof(REQUEST_V6));
- // KMS Protocol Version
- request->Version = requestBase->Version;
- // Initialize the IV
- get16RandomBytes(request->IV);
- // Set KMS Client Request Base
- memcpy(&request->RequestBase, requestBase, sizeof(REQUEST));
- // Encrypt KMS Client Request
- size_t encryptSize = sizeof(request->RequestBase);
- AesCtx Ctx;
- int_fast8_t v6 = LE16(request->MajorVer) > 5;
- AesInitKey(&Ctx, v6 ? AesKeyV6 : AesKeyV5, v6, 16);
- AesEncryptCbc(&Ctx, request->IV, (BYTE*)(&request->RequestBase), &encryptSize);
- // Return Proper Request Data
- return (BYTE*)request;
- }
- /*
- * Checks whether Length of ePID is valid
- */
- static uint8_t checkPidLength(const RESPONSE *const responseBase)
- {
- unsigned int i;
- if (LE32(responseBase->PIDSize) > (PID_BUFFER_SIZE << 1)) return FALSE;
- if (responseBase->KmsPID[(LE32(responseBase->PIDSize) >> 1) - 1]) return FALSE;
- for (i = 0; i < (LE32(responseBase->PIDSize) >> 1) - 2; i++)
- {
- if (!responseBase->KmsPID[i]) return FALSE;
- }
- return TRUE;
- }
- /*
- * "Decrypts" a KMS v4 response. Actually just copies to a fixed size buffer
- */
- RESPONSE_RESULT DecryptResponseV4(RESPONSE_V4* response_v4, const int responseSize, BYTE* const rawResponse, const BYTE* const rawRequest)
- {
- const int copySize =
- V4_PRE_EPID_SIZE +
- (LE32(((RESPONSE_V4*)rawResponse)->ResponseBase.PIDSize) <= PID_BUFFER_SIZE << 1 ?
- LE32(((RESPONSE_V4*)rawResponse)->ResponseBase.PIDSize) :
- PID_BUFFER_SIZE << 1);
- const int messageSize = copySize + V4_POST_EPID_SIZE;
- memcpy(response_v4, rawResponse, copySize);
- memcpy(&response_v4->ResponseBase.CMID, rawResponse + copySize, responseSize - copySize);
- // ensure PID is null terminated
- response_v4->ResponseBase.KmsPID[PID_BUFFER_SIZE - 1] = 0;
- uint8_t* mac = rawResponse + messageSize;
- AesCmacV4(rawResponse, messageSize, mac);
- REQUEST_V4* request_v4 = (REQUEST_V4*)rawRequest;
- RESPONSE_RESULT result;
- result.mask = (DWORD)~0;
- result.PidLengthOK = checkPidLength((RESPONSE*)rawResponse);
- result.VersionOK = response_v4->ResponseBase.Version == request_v4->RequestBase.Version;
- result.HashOK = !memcmp(&response_v4->MAC, mac, sizeof(response_v4->MAC));
- result.TimeStampOK = !memcmp(&response_v4->ResponseBase.ClientTime, &request_v4->RequestBase.ClientTime, sizeof(FILETIME));
- result.ClientMachineIDOK = !memcmp(&response_v4->ResponseBase.CMID, &request_v4->RequestBase.CMID, sizeof(GUID));
- result.effectiveResponseSize = responseSize;
- result.correctResponseSize = sizeof(RESPONSE_V4) - sizeof(response_v4->ResponseBase.KmsPID) + LE32(response_v4->ResponseBase.PIDSize);
- return result;
- }
- static RESPONSE_RESULT VerifyResponseV6(RESPONSE_RESULT result, RESPONSE_V6* response_v6, REQUEST_V6* request_v6, BYTE* const rawResponse)
- {
- // Check IVs
- result.IVsOK = !memcmp // In V6 the XoredIV is actually the request IV
- (
- response_v6->XoredIVs,
- request_v6->IV,
- sizeof(response_v6->XoredIVs)
- );
- result.IVnotSuspicious = !!memcmp // If IVs are identical, it is obviously an emulator
- (
- request_v6->IV,
- response_v6->IV,
- sizeof(request_v6->IV)
- );
- // Check Hmac
- int_fast8_t tolerance;
- BYTE OldHmac[sizeof(response_v6->HMAC)];
- result.HmacSha256OK = FALSE;
- memcpy // Save received HMAC to compare with calculated HMAC later
- (
- OldHmac,
- response_v6->HMAC,
- sizeof(response_v6->HMAC)
- );
- //AesEncryptBlock(Ctx, Response_v6->IV); // CreateV6Hmac needs original IV as received over the network
- for (tolerance = -1; tolerance < 2; tolerance++)
- {
- CreateV6Hmac
- (
- rawResponse + sizeof(response_v6->Version), // Pointer to start of the encrypted part of the response
- (size_t)result.correctResponseSize - sizeof(response_v6->Version), // size of the encrypted part
- tolerance // tolerance -1, 0, or +1
- );
- result.HmacSha256OK = !memcmp // Compare both HMACs
- (
- OldHmac,
- rawResponse + (size_t)result.correctResponseSize - sizeof(response_v6->HMAC),
- sizeof(OldHmac)
- );
- if (result.HmacSha256OK) break;
- }
- return result;
- }
- static RESPONSE_RESULT VerifyResponseV5(RESPONSE_RESULT result, REQUEST_V5* request_v5, RESPONSE_V5* response_v5)
- {
- // Check IVs: in V5 (and only v5) request and response IVs must match
- result.IVsOK = !memcmp(request_v5->IV, response_v5->IV, sizeof(request_v5->IV));
- // V5 has no Hmac, always set to TRUE
- result.HmacSha256OK = TRUE;
- return result;
- }
- /*
- * Decrypts a KMS v5 or v6 response received from a server.
- * hwid must supply a valid 16 byte buffer for v6. hwid is ignored in v5
- */
- RESPONSE_RESULT DecryptResponseV6(RESPONSE_V6* response_v6, int responseSize, BYTE* const response, const BYTE* const rawRequest, BYTE* hwid)
- {
- RESPONSE_RESULT result;
- result.mask = (DWORD)~0; // Set all bits in the results mask to 1. Assume success first.
- result.effectiveResponseSize = responseSize;
- int copySize1 =
- sizeof(response_v6->Version);
- // Decrypt KMS Server Response (encrypted part starts after RequestIV)
- responseSize -= copySize1;
- AesCtx Ctx;
- const int_fast8_t v6 = LE16(((RESPONSE_V6*)response)->MajorVer) > 5;
- AesInitKey(&Ctx, v6 ? AesKeyV6 : AesKeyV5, v6, AES_KEY_BYTES);
- AesDecryptCbc(&Ctx, NULL, response + copySize1, responseSize);
- // Check padding
- BYTE* lastPadByte = response + (size_t)result.effectiveResponseSize - 1;
- // Must be from 1 to 16
- if (!*lastPadByte || *lastPadByte > AES_BLOCK_BYTES)
- {
- result.DecryptSuccess = FALSE;
- return result;
- }
- // Check if pad bytes are all the same
- BYTE* padByte;
- for (padByte = lastPadByte - *lastPadByte + 1; padByte < lastPadByte; padByte++)
- {
- if (*padByte != *lastPadByte)
- {
- result.DecryptSuccess = FALSE;
- return result;
- }
- }
- // Add size of Version, KmsPIDLen and variable size PID
- DWORD pidSize = LE32(((RESPONSE_V6*)response)->ResponseBase.PIDSize);
- copySize1 +=
- V6_UNENCRYPTED_SIZE +
- sizeof(response_v6->ResponseBase.PIDSize) +
- (pidSize <= PID_BUFFER_SIZE << 1 ? pidSize : PID_BUFFER_SIZE << 1);
- // Copy part 1 of response up to variable sized PID
- memcpy(response_v6, response, copySize1);
- // ensure PID is null terminated
- response_v6->ResponseBase.KmsPID[PID_BUFFER_SIZE - 1] = 0;
- // Copy part 2
- const size_t copySize2 = v6 ? V6_POST_EPID_SIZE : V5_POST_EPID_SIZE;
- memcpy(&response_v6->ResponseBase.CMID, response + copySize1, copySize2);
- // Decrypting the response is finished here. Now we check the results for validity
- // A basic client doesn't need the stuff below this comment but we want to use vlmcs
- // as a debug tool for KMS emulators.
- REQUEST_V6* request_v6 = (REQUEST_V6*)rawRequest;
- const DWORD decryptSize = sizeof(request_v6->IV) + sizeof(request_v6->RequestBase) + sizeof(request_v6->Pad);
- AesDecryptCbc(&Ctx, NULL, request_v6->IV, decryptSize);
- // Check that all version informations are the same
- result.VersionOK =
- request_v6->Version == response_v6->ResponseBase.Version &&
- request_v6->Version == response_v6->Version &&
- request_v6->Version == request_v6->RequestBase.Version;
- // Check Base Request
- result.PidLengthOK = checkPidLength(&((RESPONSE_V6*)response)->ResponseBase);
- result.TimeStampOK = !memcmp(&response_v6->ResponseBase.ClientTime, &request_v6->RequestBase.ClientTime, sizeof(FILETIME));
- result.ClientMachineIDOK = IsEqualGUID(&response_v6->ResponseBase.CMID, &request_v6->RequestBase.CMID);
- // Rebuild Random Key and Sha256 Hash
- BYTE HashVerify[sizeof(response_v6->Hash)];
- BYTE RandomKey[sizeof(response_v6->RandomXoredIVs)];
- memcpy(RandomKey, request_v6->IV, sizeof(RandomKey));
- XorBlock(response_v6->RandomXoredIVs, RandomKey);
- Sha256(RandomKey, sizeof(RandomKey), HashVerify);
- result.HashOK = !memcmp(response_v6->Hash, HashVerify, sizeof(HashVerify));
- // size before encryption (padding not included)
- result.correctResponseSize =
- (v6 ? sizeof(RESPONSE_V6) : sizeof(RESPONSE_V5))
- - sizeof(response_v6->ResponseBase.KmsPID)
- + LE32(response_v6->ResponseBase.PIDSize);
- // Version specific stuff
- if (v6)
- {
- // Copy the HwId
- memcpy(hwid, response_v6->HwId, sizeof(response_v6->HwId));
- // Verify the V6 specific part of the response
- result = VerifyResponseV6(result, response_v6, request_v6, response);
- }
- else // V5
- {
- // Verify the V5 specific part of the response
- result = VerifyResponseV5(result, request_v6, (RESPONSE_V5*)response_v6);
- }
- // padded size after encryption
- result.correctResponseSize += (~(result.correctResponseSize - sizeof(response_v6->ResponseBase.Version)) & 0xf) + 1;
- return result;
- }
|