diff --git a/README.md b/README.md index 46f08f7..01ea514 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ In light of the recent exponential interest in this project I've decided to put * Select the **telephone activation** method, then, run `umskt -i ` using the `Installation ID` the activation Wizard provides for you - * If you're activating a non-Windows product, use `umskt -i -m `, where `` is one of `OFFICEXP`, `OFFICE2K3`, `OFFICE2K7`, or `PLUSDME` + * If you're activating a non-Windows product, use `umskt -i -m `, where `` is one of `OFFICEXP`, `OFFICE2K3`, `OFFICE2K7`, `PLUSDME`, or `OFFICEACC` * If activating Office 2003/2007, use `umskt -i -m -p ` #### 4. Profit! diff --git a/keys.json b/keys.json index b842e0e..ab9b78f 100644 --- a/keys.json +++ b/keys.json @@ -94,7 +94,10 @@ "BINK": ["52", "53"] }, "Plus! Digital Media Edition for Windows XP": { - "BINK": ["52", "53"] + "BINK": [ "52", "53" ] + }, + "Office Accounting 2006 / 2007 / 2008 / 2009": { + "BINK": [ "52", "53" ] }, "Windows Longhorn (6.0.4033.0)": { "BINK": ["54", "55"] diff --git a/src/cli.cpp b/src/cli.cpp index d7b0a5e..49cde08 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -62,12 +62,12 @@ void CLI::showHelp(char *argv[]) { fmt::print("\t-n --number\tnumber of keys to generate (defaults to 1)\n"); fmt::print("\t-f --file\tspecify which keys file to load\n"); fmt::print("\t-i --instid\tinstallation ID used to generate confirmation ID (reads from stdin if no argument provided)\n"); - fmt::print("\t-m --mode\tproduct family to activate.\n\t\t\tvalid options are \"WINDOWS\", \"OFFICEXP\", \"OFFICE2K3\", \"OFFICE2K7\" or \"PLUSDME\"\n\t\t\t(defaults to \"WINDOWS\")\n"); + fmt::print("\t-m --mode\tproduct family to activate.\n\t\t\tvalid options are \"WINDOWS\", \"OFFICEXP\", \"OFFICE2K3\", \"OFFICE2K7\", \"PLUSDME\", or \"OFFICEACC\"\n\t\t\t(defaults to \"WINDOWS\")\n"); fmt::print("\t-p --productid\tthe product ID of the Program to activate. only required for Office 2K3 and Office 2K7 programs\n"); fmt::print("\t-b --binkid\tspecify which BINK identifier to load (defaults to 2E)\n"); fmt::print("\t-l --list\tshow which products/binks can be loaded\n"); fmt::print("\t-c --channelid\tspecify which Channel Identifier to use (defaults to 640)\n"); - fmt::print("\t-s --serial\tspecifies a serial (eg. 123456) or comma-separated serial range (recommended for BINK2002, eg. 1234,5678) to use in the product ID (defaults to 0,999999)\n"); + fmt::print("\t-s --serial\tspecifies a serial (eg. 123456) or comma-separated serial range\n\t\t\t(recommended for BINK2002, eg. 1234,5678) to use in the product ID (defaults to 0,999999)\n"); fmt::print("\t-u --upgrade\tspecifies the Product Key will be an \"Upgrade\" version\n"); fmt::print("\t-V --validate\tproduct key to validate signature\n"); fmt::print("\t-N --nonewlines\tdisables newlines (for easier embedding in other apps)\n"); @@ -198,11 +198,13 @@ int CLI::parseCommandLine(int argc, char* argv[], Options* options) { options->activationMode = OFFICE_XP; } else if (strcmp(p, "OFFICE2K3") == 0) { options->activationMode = OFFICE_2K3; - } else if (strcmp(p, "OFFICE2K7") == 0) { + } else if (strcmp(p, "OFFICE2K7") == 0) { options->activationMode = OFFICE_2K7; } else if (strcmp(p, "PLUSDME") == 0) { options->activationMode = PLUS_DME; - } + } else if (strcmp(p, "OFFICEACC") == 0) { + options->activationMode = OFFICE_ACC; + } i++; } else if (arg == "-p" || arg == "--productid") { if (i == argc -1) { diff --git a/src/cli.h b/src/cli.h index d01b463..4de5d87 100644 --- a/src/cli.h +++ b/src/cli.h @@ -42,6 +42,7 @@ enum ACTIVATION_ALGORITHM { OFFICE_2K3 = 2, OFFICE_2K7 = 3, PLUS_DME = 4, + OFFICE_ACC = 5, }; enum MODE { diff --git a/src/libumskt/confid/confid.cpp b/src/libumskt/confid/confid.cpp index 92582cc..14787cb 100644 --- a/src/libumskt/confid/confid.cpp +++ b/src/libumskt/confid/confid.cpp @@ -128,6 +128,7 @@ QWORD ConfirmationID::ui128_quotient_mod(QWORD lo, QWORD hi) __umul128(lo, 0x4FA8E4A40CDAE44A, &prod1); break; case 4: + case 5: __umul128(lo, 0x2C5C4D3654A594F0, &prod1); } QWORD part1hi; @@ -142,6 +143,7 @@ QWORD ConfirmationID::ui128_quotient_mod(QWORD lo, QWORD hi) part1lo = __umul128(lo, 0x2CBAF12A59BBE, &part1hi); break; case 4: + case 5: part1lo = __umul128(lo, 0x2D36C691A4EA5, &part1hi); } QWORD part2hi; @@ -156,6 +158,7 @@ QWORD ConfirmationID::ui128_quotient_mod(QWORD lo, QWORD hi) part2lo = __umul128(hi, 0x4FA8E4A40CDAE44A, &part2hi); break; case 4: + case 5: part2lo = __umul128(hi, 0x2C5C4D3654A594F0, &part2hi); } QWORD sum1 = part1lo + part2lo; @@ -175,6 +178,7 @@ QWORD ConfirmationID::ui128_quotient_mod(QWORD lo, QWORD hi) prod3lo = __umul128(hi, 0x2CBAF12A59BBE, &prod3hi); break; case 4: + case 5: prod3lo = __umul128(hi, 0x2D36C691A4EA5, &prod3hi); } prod3lo += prod2; @@ -724,6 +728,7 @@ void ConfirmationID::Mix(unsigned char* buffer, size_t bufSize, const unsigned c break; case 2: case 3: + case 5: sha1_input[0] = 0x79; memcpy(sha1_input + 1, buffer + half, half); memcpy(sha1_input + 1 + half, key, keySize); @@ -764,6 +769,7 @@ void ConfirmationID::Unmix(unsigned char* buffer, size_t bufSize, const unsigned break; case 2: case 3: + case 5: sha1_input[0] = 0x79; memcpy(sha1_input + 1, buffer, half); memcpy(sha1_input + 1 + half, key, keySize); @@ -812,6 +818,7 @@ int ConfirmationID::Generate(const char* installation_id_str, char confirmation_ f[5] = 0x1; break; case 4: + case 5: MOD = 0x16A5DABA0605983; NON_RESIDUE = 2; f[0] = 0x334F24F75CAA0E; @@ -821,7 +828,7 @@ int ConfirmationID::Generate(const char* installation_id_str, char confirmation_ f[4] = 0x163694F26056DB; f[5] = 0x1; } - unsigned char installation_id[19]; // 10**45 < 256**19 + unsigned char installation_id[20]; // 10**45 < 256**19 size_t installation_id_len = 0; const char* p = installation_id_str; size_t count = 0, totalCount = 0; @@ -845,7 +852,7 @@ int ConfirmationID::Generate(const char* installation_id_str, char confirmation_ check += (count % 2 ? d * 2 : d); count++; totalCount++; - if (totalCount > 45) + if (totalCount > 50) return ERR_TOO_LARGE; unsigned char carry = d; for (i = 0; i < installation_id_len; i++) { @@ -866,6 +873,7 @@ int ConfirmationID::Generate(const char* installation_id_str, char confirmation_ switch (activationMode) { case 0: case 4: + case 5: iid_key[0] = 0x6A; iid_key[1] = 0xC8; iid_key[2] = 0x5E; @@ -880,7 +888,9 @@ int ConfirmationID::Generate(const char* installation_id_str, char confirmation_ iid_key[3] = 0xF3; } Unmix(installation_id, totalCount == 41 ? 17 : 19, iid_key, 4); - if (installation_id[18] >= 0x10 && overrideVersion == false) + if (activationMode != 5 && installation_id[18] >= 0x10 && overrideVersion == false) + return ERR_UNKNOWN_VERSION; + if (activationMode == 5 && installation_id[19] != 0xB) return ERR_UNKNOWN_VERSION; #pragma pack(push, 1) @@ -917,6 +927,13 @@ int ConfirmationID::Generate(const char* installation_id_str, char confirmation_ } } + break; + case 5: + memcpy(&parsed, installation_id, sizeof(parsed)); + productID[0] = parsed.ProductIDLow & ((1 << 17) - 1); + productID[1] = (parsed.ProductIDLow >> 17) & ((1 << 10) - 1); + productID[2] = (parsed.KeySHA1 << 8) | parsed.ProductIDHigh; + productID[3] = (parsed.ProductIDLow >> 27) & ((1 << 17) - 1); break; case 2: case 3: @@ -950,8 +967,8 @@ int ConfirmationID::Generate(const char* installation_id_str, char confirmation_ productID[2] = stoi(productid.substr(10,7)); productID[3] = stoi(productid.substr(18,5)); } - //fmt::print("ProductID: {}-{}-{}-{} \n", productID[0], productID[1], productID[2], productID[3]); } + // fmt::print("ProductID: {}-{}-{}-{} \n", productID[0], productID[1], productID[2], productID[3]); unsigned char keybuf[16]; memcpy(keybuf, &parsed.HardwareID, 8); @@ -974,6 +991,7 @@ int ConfirmationID::Generate(const char* installation_id_str, char confirmation_ case 0: case 1: case 4: + case 5: u.buffer[7] = attempt; break; case 2: @@ -1001,6 +1019,7 @@ int ConfirmationID::Generate(const char* installation_id_str, char confirmation_ divisor_mul128(&d, 0xEFE0302A1F7A5341, 0x01FB8CF48A70DF, &d); break; case 4: + case 5: divisor_mul128(&d, 0x7C4254C43A5D1181, 0x01C61212ECE610, &d); } union {