Last active
June 12, 2026 09:16
-
-
Save Troll338cz/308e298a5fb1b18da0fd14d5c061f7e1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <unistd.h> | |
| #include <stdio.h> | |
| #include <stdint.h> | |
| #include <fcntl.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <sys/ioctl.h> | |
| #include <stdbool.h> | |
| #include <string.h> | |
| #include <openssl/evp.h> | |
| #include <openssl/err.h> | |
| #include <b64/cencode.h> | |
| #include <b64/cdecode.h> | |
| typedef uint32_t _DWORD; | |
| typedef uint8_t _BYTE; | |
| // Build, OpenSSL and libb64-dev needed: | |
| // gcc Zyxel_encrypt_.c -o Zyxel_encrypt_ -lcrypto -lb64 | |
| // | |
| // Rewriten code from /bin/zcmd | |
| // Does not support "_encryp1_", algo is the same key is dynamic ("%s%s%s", zcmdData1, (const char *)(objNameShmAddr+*(unsigned __int16 *)(schemaShmAddr + 18036)), paramNameShmAddr) | |
| // Inspired by https://th0mas.nl/2020/03/26/getting-root-on-a-zyxel-vmg8825-t50-router/ | |
| // Mentions of "but the actual key is derived from the supervisor password" probably means this wont work on those configs ither, unless you know it | |
| // | |
| // Tested on default configs from /etc/sysconfig.tar.gz configs on VMG4005-B60A with software V5.15(ABQA.2)b4_D0 | |
| EVP_CIPHER_CTX *aes_init(bool decrypt, const char *key) { | |
| _BYTE v17[32]; // [sp+20h] [bp-54h] BYREF | |
| _BYTE v18[32]; // [sp+40h] [bp-34h] BYREF | |
| int v19; | |
| int keyl = strlen(key); | |
| // Salt | |
| _DWORD v6[2]; | |
| v6[0] = *(_DWORD *)"90"; | |
| v6[1] = 54321; | |
| // Create keys | |
| v19 = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), (const unsigned char *)v6, key, keyl, 5, v18, v17); | |
| EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); | |
| // Create EVP context | |
| if (decrypt) | |
| EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), 0, v18, v17); | |
| else | |
| EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), 0, v18, v17); | |
| return ctx; | |
| } | |
| char *aes_encrypt(EVP_CIPHER_CTX *ctx, const unsigned char *a2, size_t *a3) | |
| { | |
| int v8; // [sp+18h] [bp-14h] BYREF | |
| int v9; // [sp+1Ch] [bp-10h] BYREF | |
| char *v10; // [sp+20h] [bp-Ch] | |
| char *v11; // [sp+24h] [bp-8h] | |
| v9 = *a3; | |
| v8 = 0; | |
| v11 = (char *)calloc(1u, v9 + 33); | |
| if ( !v11 ) | |
| printf( "aes_encrypt, fail to calloc memory, size = %zu", v9 + 33); | |
| v10 = v11; | |
| if ( v11 ) | |
| { | |
| v9 = 0; | |
| EVP_EncryptInit_ex(ctx, 0, 0, 0, 0); | |
| EVP_EncryptUpdate(ctx, v10, &v9, a2, *a3); | |
| EVP_EncryptFinal_ex(ctx, &v10[v9], &v8); | |
| *a3 = v9 + v8; | |
| return v10; | |
| } | |
| else | |
| { | |
| printf("aes_encrypt memory insufficient"); | |
| return 0; | |
| } | |
| } | |
| char *aes_decrypt(EVP_CIPHER_CTX *ctx, const unsigned char *a2, size_t *a3) | |
| { | |
| int v8; // [sp+18h] [bp-14h] BYREF | |
| int v9; // [sp+1Ch] [bp-10h] BYREF | |
| char *v10; // [sp+20h] [bp-Ch] | |
| char *v11; // [sp+24h] [bp-8h] | |
| v9 = *a3; | |
| v8 = 0; | |
| v11 = (char *)calloc(1u, v9 + 33); | |
| if ( !v11 ) | |
| printf("aes_decrypt fail to calloc memory, size = %zu", v9 + 33); | |
| v10 = v11; | |
| if ( v11 ) | |
| { | |
| EVP_DecryptInit_ex(ctx, 0, 0, 0, 0); | |
| EVP_DecryptUpdate(ctx, v10, &v9, a2, *a3); | |
| EVP_DecryptFinal_ex(ctx, &v10[v9], &v8); | |
| *a3 = v9 + v8; | |
| return v10; | |
| } | |
| else | |
| { | |
| printf("aes_decrypt memory insufficient"); | |
| return 0; | |
| } | |
| } | |
| // Example impl from: https://github.com/BuLogics/libb64/blob/master/examples/c-example1.c | |
| #define SIZE 1024 | |
| char* b64_encode(const char* input) | |
| { | |
| /* set up a destination buffer large enough to hold the encoded data */ | |
| char* output = (char*)malloc(SIZE); | |
| /* keep track of our encoded position */ | |
| char* c = output; | |
| /* store the number of bytes encoded by a single call */ | |
| int cnt = 0; | |
| /* we need an encoder state */ | |
| base64_encodestate s; | |
| /*---------- START ENCODING ----------*/ | |
| /* initialise the encoder state */ | |
| base64_init_encodestate(&s); | |
| /* gather data from the input and send it to the output */ | |
| cnt = base64_encode_block(input, strlen(input), c, &s); | |
| c += cnt; | |
| /* since we have encoded the entire input string, we know that | |
| there is no more input data; finalise the encoding */ | |
| cnt = base64_encode_blockend(c, &s); | |
| c += cnt; | |
| /*---------- STOP ENCODING ----------*/ | |
| /* we want to print the encoded data, so null-terminate it: */ | |
| *c = 0; | |
| return output; | |
| } | |
| char* b64_decode(const char* input) | |
| { | |
| /* set up a destination buffer large enough to hold the encoded data */ | |
| char* output = (char*)malloc(SIZE); | |
| /* keep track of our decoded position */ | |
| char* c = output; | |
| /* store the number of bytes decoded by a single call */ | |
| int cnt = 0; | |
| /* we need a decoder state */ | |
| base64_decodestate s; | |
| /*---------- START DECODING ----------*/ | |
| /* initialise the decoder state */ | |
| base64_init_decodestate(&s); | |
| /* decode the input data */ | |
| cnt = base64_decode_block(input, strlen(input), c, &s); | |
| c += cnt; | |
| /* note: there is no base64_decode_blockend! */ | |
| /*---------- STOP DECODING ----------*/ | |
| /* we want to print the decoded data, so null-terminate it: */ | |
| *c = 0; | |
| return output; | |
| } | |
| int main(int argc, char *argv[]) { | |
| // Example usage: | |
| // "_encrypt_YLXO6f1ShezIxTe2KLE9TQ==" => "1234567890" | |
| // "1234567890" => "_encrypt_YLXO6f1ShezIxTe2KLE9TQ==" | |
| // From funcs zcmdInit1 ... zcmdInit6 | |
| const char *key = "ThiSISEncryptioNKeY"; | |
| if(argc != 2 && argc != 3) { | |
| printf("%s <string> <key>\n", argv[0]); | |
| exit(1); | |
| } else { | |
| if(argc == 3) | |
| { | |
| key = argv[2]; | |
| } | |
| if( strncmp(argv[1], "_encrypt_", 9) == 0) | |
| { | |
| printf("Decrypting: %s\n", argv[1]); | |
| EVP_CIPHER_CTX *dec = aes_init(true, key); | |
| unsigned char *dec_raw; | |
| dec_raw = b64_decode( (char *)argv[1]+9 ); | |
| size_t raw_size = strlen(dec_raw); | |
| char *output; | |
| output = aes_decrypt(dec, dec_raw, &raw_size); | |
| printf("Result: %s\n", output); | |
| } else { | |
| printf("Encrypting: %s\n", argv[1]); | |
| EVP_CIPHER_CTX *enc = aes_init(false, key); | |
| size_t raw_size = strlen(argv[1])+1; | |
| char *ptr; | |
| ptr = aes_encrypt(enc, argv[1], &raw_size); | |
| unsigned char *enc_raw; | |
| enc_raw = b64_encode( ptr ); | |
| printf("Result: %s%s", "_encrypt_", (const char *)enc_raw); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment