diff --git a/common/base64.c b/common/base64.c new file mode 100644 index 0000000..6755fcb --- /dev/null +++ b/common/base64.c @@ -0,0 +1,156 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + + +static unsigned char base64_table[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +void set_base64_table(const char* table) +{ + memcpy(base64_table, table, sizeof(base64_table) - 1); +} + +/** + * base64_encode - Base64 encode + * @src: Data to be encoded + * @len: Length of the data to be encoded + * @out_len: Pointer to output length variable, or %NULL if not used + * Returns: Allocated buffer of out_len bytes of encoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. Returned buffer is + * nul terminated to make it easier to use as a C string. The nul terminator is + * not included in out_len. + */ +unsigned char * base64_encode(const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char *out, *pos; + const unsigned char *end, *in; + size_t olen; + int line_len; + + olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ + olen += olen / 72; /* line feeds */ + olen++; /* nul termination */ + if (olen < len) + return NULL; /* integer overflow */ + out = malloc(olen); + if (out == NULL) + return NULL; + + end = src + len; + in = src; + pos = out; + line_len = 0; + while (end - in >= 3) { + *pos++ = base64_table[in[0] >> 2]; + *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = base64_table[in[2] & 0x3f]; + in += 3; + line_len += 4; + if (line_len >= 72) { + *pos++ = '\n'; + line_len = 0; + } + } + + if (end - in) { + *pos++ = base64_table[in[0] >> 2]; + if (end - in == 1) { + *pos++ = base64_table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } else { + *pos++ = base64_table[((in[0] & 0x03) << 4) | + (in[1] >> 4)]; + *pos++ = base64_table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + line_len += 4; + } + + if (line_len) + *pos++ = '\n'; + + *pos = '\0'; + if (out_len) + *out_len = pos - out; + return out; +} + + +/** + * base64_decode - Base64 decode + * @src: Data to be decoded + * @len: Length of the data to be decoded + * @out_len: Pointer to output length variable + * Returns: Allocated buffer of out_len bytes of decoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. + */ +unsigned char * base64_decode(const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char dtable[256], *out, *pos, block[4], tmp; + size_t i, count, olen; + int pad = 0; + + memset(dtable, 0x80, 256); + for (i = 0; i < sizeof(base64_table) - 1; i++) + dtable[base64_table[i]] = (unsigned char) i; + dtable['='] = 0; + + count = 0; + for (i = 0; i < len; i++) { + if (dtable[src[i]] != 0x80) + count++; + } + + if (count == 0 || count % 4) + return NULL; + + olen = count / 4 * 3; + pos = out = malloc(olen); + if (out == NULL) + return NULL; + + count = 0; + for (i = 0; i < len; i++) { + tmp = dtable[src[i]]; + if (tmp == 0x80) + continue; + + if (src[i] == '=') + pad++; + block[count] = tmp; + count++; + if (count == 4) { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + if (pad) { + if (pad == 1) + pos--; + else if (pad == 2) + pos -= 2; + else { + /* Invalid padding */ + free(out); + return NULL; + } + break; + } + } + } + + *out_len = pos - out; + return out; +} diff --git a/mc4-cheat-decrypter/Makefile b/mc4-cheat-decrypter/Makefile new file mode 100644 index 0000000..b666961 --- /dev/null +++ b/mc4-cheat-decrypter/Makefile @@ -0,0 +1,10 @@ +# MC4 Cheat Decrypter +# (c)2023 Damian Parrino + +all: decrypter + +decrypter: + gcc -D _GNU_SOURCE -o mc4-cheat-decrypter main.c + +clean: + -rm -f mc4-cheat-decrypter diff --git a/mc4-cheat-decrypter/README.md b/mc4-cheat-decrypter/README.md new file mode 100644 index 0000000..7b030ea --- /dev/null +++ b/mc4-cheat-decrypter/README.md @@ -0,0 +1,11 @@ +# MC4 Cheat Decrypter + +A tool to decrypt MC4 cheat files + +``` +USAGE: ./mc4-cheat-decrypter [option] filename + +OPTIONS Explanation: + -d Decrypt File + -e Encrypt File +``` diff --git a/mc4-cheat-decrypter/main.c b/mc4-cheat-decrypter/main.c new file mode 100644 index 0000000..6aae31b --- /dev/null +++ b/mc4-cheat-decrypter/main.c @@ -0,0 +1,110 @@ +/* +* +* MC4 Cheat Decrypter - (c) 2023 by Bucanero - www.bucanero.com.ar +* +* Keys reversed from RAN SHN-Injector 1.08 by TetzkatLipHoka (TLH) +* +*/ + +#define CBC 1 + +#include "../common/iofile.c" +#include "../common/aes.c" +#include "../common/base64.c" + +const unsigned char MC4_AES256CBC_KEY[] = "304c6528f659c766110239a51cl5dd9c"; +const unsigned char MC4_AES256CBC_IV[] = "u@}kzW2u[u(8DWar"; + + +u8* decrypt_data(u8* data, size_t* size) +{ + u8* bin_data; + size_t bin_size; + struct AES_ctx ctx; + + printf("[*] Base64 Encoded Size: %zu bytes\n", *size); + + bin_data = base64_decode(data, *size, &bin_size); + *size = bin_size; + free(data); + + printf("[*] Total Decrypted Size: %zu bytes\n", bin_size); + + AES_init_ctx_iv(&ctx, MC4_AES256CBC_KEY, MC4_AES256CBC_IV); + AES_CBC_decrypt_buffer(&ctx, bin_data, bin_size); + + printf("[*] Decrypted File Successfully!\n\n"); + return bin_data; +} + +u8* encrypt_data(u8* data, size_t* size) +{ + u8* b64_data; + size_t b64_size; + struct AES_ctx ctx; + + printf("[*] Total XML Size: %zu bytes\n", *size); + + AES_init_ctx_iv(&ctx, MC4_AES256CBC_KEY, MC4_AES256CBC_IV); + AES_CBC_encrypt_buffer(&ctx, data, *size); + + b64_data = base64_encode(data, *size, &b64_size); + *size = b64_size; + free(data); + + printf("[*] Total Encrypted Size: %zu bytes\n", b64_size); + printf("[*] Encrypted File Successfully!\n\n"); + return b64_data; +} + +void print_usage(const char* argv0) +{ + printf("USAGE: %s [option] filename\n\n", argv0); + printf("OPTIONS Explanation:\n"); + printf(" -d Decrypt File\n"); + printf(" -e Encrypt File\n\n"); + return; +} + +int main(int argc, char **argv) +{ + size_t len; + u8* data; + char *opt, *bak; + + printf("\nMC4 Cheat Decrypter 0.1.0 - (c) 2023 by Bucanero\n\n"); + + if (--argc < 2) + { + print_usage(argv[0]); + return -1; + } + + opt = argv[1]; + if (*opt++ != '-' || (*opt != 'd' && *opt != 'e')) + { + print_usage(argv[0]); + return -1; + } + + if (read_buffer(argv[2], &data, &len) != 0) + { + printf("[*] Could Not Access The File (%s)\n", argv[2]); + return -1; + } + // Save a file backup + asprintf(&bak, "%s.bak", argv[2]); + write_buffer(bak, data, len); + + if (*opt == 'd') + data = decrypt_data(data, &len); + else + data = encrypt_data(data, &len); + + write_buffer(argv[2], data, len); + + free(bak); + free(data); + + return 0; +} diff --git a/mc4-cheat-decrypter/samples/CUSA32091_01.02.mc4 b/mc4-cheat-decrypter/samples/CUSA32091_01.02.mc4 new file mode 100644 index 0000000..defa3f0 --- /dev/null +++ b/mc4-cheat-decrypter/samples/CUSA32091_01.02.mc4 @@ -0,0 +1 @@ +AgKHPLxZwZ+2YfYslmLUXGyUIJK0NSn6118NipwxKEwTgDtPaDO2TMpugGI9h3o9Rkx++qP4HKt8vk/4J+mtwAAQT223dPM5Njvb5dNdE/WbmMve6nBLodseDrYK7elwAGw99Igvx6qAo+DP020C2sU+4O73HwvAYeWvZ8EE/pEtCH4KeacF6OOS9HFn8t/XSSRP3+F9yuSFXmze3q/7XBh1bYqawaX7Eq3RSnsuaPbuvRihcB3+4SuSctXxKbKkSg2iAlhy/EYX89HYZPkCoTijA0NR5EKxHUwVhSwDknGMYMGQS/qyKKnD2n8Kd26BUwZQlgsA0pQuUuqi7FSFTLYfIPbIAFKABxuPeLdVGkl75XAGzkIVj98TDM5GU0vbo1oL6mmWZMpui0vRrAvHcgpHcDn/FL5vWRT5o/rlpvS9T6E5RWAX88l8pbJa03npyBMW05CIr3sjX/ZSQ6ZoELNlivQB6d1rJJyQf8PKbcyGB7dmgvoiixsbYvURVJwVDhToAfwVW/8bAJ6Vng/3Z7ItZCklqA0fMIIeqF2j44vjE7QQJMCqsZHyYjXoR+33gUOzvB3/MUvDb3wVU5NOWCacJ4uECqs0DjmPrES+zmZpux5rL/ff2Xg/jfFFcaaOHMoTtW7X/lUX9EcEq49KLx4RJ9feNsiUXqJWuwT8ePWT0EvIXiXpTzdGi0IbJtuiNb9ScRgnzmGX9NetXuc+oyq7NUafTM0l/MrhFdx4f1vTag6bjaMCeaZsYMR2b1utMI78iv+aUZ3DCr6kAbE1L61Pc9SVDJFeXV0DdZfL/59d0baYA3P2tqM1p4oDclqvRVTOZM1EMzCOtGtmAECtFcZEsxqARUbVhQznlPT5gDFkgv6mMq11NtRhcpp+X5Tdsp6njX/pPLE3+FgEIsTzvLX4ZhhaobViRBSxstQ1xZYKIJ7vzdzp3hP0kNsvvPHwuM9e/Pt44aZ51E2DMup3zwXKLhonunsbmo/QOnSu5CEqqCOlXh7S8JtYG6jsJ3vAYQ5yrwVr/cGRQ/WYHKUuasmOIZ++Obap8vNJl9jc8LColrx/hQAw3eO3HIsPwAq3ch8tUdysXyTvDth8u4b4D+CK2iogX/St0BfcDpMKud2XW3aoF+upvA76I88RkOUTlQZEw0BL2w76ITZZEsuLA+8Gzw9s+OMAOViPvabrKG8zCWvSYAsSI1TT4eYKNn+WtPwIdlx+N9HhKbM8RFv8mReSG4yXoLqTo7xktJY8QPJBtLt2PdST0u7sFVI/v2b+Mf7tIDB2berApbMwYuQs/b86sB03MWJjB9Rdl/MwrVTnUko85qMRu6IAgOfTpkSIXvuVdcthjX5ZowesSb95zizDNuwCxzESy8u3K6ve6WiGDSYNp7md6ux0v1iKWphgvI4+bf4urQl5H5v4KdPIeQQ6QLu3s89RHBeDXllClRW2ylj7OaYZKHj58LcMhEPTzTFcO0//oCGdBU/x5I+cgnAajoyfcakhfrCB7QOrClF/ytrxY42EBe29yRMekxwF0OSLvV3842KJnyLwUNi9GgoBvfsZWvnYPH8UGneixoAGki8j/z1Dh43SooLqmKq5RXpOo585JZ4qmAdwTtlfUaLU6XrPBThOPYUZbq4JiP2l3nJDtr1vYDoxDeEmYS22APFSgUjTniUxSPGiKyhfOw== \ No newline at end of file diff --git a/mc4-cheat-decrypter/samples/CUSA32091_01.02.mc4.BIN b/mc4-cheat-decrypter/samples/CUSA32091_01.02.mc4.BIN new file mode 100644 index 0000000..e2a5110 Binary files /dev/null and b/mc4-cheat-decrypter/samples/CUSA32091_01.02.mc4.BIN differ diff --git a/mc4-cheat-decrypter/samples/CUSA32091_01.02.mc4.DEC b/mc4-cheat-decrypter/samples/CUSA32091_01.02.mc4.DEC new file mode 100644 index 0000000..1cc85db --- /dev/null +++ b/mc4-cheat-decrypter/samples/CUSA32091_01.02.mc4.DEC @@ -0,0 +1,48 @@ + + + + + + + True +
0
+ 42C216 + 90-90-90-90-90 + E8-05-00-00-00 +
+
+ + + True +
0
+ 40F548 + 8B-87-14-02-00-00 + 8B-87-18-02-00-00 +
+ + True +
0
+ 40F552 + FF-C0 + FF-C8 +
+
+ + + True +
0
+ 40F430 + 8B-87-18-02-00-00 + 8B-87-14-02-00-00 +
+
+
+ + + + + + + + + diff --git a/mc4-cheat-decrypter/samples/RAN_-_SHNInjector_v1.08.7z b/mc4-cheat-decrypter/samples/RAN_-_SHNInjector_v1.08.7z new file mode 100644 index 0000000..3749fa3 Binary files /dev/null and b/mc4-cheat-decrypter/samples/RAN_-_SHNInjector_v1.08.7z differ