834 lines
26 KiB
C++
834 lines
26 KiB
C++
// Includes and Namespaces
|
|
#include <regex>
|
|
#include <iostream>
|
|
#include <stdio.h>
|
|
#include <string>
|
|
#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 |