You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
vlmcsd/src/kms.h

411 lines
10 KiB
C

#ifndef __kms_h
#define __kms_h
#ifndef CONFIG
#define CONFIG "config.h"
#endif // CONFIG
#include CONFIG
#if _MSC_VER
//#include <time.h>
#else
#include <sys/time.h>
#endif // _MSC_VER
//#include <stdlib.h>
#include "types.h"
//
// REQUEST... types are actually fixed size
// RESPONSE... size may vary, defined here is max possible size
//
#define MAX_RESPONSE_SIZE 384
#define PID_BUFFER_SIZE 64
#define MAX_REQUEST_SIZE sizeof(REQUEST_V6)
#define WORKSTATION_NAME_BUFFER 64
// Constants for V6 time stamp interval
#define TIME_C1 0x00000022816889BDULL
#define TIME_C2 0x000000208CBAB5EDULL
#define TIME_C3 0x3156CD5AC628477AULL
#define VERSION_INFO union \
{ \
DWORD Version;\
struct { \
WORD MinorVer; \
WORD MajorVer; \
} /*__packed*/; \
} /*__packed*/
// Aliases for various KMS struct members
#define IsClientVM VMInfo
#define GraceTime BindingExpiration
#define MinutesRemaingInCurrentStatus BindingExpiration
#define ID ActID
#define ApplicationID AppID
#define SkuId ActID
#define KmsId KMSID
#define ClientMachineId CMID
#define MinimumClients N_Policy
#define TimeStamp ClientTime
#define PreviousCLientMachineId CMID_prev
#define Salt IV
#define XorSalt XoredIVs
#define ActivationInterval VLActivationInterval
#define RenewalInterval VLRenewalInterval
#define MAX_CLIENTS 671
typedef struct
{
GUID Guid[MAX_CLIENTS];
int_fast16_t CurrentCount;
int_fast16_t MaxCount;
int_fast16_t CurrentPosition;
} ClientList_t, *PClientList_t;
typedef struct {
VERSION_INFO;
DWORD VMInfo; // 0 = client is bare metal / 1 = client is VM
DWORD LicenseStatus; // 0 = Unlicensed, 1 = Licensed (Activated), 2 = OOB grace, 3 = OOT grace, 4 = NonGenuineGrace, 5 = Notification, 6 = extended grace
DWORD BindingExpiration; // Expiration of the current status in minutes (e.g. when KMS activation or OOB grace expires).
GUID AppID; // Can currently be Windows, Office2010 or Office2013 (see kms.c, table AppList).
GUID ActID; // Most detailed product list. One product key per ActID (see kms.c, table ExtendedProductList). Is ignored by KMS server.
GUID KMSID; // This is actually what the KMS server uses to grant or refuse activation (see kms.c, table BasicProductList).
GUID CMID; // Client machine id. Used by the KMS server for counting minimum clients.
DWORD N_Policy; // Minimum clients required for activation.
FILETIME ClientTime; // Current client time.
GUID CMID_prev; // previous client machine id. All zeros, if it never changed.
WCHAR WorkstationName[64]; // Workstation name. FQDN if available, NetBIOS otherwise.
} /*__packed*/ REQUEST;
typedef struct {
VERSION_INFO;
DWORD PIDSize; // Size of PIDData in bytes.
WCHAR KmsPID[PID_BUFFER_SIZE]; // ePID (must include terminating zero)
GUID CMID; // Client machine id. Must be the same as in request.
FILETIME ClientTime; // Current client time. Must be the same as in request.
DWORD Count; // Current activated machines. KMS server counts up to N_Policy << 1 then stops
DWORD VLActivationInterval; // Time in minutes when clients should retry activation if it was unsuccessful (default 2 hours)
DWORD VLRenewalInterval; // Time in minutes when clients should renew KMS activation (default 7 days)
} /*__packed*/ RESPONSE;
#ifdef _DEBUG
typedef struct {
VERSION_INFO;
DWORD PIDSize;
WCHAR KmsPID[49]; // Set this to the ePID length you want to debug
GUID CMID;
FILETIME ClientTime;
DWORD Count;
DWORD VLActivationInterval;
DWORD VLRenewalInterval;
} __packed RESPONSE_DEBUG;
#endif
typedef struct {
REQUEST RequestBase; // Base request
BYTE MAC[16]; // Aes 160 bit CMAC
} /*__packed*/ REQUEST_V4;
typedef struct {
RESPONSE ResponseBase; // Base response
BYTE MAC[16]; // Aes 160 bit CMAC
} /*__packed*/ RESPONSE_V4;
typedef struct {
VERSION_INFO; // unencrypted version info
BYTE IV[16]; // IV
REQUEST RequestBase; // Base Request
BYTE Pad[4]; // since this struct is fixed, we use fixed PKCS pad bytes
} /*__packed*/ REQUEST_V5;
typedef REQUEST_V5 REQUEST_V6; // v5 and v6 requests are identical
typedef struct {
VERSION_INFO;
BYTE IV[16];
RESPONSE ResponseBase;
BYTE RandomXoredIVs[16]; // If RequestIV was used for decryption: Random ^ decrypted Request IV ^ ResponseIV. If NULL IV was used for decryption: Random ^ decrypted Request IV
BYTE Hash[32]; // SHA256 of Random used in RandomXoredIVs
BYTE HwId[8]; // HwId from the KMS server
BYTE XoredIVs[16]; // If RequestIV was used for decryption: decrypted Request IV ^ ResponseIV. If NULL IV was used for decryption: decrypted Request IV.
BYTE HMAC[16]; // V6 Hmac (low 16 bytes only), see kms.c CreateV6Hmac
//BYTE Pad[10]; // Pad is variable sized. So do not include in struct
} /*__packed*/ RESPONSE_V6;
typedef struct { // not used except for sizeof(). Fields are the same as RESPONSE_V6
VERSION_INFO;
BYTE IV[16];
RESPONSE ResponseBase;
BYTE RandomXoredIVs[16];
BYTE Hash[32];
} /*__packed*/ RESPONSE_V5;
#ifdef _DEBUG
typedef struct { // Debug structure for direct casting of RPC data in debugger
VERSION_INFO;
BYTE IV[16];
RESPONSE_DEBUG ResponseBase;
BYTE RandomXoredIVs[16];
BYTE MAC[32];
BYTE Unknown[8];
BYTE XorSalts[16];
BYTE HMAC[16];
BYTE Pad[16];
} __packed RESPONSE_V6_DEBUG;
#endif
#define V4_PRE_EPID_SIZE ( \
sizeof(((RESPONSE*)0)->Version) + \
sizeof(((RESPONSE*)0)->PIDSize) \
)
#define V4_POST_EPID_SIZE ( \
sizeof(((RESPONSE*)0)->CMID) + \
sizeof(((RESPONSE*)0)->ClientTime) + \
sizeof(((RESPONSE*)0)->Count) + \
sizeof(((RESPONSE*)0)->VLActivationInterval) + \
sizeof(((RESPONSE*)0)->VLRenewalInterval) \
)
#define V6_DECRYPT_SIZE ( \
sizeof(((REQUEST_V6*)0)->IV) + \
sizeof(((REQUEST_V6*)0)->RequestBase) + \
sizeof(((REQUEST_V6*)0)->Pad) \
)
#define V6_UNENCRYPTED_SIZE ( \
sizeof(((RESPONSE_V6*)0)->Version) + \
sizeof(((RESPONSE_V6*)0)->IV) \
)
#define V6_PRE_EPID_SIZE ( \
V6_UNENCRYPTED_SIZE + \
sizeof(((RESPONSE*)0)->Version) + \
sizeof(((RESPONSE*)0)->PIDSize) \
)
#define V5_POST_EPID_SIZE ( \
V4_POST_EPID_SIZE + \
sizeof(((RESPONSE_V6*)0)->RandomXoredIVs) + \
sizeof(((RESPONSE_V6*)0)->Hash) \
)
#define V6_POST_EPID_SIZE ( \
V5_POST_EPID_SIZE + \
sizeof(((RESPONSE_V6*)0)->HwId) + \
sizeof(((RESPONSE_V6*)0)->XoredIVs) + \
sizeof(((RESPONSE_V6*)0)->HMAC) \
)
#define RESPONSE_RESULT_OK ((1 << 10) - 1) //(9 bits)
typedef union
{
DWORD mask;
struct
{
BOOL HashOK : 1;
BOOL TimeStampOK : 1;
BOOL ClientMachineIDOK : 1;
BOOL VersionOK : 1;
BOOL IVsOK : 1;
BOOL DecryptSuccess : 1;
BOOL HmacSha256OK : 1;
BOOL PidLengthOK : 1;
BOOL RpcOK : 1;
BOOL IVnotSuspicious : 1;
BOOL reserved3 : 1;
BOOL reserved4 : 1;
BOOL reserved5 : 1;
BOOL reserved6 : 1;
uint32_t effectiveResponseSize : 9;
uint32_t correctResponseSize : 9;
};
} RESPONSE_RESULT;
typedef BYTE hwid_t[8];
typedef enum
{
None = 0,
UseNdr64 = 1 << 0,
UseForEpid = 1 << 1,
MayBeServer = 1 << 2,
} HostBuildFlag;
typedef struct CsvlkData
{
union
{
uint64_t EPidOffset;
char* EPid;
};
int64_t ReleaseDate;
uint32_t GroupId;
uint32_t MinKeyId;
uint32_t MaxKeyId;
uint8_t MinActiveClients;
uint8_t Reserved[3];
} CsvlkData_t, *PCsvlkData_t;
typedef struct VlmcsdData
{
union
{
GUID Guid;
uint8_t GuidBytes[16];
};
union
{
uint64_t NameOffset;
char* Name;
};
uint8_t AppIndex;
uint8_t KmsIndex;
uint8_t ProtocolVersion;
uint8_t NCountPolicy;
uint8_t IsRetail;
uint8_t IsPreview;
uint8_t EPidIndex;
uint8_t reserved;
} VlmcsdData_t, *PVlmcsdData_t;
typedef struct
{
union
{
uint64_t Offset;
void* Pointer;
};
} DataPointer_t;
#define KMS_OPTIONS_USENDR64 1 << 0
typedef struct HostBuild
{
union
{
uint64_t DisplayNameOffset;
char* DisplayName;
};
int64_t ReleaseDate;
int32_t BuildNumber;
int32_t PlatformId;
HostBuildFlag Flags;
uint8_t reserved[4];
} HostBuild_t, *PHostBuild_t;
typedef struct VlmcsdHeader
{
BYTE Magic[4];
VERSION_INFO;
uint8_t CsvlkCount;
uint8_t Flags;
uint8_t Reserved[2];
union
{
int32_t Counts[5];
struct
{
int32_t AppItemCount;
int32_t KmsItemCount;
int32_t SkuItemCount;
int32_t HostBuildCount;
int32_t reserved2Counts;
};
};
union
{
DataPointer_t Datapointers[5];
struct
{
union
{
uint64_t AppItemOffset;
PVlmcsdData_t AppItemList;
};
union
{
uint64_t KmsItemOffset;
PVlmcsdData_t KmsItemList;
};
union
{
uint64_t SkuItemOffset;
PVlmcsdData_t SkuItemList;
};
union
{
uint64_t HostBuildOffset;
PHostBuild_t HostBuildList;
};
union
{
uint64_t Reserved2Offset;
void* Reserved2List;
};
CsvlkData_t CsvlkData[1];
};
};
} VlmcsdHeader_t, *PVlmcsdHeader_t;
//#define EPID_INDEX_WINDOWS 0
//#define EPID_INDEX_OFFICE2010 1
//#define EPID_INDEX_OFFICE2013 2
//#define EPID_INDEX_OFFICE2016 3
//#define EPID_INDEX_WINCHINAGOV 4
typedef HRESULT(__stdcall *RequestCallback_t)(REQUEST* baseRequest, RESPONSE *const baseResponse, BYTE *const hwId, const char* const ipstr);
size_t CreateResponseV4(REQUEST_V4 *const Request, BYTE *const response_data, const char* const ipstr);
size_t CreateResponseV6(REQUEST_V6 *restrict Request, BYTE *const response_data, const char* const ipstr);
BYTE *CreateRequestV4(size_t *size, const REQUEST* requestBase);
BYTE *CreateRequestV6(size_t *size, const REQUEST* requestBase);
void randomPidInit();
void get16RandomBytes(void* ptr);
RESPONSE_RESULT DecryptResponseV6(RESPONSE_V6* response_v6, int responseSize, BYTE* const response, const BYTE* const rawRequest, BYTE* hwid);
RESPONSE_RESULT DecryptResponseV4(RESPONSE_V4* response_v4, const int responseSize, BYTE* const rawResponse, const BYTE* const rawRequest);
void getUnixTimeAsFileTime(FILETIME* ts);
__pure int64_t fileTimeToUnixTime(FILETIME* ts);
#ifndef IS_LIBRARY
int32_t getProductIndex(const GUID* guid, const PVlmcsdData_t list, const int32_t count, char** name, char** ePid);
#if !defined(NO_INI_FILE)||!defined(NO_VERBOSE_LOG)
const char* getNextString(const char* s);
#endif // !defined(NO_INI_FILE)||!defined(NO_VERBOSE_LOG)
#endif // IS_LIBRARY
#ifndef NO_STRICT_MODES
void InitializeClientLists();
void CleanUpClientLists();
#endif // !NO_STRICT_MODES
extern RequestCallback_t CreateResponseBase;
#ifdef _PEDANTIC
uint16_t IsValidLcid(const uint16_t lcid);
uint32_t IsValidHostBuild(const int32_t hostBuild);
#endif // _PEDANTIC
#endif // __kms_h