2 #define CONFIG "config.h"
17 #include <sys/types.h>
21 #include <sys/ioctl.h>
26 #include "shared_globals.h"
32 #include "msrpc-client.h"
39 #define VLMCS_OPTION_GRAB_INI 1
40 #define VLMCS_OPTION_NO_GRAB_INI 2
42 #define kmsVersionMinor 0 // Currently constant. May change in future KMS versions
44 // Function Prototypes
45 static void CreateRequestBase(REQUEST
*Request
);
49 static int_fast8_t verbose
= FALSE
;
50 static int_fast8_t VMInfo
= FALSE
;
51 static int_fast8_t dnsnames
= TRUE
;
52 static int FixedRequests
= 0;
53 static BYTE LicenseStatus
= 0x02;
54 static const char *CMID
= NULL
;
55 static const char *CMID_prev
= NULL
;
56 static const char *WorkstationName
= NULL
;
57 static int BindingExpiration
= 43200; //30 days
58 static const char *RemoteAddr
;
59 static int_fast8_t ReconnectForEachRequest
= FALSE
;
60 static int AddressFamily
= AF_UNSPEC
;
61 static int_fast8_t incompatibleOptions
= 0;
62 static const char* fn_ini_client
= NULL
;
65 static int_fast8_t NoSrvRecordPriority
= FALSE
;
69 // Structure for handling "License Packs" (e.g. Office2013v5 or WindowsVista)
72 const char *names
; //This is a list of strings. Terminate with additional Zero!!!
81 typedef char iniFileEpidLines
[3][256];
83 // Well known "license packs"
84 static const LicensePack LicensePackList
[] =
86 // List of names min lics version appID skuId KMSCountedID
87 /* 000 */ { "Vista\000W6\000"
89 "Windows\000", 25, 4, PWINGUID
, { 0x4f3d1606, 0x3fea, 0x4c01, { 0xbe, 0x3c, 0x8d, 0x67, 0x1c, 0x40, 0x1e, 0x3b, } }, { 0x212a64dc, 0x43b1, 0x4d3d, { 0xa3, 0x0c, 0x2f, 0xc6, 0x9d, 0x20, 0x95, 0xc6 } } },
90 /* 001 */ { "W7\000Windows7\000", 25, 4, PWINGUID
, { 0xb92e9980, 0xb9d5, 0x4821, { 0x9c, 0x94, 0x14, 0x0f, 0x63, 0x2f, 0x63, 0x12, } }, { 0x7fde5219, 0xfbfa, 0x484a, { 0x82, 0xc9, 0x34, 0xd1, 0xad, 0x53, 0xe8, 0x56 } } },
91 /* 002 */ { "W8\000Windows8\000", 25, 5, PWINGUID
, { 0xa98bcd6d, 0x5343, 0x4603, { 0x8a, 0xfe, 0x59, 0x08, 0xe4, 0x61, 0x11, 0x12, } }, { 0x3c40b358, 0x5948, 0x45af, { 0x92, 0x3b, 0x53, 0xd2, 0x1f, 0xcc, 0x7e, 0x79 } } },
92 /* 003 */ { "W8C\000Windows8C\000", 25, 5, PWINGUID
, { 0xc04ed6bf, 0x55c8, 0x4b47, { 0x9f, 0x8e, 0x5a, 0x1f, 0x31, 0xce, 0xee, 0x60, } }, { 0xbbb97b3b, 0x8ca4, 0x4a28, { 0x97, 0x17, 0x89, 0xfa, 0xbd, 0x42, 0xc4, 0xac } } },
93 /* 004 */ { "W81\000Windows81\000", 25, 6, PWINGUID
, { 0xc06b6981, 0xd7fd, 0x4a35, { 0xb7, 0xb4, 0x05, 0x47, 0x42, 0xb7, 0xaf, 0x67, } }, { 0xcb8fc780, 0x2c05, 0x495a, { 0x97, 0x10, 0x85, 0xaf, 0xff, 0xc9, 0x04, 0xd7 } } },
94 /* 005 */ { "W81C\000Windows81C\000", 25, 6, PWINGUID
, { 0xfe1c3238, 0x432a, 0x43a1, { 0x8e, 0x25, 0x97, 0xe7, 0xd1, 0xef, 0x10, 0xf3, } }, { 0x6d646890, 0x3606, 0x461a, { 0x86, 0xab, 0x59, 0x8b, 0xb8, 0x4a, 0xce, 0x82 } } },
95 /* 006 */ { "W10\000Windows10\000", 25, 6, PWINGUID
, { 0x73111121, 0x5638, 0x40f6, { 0xbc, 0x11, 0xf1, 0xd7, 0xb0, 0xd6, 0x43, 0x00, } }, { 0x58e2134f, 0x8e11, 0x4d17, { 0x9c, 0xb2, 0x91, 0x06, 0x9c, 0x15, 0x11, 0x48 } } },
96 /* 007 */ { "W10C\000Windows10C\000", 25, 6, PWINGUID
, { 0x58e97c99, 0xf377, 0x4ef1, { 0x81, 0xd5, 0x4a, 0xd5, 0x52, 0x2b, 0x5f, 0xd8, } }, { 0xe1c51358, 0xfe3e, 0x4203, { 0xa4, 0xa2, 0x3b, 0x6b, 0x20, 0xc9, 0x73, 0x4e } } },
97 /* 008 */ { "2008" "\0" "2008A\000", 5, 4, PWINGUID
, { 0xddfa9f7c, 0xf09e, 0x40b9, { 0x8c, 0x1a, 0xbe, 0x87, 0x7a, 0x9a, 0x7f, 0x4b, } }, { 0x33e156e4, 0xb76f, 0x4a52, { 0x9f, 0x91, 0xf6, 0x41, 0xdd, 0x95, 0xac, 0x48 } } },
98 /* 009 */ { "2008B\000", 5, 4, PWINGUID
, { 0xc1af4d90, 0xd1bc, 0x44ca, { 0x85, 0xd4, 0x00, 0x3b, 0xa3, 0x3d, 0xb3, 0xb9, } }, { 0x8fe53387, 0x3087, 0x4447, { 0x89, 0x85, 0xf7, 0x51, 0x32, 0x21, 0x5a, 0xc9 } } },
99 /* 010 */ { "2008C\000", 5, 4, PWINGUID
, { 0x68b6e220, 0xcf09, 0x466b, { 0x92, 0xd3, 0x45, 0xcd, 0x96, 0x4b, 0x95, 0x09, } }, { 0x8a21fdf3, 0xcbc5, 0x44eb, { 0x83, 0xf3, 0xfe, 0x28, 0x4e, 0x66, 0x80, 0xa7 } } },
100 /* 011 */ { "2008R2" "\0" "2008R2A\000", 5, 4, PWINGUID
, { 0xa78b8bd9, 0x8017, 0x4df5, { 0xb8, 0x6a, 0x09, 0xf7, 0x56, 0xaf, 0xfa, 0x7c, } }, { 0x0fc6ccaf, 0xff0e, 0x4fae, { 0x9d, 0x08, 0x43, 0x70, 0x78, 0x5b, 0xf7, 0xed } } },
101 /* 012 */ { "2008R2B\000", 5, 4, PWINGUID
, { 0x620e2b3d, 0x09e7, 0x42fd, { 0x80, 0x2a, 0x17, 0xa1, 0x36, 0x52, 0xfe, 0x7a, } }, { 0xca87f5b6, 0xcd46, 0x40c0, { 0xb0, 0x6d, 0x8e, 0xcd, 0x57, 0xa4, 0x37, 0x3f } } },
102 /* 013 */ { "2008R2C\000", 5, 4, PWINGUID
, { 0x7482e61b, 0xc589, 0x4b7f, { 0x8e, 0xcc, 0x46, 0xd4, 0x55, 0xac, 0x3b, 0x87, } }, { 0xb2ca2689, 0xa9a8, 0x42d7, { 0x93, 0x8d, 0xcf, 0x8e, 0x9f, 0x20, 0x19, 0x58 } } },
103 /* 014 */ { "2012\000", 5, 5, PWINGUID
, { 0xf0f5ec41, 0x0d55, 0x4732, { 0xaf, 0x02, 0x44, 0x0a, 0x44, 0xa3, 0xcf, 0x0f, } }, { 0x8665cb71, 0x468c, 0x4aa3, { 0xa3, 0x37, 0xcb, 0x9b, 0xc9, 0xd5, 0xea, 0xac } } },
104 /* 015 */ { "2012R2\000" "12R2\000", 5, 6, PWINGUID
, { 0x00091344, 0x1ea4, 0x4f37, { 0xb7, 0x89, 0x01, 0x75, 0x0b, 0xa6, 0x98, 0x8c, } }, { 0x8456EFD3, 0x0C04, 0x4089, { 0x87, 0x40, 0x5b, 0x72, 0x38, 0x53, 0x5a, 0x65 } } },
105 /* 016 */ { "Office2010\000O14\000", 5, 4, POFFICE2010GUID
, { 0x6f327760, 0x8c5c, 0x417c, { 0x9b, 0x61, 0x83, 0x6a, 0x98, 0x28, 0x7e, 0x0c, } }, { 0xe85af946, 0x2e25, 0x47b7, { 0x83, 0xe1, 0xbe, 0xbc, 0xeb, 0xea, 0xc6, 0x11 } } },
106 /* 017 */ { "Office2013\000O15\000", 5, 6, POFFICE2013GUID
, { 0xb322da9c, 0xa2e2, 0x4058, { 0x9e, 0x4e, 0xf5, 0x9a, 0x69, 0x70, 0xbd, 0x69, } }, { 0xe6a6f1bf, 0x9d40, 0x40c3, { 0xaa, 0x9f, 0xc7, 0x7b, 0xa2, 0x15, 0x78, 0xc0 } } },
107 /* 018 */ { "Office2013V5\000", 5, 5, POFFICE2013GUID
, { 0xb322da9c, 0xa2e2, 0x4058, { 0x9e, 0x4e, 0xf5, 0x9a, 0x69, 0x70, 0xbd, 0x69, } }, { 0xe6a6f1bf, 0x9d40, 0x40c3, { 0xaa, 0x9f, 0xc7, 0x7b, 0xa2, 0x15, 0x78, 0xc0 } } },
108 /* 019 */ { "Office2016\000" "O16\000", 5, 6, POFFICE2013GUID
, { 0xd450596f, 0x894d, 0x49e0, { 0x96, 0x6a, 0xfd, 0x39, 0xed, 0x4c, 0x4c, 0x64, } }, { 0x85b5f61b, 0x320b, 0x4be3, { 0x81, 0x4a, 0xb7, 0x6b, 0x2b, 0xfa, 0xfc, 0x82 } } },
109 /* 020 */ { NULL
, 0, 0, NULL
, { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }, { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } }
115 const char* first
[16];
116 const char* second
[16];
121 // Some names for the DNS name random generator
122 static DnsNames ClientDnsNames
=
124 { "www", "ftp", "kms", "hack-me", "smtp", "ns1", "mx1", "ns1", "pop3", "imap", "mail", "dns", "headquarter", "we-love", "_vlmcs._tcp", "ceo-laptop" },
125 { ".microsoft", ".apple", ".amazon", ".samsung", ".adobe", ".google", ".yahoo", ".facebook", ".ubuntu", ".oracle", ".borland", ".htc", ".acer", ".windows", ".linux", ".sony" },
126 { ".com", ".net", ".org", ".cn", ".co.uk", ".de", ".com.tw", ".us", ".fr", ".it", ".me", ".info", ".biz", ".co.jp", ".ua", ".at", ".es", ".pro", ".by", ".ru", ".pl", ".kr" }
130 // This is the one, we are actually using. We use Vista, if user selects nothing
131 LicensePack ActiveLicensePack
;
134 // Request Count Control Variables
135 static int RequestsToGo
= 1;
136 static BOOL firstRequestSent
= FALSE
;
139 static void string2UuidOrExit(const char *const restrict input
, GUID
*const restrict guid
)
141 if (strlen(input
) != GUID_STRING_LENGTH
|| !string2Uuid(input
, guid
))
143 errorout("Fatal: Command line contains an invalid GUID.\n");
151 __noreturn
static void clientUsage(const char* const programName
)
156 "Usage: %s [options] [ <host>[:<port>] | .<domain> | - ] [options]\n\n"
158 "Usage: %s [options] [<host>[:<port>]] [options]\n\n"
165 " -4 Force V4 protocol\n"
166 " -5 Force V5 protocol\n"
167 " -6 Force V6 protocol\n"
169 " -i <IpVersion> Use IP protocol (4 or 6)\n"
171 " -e Show some valid examples\n"
172 " -x Show valid Apps\n"
173 " -d no DNS names, use Netbios names (no effect if -w is used)\n\n"
175 "Advanced options:\n\n"
177 " -a <AppGUID> Use custom Application GUID\n"
178 " -s <ActGUID> Use custom Activation Configuration GUID\n"
179 " -k <KmsGUID> Use custom KMS GUID\n"
180 " -c <ClientGUID> Use custom Client GUID. Default: Use random\n"
181 " -o <PreviousClientGUID> Use custom Prevoius Client GUID. Default: ZeroGUID\n"
182 " -w <Workstation> Use custom workstation name. Default: Use random\n"
183 " -r <RequiredClientCount> Fake required clients\n"
184 " -n <Requests> Fixed # of requests (Default: Enough to charge)\n"
185 " -m Pretend to be a virtual machine\n"
186 " -G <file> Get ePID/HwId data and write to <file>. Can't be used with -l, -4, -5, -6, -a, -s, -k, -r and -n\n"
188 " -T Use a new TCP connection for each request.\n"
189 " -N <0|1> disable or enable NDR64. Default: 1\n"
190 " -B <0|1> disable or enable RPC bind time feature negotiation. Default: 1\n"
192 " -t <LicenseStatus> Use specfic license status (0 <= T <= 6)\n"
193 " -g <BindingExpiration> Use a specfic binding expiration time in minutes. Default 43200\n"
195 " -P Ignore priority and weight in DNS SRV records\n"
198 " -p Don't use multiplexed RPC bind\n"
202 "<port>:\t\tTCP port name of the KMS to use. Default 1688.\n"
203 "<host>:\t\thost name of the KMS to use. Default 127.0.0.1\n"
205 ".<domain>:\tfind KMS server in <domain> via DNS\n"
207 "<app>:\t\t(Type %s -x to see a list of valid apps)\n\n",
208 Version
, programName
, programName
214 __pure
static int getLineWidth(void)
216 #ifdef TERMINAL_FIXED_WIDTH // For Toolchains that to not have winsize
217 return TERMINAL_FIXED_WIDTH
;
218 #else // Can determine width of terminal
223 if(ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &w
))
225 return 80; // Return this if stdout is not a tty
232 CONSOLE_SCREEN_BUFFER_INFO csbiInfo
;
233 HANDLE hStdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
235 if (!GetConsoleScreenBufferInfo(hStdout
, &csbiInfo
))
237 return 80; // Return this if stdout is not a Console
240 return csbiInfo
.srWindow
.Right
- csbiInfo
.srWindow
.Left
;
244 #endif // Can determine width of terminal
248 __noreturn
static void showProducts(PRINTFUNC p
)
250 int cols
= getLineWidth();
256 #if !defined(NO_EXTENDED_PRODUCT_LIST) && !defined(NO_BASIC_PRODUCT_LIST)
261 "can be used with -l:\n\n"
264 const LicensePack
* lp
;
266 itemsPerLine
= cols
/ 20;
267 if (!itemsPerLine
) itemsPerLine
= 1;
269 for (i
= 1, lp
= LicensePackList
; lp
->names
; lp
++)
273 for (name
= lp
->names
; *name
; name
+= strlen(name
) + 1, i
++)
277 if (!(i
% itemsPerLine
)) p("\n");
283 #if !defined(NO_EXTENDED_PRODUCT_LIST) && !defined(NO_BASIC_PRODUCT_LIST)
285 const KmsIdList
* currentProduct
;
286 uint_fast8_t longestString
= 0;
287 uint8_t k
, items
= getExtendedProductListSize();
289 p("You may also use these product names or numbers:\n\n");
291 for (currentProduct
= ExtendedProductList
; currentProduct
->name
; currentProduct
++)
293 uint_fast8_t len
= strlen(currentProduct
->name
);
295 if (len
> longestString
)
299 itemsPerLine
= cols
/ (longestString
+ 10);
300 if (!itemsPerLine
) itemsPerLine
= 1;
301 uint8_t lines
= items
/ itemsPerLine
;
302 if (items
% itemsPerLine
) lines
++;
304 for (i
= 0; i
< lines
; i
++)
306 for (k
= 0; k
< itemsPerLine
; k
++)
309 uint8_t index
= k
* lines
+ i
;
311 if (index
>= items
) break;
313 p("%3u = %s", index
+ 1, ExtendedProductList
[index
].name
);
315 for (j
= 0; j
< longestString
+ 4 - strlen(ExtendedProductList
[index
].name
); j
++)
326 #endif // !defined(NO_EXTENDED_PRODUCT_LIST) && !defined(NO_BASIC_PRODUCT_LIST)
331 __noreturn
static void examples(const char* const programName
)
334 "\nRequest activation for Office2013 using V4 protocol from 192.168.1.5:1688\n"
335 "\t%s -l O15 -4 192.168.1.5\n"
336 "\t%s -l O15 -4 192.168.1.5:1688\n\n"
338 "Request activation for Windows Server 2012 using V4 protocol from localhost:1688\n"
339 "\t%s -4 -l Windows -k 8665cb71-468c-4aa3-a337-cb9bc9d5eaac\n"
341 "\t%s -4 -l 2012 [::1]:1688\n"
342 "\t%s -4 -l 12 127.0.0.2:1688\n\n"
344 "Send 100,000 requests to localhost:1688\n"
345 "\t%s -n 100000 -l Office2010\n\n"
347 "Request Activation for Windows 8 from 10.0.0.1:4711 and pretend to be Steve Ballmer\n"
348 "\t%s -l Windows8 -w steveb1.redmond.microsoft.com 10.0.0.1:4711\n\n",
349 programName
, programName
, programName
, programName
, programName
, programName
, programName
, programName
359 __noreturn
static void clientUsage(const char* const programName
)
361 errorout("Incorrect parameter specified.\n");
369 static BOOL
findLicensePackByName(const char* const name
, LicensePack
* const lp
)
371 // Try to find a package in the short list first
373 LicensePack
*licensePack
;
374 for (licensePack
= (LicensePack
*)&LicensePackList
; licensePack
->names
; licensePack
++)
376 const char *currentName
;
377 for (currentName
= licensePack
->names
; *currentName
; currentName
+= strlen(currentName
) + 1)
379 if (!strcasecmp(name
, currentName
))
387 #if defined(NO_BASIC_PRODUCT_LIST) || defined(NO_EXTENDED_PRODUCT_LIST)
391 #else // Both Lists are available
393 // search extended product list
395 uint8_t items
= getExtendedProductListSize();
398 if (stringToInt(name
, 1, items
, &index
))
404 for (index
= 0; index
< items
; index
++)
406 if (!strcasecmp(ExtendedProductList
[index
].name
, name
)) break;
409 if (index
>= items
) return FALSE
;
412 lp
->AppID
= &AppList
[ExtendedProductList
[index
].AppIndex
].guid
;
413 lp
->KMSID
= ProductList
[ExtendedProductList
[index
].KmsIndex
].guid
;
414 lp
->ActID
= ExtendedProductList
[index
].guid
;
415 lp
->N_Policy
= ProductList
[ExtendedProductList
[index
].KmsIndex
].KMS_PARAM_REQUIREDCOUNT
;
416 lp
->kmsVersionMajor
= ProductList
[ExtendedProductList
[index
].KmsIndex
].KMS_PARAM_MAJOR
;
420 #endif // Both Lists are available
423 static const char* const client_optstring
= "+N:B:i:l:a:s:k:c:w:r:n:t:g:G:o:pPTv456mexd";
426 //First pass. We handle only "-l". Since -a -k -s -4 -5 and -6 are exceptions to -l, we process -l first
427 static void parseCommandLinePass1(const int argc
, CARGV argv
)
432 for (opterr
= 0; ( o
= getopt(argc
, (char* const*)argv
, client_optstring
) ) > 0; ) switch (o
)
434 case 'l': // Set "License Pack" and protocol version (e.g. Windows8, Office2013v5, ...)
436 if (!findLicensePackByName(optarg
, &ActiveLicensePack
))
438 errorout("Invalid client application. \"%s\" is not valid for -l.\n\n", optarg
);
440 showProducts(&errorout
);
452 // Second Pass. Handle all options except "-l"
453 static void parseCommandLinePass2(const char *const programName
, const int argc
, CARGV argv
)
458 for (opterr
= 0; ( o
= getopt(argc
, (char* const*)argv
, client_optstring
) ) > 0; ) switch (o
)
462 case 'e': // Show examples
464 examples(programName
);
467 case 'x': // Show Apps
469 showProducts(&printf
);
478 NoSrvRecordPriority
= TRUE
;
485 incompatibleOptions
|= VLMCS_OPTION_GRAB_INI
;
486 fn_ini_client
= optarg
;
492 if (!getArgumentBool(&UseRpcNDR64
, optarg
)) clientUsage(programName
);
496 if (!getArgumentBool(&UseRpcBTFN
, optarg
)) clientUsage(programName
);
501 switch(getOptionArgumentInt(o
, 4, 6))
504 AddressFamily
= AF_INET
;
507 AddressFamily
= AF_INET6
;
510 errorout("IPv5 does not exist.\n");
517 case 'p': // Multiplexed RPC
519 UseMultiplexedRpc
= FALSE
;
524 case 'n': // Fixed number of Requests (regardless, whether they are required)
526 incompatibleOptions
|= VLMCS_OPTION_NO_GRAB_INI
;
527 FixedRequests
= getOptionArgumentInt(o
, 1, INT_MAX
);
530 case 'r': // Fake minimum required client count
532 incompatibleOptions
|= VLMCS_OPTION_NO_GRAB_INI
;
533 ActiveLicensePack
.N_Policy
= getOptionArgumentInt(o
, 1, INT_MAX
);
536 case 'c': // use a specific client GUID
538 // If using a constant Client ID, send only one request unless /N= explicitly specified
539 if (!FixedRequests
) FixedRequests
= 1;
544 case 'o': // use a specific previous client GUID
549 case 'a': // Set specific App Id
551 incompatibleOptions
|= VLMCS_OPTION_NO_GRAB_INI
;
552 ActiveLicensePack
.AppID
= (GUID
*)vlmcsd_malloc(sizeof(GUID
));
554 string2UuidOrExit(optarg
, (GUID
*)ActiveLicensePack
.AppID
);
557 case 'g': // Set custom "grace" time in minutes (default 30 days)
559 BindingExpiration
= getOptionArgumentInt(o
, 0, INT_MAX
);
562 case 's': // Set specfic SKU ID
564 incompatibleOptions
|= VLMCS_OPTION_NO_GRAB_INI
;
565 string2UuidOrExit(optarg
, &ActiveLicensePack
.ActID
);
568 case 'k': // Set specific KMS ID
570 incompatibleOptions
|= VLMCS_OPTION_NO_GRAB_INI
;
571 string2UuidOrExit(optarg
, &ActiveLicensePack
.KMSID
);
574 case '4': // Force V4 protocol
575 case '5': // Force V5 protocol
576 case '6': // Force V5 protocol
578 incompatibleOptions
|= VLMCS_OPTION_NO_GRAB_INI
;
579 ActiveLicensePack
.kmsVersionMajor
= o
- 0x30;
582 case 'd': // Don't use DNS names
587 case 'v': // Be verbose
592 case 'm': // Pretend to be a virtual machine
597 case 'w': // WorkstationName (max. 63 chars)
599 WorkstationName
= optarg
;
601 if (strlen(WorkstationName
) > 63)
603 errorout("\007WARNING! Truncating Workstation name to 63 characters (%s).\n", WorkstationName
);
610 LicenseStatus
= getOptionArgumentInt(o
, 0, 6) & 0xff;
617 ReconnectForEachRequest
= TRUE
;
623 incompatibleOptions
|= VLMCS_OPTION_NO_GRAB_INI
;
627 clientUsage(programName
);
629 if ((incompatibleOptions
& (VLMCS_OPTION_NO_GRAB_INI
| VLMCS_OPTION_GRAB_INI
)) == (VLMCS_OPTION_NO_GRAB_INI
| VLMCS_OPTION_GRAB_INI
))
630 clientUsage(programName
);
635 * Compares 2 GUIDs where one is host-endian and the other is little-endian (network byte order)
637 int_fast8_t IsEqualGuidLEHE(const GUID
* const guid1
, const GUID
* const guid2
)
640 LEGUID(&tempGuid
, guid2
);
641 return IsEqualGUID(guid1
, &tempGuid
);
646 static void checkRpcLevel(const REQUEST
* request
, RESPONSE
* response
)
648 if (!RpcFlags
.HasNDR32
)
649 errorout("\nWARNING: Server's RPC protocol does not support NDR32.\n");
651 if (UseRpcBTFN
&& UseRpcNDR64
&& RpcFlags
.HasNDR64
&& !RpcFlags
.HasBTFN
)
652 errorout("\nWARNING: Server's RPC protocol has NDR64 but no BTFN.\n");
654 if (!IsEqualGuidLEHE(&request
->KMSID
, &ProductList
[15].guid
) && UseRpcBTFN
&& !RpcFlags
.HasBTFN
)
655 errorout("\nWARNING: A server with pre-Vista RPC activated a product other than Office 2010.\n");
660 static void displayResponse(const RESPONSE_RESULT result
, const REQUEST
* request
, RESPONSE
* response
, BYTE
*hwid
)
664 if (!result
.RpcOK
) errorout("\n\007ERROR: Non-Zero RPC result code.\n");
665 if (!result
.DecryptSuccess
) errorout("\n\007ERROR: Decryption of V5/V6 response failed.\n");
666 if (!result
.IVsOK
) errorout("\n\007ERROR: AES CBC initialization vectors (IVs) of request and response do not match.\n");
667 if (!result
.PidLengthOK
) errorout("\n\007ERROR: The length of the PID is not valid.\n");
668 if (!result
.HashOK
) errorout("\n\007ERROR: Computed hash does not match hash in response.\n");
669 if (!result
.ClientMachineIDOK
) errorout("\n\007ERROR: Client machine GUIDs of request and response do not match.\n");
670 if (!result
.TimeStampOK
) errorout("\n\007ERROR: Time stamps of request and response do not match.\n");
671 if (!result
.VersionOK
) errorout("\n\007ERROR: Protocol versions of request and response do not match.\n");
672 if (!result
.HmacSha256OK
) errorout("\n\007ERROR: Keyed-Hash Message Authentication Code (HMAC) is incorrect.\n");
673 if (!result
.IVnotSuspicious
) errorout("\nWARNING: Response uses an IV following KMSv5 rules in KMSv6 protocol.\n");
675 if (result
.effectiveResponseSize
!= result
.correctResponseSize
)
677 errorout("\n\007WARNING: Size of RPC payload (KMS Message) should be %u but is %u.", result
.correctResponseSize
, result
.effectiveResponseSize
);
681 checkRpcLevel(request
, response
);
684 if (!result
.DecryptSuccess
) return; // Makes no sense to display anything
686 char ePID
[3 * PID_BUFFER_SIZE
];
687 if (!ucs2_to_utf8(response
->KmsPID
, ePID
, PID_BUFFER_SIZE
, 3 * PID_BUFFER_SIZE
))
689 memset(ePID
+ 3 * PID_BUFFER_SIZE
- 3, 0, 3);
692 // Read KMSPID from Response
695 printf(" -> %s", ePID
);
697 if (LE16(response
->MajorVer
) > 5)
700 printf(" (%016llX)", (unsigned long long)BE64(*(uint64_t*)hwid
));
702 printf(" (%016I64X)", (unsigned long long)BE64(*(uint64_t*)hwid
));
711 "\n\nResponse from KMS server\n========================\n\n"
712 "Size of KMS Response : %u (0x%x)\n", result
.effectiveResponseSize
, result
.effectiveResponseSize
715 logResponseVerbose(ePID
, hwid
, response
, &printf
);
721 static void connectRpc(RpcCtx
*s
)
725 *s
= connectToAddress(RemoteAddr
, AddressFamily
, FALSE
);
726 if (*s
== INVALID_RPCCTX
)
728 errorout("Fatal: Could not connect to %s\n", RemoteAddr
);
733 printf("\nPerforming RPC bind ...\n");
735 if (rpcBindClient(*s
, verbose
))
737 errorout("Fatal: Could not bind RPC\n");
741 if (verbose
) printf("... successful\n");
745 static kms_server_dns_ptr
* serverlist
= NULL
;
746 static int numServers
= 0;
747 //static int_fast8_t ServerListAlreadyPrinted = FALSE;
750 if (!strcmp(RemoteAddr
, "-") || *RemoteAddr
== '.') // Get KMS server via DNS SRV record
753 numServers
= getKmsServerList(&serverlist
, RemoteAddr
);
757 errorout("Fatal: No KMS servers found\n");
761 if (!NoSrvRecordPriority
) sortSrvRecords(serverlist
, numServers
);
763 if (verbose
/*&& !ServerListAlreadyPrinted*/)
765 for (i
= 0; i
< numServers
; i
++)
768 "Found %-40s (priority: %hu, weight: %hu, randomized weight: %i)\n",
769 serverlist
[i
]->serverName
,
770 serverlist
[i
]->priority
, serverlist
[i
]->weight
,
771 NoSrvRecordPriority
? 0 : serverlist
[i
]->random_weight
776 //ServerListAlreadyPrinted = TRUE;
779 else // Just use the server supplied on the command line
783 serverlist
= (kms_server_dns_ptr
*)vlmcsd_malloc(sizeof(kms_server_dns_ptr
));
784 *serverlist
= (kms_server_dns_ptr
)vlmcsd_malloc(sizeof(kms_server_dns_t
));
787 strncpy((*serverlist
)->serverName
, RemoteAddr
, sizeof((*serverlist
)->serverName
));
791 for (i
= 0; i
< numServers
; i
++)
793 *s
= connectToAddress(serverlist
[i
]->serverName
, AddressFamily
, (*RemoteAddr
== '.' || *RemoteAddr
== '-'));
795 if (*s
== INVALID_RPCCTX
) continue;
798 printf("\nPerforming RPC bind ...\n");
800 if (rpcBindClient(*s
, verbose
))
802 errorout("Warning: Could not bind RPC\n");
806 if (verbose
) printf("... successful\n");
811 errorout("Fatal: Could not connect to any KMS server\n");
818 static int SendActivationRequest(const RpcCtx sock
, RESPONSE
*baseResponse
, REQUEST
*baseRequest
, RESPONSE_RESULT
*result
, BYTE
*const hwid
)
820 size_t requestSize
, responseSize
;
821 BYTE
*request
, *response
;
826 if (LE16(baseRequest
->MajorVer
) == 4)
827 request
= CreateRequestV4(&requestSize
, baseRequest
);
829 request
= CreateRequestV6(&requestSize
, baseRequest
);
831 if (!(status
= rpcSendRequest(sock
, request
, requestSize
, &response
, &responseSize
)))
833 if (LE16(((RESPONSE
*)(response
))->MajorVer
) == 4)
835 RESPONSE_V4 response_v4
;
836 *result
= DecryptResponseV4(&response_v4
, responseSize
, response
, request
);
837 memcpy(baseResponse
, &response_v4
.ResponseBase
, sizeof(RESPONSE
));
841 RESPONSE_V6 response_v6
;
842 *result
= DecryptResponseV6(&response_v6
, responseSize
, response
, request
, hwid
);
843 memcpy(baseResponse
, &response_v6
.ResponseBase
, sizeof(RESPONSE
));
846 result
->RpcOK
= TRUE
;
849 if (response
) free(response
);
855 static int sendRequest(RpcCtx
*const s
, REQUEST
*const request
, RESPONSE
*const response
, hwid_t hwid
, RESPONSE_RESULT
*const result
)
857 CreateRequestBase(request
);
859 if (*s
== INVALID_RPCCTX
)
863 // Check for lame KMS emulators that close the socket after each request
864 int_fast8_t disconnected
= isDisconnected(*s
);
867 errorout("\nWarning: Server closed RPC connection (probably non-multitasked KMS emulator)\n");
869 if (ReconnectForEachRequest
|| disconnected
)
876 printf("Sending activation request (KMS V%u) ", ActiveLicensePack
.kmsVersionMajor
);
879 return SendActivationRequest(*s
, response
, request
, result
, hwid
);
883 static void displayRequestError(RpcCtx
*const s
, const int status
, const int currentRequest
, const int totalRequests
)
885 errorout("\nError 0x%08X while sending request %u of %u\n", status
, currentRequest
, RequestsToGo
+ totalRequests
);
889 case 0xC004F042: // not licensed
890 errorout("The server refused to activate the requested product\n");
893 case 0x8007000D: // e.g. v6 protocol on a v5 server
894 errorout("The server didn't understand the request\n");
898 errorout("An RPC protocol error has occured\n");
909 static void newIniBackupFile(const char* const restrict fname
)
911 FILE *restrict f
= fopen(fname
, "wb");
915 errorout("Fatal: Cannot create %s: %s\n", fname
, strerror(errno
));
921 errorout("Fatal: Cannot write to %s: %s\n", fname
, strerror(errno
));
928 static void updateIniFile(iniFileEpidLines
* const restrict lines
)
930 int_fast8_t lineWritten
[_countof(*lines
)];
933 int_fast8_t iniFileExistedBefore
= TRUE
;
934 unsigned int lineNumber
;
936 memset(lineWritten
, FALSE
, sizeof(lineWritten
));
938 char* restrict fn_bak
= (char*)vlmcsd_malloc(strlen(fn_ini_client
) + 2);
940 strcpy(fn_bak
, fn_ini_client
);
943 if (stat(fn_ini_client
, &statbuf
))
947 errorout("Fatal: %s: %s\n", fn_ini_client
, strerror(errno
));
952 iniFileExistedBefore
= FALSE
;
953 newIniBackupFile(fn_bak
);
958 unlink(fn_bak
); // Required for Windows. Most Unix systems don't need it.
959 if (rename(fn_ini_client
, fn_bak
))
961 errorout("Fatal: Cannot create %s: %s\n", fn_bak
, strerror(errno
));
966 printf("\n%s file %s\n", iniFileExistedBefore
? "Updating" : "Creating", fn_ini_client
);
968 FILE *restrict in
, *restrict out
;
970 in
= fopen(fn_bak
, "rb");
974 errorout("Fatal: Cannot open %s: %s\n", fn_bak
, strerror(errno
));
978 out
= fopen(fn_ini_client
, "wb");
982 errorout("Fatal: Cannot create %s: %s\n", fn_ini_client
, strerror(errno
));
986 char sourceLine
[256];
988 for (lineNumber
= 1; fgets(sourceLine
, sizeof(sourceLine
), in
); lineNumber
++)
990 for (i
= 0; i
< _countof(*lines
); i
++)
992 if (*(*lines
)[i
] && !strncasecmp(sourceLine
, (*lines
)[i
], GUID_STRING_LENGTH
))
994 if (lineWritten
[i
]) break;
996 fprintf(out
, "%s", (*lines
)[i
]);
997 printf("line %2i: %s", lineNumber
, (*lines
)[i
]);
998 lineWritten
[i
] = TRUE
;
1003 if (i
>= _countof(*lines
))
1005 fprintf(out
, "%s", sourceLine
);
1011 errorout("Fatal: Cannot read from %s: %s\n", fn_bak
, strerror(errno
));
1017 for (i
= 0; i
< _countof(*lines
); i
++)
1019 if (!lineWritten
[i
] && *(*lines
)[i
])
1021 fprintf(out
, "%s", (*lines
)[i
]);
1022 printf("line %2i: %s", lineNumber
+ i
, (*lines
)[i
]);
1028 errorout("Fatal: Cannot write to %s: %s\n", fn_ini_client
, strerror(errno
));
1032 if (!iniFileExistedBefore
) unlink(fn_bak
);
1037 static void grabServerData()
1039 RpcCtx s
= INVALID_RPCCTX
;
1041 iniFileEpidLines lines
;
1042 int_fast8_t Licenses
[_countof(lines
)] = { 0, 15, 14 };
1045 RESPONSE_RESULT result
;
1051 for (i
= 0; i
< _countof(lines
); i
++) *lines
[i
] = 0;
1053 for (i
= 0; i
< _countof(Licenses
) && MajorVer
> 3; i
++)
1055 ActiveLicensePack
= LicensePackList
[Licenses
[i
]];
1056 ActiveLicensePack
.kmsVersionMajor
= MajorVer
;
1057 status
= sendRequest(&s
, &request
, &response
, hwid
, &result
);
1058 printf("%-11s", ActiveLicensePack
.names
);
1062 displayRequestError(&s
, status
, i
+ 7 - MajorVer
, 9 - MajorVer
);
1064 if (status
== 1) break;
1066 if ((status
& 0xF0000000) == 0x80000000)
1075 printf("%i of %i", (int)(i
+ 7 - MajorVer
), (int)(9 - MajorVer
));
1076 displayResponse(result
, &request
, &response
, hwid
);
1078 char guidBuffer
[GUID_STRING_LENGTH
+ 1];
1079 char ePID
[3 * PID_BUFFER_SIZE
];
1081 uuid2StringLE(&request
.AppID
, guidBuffer
);
1083 if (!ucs2_to_utf8(response
.KmsPID
, ePID
, PID_BUFFER_SIZE
, 3 * PID_BUFFER_SIZE
))
1085 memset(ePID
+ 3 * PID_BUFFER_SIZE
- 3, 0, 3);
1088 snprintf(lines
[i
], sizeof(lines
[0]), "%s = %s", guidBuffer
, ePID
);
1090 if (response
.MajorVer
> 5)
1092 len
= strlen(lines
[i
]);
1093 snprintf (lines
[i
] + len
, sizeof(lines
[0]) - len
, "/ %02X %02X %02X %02X %02X %02X %02X %02X", hwid
[0], hwid
[1], hwid
[2], hwid
[3], hwid
[4], hwid
[5], hwid
[6], hwid
[7]);
1096 len
= strlen(lines
[i
]);
1097 snprintf(lines
[i
] + len
, sizeof(lines
[0]) - len
, "\n");
1101 if (strcmp(fn_ini_client
, "-"))
1103 updateIniFile(&lines
);
1108 for (i
= 0; i
< _countof(lines
); i
++) printf("%s", lines
[i
]);
1113 int client_main(const int argc
, CARGV argv
)
1115 #if defined(_WIN32) && !defined(USE_MSRPC)
1117 // Windows Sockets must be initialized
1122 if ((error
= WSAStartup(0x0202, &wsadata
)))
1124 printerrorf("Fatal: Could not initialize Windows sockets (Error: %d).\n", error
);
1132 // We are not a service
1133 IsNTService
= FALSE
;
1135 // Set console output page to UTF-8
1136 // SetConsoleOutputCP(65001);
1138 #endif // _NTSERVICE
1141 ActiveLicensePack
= *LicensePackList
; //first license is Windows Vista
1143 parseCommandLinePass1(argc
, argv
);
1145 int_fast8_t useDefaultHost
= FALSE
;
1148 RemoteAddr
= argv
[optind
];
1150 useDefaultHost
= TRUE
;
1152 int hostportarg
= optind
;
1154 if (optind
< argc
- 1)
1156 parseCommandLinePass1(argc
- hostportarg
, argv
+ hostportarg
);
1158 if (optind
< argc
- hostportarg
)
1159 clientUsage(argv
[0]);
1162 parseCommandLinePass2(argv
[0], argc
, argv
);
1164 if (optind
< argc
- 1)
1165 parseCommandLinePass2(argv
[0], argc
- hostportarg
, argv
+ hostportarg
);
1168 RemoteAddr
= AddressFamily
== AF_INET6
? "::1" : "127.0.0.1";
1170 if (fn_ini_client
!= NULL
)
1175 RpcCtx s
= INVALID_RPCCTX
;
1177 for (requests
= 0, RequestsToGo
= ActiveLicensePack
.N_Policy
- 1; RequestsToGo
; requests
++)
1181 RESPONSE_RESULT result
;
1184 int status
= sendRequest(&s
, &request
, &response
, hwid
, &result
);
1186 if (FixedRequests
) RequestsToGo
= FixedRequests
- requests
- 1;
1190 displayRequestError(&s
, status
, requests
+ 1, RequestsToGo
+ requests
+ 1);
1191 if (!FixedRequests
) RequestsToGo
= 0;
1197 if (firstRequestSent
&& ActiveLicensePack
.N_Policy
- (int)response
.Count
>= RequestsToGo
)
1199 errorout("\nThe KMS server does not increment it's active clients. Aborting...\n");
1204 RequestsToGo
= ActiveLicensePack
.N_Policy
- response
.Count
;
1205 if (RequestsToGo
< 0) RequestsToGo
= 0;
1210 printf("%i of %i ", requests
+ 1, RequestsToGo
+ requests
+ 1);
1211 displayResponse(result
, &request
, &response
, hwid
);
1212 firstRequestSent
= TRUE
;
1221 // Create Base KMS Client Request
1222 static void CreateRequestBase(REQUEST
*Request
)
1225 Request
->MinorVer
= LE16((WORD
)kmsVersionMinor
);
1226 Request
->MajorVer
= LE16((WORD
)ActiveLicensePack
.kmsVersionMajor
);
1227 Request
->VMInfo
= LE32(VMInfo
);
1228 Request
->LicenseStatus
= LE32(LicenseStatus
);
1229 Request
->BindingExpiration
= LE32(BindingExpiration
);
1230 LEGUID(&Request
->AppID
, ActiveLicensePack
.AppID
);
1231 LEGUID(&Request
->ActID
, &ActiveLicensePack
.ActID
);
1232 LEGUID(&Request
->KMSID
, &ActiveLicensePack
.KMSID
);
1234 getUnixTimeAsFileTime(&Request
->ClientTime
);
1235 Request
->N_Policy
= LE32(ActiveLicensePack
.N_Policy
);
1242 string2UuidOrExit(CMID
, &tempGUID
);
1243 LEGUID(&Request
->CMID
, &tempGUID
);
1247 get16RandomBytes(&Request
->CMID
);
1249 // Set reserved UUID bits
1250 Request
->CMID
.Data4
[0] &= 0x3F;
1251 Request
->CMID
.Data4
[0] |= 0x80;
1253 // Set UUID type 4 (random UUID)
1254 Request
->CMID
.Data3
&= LE16(0xfff);
1255 Request
->CMID
.Data3
|= LE16(0x4000);
1260 string2UuidOrExit(CMID_prev
, &tempGUID
);
1261 LEGUID(&Request
->CMID_prev
, &tempGUID
);
1265 memset(&Request
->CMID_prev
, 0, sizeof(Request
->CMID_prev
));
1269 static const char alphanum
[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /*"abcdefghijklmnopqrstuvwxyz" */;
1271 if (WorkstationName
)
1273 utf8_to_ucs2(Request
->WorkstationName
, WorkstationName
, WORKSTATION_NAME_BUFFER
, WORKSTATION_NAME_BUFFER
* 3);
1278 unsigned int index
= rand() % _countof(ClientDnsNames
.first
);
1279 len
= utf8_to_ucs2(Request
->WorkstationName
, ClientDnsNames
.first
[index
], WORKSTATION_NAME_BUFFER
, WORKSTATION_NAME_BUFFER
* 3);
1281 index
= rand() % _countof(ClientDnsNames
.second
);
1282 len2
= utf8_to_ucs2(Request
->WorkstationName
+ len
, ClientDnsNames
.second
[index
], WORKSTATION_NAME_BUFFER
, WORKSTATION_NAME_BUFFER
* 3);
1284 index
= rand() % _countof(ClientDnsNames
.tld
);
1285 utf8_to_ucs2(Request
->WorkstationName
+ len
+ len2
, ClientDnsNames
.tld
[index
], WORKSTATION_NAME_BUFFER
, WORKSTATION_NAME_BUFFER
* 3);
1289 unsigned int size
= (rand() % 14) + 1;
1290 const unsigned char *dummy
;
1293 for (i
= 0; i
< size
; i
++)
1295 Request
->WorkstationName
[i
] = utf8_to_ucs2_char((unsigned char*)alphanum
+ (rand() % (sizeof(alphanum
) - 1)), &dummy
);
1298 Request
->WorkstationName
[size
] = 0;
1304 printf("\nRequest Parameters\n==================\n\n");
1305 logRequestVerbose(Request
, &printf
);