// Includes and Namespaces #include #include #include #include #include "Crypto.h" #include "Hash.h" #include "KMSServer.h" #include "KMSClientLogic.h" #include "KMSClientSettings.h" using namespace std; // Link Libraries #pragma comment(lib, "rpcrt4.lib") // Hold KMS Client Settings KMSClientSettings ClientSettings; // Windows Service Parameters for Service Application SERVICE_STATUS ClientServiceStatus; SERVICE_STATUS_HANDLE ClientServiceHandle; #pragma region Application Initialization Functions // Load Application Parameters from Command-Line void LoadClientParameters(int argc, wchar_t *argv[], bool RunAsService) { // Initialize KMS Client Settings Object ClientSettings.Initialize(); ClientSettings.RunAsService = RunAsService; #pragma region Command-Line // Handle Command-Line Arguments (KMS Port or Help) if (argc >= 2) { if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, argv[1], -1, L"/?", -1) == CSTR_EQUAL) { printf("Usage:\n"); printf("[KMS Port] [KMS Host] [Client Mode]\n\n"); printf("KMS Port:\n"); printf("\tDefaultPort:\t\tUse the built-in KMS Port.\n"); printf("\tInteger:\t\tNumber from 1 to 65535.\n\n"); printf("KMS Host:\n"); printf("\tDefaultHost:\t\tUse the built-in KMS Host Address.\n"); printf("\tString:\t\t\tA DNS Name or IP Address.\n\n"); printf("Client Mode:\n"); printf("\tWindows:\t\tWindows Vista Enterprise KMS (V4) Client.\n"); printf("\tWindowsVista:\t\tWindows Vista Enterprise KMS (V4) Client.\n"); printf("\tWindows7:\t\tWindows 7 Enterprise KMS (V4) Client.\n"); printf("\tWindows8:\t\tWindows 8 Enterprise KMS (V5) Client.\n"); printf("\tWindows81:\t\tWindows 8 Enterprise KMS (V6) Client.\n"); printf("\tOffice2010:\t\tOffice 2010 Pro Plus KMS (V4) Client.\n"); printf("\tOffice2013:\t\tOffice 2013 Pro Plus KMS (V4) Client.\n"); printf("\tOffice2013V4:\t\tOffice 2013 Pro Plus KMS (V4) Client.\n"); printf("\tOffice2013V5:\t\tOffice 2013 Pro Plus KMS (V5) Client.\n\n"); printf("\tOffice2013V6:\t\tOffice 2013 Pro Plus KMS (V6) Client.\n\n"); printf("Example:\n"); printf("\tC:\\>\"KMS Client.exe\" 1688 127.0.0.2 Windows"); ClientWriteLogErrorTerminate(L"\n", -1); } else { ClientValidateKMSPort(argv[1]); } } // Handle Command-Line Arguments (KMS Host) if (argc >= 3) { ClientValidateKMSHost(argv[2]); } // Handle Command-Line Arguments (Client Mode) if (argc >= 4) { ClientValidateKMSClientMode(argv[3]); } #pragma endregion } // Start RPC Connection and try to contact a KMS Server. void StartKMSClient() { // RPC Parameters RPC_STATUS status; RPC_WSTR pszUuid = NULL; RPC_WSTR pszProtocolSequence = (RPC_WSTR)L"ncacn_ip_tcp"; RPC_WSTR pszNetworkAddress = (RPC_WSTR)ClientSettings.KMSHost; RPC_WSTR pszEndpoint = (RPC_WSTR)ClientSettings.KMSPort; RPC_WSTR pszOptions = NULL; RPC_WSTR pszStringBinding = NULL; // Create String Binding status = RpcStringBindingCompose ( pszUuid, pszProtocolSequence, pszNetworkAddress, pszEndpoint, pszOptions, &pszStringBinding ); if (status) { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"RpcStringBindingCompose failed with code %i.\n", status); ClientWriteLogErrorTerminate(Message, status); } // Get RPC Binding Handle from String Binding status = RpcBindingFromStringBinding(pszStringBinding, &KMSServer_v1_0_c_ifspec); if (status) { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"RpcBindingFromStringBinding failed with code %i.\n", status); ClientWriteLogErrorTerminate(Message, status); } ClientWriteLogInformation(L"\nKMS Client Emulator started successfully.\n"); // Send Requests int RequestsNeeded = ClientSettings.RequiredClientCount; for (int requests = 0; requests < RequestsNeeded; requests++) { // Define the size of the request int sizeRequest = 0; if (ClientSettings.KMSProtocolMajorVersion == 4) { sizeRequest = sizeof(REQUEST_V4); } else if (ClientSettings.KMSProtocolMajorVersion == 5) { sizeRequest = sizeof(REQUEST_V5); } else { sizeRequest = sizeof(REQUEST_V6); } // Create KMS Client Request PBYTE request = (PBYTE)midl_user_allocate(sizeRequest); memcpy(request, (PBYTE)CreateRequest(), sizeRequest); // Send KMS Client Request to KMS Server status = SendRequest(request, requests, &RequestsNeeded); if (status) { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Activation request (KMS V%i.%i) %i of %i failed.\n", ClientSettings.KMSProtocolMajorVersion, ClientSettings.KMSProtocolMinorVersion, requests + 1, RequestsNeeded); ClientWriteLogErrorTerminate(Message, status); } else { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Activation request (KMS V%i.%i) %i of %i sent.\n", ClientSettings.KMSProtocolMajorVersion, ClientSettings.KMSProtocolMinorVersion, requests + 1, RequestsNeeded); ClientWriteLogInformation(Message); } } // Free String Binding status = RpcStringFree(&pszStringBinding); if (status) { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"RpcStringFree failed with code %i.\n", status); ClientWriteLogErrorTerminate(Message, status); } // Free RPC Binding status = RpcBindingFree(&KMSServer_v1_0_c_ifspec); if (status) { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"RpcBindingFree failed with code %i.\n", status); ClientWriteLogErrorTerminate(Message, status); } } #pragma endregion #pragma region KMS Client Request Generation Functions // Create KMS Client Request Data Based on KMS Client Protocol Version. PBYTE CreateRequest() { // KMS Protocol Major Version if (ClientSettings.KMSProtocolMajorVersion == 4) { return CreateRequestV4(); } else if (ClientSettings.KMSProtocolMajorVersion == 5) { return CreateRequestV5(); } else { return CreateRequestV6(); } } // Create Base KMS Client Request Object. void CreateRequestBase(REQUEST* const Request) { // KMS Protocol Version Request->MajorVer = ClientSettings.KMSProtocolMajorVersion; Request->MinorVer = ClientSettings.KMSProtocolMinorVersion; // KMS Client is NOT a VM Request->IsClientVM = 0; // License Status Request->LicenseStatus = ClientSettings.KMSClientLicenseStatus; // Grace Time Request->GraceTime = 43200; // Application ID UuidFromStringW((RPC_WSTR)ClientSettings.KMSClientAppID, &Request->ApplicationId); // SKU ID UuidFromStringW((RPC_WSTR)ClientSettings.KMSClientSkuID, &Request->SkuId); // KMS Counted ID UuidFromStringW((RPC_WSTR)ClientSettings.KMSClientKMSCountedID, &Request->KmsCountedId); // CMID CoCreateGuid(&Request->ClientMachineId); // Minimum Clients Request->RequiredClientCount = ClientSettings.RequiredClientCount; // Timestamp GetSystemTimeAsFileTime(&Request->RequestTime); // Machine Name static const char alphanum[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"; // Seed Random Number Generator srand(GetTickCount()); // Generate Random Machine Name (Up to 63 Characters) int MachineNameLength = rand() % 63 + 1; for (int i = 0; i < MachineNameLength; i++) { Request->MachineName[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; } Request->MachineName[MachineNameLength] = 0; } // Create Hashed KMS Client Request Data for KMS Protocol Version 4. PBYTE CreateRequestV4() { // Allocate KMS Client Request Buffer PBYTE request = (PBYTE)midl_user_allocate(sizeof(REQUEST_V4)); // Clean buffer memory memset(request, 0x00, sizeof(REQUEST_V4)); // Create KMS Client Request Base CreateRequestBase((REQUEST*)request); // Create Hash GetHash(sizeof(REQUEST), request, request + sizeof(REQUEST)); // Return Request return request; } // Create Encrypted KMS Client Request Data for KMS Protocol Version 5. PBYTE CreateRequestV5() { // Allocate KMS Client Request Buffer PBYTE request = (PBYTE)midl_user_allocate(sizeof(REQUEST_V5)); // Clean buffer memory memset(request, 0x00, sizeof(REQUEST_V5)); // Temporary Pointer for access to REQUEST_V5 structure REQUEST_V5 *requestptr = (REQUEST_V5 *)request; // KMS Protocol Version requestptr->MajorVer = ClientSettings.KMSProtocolMajorVersion; requestptr->MinorVer = ClientSettings.KMSProtocolMinorVersion; // Seed Random Number Generator srand(GetTickCount()); // Generate a Random Salt Key for(int i = 0; i < 16; i++) { requestptr->Salt[i] = rand() % 256; } // Set KMS Client Request Base CreateRequestBase(&requestptr->RequestBase); // Encrypted Size DWORD EncryptedSize = sizeof(requestptr->RequestBase); // AES-128 Encrypt AESEncryptMessage(requestptr->Salt, (PBYTE)(&requestptr->RequestBase), &EncryptedSize, sizeof(requestptr->RequestBase) + sizeof(requestptr->Pad)); // Return Request return request; } // Create Encrypted KMS Client Request Data for KMS Protocol Version 6. PBYTE CreateRequestV6() { // V6: AES key BYTE AES_V6_KEY[16] = {0xA9, 0x4A, 0x41, 0x95, 0xE2, 0x01, 0x43, 0x2D, 0x9B, 0xCB, 0x46, 0x04, 0x05, 0xD8, 0x4A, 0x21}; // Allocate KMS Client Request Buffer PBYTE request = (PBYTE)midl_user_allocate(sizeof(REQUEST_V6)); // Clean buffer memory memset(request, 0x00, sizeof(REQUEST_V6)); // Temporary Pointer for access to REQUEST_V6 structure REQUEST_V6 *requestptr = (REQUEST_V6 *)request; // KMS Protocol Version requestptr->MajorVer = ClientSettings.KMSProtocolMajorVersion; requestptr->MinorVer = ClientSettings.KMSProtocolMinorVersion; // Seed Random Number Generator srand(GetTickCount()); // Generate a Random Salt Key for(int i = 0; i < 16; i++) { requestptr->Salt[i] = rand() % 256; } // Set KMS Client Request Base CreateRequestBase(&requestptr->RequestBase); // Set Padding to 0x04 memset(&requestptr->Pad, 0x04, sizeof(&requestptr->Pad)); // Encrypted Size DWORD EncryptedSize = sizeof(requestptr->RequestBase) + sizeof(requestptr->Pad); AesInit(AES_TYPE_128, AES_MODE_CBC, 0x04, AES_V6_KEY, requestptr->Salt); EncryptMessage(EncryptedSize, (PBYTE)(&requestptr->RequestBase)); AesClear(); // Return Request return request; } // Read KMS Server Response V4 from Byte Array void ReadResponseV4(RESPONSE_V4& Response_v4, int responseSize, PBYTE response) { int copySize = sizeof(Response_v4.ResponseBase.Version) + sizeof(Response_v4.ResponseBase.KMSPIDLength) + (((RESPONSE_V4*)response)->ResponseBase.KMSPIDLength <= PID_BUFFER_SIZE << 1 ? ((RESPONSE_V4*)response)->ResponseBase.KMSPIDLength : PID_BUFFER_SIZE << 1); memcpy(&Response_v4, response, copySize); memcpy(&Response_v4.ResponseBase.ClientMachineId, response + copySize, responseSize - copySize); // Ensure KMSPID is NULL Terminated Response_v4.ResponseBase.KMSPID[PID_BUFFER_SIZE - 1] = 0; } // Read KMS Server Response V5 from Byte Array void ReadResponseV5(RESPONSE_V5& Response_v5, int responseSize, PBYTE response) { // Get Size of the First Part of the Response int copySize1 = sizeof(Response_v5.Version) + sizeof(Response_v5.RequestSalt); // Decrypt KMS Server Response (Encrypted part starts after RequestSalt) responseSize -= copySize1; AESDecryptMessage(((RESPONSE_V5*)(response))->RequestSalt, response + copySize1, (DWORD*)&responseSize); // Add Size of KMS Protocol Version, KMS PID Length and KMS PID (Variable Sized) copySize1 += sizeof(Response_v5.ResponseBase.Version) + sizeof(Response_v5.ResponseBase.KMSPIDLength) + (((RESPONSE_V5*)response)->ResponseBase.KMSPIDLength <= PID_BUFFER_SIZE << 1 ? ((RESPONSE_V5*)response)->ResponseBase.KMSPIDLength : PID_BUFFER_SIZE << 1); // Copy Part 1 of Response up to KMS PID (Variable Sized) memcpy(&Response_v5, response, copySize1); // Ensure KMSPID is NULL Terminated Response_v5.ResponseBase.KMSPID[PID_BUFFER_SIZE - 1] = 0; // Get Size of the Second Part of the Response int copySize2 = sizeof(Response_v5.ResponseBase.ClientMachineId) + sizeof(Response_v5.ResponseBase.RequestTime) + sizeof(Response_v5.ResponseBase.KMSCurrentCount) + sizeof(Response_v5.ResponseBase.VLActivationInterval) + sizeof(Response_v5.ResponseBase.VLRenewalInterval) + sizeof(Response_v5.Salt) + sizeof(Response_v5.Hash); // Copy Part 2 of Response memcpy(&Response_v5.ResponseBase.ClientMachineId, response + copySize1, copySize2); } // Read KMS Server Response V6 from Byte Array void ReadResponseV6(RESPONSE_V6& Response_v6, int responseSize, PBYTE response) { // V6: AES key BYTE AES_V6_KEY[16] = {0xA9, 0x4A, 0x41, 0x95, 0xE2, 0x01, 0x43, 0x2D, 0x9B, 0xCB, 0x46, 0x04, 0x05, 0xD8, 0x4A, 0x21}; // Get Size of the First Part of the Response int copySize = sizeof(Response_v6.Version) + sizeof(Response_v6.RequestSalt); // Read the first part. memcpy(&Response_v6, response, copySize); response += copySize; responseSize -= copySize; // Decrypt the response. AesInit(AES_TYPE_128, AES_MODE_CBC, 0x04, AES_V6_KEY, Response_v6.RequestSalt); DecryptMessage(responseSize, response); AesClear(); // Read version. copySize = sizeof(Response_v6.ResponseBase.Version); memcpy(&Response_v6.ResponseBase.Version, response, copySize); response += copySize; responseSize -= copySize; // Read KMS PID length. copySize = sizeof(Response_v6.ResponseBase.KMSPIDLength); memcpy(&Response_v6.ResponseBase.KMSPIDLength, response, copySize); response += copySize; responseSize -= copySize; // Read KMS PID. copySize = Response_v6.ResponseBase.KMSPIDLength <= PID_BUFFER_SIZE << 1 ? Response_v6.ResponseBase.KMSPIDLength : PID_BUFFER_SIZE << 1; memcpy(&Response_v6.ResponseBase.KMSPID, response, copySize); response += copySize; responseSize -= copySize; // Ensure KMSPID is NULL Terminated Response_v6.ResponseBase.KMSPID[PID_BUFFER_SIZE - 1] = 0; // Read the rest into the structure. memcpy(&Response_v6.ResponseBase.ClientMachineId, response, responseSize); } // Function to Send Request to KMS Server // Used to allow use of RpcTryExcept int SendRequest(PBYTE request, const int requestsSent, int* const requestsNeeded) { RpcTryExcept { // Allocate Memory for Response int responseSize = MAX_RESPONSE_SIZE; PBYTE resp = (PBYTE)midl_user_allocate(MAX_RESPONSE_SIZE); if (ClientSettings.KMSProtocolMajorVersion == 4) { // Call KMS Server via RPC for V4 ActivationRequest(KMSServer_v1_0_c_ifspec, sizeof(REQUEST_V4), request, &responseSize, &resp); } else if (ClientSettings.KMSProtocolMajorVersion == 5) { // Call KMS Server via RPC for V5 ActivationRequest(KMSServer_v1_0_c_ifspec, sizeof(REQUEST_V5), request, &responseSize, &resp); } else { // Call KMS Server via RPC for V6 ActivationRequest(KMSServer_v1_0_c_ifspec, sizeof(REQUEST_V6), request, &responseSize, &resp); } // Verify Response Was Received if (resp == NULL) { ClientWriteLogErrorTerminate(L"Failed to get Activation response.\n", -1); } // Determine how many more requests are needed. if (requestsSent < 1) { // Place to Store Base Response Data RESPONSE response; // KMSPID from Response WCHAR* KMSPID = L""; // KMSHWID from Response WCHAR KMSHWID[256]; // ActivatedMachines from Response DWORD ActivatedMachines; if (ClientSettings.KMSProtocolMajorVersion == 4) { // Get KMS Server Response Object RESPONSE_V4 response_v4; ReadResponseV4(response_v4, responseSize, resp); // Get Base KMS Server Response Object response = response_v4.ResponseBase; // Read KMSPID from Response KMSPID = response.KMSPID; // Read ActivatedMachines from Response ActivatedMachines = response.KMSCurrentCount; } else if (ClientSettings.KMSProtocolMajorVersion == 5) { // Get KMS Server Response Object RESPONSE_V5 response_v5; ReadResponseV5(response_v5, responseSize, resp); // Get Base KMS Server Response Object response = response_v5.ResponseBase; // Read KMSPID from Response KMSPID = response.KMSPID; // Read ActivatedMachines from Response ActivatedMachines = response.KMSCurrentCount; } else { // Get KMS Server Response Object RESPONSE_V6 response_v6; ReadResponseV6(response_v6, responseSize, resp); // Get Base KMS Server Response Object response = response_v6.ResponseBase; // Read KMSPID from Response KMSPID = response.KMSPID; // Read KMSHWID from Response swprintf_s(KMSHWID, 256, L"%02X%02X%02X%02X%02X%02X%02X%02X", response_v6.MachineHardwareHash[7], response_v6.MachineHardwareHash[6], response_v6.MachineHardwareHash[5], response_v6.MachineHardwareHash[4], response_v6.MachineHardwareHash[3], response_v6.MachineHardwareHash[2], response_v6.MachineHardwareHash[1], response_v6.MachineHardwareHash[0]); // Read ActivatedMachines from Response ActivatedMachines = response.KMSCurrentCount; } ClientWriteLogInformation(L"Successfully received response from KMS Server.\n"); // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"KMS Server PID: %s.\n", KMSPID); ClientWriteLogInformation(Message); if (ClientSettings.KMSProtocolMajorVersion > 5) { swprintf_s(Message, 256, L"KMS Server HWID: %s.\n", KMSHWID); ClientWriteLogInformation(Message); } // Send no more requests if the client count was sufficient. if (ActivatedMachines >= ClientSettings.RequiredClientCount) { *requestsNeeded = 1; } // Send as many requests as needed. else { *requestsNeeded = (ClientSettings.RequiredClientCount - ActivatedMachines) + 1; } } return 0; } RpcExcept(1) { // Get RPC Exception Code unsigned long ulCode = RpcExceptionCode(); // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode); ClientWriteLogErrorTerminate(Message, ulCode); // Return return false; } RpcEndExcept } #pragma endregion #pragma region Parameter Validation Functions // Validate KMS Port Parameter void ClientValidateKMSPort(WCHAR* KMSPort) { // Check if the KMS Port is not the Default if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSPort, -1, L"DefaultPort", -1) != CSTR_EQUAL) { // Check if KMS Port is Valid Number if (regex_match(KMSPort, wregex(L"^([0-9]+)$"))) { // Check if KMS Port is Valid Range if(_wtoi(KMSPort) < 1 || _wtoi(KMSPort) > 65535) { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Invalid KMS Port Range! %s is not a valid argument.\n", KMSPort); ClientWriteLogErrorTerminate(Message, -1); } else { // Apply Setting StringCchCopyW(ClientSettings.KMSPort, PORT_BUFFER_SIZE, KMSPort); // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"KMS Port: %s \n", KMSPort); ClientWriteLogInformation(Message); } } else { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Invalid KMS Port! %s is not a valid argument.\n", KMSPort); ClientWriteLogErrorTerminate(Message, -1); } } } // Validate KMS Host Parameter void ClientValidateKMSHost(WCHAR* KMSHost) { // Check if the KMS PID is not the Default if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSHost, -1, L"DefaultHost", -1) != CSTR_EQUAL) { // Apply Setting StringCchCopyW(ClientSettings.KMSHost, 256, KMSHost); // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"KMS Host: %s \n", KMSHost); ClientWriteLogInformation(Message); } } // Validate KMS Client Mode void ClientValidateKMSClientMode(WCHAR* KMSClientMode) { // Check if KMS Client Mode is Valid if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSClientMode, -1, L"Windows", -1) == CSTR_EQUAL || CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSClientMode, -1, L"WindowsVista", -1) == CSTR_EQUAL) { ClientSettings.RequiredClientCount = 25; ClientSettings.KMSProtocolMajorVersion = 4; StringCchCopyW(ClientSettings.KMSClientAppID, GUID_BUFFER_SIZE, L"55c92734-d682-4d71-983e-d6ec3f16059f"); StringCchCopyW(ClientSettings.KMSClientSkuID, GUID_BUFFER_SIZE, L"cfd8ff08-c0d7-452b-9f60-ef5c70c32094"); StringCchCopyW(ClientSettings.KMSClientKMSCountedID, GUID_BUFFER_SIZE, L"212a64dc-43b1-4d3d-a30c-2fc69d2095c6"); } else if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSClientMode, -1, L"Windows7", -1) == CSTR_EQUAL) { ClientSettings.RequiredClientCount = 25; ClientSettings.KMSProtocolMajorVersion = 4; StringCchCopyW(ClientSettings.KMSClientAppID, GUID_BUFFER_SIZE, L"55c92734-d682-4d71-983e-d6ec3f16059f"); StringCchCopyW(ClientSettings.KMSClientSkuID, GUID_BUFFER_SIZE, L"ae2ee509-1b34-41c0-acb7-6d4650168915"); StringCchCopyW(ClientSettings.KMSClientKMSCountedID, GUID_BUFFER_SIZE, L"7fde5219-fbfa-484a-82c9-34d1ad53e856"); } else if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSClientMode, -1, L"Windows8", -1) == CSTR_EQUAL) { ClientSettings.RequiredClientCount = 25; ClientSettings.KMSProtocolMajorVersion = 5; StringCchCopyW(ClientSettings.KMSClientAppID, GUID_BUFFER_SIZE, L"55c92734-d682-4d71-983e-d6ec3f16059f"); StringCchCopyW(ClientSettings.KMSClientSkuID, GUID_BUFFER_SIZE, L"458e1bec-837a-45f6-b9d5-925ed5d299de"); StringCchCopyW(ClientSettings.KMSClientKMSCountedID, GUID_BUFFER_SIZE, L"3c40b358-5948-45af-923b-53d21fcc7e79"); } else if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSClientMode, -1, L"Windows81", -1) == CSTR_EQUAL) { ClientSettings.RequiredClientCount = 25; ClientSettings.KMSProtocolMajorVersion = 6; StringCchCopyW(ClientSettings.KMSClientAppID, GUID_BUFFER_SIZE, L"55c92734-d682-4d71-983e-d6ec3f16059f"); StringCchCopyW(ClientSettings.KMSClientSkuID, GUID_BUFFER_SIZE, L"81671aaf-79d1-4eb1-b004-8cbbe173afea"); StringCchCopyW(ClientSettings.KMSClientKMSCountedID, GUID_BUFFER_SIZE, L"cb8fc780-2c05-495a-9710-85afffc904d7"); } else if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSClientMode, -1, L"Office2010", -1) == CSTR_EQUAL) { ClientSettings.RequiredClientCount = 5; ClientSettings.KMSProtocolMajorVersion = 4; StringCchCopyW(ClientSettings.KMSClientAppID, GUID_BUFFER_SIZE, L"59a52881-a989-479d-af46-f275c6370663"); StringCchCopyW(ClientSettings.KMSClientSkuID, GUID_BUFFER_SIZE, L"6f327760-8c5c-417c-9b61-836a98287e0c"); StringCchCopyW(ClientSettings.KMSClientKMSCountedID, GUID_BUFFER_SIZE, L"e85af946-2e25-47b7-83e1-bebcebeac611"); } else if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSClientMode, -1, L"Office2013", -1) == CSTR_EQUAL || CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSClientMode, -1, L"Office2013V4", -1) == CSTR_EQUAL) { ClientSettings.RequiredClientCount = 5; ClientSettings.KMSProtocolMajorVersion = 4; StringCchCopyW(ClientSettings.KMSClientAppID, GUID_BUFFER_SIZE, L"0ff1ce15-a989-479d-af46-f275c6370663"); StringCchCopyW(ClientSettings.KMSClientSkuID, GUID_BUFFER_SIZE, L"b322da9c-a2e2-4058-9e4e-f59a6970bd69"); StringCchCopyW(ClientSettings.KMSClientKMSCountedID, GUID_BUFFER_SIZE, L"e6a6f1bf-9d40-40c3-aa9f-c77ba21578c0"); } else if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSClientMode, -1, L"Office2013V5", -1) == CSTR_EQUAL) { ClientSettings.RequiredClientCount = 5; ClientSettings.KMSProtocolMajorVersion = 5; StringCchCopyW(ClientSettings.KMSClientAppID, GUID_BUFFER_SIZE, L"0ff1ce15-a989-479d-af46-f275c6370663"); StringCchCopyW(ClientSettings.KMSClientSkuID, GUID_BUFFER_SIZE, L"b322da9c-a2e2-4058-9e4e-f59a6970bd69"); StringCchCopyW(ClientSettings.KMSClientKMSCountedID, GUID_BUFFER_SIZE, L"e6a6f1bf-9d40-40c3-aa9f-c77ba21578c0"); } else if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSClientMode, -1, L"Office2013V6", -1) == CSTR_EQUAL) { ClientSettings.RequiredClientCount = 5; ClientSettings.KMSProtocolMajorVersion = 6; StringCchCopyW(ClientSettings.KMSClientAppID, GUID_BUFFER_SIZE, L"0ff1ce15-a989-479d-af46-f275c6370663"); StringCchCopyW(ClientSettings.KMSClientSkuID, GUID_BUFFER_SIZE, L"b322da9c-a2e2-4058-9e4e-f59a6970bd69"); StringCchCopyW(ClientSettings.KMSClientKMSCountedID, GUID_BUFFER_SIZE, L"e6a6f1bf-9d40-40c3-aa9f-c77ba21578c0"); } else { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Invalid KMS Client Type! %s is not a valid argument.\n", KMSClientMode); ClientWriteLogErrorTerminate(Message, -1); } // Apply Setting StringCchCopyW(ClientSettings.KMSClientMode, 256, KMSClientMode); // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"KMS Client Mode: %s \n", KMSClientMode); ClientWriteLogInformation(Message); } #pragma endregion #pragma region Logging Functions // Log an informational message to the Console or Windows Application Event Log. void ClientWriteLogInformation(WCHAR* const Message) { // Log Message Buffer WCHAR logMessage[256]; // Write Log Message to Buffer StringCbPrintfW(logMessage, 256, Message); // Choose Log Source if (ClientSettings.RunAsService) { // Output to Windows Event Log: Qualifiers: 16384, EventId: 12290 ClientWriteEventLogEntry(0x40003002, logMessage, EVENTLOG_INFORMATION_TYPE); } else { // Output to Console wprintf(L"%s", logMessage); } } // Log an error message to the Console or Windows Application Event Log. void ClientWriteLogError(WCHAR* const Message) { // Log Message Buffer WCHAR logMessage[256]; // Write Log Message to Buffer StringCbPrintfW(logMessage, 256, Message); // Choose Log Source if (ClientSettings.RunAsService) { // Output to Windows Event Log: Qualifiers: 16384, EventId: 902 ClientWriteEventLogEntry(0x40000386, logMessage, EVENTLOG_ERROR_TYPE); } else { // Output to Console wprintf(L"%s", logMessage); } } // Log an error message to the Console or Windows Application Event Log and terminate program. void ClientWriteLogErrorTerminate(WCHAR* const Message, int ExitCode) { // Call ClientWriteLogError ClientWriteLogError(Message); if (!ClientSettings.RunAsService) { // Exit Program exit(ExitCode); } else { // Exit Service ClientServiceStatus.dwCurrentState = SERVICE_STOPPED; ClientServiceStatus.dwWin32ExitCode = ExitCode; SetServiceStatus(ClientServiceHandle, &ClientServiceStatus); } } // Log a message to the Windows Application Event Log. void ClientWriteEventLogEntry(DWORD dwIdentifier, WCHAR* const lpszMessage, WORD wType) { HANDLE hEventSource = OpenEventLogW(NULL, L"KmsRequests"); // Provider: KmsRequests or Microsoft-Windows-Security-SPP if(hEventSource != NULL) { ReportEventW( hEventSource, // Event log handle wType, // Event type NULL, // Event category dwIdentifier, // Event identifier NULL, // No security identifier 1, // Size of lpszStrings array NULL, // No binary data (LPCWSTR*)&lpszMessage, // Array of strings NULL // No binary data ); CloseEventLog(hEventSource); } } #pragma endregion