// Includes and Namespaces #include #include #include #include #include #include #include #include "Crypto.h" #include "Hash.h" #include "KMSPID.h" #include "KMSHWID.h" #include "KMSServer.h" #include "KMSServerLogic.h" #include "KMSServerSettings.h" using namespace std; // Link Libraries #pragma comment(lib, "rpcrt4.lib") #pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "ws2_32.lib") // Hold KMS Server Settings KMSServerSettings ServerSettings; // Windows Service Parameters for Service Application SERVICE_STATUS ServerServiceStatus; SERVICE_STATUS_HANDLE ServerServiceHandle; // Defined in Hash.cpp extern HMAC_KEYBLOB Hmac_keyblob; #pragma region Application Initialization Functions // Load Application Parameters from Command-Line or Registry. void LoadServerParameters(int argc, wchar_t* argv[], bool RunAsService) { // Initialize KMS Server Settings Object ServerSettings.Initialize(); ServerSettings.RunAsService = RunAsService; if (!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 PID] [KMS HWID] [Activation Interval] [Renewal Interval] [Kill Processes]\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 PID:\n"); printf("\tRandomKMSPID:\t\tGenerate a random KMS PID.\n"); printf("\tString:\t\t\tA Microsoft Extended Product Key ID.\n\n"); printf("KMS HWID:\n"); printf("\tDefaultKMSHWID:\t\tUse the built-in KMS HWID.\n"); printf("\tString:\t\t\t16 Hex character KMS HWID (No 0x).\n\n"); printf("Activation Interval:\n"); printf("\tDefaultAI:\t\tUse the built-in Activation Interval.\n"); printf("\tInteger:\t\tNumber (in minutes) from 15 to 43200.\n\n"); printf("Renewal Interval:\n"); printf("\tDefaultRI:\t\tUse the built-in Renewal Interval.\n"); printf("\tInteger:\t\tNumber (in minutes) from 15 to 43200.\n\n"); printf("Kill Processes:\n"); printf("\tKillProcessOnPort:\tForce open the KMS Port if this is present.\n\n"); printf("Example:\n"); printf("\tC:\\>\"KMS Server.exe\" 1688 RandomKMSPID DefaultKMSHWID 43200 43200 KillProcessOnPort"); ServerWriteLogErrorTerminate(L"\n", -1); } else { ServerValidateKMSPort(argv[1]); } } // Handle Command-Line Arguments (KMS PID) if (argc >= 3) { ServerValidateKMSPID(argv[2]); } // Handle Command-Line Arguments (KMS HWID) if (argc >= 4) { ServerValidateKMSHWID(argv[3]); } // Handle Command-Line Arguments (Activation Interval) if (argc >= 5) { if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, argv[4], -1, L"DefaultAI", -1) != CSTR_EQUAL) { // Check if Activation Interval is Valid Number if (regex_match(argv[4], wregex(L"^([0-9]+)$"))) { ServerValidateVLActivationInterval(_wtoi(argv[4])); } else { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Invalid KMS Activation Interval! %s is not a valid argument.\n", argv[4]); ServerWriteLogErrorTerminate(Message, -1); } } } // Handle Command-Line Arguments (Renewal Interval) if (argc >= 6) { if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, argv[5], -1, L"DefaultRI", -1) != CSTR_EQUAL) { // Check if Renewal Interval is Valid Number if (regex_match(argv[5], wregex(L"^([0-9]+)$"))) { ServerValidateVLRenewalInterval(_wtoi(argv[5])); } else { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Invalid KMS Renewal Interval! %s is not a valid argument.\n", argv[5]); ServerWriteLogErrorTerminate(Message, -1); } } } // Handle Command-Line Arguments (Free TCP/IP) if (argc >= 7) { if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, argv[6], -1, L"KillProcessOnPort", -1) == CSTR_EQUAL) { // Apply Setting ServerSettings.KillProcesses = true; ServerWriteLogInformation(L"KMS Port Process Termination: Enabled \n"); } else { // Apply Setting ServerSettings.KillProcesses = false; ServerWriteLogInformation(L"KMS Port Process Termination: Disabled \n"); } } #pragma endregion } else { #pragma region Registry // Create Buffers for Values WCHAR KMSPID[256] = {0}; WCHAR KMSHWID[256] = {0}; WCHAR KMSPort[256] = {0}; DWORD VLActivationInterval = 0; DWORD VLRenewalInterval = 0; DWORD KillProcesses = 0; // Open Registry Key HKEY hKey; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\KMSServerService\\Parameters", NULL, KEY_READ, &hKey) == ERROR_SUCCESS) { // Buffer Size DWORD bufferSize = 0; // Handle Registry Parameters (KMS PID) bufferSize = 256; RegQueryValueExW(hKey, L"KMSPID", NULL, NULL, (LPBYTE)KMSPID, &bufferSize); // Handle Registry Parameters (KMS HWID) bufferSize = 256; RegQueryValueExW(hKey, L"KMSHWID", NULL, NULL, (LPBYTE)KMSHWID, &bufferSize); // Handle Registry Parameters (KMS Port) bufferSize = 256; RegQueryValueExW(hKey, L"KMSPort", NULL, NULL, (LPBYTE)KMSPort, &bufferSize); // Handle Registry Parameters (Activation Interval) bufferSize = sizeof(DWORD); RegQueryValueExW(hKey, L"VLActivationInterval", NULL, NULL, (LPBYTE)&VLActivationInterval, &bufferSize); // Handle Registry Parameters (Renewal Interval) bufferSize = sizeof(DWORD); RegQueryValueExW(hKey, L"VLRenewalInterval", NULL, NULL, (LPBYTE)&VLRenewalInterval, &bufferSize); // Handle Registry Parameters (Free TCP/IP) bufferSize = sizeof(DWORD); RegQueryValueExW(hKey, L"KillProcessOnPort", NULL, NULL, (LPBYTE)&KillProcesses, &bufferSize); // Close Registry Key RegCloseKey(hKey); } // Validate Values ServerValidateKMSPort(KMSPort); ServerValidateKMSPID(KMSPID); ServerValidateKMSHWID(KMSHWID); ServerValidateVLActivationInterval(VLActivationInterval); ServerValidateVLRenewalInterval(VLRenewalInterval); // Handle External Process Termination if (KillProcesses > 0) { // Apply Setting ServerSettings.KillProcesses = true; ServerWriteLogInformation(L"KMS Port Process Termination: Enabled \n"); } else { // Apply Setting ServerSettings.KillProcesses = false; ServerWriteLogInformation(L"KMS Port Process Termination: Disabled \n"); } #pragma endregion } } // Start RPC Connection and listen indefinitely for KMS Clients. void StartKMSServer() { // Uses the protocol combined with the endpoint for receiving remote procedure calls. RPC_STATUS status = RpcServerUseProtseqEp ( // Use TCP/IP protocol. (RPC_WSTR)L"ncacn_ip_tcp", // Backlog queue length for TCP/IP. RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // TCP/IP port to use. (RPC_WSTR)ServerSettings.KMSPort, // No security. NULL ); if (status) { // TCP/IP Port in Use if (status == RPC_S_DUPLICATE_ENDPOINT && ServerSettings.KillProcesses) { // TCP Table and TCP Table Size MIB_TCPTABLE_OWNER_PID *pTCPInfo; DWORD dwSize = 0; // Get TCP Table Size GetExtendedTcpTable(NULL, &dwSize, true, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0); // Allocate Memory for TCP Table pTCPInfo = (MIB_TCPTABLE_OWNER_PID*)malloc(dwSize); // Get TCP Table Data GetExtendedTcpTable(pTCPInfo, &dwSize, true, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0); // Read TCP Table Data for (DWORD i = 0; i < pTCPInfo->dwNumEntries; i++) { // Get Process ID, Opened Port of the Process and KMS Port DWORD processID = pTCPInfo->table[i].dwOwningPid; DWORD kmsport = _wtoi(ServerSettings.KMSPort); DWORD port = ntohs((u_short)pTCPInfo->table[i].dwLocalPort); // Check if this Process has the KMS Port if (port == kmsport) { // Enable Debug Privileges HANDLE tokenHandle; OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tokenHandle); TOKEN_PRIVILEGES privilegeToken; LookupPrivilegeValue(0, SE_DEBUG_NAME, &privilegeToken.Privileges[0].Luid); privilegeToken.PrivilegeCount = 1; privilegeToken.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(tokenHandle, 0, &privilegeToken, sizeof(TOKEN_PRIVILEGES), 0, 0); CloseHandle(tokenHandle); // Kill Process using the KMS Port HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, processID); if (hProcess != NULL) { TerminateProcess(hProcess, 0); CloseHandle(hProcess); } else { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Failed to get handle to kill Process ID: %i.\n", processID); ServerWriteLogErrorTerminate(Message, -1); } break; } } // Connect on Port Again Sleep(5000); status = RpcServerUseProtseqEp ( // Use TCP/IP protocol. (RPC_WSTR)L"ncacn_ip_tcp", // Backlog queue length for TCP/IP. RPC_C_PROTSEQ_MAX_REQS_DEFAULT, // TCP/IP port to use. (RPC_WSTR)ServerSettings.KMSPort, // No security. NULL ); } else { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"RpcServerUseProtseqEp failed with code %i.\n", status); ServerWriteLogErrorTerminate(Message, status); } } // Registers the KMSServer interface. status = RpcServerRegisterIfEx ( // Interface to register. KMSServer_v1_0_s_ifspec, // Use the MIDL generated entry-point vector. NULL, // Use the MIDL generated entry-point vector. NULL, // Interface Registration Flags RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH | RPC_IF_AUTOLISTEN, // Maximum Calls RPC_C_LISTEN_MAX_CALLS_DEFAULT, // No Security Callback Function NULL ); if (status) { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"RpcServerRegisterIfEx failed with code %i.\n", status); ServerWriteLogErrorTerminate(Message, status); } ServerWriteLogInformation(L"\nKMS Server Emulator started successfully.\n"); // Start to listen for remote procedure calls for all registered interfaces. // This call will not return until RpcMgmtStopServerListening is called or the program is exited. status = RpcServerListen ( // Recommended minimum number of threads. 1, // Recommended maximum number of threads. RPC_C_LISTEN_MAX_CALLS_DEFAULT, // Start listening now. 0 ); if (status) { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"RpcServerListen failed with code %i.\n", status); ServerWriteLogErrorTerminate(Message, status); } } // Stop RPC Connection void StopKMSServer() { RpcMgmtStopServerListening(NULL); RpcServerUnregisterIf(NULL, NULL, FALSE); } #pragma endregion #pragma region RPC Interface Functions // RPC Function to Build and Send a KMS Server Response. int ActivationResponse(handle_t IDL_handle, int requestSize, unsigned char *request, int *responseSize, unsigned char **response) { // No Unreferenced Parameter Warnings UNREFERENCED_PARAMETER(IDL_handle); // Verify Request Size if (requestSize < 92) { return RPC_S_INVALID_ENDPOINT_FORMAT; } // KMS Protocol Version if (request[2] == 4 && request[0] == 0) { // Send Response to KMS Client *response = CreateResponseV4((REQUEST_V4 *)request, responseSize); // Log Sent Response ServerWriteLogInformation(L"Activation response (KMS V4.0) sent.\n"); // Return to RPC Interface return RPC_S_OK; } else if (request[2] == 5 && request[0] == 0) { // Send Response to KMS Client *response = CreateResponseV5((REQUEST_V5 *)request, responseSize); // Log Sent Response ServerWriteLogInformation(L"Activation response (KMS V5.0) sent.\n"); // Return to RPC Interface return RPC_S_OK; } else if (request[2] == 6 && request[0] == 0) { // Send Response to KMS Client *response = CreateResponseV6((REQUEST_V6 *)request, responseSize); // Log Sent Response ServerWriteLogInformation(L"Activation response (KMS V6.0) sent.\n"); // Return to RPC Interface return RPC_S_OK; } else { // Unsupported Protocol return RPC_S_INVALID_VERS_OPTION; } } #pragma endregion #pragma region KMS Server Response Generation Functions // Create Base KMS Server Response Object and handle KMS PID and HWID. DWORD CreateResponseBase(REQUEST* const Request, PBYTE const Response) { // Generate KMS PID or use Command Argument WCHAR kmsPIDInstance[PID_BUFFER_SIZE] = { 0 }; // Try to Get Application Specific KMS PID and HWID if running as KMS Server Service if (ServerSettings.RunAsService) { GetKMSPID(kmsPIDInstance, Request); } // No Specific KMS PID or not running as KMS Server Service if (!regex_match(kmsPIDInstance, 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})$"))) { if (ServerSettings.GenerateRandomKMSPID) { // Build Random KMS PID CreateKMSPID(kmsPIDInstance, Request); // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"\nKMS PID Generated: %s \n", kmsPIDInstance); ServerWriteLogInformation(Message); } else { // Use Global KMS PID from Settings StringCchCopyW(kmsPIDInstance, PID_BUFFER_SIZE, ServerSettings.KMSPID); } } // Get KMS PID Length DWORD kmsPIDLen = (DWORD)((wcslen(kmsPIDInstance) + 1) * sizeof(WCHAR)); // Current pointer PBYTE current = Response; // Set KMS Protocol Minor Version & Major Version *(PDWORD)current = *(PDWORD)Request; current += sizeof(DWORD); // Set KMS PID Length *(PDWORD)current = kmsPIDLen; current += sizeof(DWORD); // Copy KMS PID memcpy(current, kmsPIDInstance, kmsPIDLen); current += kmsPIDLen; // Copy Client Machine ID memcpy(current, &Request->ClientMachineId, sizeof(GUID)); current += sizeof(GUID); // Copy KMS Client Request Timestamp memcpy(current, &Request->RequestTime, sizeof(FILETIME)); current += sizeof(FILETIME); // Set KMS Client Count Parameter *(PDWORD)current = ServerSettings.CurrentClientCount; current += sizeof(DWORD); // Set KMS Activation Interval Parameter *(PDWORD)current = ServerSettings.VLActivationInterval; current += sizeof(DWORD); // Set KMS Renewal Interval Parameter *(PDWORD)current = ServerSettings.VLRenewalInterval; current += sizeof(DWORD); // Return ResponseBase Size return (DWORD)(current - Response); } // Create Hashed KMS Server Response Data for KMS Protocol Version 4. PBYTE CreateResponseV4(REQUEST_V4* const Request, int* const responseSize) { // Allocate KMS Server Response Buffer BYTE buffer[MAX_RESPONSE_SIZE] = {0}; // Create KMS Server Response Base int size = CreateResponseBase(&Request->RequestBase, buffer); // Create Hash GetHash(size, buffer, buffer + size); // Create Proper Response with Hash *responseSize = size + 16; PBYTE response = (PBYTE)midl_user_allocate(*responseSize); memcpy(response, buffer, *responseSize); // Return Response return response; } // Create Encrypted KMS Server Response Data for KMS Protocol Version 5. PBYTE CreateResponseV5(REQUEST_V5* const Request, int* const responseSize) { // Allocate Response Buffer BYTE buffer[MAX_RESPONSE_SIZE] = {0}; // Current pointer PBYTE current = buffer; // Set KMS Protocol Minor Version & Major Version *(PDWORD)current = *(PDWORD)Request; current += sizeof(DWORD); // Store Response Salt pointer PBYTE ResponseSalt = current; // Copy Response Salt memcpy(current, Request->Salt, 16); current += 16; // AES-128 Decrypt DWORD DecryptSize = sizeof(Request->Salt) + sizeof(Request->RequestBase) + sizeof(Request->Pad); AESDecryptMessage(Request->Salt, Request->Salt, &DecryptSize); // Store Encrypt start pointer PBYTE EncryptStart = current; // Create Response Base Object current += CreateResponseBase(&Request->RequestBase, current); // Random Salt BYTE RandomSalt[16]; // Seed Random Number Generator srand(GetTickCount()); // Generate a Random Salt Key for(int i = 0; i < 16; i++) { RandomSalt[i] = rand() % 256; current[i] = Request->Salt[i] ^ ResponseSalt[i] ^ RandomSalt[i]; } current += 16; // Create Hash GetHashSHA256(16, RandomSalt, current); current += 32; // Encrypted and Unencrypted size (KMS Protocol Major Version (2) + KMS Protocol Minor Version (2) + Salt (16)) DWORD UnencryptedSize = 20; DWORD EncryptedSize = (DWORD)(current - EncryptStart); // AES-128 Encrypt AESEncryptMessage(ResponseSalt, EncryptStart, &EncryptedSize, MAX_RESPONSE_SIZE - UnencryptedSize); // Make proper response with correct size *responseSize = EncryptedSize + UnencryptedSize; PBYTE response = (PBYTE)midl_user_allocate(*responseSize); memcpy(response, buffer, *responseSize); // Return Response return response; } // Create Encrypted KMS Server Response Data for KMS Protocol Version 6. PBYTE CreateResponseV6(REQUEST_V6* const Request, int* const responseSize) { // 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 Response Buffer BYTE buffer[MAX_RESPONSE_SIZE] = {0}; // Current pointer PBYTE current = buffer; // Set KMS Protocol Minor Version & Major Version *(PDWORD)current = *(PDWORD)Request; current += sizeof(DWORD); // Store Response Salt pointer PBYTE ResponseSalt = current; // Copy Response Salt memcpy(current, Request->Salt, 16); current += 16; // AES-128 Decrypt DWORD DecryptSize = sizeof(Request->Salt) + sizeof(Request->RequestBase) + sizeof(Request->Pad); // Modded AES-CBC Decrypt AesInit(AES_TYPE_128, AES_MODE_CBC, 0x04, AES_V6_KEY, Request->Salt); DecryptMessage(DecryptSize, Request->Salt); AesClear(); // Store Encrypt start pointer PBYTE EncryptStart = current; // Create Response Base Object current += CreateResponseBase(&Request->RequestBase, current); // Random Salt BYTE RandomSalt[16]; // Seed Random Number Generator srand(GetTickCount()); // Generate a Random Salt Key for(int i = 0; i < 16; i++) { RandomSalt[i] = rand() % 256; current[i] = Request->Salt[i] ^ ResponseSalt[i] ^ RandomSalt[i]; } current += 16; // Create Hash GetHashSHA256(16, RandomSalt, current); current += 32; #pragma region KMS HWID // Try to Get Application Specific KMS HWID if running as KMS Server Service QWORD kmsHWIDInstance = 0x0; if (ServerSettings.RunAsService) { GetKMSHWID(&kmsHWIDInstance, &Request->RequestBase); } // No Specific KMS HWID or not running as KMS Server Service if (kmsHWIDInstance == 0x0) { // Use Global KMS PID from Settings kmsHWIDInstance = ServerSettings.KMSHWID; } // Machine Hardware Hash *(PQWORD) current = kmsHWIDInstance; current += 8; #pragma endregion // HMAC message buffer BYTE Hmac_msg[256]; // Xor2 and Hmac_msg for(int i = 0; i < 16; i++) { Hmac_msg[i] = current[i] = Request->Salt[i] ^ ResponseSalt[i]; } current += 16; // HMAC size DWORD Hmac_size = current - EncryptStart; memcpy(Hmac_msg + 16, EncryptStart, Hmac_size); Hmac_size += 16; // HMAC-SHA256 BYTE Hmac_hash[32]; GetHmacKey(&Request->RequestBase.RequestTime, Hmac_keyblob.rgbKeyData); GetHmacSHA256(Hmac_size, Hmac_msg, Hmac_hash); memcpy(current, Hmac_hash + 16, 16); current += 16; // Encrypted and Unencrypted size (KMS Protocol Major Version (2) + KMS Protocol Minor Version (2) + Salt (16)) DWORD EncryptSize = (DWORD)(current - EncryptStart); // PKCS5 Padding BYTE bPadding =(~EncryptSize + 1) & 0x0f; if(bPadding == 0){ bPadding = 16; } memset(current, bPadding, bPadding); EncryptSize += bPadding; // Modded AES-CBC Encrypt AesInit(AES_TYPE_128, AES_MODE_CBC, bPadding, AES_V6_KEY, ResponseSalt); EncryptMessage(EncryptSize, EncryptStart); AesClear(); // Make proper response with correct size *responseSize = EncryptSize + 20; PBYTE response = (PBYTE)midl_user_allocate(*responseSize); memcpy(response, buffer, *responseSize); // Return Response return response; } #pragma endregion #pragma region Parameter Validation Functions // Validate KMS Port Parameter void ServerValidateKMSPort(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); ServerWriteLogErrorTerminate(Message, -1); } else { // Apply Setting StringCchCopyW(ServerSettings.KMSPort, PORT_BUFFER_SIZE, KMSPort); // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"KMS Port: %s \n", KMSPort); ServerWriteLogInformation(Message); } } else { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Invalid KMS Port! %s is not a valid argument.\n", KMSPort); ServerWriteLogErrorTerminate(Message, -1); } } } // Validate KMS PID Parameter void ServerValidateKMSPID(WCHAR* KMSPID) { // Check if KMS PID should be Random if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSPID, -1, L"RandomKMSPID", -1) == CSTR_EQUAL) { ServerSettings.GenerateRandomKMSPID = true; } // Check if KMS PID is Valid else if (regex_match(KMSPID, 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})$"))) { // Apply Setting StringCchCopyW(ServerSettings.KMSPID, PID_BUFFER_SIZE, KMSPID); // Disable Random KMSPID Generation ServerSettings.GenerateRandomKMSPID = false; // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"KMS PID: %s \n", KMSPID); ServerWriteLogInformation(Message); } else { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Invalid KMS PID! %s is not a valid argument.\n", KMSPID); ServerWriteLogErrorTerminate(Message, -1); } } // Validate KMS HWID Parameter void ServerValidateKMSHWID(WCHAR* KMSHWID) { // Check if the KMS Port is not the Default if (CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, KMSHWID, -1, L"DefaultKMSHWID", -1) != CSTR_EQUAL) { // Check if KMS HWID is Valid Hex String if (regex_match(KMSHWID, wregex(L"^[a-fA-F0-9]{16}$"))) { // Apply Setting ServerSettings.KMSHWID = wcstoull(KMSHWID, NULL, 16); // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"KMS HWID: %s \n", KMSHWID); ServerWriteLogInformation(Message); } else { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Invalid KMS Hardware ID! %s is not a valid argument.\n", KMSHWID); ServerWriteLogErrorTerminate(Message, -1); } } } // Validate KMS Activation Interval Parameter void ServerValidateVLActivationInterval(int VLActivationInterval) { // Check if KMS Activation Interval is Valid Range if (VLActivationInterval < 15 || VLActivationInterval > 43200) { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Invalid KMS Activation Interval Range! %i is not a valid argument.\n", VLActivationInterval); ServerWriteLogErrorTerminate(Message, -1); } else { // Apply Setting ServerSettings.VLActivationInterval = VLActivationInterval; // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"KMS Activation Interval: %i minutes \n", VLActivationInterval); ServerWriteLogInformation(Message); } } // Validate KMS Activation Interval Parameter void ServerValidateVLRenewalInterval(int VLRenewalInterval) { // Check if KMS Renewal Interval is Valid Range if (VLRenewalInterval < 15 || VLRenewalInterval > 43200) { // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"Invalid KMS Renewal Interval Range! %i is not a valid argument.\n", VLRenewalInterval); ServerWriteLogErrorTerminate(Message, -1); } else { // Apply Setting ServerSettings.VLRenewalInterval = VLRenewalInterval; // Format Log Message WCHAR Message[256]; swprintf_s(Message, 256, L"KMS Renewal Interval: %i minutes \n", VLRenewalInterval); ServerWriteLogInformation(Message); } } #pragma endregion #pragma region Logging Functions // Log an informational message to the Console or Windows Application Event Log. void ServerWriteLogInformation(WCHAR* const Message) { // Log Message Buffer WCHAR logMessage[256]; // Write Log Message to Buffer StringCbPrintfW(logMessage, 256, Message); // Choose Log Source if (ServerSettings.RunAsService) { // Output to Windows Event Log: Qualifiers: 16384, EventId: 12290 ServerWriteEventLogEntry(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 ServerWriteLogError(WCHAR* const Message) { // Log Message Buffer WCHAR logMessage[256]; // Write Log Message to Buffer StringCbPrintfW(logMessage, 256, Message); // Choose Log Source if (ServerSettings.RunAsService) { // Output to Windows Event Log: Qualifiers: 16384, EventId: 902 ServerWriteEventLogEntry(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 ServerWriteLogErrorTerminate(WCHAR* const Message, int ExitCode) { // Call ServerWriteLogError ServerWriteLogError(Message); if (!ServerSettings.RunAsService) { // Exit Program exit(ExitCode); } else { // Exit Service ServerServiceStatus.dwCurrentState = SERVICE_STOPPED; ServerServiceStatus.dwWin32ExitCode = ExitCode; SetServiceStatus(ServerServiceHandle, &ServerServiceStatus); } } // Log a message to the Windows Application Event Log. void ServerWriteEventLogEntry(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