Kms sources from google.init.
This commit is contained in:
1 parent
47778e32f0
commit
4e22666689
58 files changed
+6752
No files matched your search
@@ -0,0 +1,949 @@
|
||||
// Includes and Namespaces
|
||||
#include <regex>
|
||||
#include <iostream>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#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
|
||||
Reference in new issue
Block a user