From e7722b3a47d62bfb654364ccc6b9a737c5a34217 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Fri, 24 Nov 2023 07:43:36 -0500 Subject: [PATCH 01/27] util.c: create table for detect_model() --- src/util.c | 75 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/src/util.c b/src/util.c index a6eae312..38c062b3 100644 --- a/src/util.c +++ b/src/util.c @@ -401,44 +401,53 @@ int isdatetime(const char *datetime) { } } +bool is_str_printable(const char *str) { + for (const char *p = str; *p != '\0'; p++) { + if (isprint(*p) == 0) { + return false; + } + } + + return true; +} + +static const struct { + const char *name; + part_struct_type type; + const char *description; +} part_type_table[] = { + {"mstar_map0", STRUCT_MTDINFO, "MStar Saturn6 / Saturn7 / M1(A) / LM1"}, // ? + {"bcm35xx_map0", STRUCT_MTDINFO, "BCM 2010 (BCM35XX)"}, // 2010 + {"bcm35230_map0", STRUCT_MTDINFO, "BCM 2011 (BCM35230)"}, // 2011 + {"mtk3569-emmc", STRUCT_PARTINFOv1, "MTK A1 (MT5369/MTK5369)"}, // 2012 + {"l9_emmc", STRUCT_PARTINFOv1, "LX L9 (LG1152)"}, // 2012 + {"mtk3598-emmc", STRUCT_PARTINFOv2, "MTK A2 (MT5398/MTK5389/M13)"}, // 2013 + {"h13_emmc", STRUCT_PARTINFOv2, "LX H13 (LG1154) / M14 (LG1311)"}, // 2013/2014 + {"mstar-emmc", STRUCT_PARTINFOv2, "MStar LM14"}, // 2014 +}; + /* detect_model - detect model and corresponding part struct */ static void detect_model(const struct p2_device_info *pid) { - part_type = STRUCT_INVALID; + char name[STR_LEN_MAX + 1]; - int ismtk1 = !strcmp("mtk3569-emmc", pid->name); //match mtk2012 - int ismtk2 = !strcmp("mtk3598-emmc", pid->name); //match mtk2013 - int is1152 = !strcmp("l9_emmc", pid->name); //match 1152 - int is1154 = !strcmp("h13_emmc", pid->name); //match 1154/lg1311 - int isbcm1 = !strcmp("bcm35xx_map0", pid->name); //match broadcom - int isbcm2 = !strcmp("bcm35230_map0", pid->name); //match broadcom - int ismstar = !strcmp("mstar_map0", pid->name); //match mstar - int islm14 = !strcmp("mstar-emmc", pid->name); //match lm14 - - if (ismtk1) - modelname = "Mtk 2012 - MTK5369 (Cortex-A9 single-core)"; - else if (ismtk2) - modelname = "Mtk 2013 - MTK5398 (Cobra Cortex-A9 dual-core)"; - else if (is1152) - modelname = "LG1152 (L9)"; - else if (is1154) - modelname = "LG1154 (H13) / LG1311 (M14)"; - else if (isbcm1) - modelname = "BCM 2010 - BCM35XX"; - else if (isbcm2) - modelname = "BCM 2011 - BCM35230"; - else if (ismstar) - modelname = "Mstar Saturn6 / Saturn7 / M1 / M1a / LM1"; - else if (islm14) - modelname = "Mstar LM14"; - else - return; + strncpy(name, pid->name, STR_LEN_MAX); + name[STR_LEN_MAX] = '\0'; + + for (unsigned int i = 0; i < countof(part_type_table); i++) { + if (strcmp(part_type_table[i].name, name) == 0) { + modelname = part_type_table[i].description; + part_type = part_type_table[i].type; + return; + } + } + + part_type = STRUCT_INVALID; + modelname = NULL; - if (ismtk2 || is1154 || islm14) { - part_type = STRUCT_PARTINFOv2; - } else if (ismtk1 || is1152) { - part_type = STRUCT_PARTINFOv1; + if (is_str_printable(name)) { + fprintf(stderr, "unknown part type: '%s'\n", name); } else { - part_type = STRUCT_MTDINFO; + fputs("unknown part type (non-printable characters)\n", stderr); } return; From 326b47891f0864935bd20688f43a291b92355a32 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Fri, 24 Nov 2023 08:19:40 -0500 Subject: [PATCH 02/27] util.c: various improvements Added some error handling. Tried to choose better types. Also made some modifications to util.h and common.h. --- include/util.h | 2 +- src/util.c | 88 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/include/util.h b/include/util.h index a463dbc7..4fa5d51f 100644 --- a/include/util.h +++ b/include/util.h @@ -46,7 +46,7 @@ void unnfsb(const char *filename, const char *extractedFile); MFILE *is_gzip(const char *filename); int is_jffs2(const char *filename); int isSTRfile(const char *filename); -int isdatetime(const char *datetime); +bool is_datetime(const char *datetime); int isPartPakfile(const char *filename); int is_kernel(const char *image_file); void extract_kernel(const char *image_file, const char *destination_file); diff --git a/src/util.c b/src/util.c index 38c062b3..ef524ad9 100644 --- a/src/util.c +++ b/src/util.c @@ -9,17 +9,19 @@ #include #include #include +#include +#include + #include -#include #include -#include +#include #include -#include -#include -#include +#include #include -#include +#include + +#include "config.h" #include "common.h" #include "mfile.h" #include "util.h" @@ -173,8 +175,8 @@ void hexdump(const void *pAddressIn, long lSize) { buf.lSize = lSize; while (buf.lSize > 0) { - pTmp = (unsigned char *)buf.pData; - lOutLen = (int)buf.lSize; + pTmp = (unsigned char *) buf.pData; + lOutLen = (int) buf.lSize; if (lOutLen > 16) lOutLen = 16; @@ -389,15 +391,15 @@ int isSTRfile(const char *filename) { return result; } -int isdatetime(const char *datetime) { +bool is_datetime(const char *datetime) { struct tm time_val; // datetime format is YYYYMMDD - if (strptime(datetime, "%Y%m%d", &time_val) != 0 - && ((time_val.tm_year+1900) > 2005)) { - return 1; + if ((strptime(datetime, "%Y%m%d", &time_val) != NULL) + && ((time_val.tm_year + 1900) > 2005)) { + return true; } else { - return 0; + return false; } } @@ -465,10 +467,10 @@ int isPartPakfile(const char *filename) { char *cmagic = NULL; asprintf(&cmagic, "%x", partinfo.magic); - int r = isdatetime(cmagic); + bool valid = is_datetime((const char *) cmagic); free(cmagic); - if (r == 0) { + if (!valid) { return 0; } @@ -502,25 +504,59 @@ int is_kernel(const char *image_file) { void extract_kernel(const char *image_file, const char *destination_file) { FILE *file = fopen(image_file, "rb"); - if (file == NULL) - err_exit("Can't open file %s", image_file); + if (file == NULL) { + err_exit("Can't open file %s\n", image_file); + } + + if (fseek(file, 0, SEEK_END) != 0) { + fclose(file); + err_exit("fseek on %s failed: %s\n", image_file, strerror(errno)); + } + + long file_length = ftell(file); + if (file_length < 0) { + fclose(file); + err_exit("ftell on %s failed: %s\n", image_file, strerror(errno)); + } - fseek(file, 0, SEEK_END); - int fileLength = ftell(file); rewind(file); - unsigned char *buffer = malloc(fileLength); - int read = fread(buffer, 1, fileLength, file); - if (read != fileLength) { - err_exit("Error reading file. read %d bytes from %d.\n", read, fileLength); - free(buffer); + + const size_t header_size = sizeof(struct image_header); + if ((size_t) file_length < header_size) { + fclose(file); + err_exit("File %s is too small to be a valid kernel image: %ld < %zu\n", image_file, file_length, header_size); + } + + unsigned char *buffer = malloc(file_length); + if (buffer == NULL) { + fclose(file); + err_exit("Memory allocation failed for buffer of size %ld bytes\n", file_length); } + + size_t bytes_read = fread(buffer, 1, file_length, file); fclose(file); + if (bytes_read != file_length) { + free(buffer); + err_exit("Error reading file. read %zu bytes from %ld.\n", bytes_read, file_length); + } + FILE *out = fopen(destination_file, "wb"); - int header_size = sizeof(struct image_header); - fwrite(buffer + header_size, 1, read - header_size, out); + if (out == NULL) { + free(buffer); + err_exit("Can't open file %s\n", destination_file); + } + + size_t bytes_written = fwrite(buffer + header_size, 1, bytes_read - header_size, out); free(buffer); fclose(out); + + if (bytes_written != (bytes_read - header_size)) { + /* Remove partially written output file */ + remove(destination_file); + + err_exit("Error writing file %s\n", destination_file); + } } /** From 0e2b5e262b036da6a5243fc9a1d3e9f9c5fd8084 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 31 Dec 2023 09:16:08 -0500 Subject: [PATCH 03/27] clean up various stuff --- include/util_crypto.h | 10 +++----- src/epk.c | 10 +++----- src/mediatek_pkg.c | 6 ++--- src/util_crypto.c | 59 ++++++++++++++++++++++++------------------- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/include/util_crypto.h b/include/util_crypto.h index 5bfba102..8d752bc7 100644 --- a/include/util_crypto.h +++ b/include/util_crypto.h @@ -17,12 +17,8 @@ typedef int (*CompareFunc)(uint8_t *data, size_t size); -void setKeyFile(const char *keyFile); -void setKeyFile_LG(); -void setKeyFile_MTK(); - -uint8_t *getLastKey(); -uint8_t *getLastIV(); +void setKeyFile_LG(void); +void setKeyFile_MTK(void); #define MAX_KEY_SIZE (AES_BLOCK_SIZE * 2) // AES-256 @@ -34,7 +30,7 @@ typedef struct { KeyPair *find_AES_key( uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, - int key_type, void **dataOut, int verbose + int key_type, void **dataOut, bool verbose ); #endif diff --git a/src/epk.c b/src/epk.c index 82c68304..bde0cf3e 100644 --- a/src/epk.c +++ b/src/epk.c @@ -187,7 +187,7 @@ int wrap_verifyimage(void *signature, void *data, size_t signSize, char *config_ if (result < 0) { fprintf(stderr, "WARNING: Cannot verify digital signature (maybe you don't have proper PEM file)\n\n"); } else { - printf("Succesfully verified 0x%x out of 0x%x bytes\n", effectiveSignedSize, signSize); + printf("Succesfully verified 0x%zx out of 0x%zx bytes\n", effectiveSignedSize, signSize); } return result; } @@ -197,16 +197,14 @@ int wrap_verifyimage(void *signature, void *data, size_t signSize, char *config_ */ void decryptImage(void *srcaddr, size_t len, void *dstaddr) { unsigned int remaining = len; - unsigned int decrypted = 0; + while (remaining >= AES_BLOCK_SIZE) { AES_decrypt(srcaddr, dstaddr, aesKey); srcaddr += AES_BLOCK_SIZE; dstaddr += AES_BLOCK_SIZE; remaining -= AES_BLOCK_SIZE; - decrypted++; } if (remaining != 0) { - decrypted = decrypted * AES_BLOCK_SIZE; memcpy(dstaddr, srcaddr, remaining); } } @@ -244,7 +242,7 @@ int wrap_decryptimage(void *src, size_t datalen, void *dest, char *config_dir, F if(!keyFound){ printf("Trying known AES keys...\n"); - KeyPair *keyPair = find_AES_key(src, datalen, compareFunc, KEY_ECB, (void **)&decryptedData, 1); + KeyPair *keyPair = find_AES_key(src, datalen, compareFunc, KEY_ECB, (void **)&decryptedData, true); decrypted = keyFound = (keyPair != NULL); if(decrypted){ aesKey = &(keyPair->key); @@ -292,7 +290,7 @@ void extractEPKfile(const char *epk_file, config_opts_t *config_opts){ //Make it R/W mprotect(epk->pMem, msize(epk), PROT_READ | PROT_WRITE); - printf("File size: %d bytes\n", msize(epk)); + printf("File size: %jd bytes\n", (intmax_t) msize(epk)); struct epk2_structure *epk2 = mdata(epk, struct epk2_structure); EPK_V2_HEADER_T *epkHeader = &(epk2->epkHeader); diff --git a/src/mediatek_pkg.c b/src/mediatek_pkg.c index fb9a5cc3..214eb1e1 100644 --- a/src/mediatek_pkg.c +++ b/src/mediatek_pkg.c @@ -108,14 +108,14 @@ MFILE *is_mtk_pkg(const char *pkgfile){ KeyPair *headerKey = NULL; do { - if((headerKey = find_AES_key(data, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, 0)) != NULL){ + if((headerKey = find_AES_key(data, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, false)) != NULL){ break; } /* It failed, but we want to check for Philips. * Philips has an additional 0x80 header before the normal PKG one */ - if((headerKey = find_AES_key(data + PHILIPS_HEADER_SIZE, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, 0)) != NULL){ + if((headerKey = find_AES_key(data + PHILIPS_HEADER_SIZE, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, false)) != NULL){ mtkpkg_variant_flags |= PHILIPS; } } while(0); @@ -451,7 +451,7 @@ void extract_mtk_pkg(const char *pkgFile, config_opts_t *config_opts){ compare_content_header, KEY_CBC, (void **)&decryptedPkgData, - 1 + true ); int success = dataKey != NULL; if(success){ diff --git a/src/util_crypto.c b/src/util_crypto.c index e7f2026c..6e8a9136 100644 --- a/src/util_crypto.c +++ b/src/util_crypto.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include @@ -15,25 +16,31 @@ static char *keyFileName = NULL; -void setKeyFile(const char *keyFile){ +static void setKeyFile(char *keyFile){ if(keyFileName != NULL) free(keyFileName); - keyFileName = (char *)keyFile; + keyFileName = keyFile; } -void setKeyFile_LG(){ - char *path; - asprintf(&path, "%s/AES.key", config_opts.config_dir); +void setKeyFile_LG(void){ + char *path = NULL; + if (asprintf(&path, "%s/AES.key", config_opts.config_dir) == -1) { + fprintf(stderr, "error: failed to allocate string in %s\n", __func__); + return; + } setKeyFile(path); } -void setKeyFile_MTK(){ - char *path; - asprintf(&path, "%s/MTK.key", config_opts.config_dir); +void setKeyFile_MTK(void){ + char *path = NULL; + if (asprintf(&path, "%s/MTK.key", config_opts.config_dir) == -1) { + fprintf(stderr, "error: failed to allocate string in %s\n", __func__); + return; + } setKeyFile(path); } -KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, int key_type, void **dataOut, int verbose){ +KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, int key_type, void **dataOut, bool verbose){ AES_KEY aesKey; int found = 0; @@ -47,16 +54,13 @@ KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompar return NULL; } - uint8_t key_buf[MAX_KEY_SIZE]; - uint8_t iv_buf[MAX_KEY_SIZE]; - memset(&key_buf, 0x00, sizeof(key_buf)); - memset(&iv_buf, 0x00, sizeof(iv_buf)); + uint8_t key_buf[MAX_KEY_SIZE] = {0}; + uint8_t iv_buf[MAX_KEY_SIZE] = {0}; - ssize_t read; size_t len = 0; char *line = NULL; - while ((read = getline(&line, &len, fp)) != -1) { + while (getline(&line, &len, fp) != -1) { if ((line[0] == '#') || (line[0] == '\0') || (line[0] == '\n') || (line[0] == '\r')) { /* skip commented or empty line */ @@ -64,7 +68,7 @@ KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompar } char *pos = line; - uint8_t *buf = (uint8_t *)&key_buf; + uint8_t *buf = key_buf; size_t count; if(verbose){ @@ -80,12 +84,12 @@ KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompar break; } if(verbose){ - printf("%02X", buf[count]); + printf("%02hhX", buf[count]); } pos += 2; } if(key_type == KEY_CBC && *pos == ','){ //repeat for IV - buf = (uint8_t *)&iv_buf; + buf = iv_buf; pos++; if(verbose) printf(", IV: "); @@ -96,22 +100,25 @@ KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompar if(verbose){ printf(" (aes %d) %s\n", key_bits, pos); } - AES_set_decrypt_key((uint8_t *)&key_buf, key_bits, &aesKey); + AES_set_decrypt_key(key_buf, key_bits, &aesKey); uint8_t *tmp_data = calloc(1, in_data_size); switch(key_type){ - case KEY_CBC:; + case KEY_CBC: { uint8_t iv_tmp[16]; - memcpy(&iv_tmp, &iv_buf, sizeof(iv_tmp)); - AES_cbc_encrypt(in_data, tmp_data, in_data_size, &aesKey, (uint8_t *)&iv_tmp, AES_DECRYPT); + memcpy(iv_tmp, iv_buf, sizeof(iv_tmp)); + AES_cbc_encrypt(in_data, tmp_data, in_data_size, &aesKey, iv_tmp, AES_DECRYPT); break; - case KEY_ECB:; + } + case KEY_ECB: { size_t blocks = in_data_size / AES_BLOCK_SIZE; size_t i; - for(i=0; ikey), &aesKey, sizeof(aesKey)); + memcpy(&(key->key), &aesKey, sizeof(key->key)); if(key_type == KEY_CBC){ - memcpy(&(key->ivec), &iv_buf, sizeof(iv_buf)); + memcpy(&(key->ivec), iv_buf, sizeof(key->ivec)); } free(line); fclose(fp); From b6ed6079fb0f9ed815d30a01e0dc34e944fd9c8c Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 31 Dec 2023 12:41:32 -0500 Subject: [PATCH 04/27] epk3.c: fix format specifiers --- src/epk3.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/epk3.c b/src/epk3.c index 90b8c3dd..bbc6ea2e 100644 --- a/src/epk3.c +++ b/src/epk3.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "main.h" #include "config.h" @@ -170,8 +171,8 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ epkHeader->old.epkVersion[1], epkHeader->old.epkVersion[0] ); - printf("packageInfoSize: %d\n", epkHeader->old.packageInfoSize); - printf("bChunked: %d\n", epkHeader->old.bChunked); + printf("packageInfoSize: %" PRIu32 "\n", epkHeader->old.packageInfoSize); + printf("bChunked: %" PRIu32 "\n", epkHeader->old.bChunked); if(epkType == EPK_V3_NEW){ printf("EncryptType: %.*s\n", @@ -224,7 +225,7 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ if(epkType == EPK_V3_NEW){ if(packageInfo->new.pakInfoMagic != epkHeader->new.pakInfoMagic){ - printf("pakInfoMagic mismatch! (expected: %04X, actual: %04X)\n", + printf("pakInfoMagic mismatch! (expected: %04" PRIX32 ", actual: %04" PRIX32 ")\n", epkHeader->new.pakInfoMagic, packageInfo->new.pakInfoMagic ); @@ -249,12 +250,12 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ for(uint i = 0; ipackageInfoSize != sizeof(*pak)){ - printf("Warning: Unexpected packageInfoSize '%d', expected '%d'\n", + printf("Warning: Unexpected packageInfoSize '%" PRIu32 "', expected '%zu'\n", pak->packageInfoSize, sizeof(*pak) ); } - printf("\nPAK '%s' contains %d segment(s), size %d bytes:\n", + printf("\nPAK '%s' contains %" PRIu32 " segment(s), size %" PRIu32 " bytes:\n", pak->packageName, pak->segmentInfo.segmentCount, pak->packageSize @@ -291,11 +292,11 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ } - printf(" segment #%u (name='%s', version='%s', offset='0x%lx', size='%u bytes')\n", + printf(" segment #%u (name='%s', version='%s', offset='0x%jx', size='%" PRIu32 " bytes')\n", segNo + 1, pak->packageName, pak->packageVersion, - moff(epk, dataPtr), + (intmax_t) moff(epk, dataPtr), pak->segmentInfo.segmentSize ); @@ -315,7 +316,7 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ if(epkType == EPK_V3_NEW){ uint32_t decryptedSegmentIndex = *(uint32_t *)dataPtr; if(decryptedSegmentIndex != i){ - printf("Warning: Decrypted segment doesn't match expected index! (index: %d, expected: %d)\n", + printf("Warning: Decrypted segment doesn't match expected index! (index: %" PRIu32 ", expected: %u)\n", decryptedSegmentIndex, i ); } @@ -335,4 +336,3 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ free(pakFileName); } } - From 96cf96a62c1fb6dbb77fc647d08bc011dbeb1013 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 31 Dec 2023 12:46:31 -0500 Subject: [PATCH 05/27] epk.c: check for unhandled switch cases --- src/epk.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/epk.c b/src/epk.c index bde0cf3e..443f0aba 100644 --- a/src/epk.c +++ b/src/epk.c @@ -229,6 +229,10 @@ int wrap_decryptimage(void *src, size_t datalen, void *dest, char *config_dir, F case EPK_V3: compareFunc = compare_epk3_header; break; + case RAW: /* special case below */ + break; + default: + err_exit("Error in %s: file type %d not handled\n", __func__, type); } int decrypted = 0; @@ -325,6 +329,8 @@ void extractEPKfile(const char *epk_file, config_opts_t *config_opts){ printf("[+] EPK v3 Detected\n"); extractEPK3(epk, epkType, config_opts); break; + default: + err_exit("Error in %s: file type not handled\n", __func__); } } while(0); } From 156394d8bab8aed034d8132c7323398b849d55aa Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 31 Dec 2023 12:49:25 -0500 Subject: [PATCH 06/27] epk.c: remove extraneous loop --- src/epk.c | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/src/epk.c b/src/epk.c index 443f0aba..22cecc1f 100644 --- a/src/epk.c +++ b/src/epk.c @@ -286,51 +286,49 @@ bool isEpkVersionString(const char *str){ * Detects if the EPK file is v2 or v3, and extracts it */ void extractEPKfile(const char *epk_file, config_opts_t *config_opts){ - do { - MFILE *epk = mopen_private(epk_file, O_RDONLY); - if(!epk){ - err_exit("\nCan't open file %s\n\n", epk_file); - } - //Make it R/W - mprotect(epk->pMem, msize(epk), PROT_READ | PROT_WRITE); + MFILE *epk = mopen_private(epk_file, O_RDONLY); + if(!epk){ + err_exit("\nCan't open file %s\n\n", epk_file); + } + //Make it R/W + mprotect(epk->pMem, msize(epk), PROT_READ | PROT_WRITE); - printf("File size: %jd bytes\n", (intmax_t) msize(epk)); + printf("File size: %jd bytes\n", (intmax_t) msize(epk)); - struct epk2_structure *epk2 = mdata(epk, struct epk2_structure); - EPK_V2_HEADER_T *epkHeader = &(epk2->epkHeader); + struct epk2_structure *epk2 = mdata(epk, struct epk2_structure); + EPK_V2_HEADER_T *epkHeader = &(epk2->epkHeader); - int result; - FILE_TYPE_T epkType; - if(compare_epk2_header((uint8_t *)epkHeader, sizeof(*epkHeader))){ - epkType = EPK_V2; - } else { - printf("\nTrying to decrypt EPK header...\n"); - /* Detect if the file is EPK v2 or EPK v3 */ - result = wrap_decryptimage( - epkHeader, - sizeof(EPK_V2_HEADER_T), - epkHeader, - config_opts->config_dir, - EPK, - &epkType - ); - if(result < 0){ - break; - } + int result; + FILE_TYPE_T epkType; + if(compare_epk2_header((uint8_t *)epkHeader, sizeof(*epkHeader))){ + epkType = EPK_V2; + } else { + printf("\nTrying to decrypt EPK header...\n"); + /* Detect if the file is EPK v2 or EPK v3 */ + result = wrap_decryptimage( + epkHeader, + sizeof(EPK_V2_HEADER_T), + epkHeader, + config_opts->config_dir, + EPK, + &epkType + ); + if(result < 0){ + return; } + } - switch(epkType){ - case EPK_V2: - printf("[+] EPK v2 Detected\n"); - extractEPK2(epk, config_opts); - break; - case EPK_V3: - case EPK_V3_NEW: - printf("[+] EPK v3 Detected\n"); - extractEPK3(epk, epkType, config_opts); - break; - default: - err_exit("Error in %s: file type not handled\n", __func__); - } - } while(0); + switch(epkType){ + case EPK_V2: + printf("[+] EPK v2 Detected\n"); + extractEPK2(epk, config_opts); + break; + case EPK_V3: + case EPK_V3_NEW: + printf("[+] EPK v3 Detected\n"); + extractEPK3(epk, epkType, config_opts); + break; + default: + err_exit("Error in %s: file type not handled\n", __func__); + } } From cff273d1c5294f28f2d4d416f79a4f4a3514fee9 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 31 Dec 2023 13:00:23 -0500 Subject: [PATCH 07/27] minor cleanup in mfile.[ch] --- include/mfile.h | 2 +- src/mfile.c | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/mfile.h b/include/mfile.h index 845f2948..9f34b472 100644 --- a/include/mfile.h +++ b/include/mfile.h @@ -61,7 +61,7 @@ typedef struct { void *pMem; } MFILE; -MFILE *mfile_new(); +MFILE *mfile_new(void); void *mfile_map(MFILE *file, size_t size); void *mfile_map_private(MFILE *file, size_t size); diff --git a/src/mfile.c b/src/mfile.c index 8afb9936..353bfdb1 100644 --- a/src/mfile.c +++ b/src/mfile.c @@ -17,13 +17,18 @@ #include "common.h" #include "util.h" -#define PERMS_DEFAULT (mode_t)0666 +#define PERMS_DEFAULT ((mode_t) 0666) /* * Creates a new mfile structure */ -inline MFILE *mfile_new(){ +inline MFILE *mfile_new(void){ MFILE *mem = calloc(1, sizeof(MFILE)); + + if (mem == NULL) { + err_exit("Error in %s: failed to allocate MFILE\n", __func__); + } + return mem; } @@ -31,13 +36,17 @@ inline MFILE *mfile_new(){ * Updates size and path to a file */ int _mfile_update_info(MFILE *file, const char *path){ - if(path){ - if(file->path) + if(path != NULL){ + if(file->path != NULL) free(file->path); file->path = strdup(path); } - if(stat(file->path, &(file->statBuf)) < 0) - return -1; + if(LIKELY(file->path != NULL)){ + if(stat(file->path, &(file->statBuf)) < 0) + return -1; + } else { + fprintf(stderr, "Warning: %s has no effect because file->path is NULL\n", __func__); + } return 0; } From 9fcd3449e48e47d32665a0524b20e9df727c5fb0 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 31 Dec 2023 13:29:41 -0500 Subject: [PATCH 08/27] make -n affect all filesystems --- include/config.h | 2 +- src/main.c | 54 +++++++++++++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/include/config.h b/include/config.h index 77eb2fa6..6d84df9d 100644 --- a/include/config.h +++ b/include/config.h @@ -11,7 +11,7 @@ typedef struct { char *config_dir; char *dest_dir; int enableSignatureChecking; - bool noAutoUnsquashfs; + bool noAutoExtractFs; bool signatureOnly; } config_opts_t; diff --git a/src/main.c b/src/main.c index ac81e047..59765d7e 100644 --- a/src/main.c +++ b/src/main.c @@ -103,7 +103,7 @@ int handle_file(char *file, config_opts_t *config_opts) { handle_file(dest_file, config_opts); /* SQUASHFS */ } else if (is_squashfs(file)) { - if (!config_opts->noAutoUnsquashfs) { + if (!config_opts->noAutoExtractFs) { asprintf(&dest_file, "%s/%s.unsquashfs", dest_dir, file_name); printf("UnSQUASHFS file to: %s\n", dest_file); rmrf(dest_file); @@ -133,16 +133,24 @@ int handle_file(char *file, config_opts_t *config_opts) { split_rtk_bspfw(mf, dest_dir); /* CRAMFS Big Endian */ } else if (is_cramfs_image(file, "be")) { - asprintf(&dest_file, "%s/%s.cramswap", dest_dir, file_name); - printf("Swapping cramfs endian for file %s\n", file); - cramswap(file, dest_file); - handle_file(dest_file, config_opts); + if (!config_opts->noAutoExtractFs) { + asprintf(&dest_file, "%s/%s.cramswap", dest_dir, file_name); + printf("Swapping cramfs endian for file %s\n", file); + cramswap(file, dest_file); + handle_file(dest_file, config_opts); + } else { + puts("Not UnCRAMFSing (big endian)"); + } /* CRAMFS Little Endian */ } else if (is_cramfs_image(file, "le")) { - asprintf(&dest_file, "%s/%s.uncramfs", dest_dir, file_name); - printf("UnCRAMFS %s to folder %s\n", file, dest_file); - rmrf(dest_file); - uncramfs(dest_file, file); + if (!config_opts->noAutoExtractFs) { + asprintf(&dest_file, "%s/%s.uncramfs", dest_dir, file_name); + printf("UnCRAMFS %s to folder %s\n", file, dest_file); + rmrf(dest_file); + uncramfs(dest_file, file); + } else { + puts("Not UnCRAMFSing (little endian)"); + } /* Kernel uImage */ } else if (is_kernel(file)) { asprintf(&dest_file, "%s/%s.unpaked", dest_dir, file_name); @@ -156,17 +164,21 @@ int handle_file(char *file, config_opts_t *config_opts) { dump_partinfo(file, dest_file); /* JFFS2 */ } else if (is_jffs2(file)) { - asprintf(&dest_file, "%s/%s.unjffs2", dest_dir, file_name); - printf("UnJFFS2 file %s to folder %s\n", file, dest_file); - rmrf(dest_file); + if (!config_opts->noAutoExtractFs) { + asprintf(&dest_file, "%s/%s.unjffs2", dest_dir, file_name); + printf("UnJFFS2 file %s to folder %s\n", file, dest_file); + rmrf(dest_file); - struct jffs2_main_args args = { - .erase_size = -1, - .keep_unlinked = false, - .verbose = 0 - }; + struct jffs2_main_args args = { + .erase_size = -1, + .keep_unlinked = false, + .verbose = 0 + }; - jffs2extract(file, dest_file, args); + jffs2extract(file, dest_file, args); + } else { + puts("Not UnJFFS2ing"); + } /* PVR STR (ts/m2ts video) */ } else if (isSTRfile(file)) { asprintf(&dest_file, "%s/%s.ts", dest_dir, file_name); @@ -240,7 +252,7 @@ int main(int argc, char *argv[]) { config_opts.config_dir = my_dirname(exe_dir); config_opts.dest_dir = calloc(1, PATH_MAX); config_opts.enableSignatureChecking = 0; - config_opts.noAutoUnsquashfs = false; + config_opts.noAutoExtractFs = false; config_opts.signatureOnly = false; int opt; @@ -255,7 +267,7 @@ int main(int argc, char *argv[]) { break; } case 'n':{ - config_opts.noAutoUnsquashfs = true; + config_opts.noAutoExtractFs = true; break; } case 'S':{ @@ -320,6 +332,6 @@ static int print_usage(void) { printf(" -c : extract to current directory instead of source file directory\n"); printf(" -s : enable signature checking for EPK files\n"); printf(" -S : only check signature (implies -s)\n"); - printf(" -n : no automatic unsquashfs\n\n"); + printf(" -n : no automatic filesystem extraction\n\n"); return err_ret(NULL); } From 9b53917f9554d357c08ffd0c60692bd45c1054ad Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 31 Dec 2023 13:01:12 -0500 Subject: [PATCH 09/27] check multiple paths for AES key file --- src/util_crypto.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/util_crypto.c b/src/util_crypto.c index 6e8a9136..e8f1e06c 100644 --- a/src/util_crypto.c +++ b/src/util_crypto.c @@ -14,30 +14,40 @@ #include "util.h" #include "util_crypto.h" -static char *keyFileName = NULL; +static const char *keyFileName = NULL; -static void setKeyFile(char *keyFile){ - if(keyFileName != NULL) - free(keyFileName); - keyFileName = keyFile; -} +static const char *const key_paths[] = { + "", /* directory of executable */ + "../share/epk2extract/" +}; void setKeyFile_LG(void){ - char *path = NULL; - if (asprintf(&path, "%s/AES.key", config_opts.config_dir) == -1) { - fprintf(stderr, "error: failed to allocate string in %s\n", __func__); - return; - } - setKeyFile(path); + keyFileName = "AES.key"; } void setKeyFile_MTK(void){ - char *path = NULL; - if (asprintf(&path, "%s/MTK.key", config_opts.config_dir) == -1) { - fprintf(stderr, "error: failed to allocate string in %s\n", __func__); - return; + keyFileName = "MTK.key"; +} + +static FILE *open_key_file(void) { + for (unsigned int i = 0; i < countof(key_paths); i++) { + char *path = NULL; + + if (asprintf(&path, "%s/%s%s", config_opts.config_dir, key_paths[i], keyFileName) == -1) { + fprintf(stderr, "error: failed to allocate string in %s\n", __func__); + continue; + } + + FILE *fp = fopen(path, "r"); + + free(path); + + if (fp != NULL) { + return fp; + } } - setKeyFile(path); + + return NULL; } KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, int key_type, void **dataOut, bool verbose){ @@ -48,7 +58,7 @@ KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompar err_exit("No key file selected!\n"); } - FILE *fp = fopen(keyFileName, "r"); + FILE *fp = open_key_file(); if (fp == NULL) { fprintf(stderr, "Error: Cannot open key file.\n"); return NULL; From 0b46580128ed34a57ab2a581416625ef822814a6 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 22 Mar 2026 01:57:00 -0400 Subject: [PATCH 10/27] change CompareFunc signature CompareFunc now takes a const pointer and returns bool. Separated get_epak_header_type() out from compare_epak_header() and added INVALID to FILE_TYPE_T for when get_epak_header_type() does not find a match. --- include/epk.h | 1 + include/epk2.h | 4 ++-- include/epk3.h | 4 ++-- include/util_crypto.h | 4 +++- src/epk.c | 29 +++++++++++++++++++---------- src/epk2.c | 10 +++++----- src/epk3.c | 11 +++++------ src/mediatek_pkg.c | 29 +++++++++++++---------------- src/util_crypto.c | 3 +-- 9 files changed, 51 insertions(+), 44 deletions(-) diff --git a/include/epk.h b/include/epk.h index 581e71dc..54646458 100644 --- a/include/epk.h +++ b/include/epk.h @@ -22,6 +22,7 @@ typedef enum { } BUILD_TYPE_T; typedef enum { + INVALID = -1, EPK, EPK_V2, EPK_V3, diff --git a/include/epk2.h b/include/epk2.h index ddb584b0..ce1e2c82 100644 --- a/include/epk2.h +++ b/include/epk2.h @@ -12,8 +12,8 @@ #define EPK2_MAGIC "EPK2" #define PAK_MAGIC "MPAK" -int compare_pak2_header(uint8_t *header, size_t headerSize); -int compare_epk2_header(uint8_t *header, size_t headerSize); +bool compare_pak2_header(const uint8_t *header, size_t headerSize); +bool compare_epk2_header(const uint8_t *header, size_t headerSize); MFILE *isFileEPK2(const char *epk_file); void extractEPK2(MFILE *epk, config_opts_t *config_opts); diff --git a/include/epk3.h b/include/epk3.h index ab3e78b2..5578bd64 100644 --- a/include/epk3.h +++ b/include/epk3.h @@ -10,8 +10,8 @@ #define EPK3_MAGIC "EPK3" -int compare_epk3_header(uint8_t *header, size_t headerSize); -int compare_epk3_new_header(uint8_t *header, size_t headerSize); +bool compare_epk3_header(const uint8_t *header, size_t headerSize); +bool compare_epk3_new_header(const uint8_t *header, size_t headerSize); MFILE *isFileEPK3(const char *epk_file); void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts); diff --git a/include/util_crypto.h b/include/util_crypto.h index 8d752bc7..3fd39493 100644 --- a/include/util_crypto.h +++ b/include/util_crypto.h @@ -4,6 +4,8 @@ */ #ifndef __UTIL_CRYPTO_H #define __UTIL_CRYPTO_H +#include +#include #include #include @@ -15,7 +17,7 @@ #define KEY_ECB (1 << 0) #define KEY_CBC (1 << 1) -typedef int (*CompareFunc)(uint8_t *data, size_t size); +typedef bool (*CompareFunc)(const uint8_t *data, size_t size); void setKeyFile_LG(void); void setKeyFile_MTK(void); diff --git a/src/epk.c b/src/epk.c index 22cecc1f..1d6b68bd 100644 --- a/src/epk.c +++ b/src/epk.c @@ -29,18 +29,27 @@ static int sigCheckAvailable = 0; static int firstAttempt = 1; /* - * Checks if the given data is an EPK2 or EPK3 header + * Determines the format of an EPK header + * + * Returns the detected type, or INVALID if no match found */ -int compare_epak_header(uint8_t *header, size_t headerSize){ - if(compare_epk2_header(header, headerSize)){ +static FILE_TYPE_T get_epak_header_type(const uint8_t *header, size_t headerSize) { + if (compare_epk2_header(header, headerSize)) { return EPK_V2; - } else if(compare_epk3_header(header, headerSize)){ + } else if (compare_epk3_header(header, headerSize)) { return EPK_V3; - } else if(compare_epk3_new_header(header, headerSize)){ + } else if (compare_epk3_new_header(header, headerSize)) { return EPK_V3_NEW; } - return 0; + return INVALID; +} + +/* + * Checks if the given data is an EPK2 or EPK3 header + */ +static bool compare_epak_header(const uint8_t *header, size_t headerSize) { + return (get_epak_header_type(header, headerSize) != INVALID); } /* @@ -235,12 +244,12 @@ int wrap_decryptimage(void *src, size_t datalen, void *dest, char *config_dir, F err_exit("Error in %s: file type %d not handled\n", __func__, type); } - int decrypted = 0; + bool decrypted = false; uint8_t *decryptedData = NULL; // Check if we need decryption if(type != RAW && compareFunc(src, datalen)){ - decrypted = 1; + decrypted = true; return decrypted; } @@ -258,7 +267,7 @@ int wrap_decryptimage(void *src, size_t datalen, void *dest, char *config_dir, F } else { decryptImage(src, datalen, dest); if(type == RAW) - decrypted = 1; + decrypted = true; else decrypted = compareFunc(dest, datalen); } @@ -267,7 +276,7 @@ int wrap_decryptimage(void *src, size_t datalen, void *dest, char *config_dir, F return -1; } else if(type == EPK){ if(outType != NULL){ - *outType = compare_epak_header(decryptedData, datalen); + *outType = get_epak_header_type(decryptedData, datalen); } } diff --git a/src/epk2.c b/src/epk2.c index 7ca0960b..d216141f 100644 --- a/src/epk2.c +++ b/src/epk2.c @@ -22,16 +22,16 @@ /* * Checks if the given data is a PAK2 header */ -int compare_pak2_header(uint8_t *header, size_t headerSize){ - PAK_V2_HEADER_T *hdr = (PAK_V2_HEADER_T *)header; +bool compare_pak2_header(const uint8_t *header, size_t headerSize) { + const PAK_V2_HEADER_T *hdr = (const PAK_V2_HEADER_T *) header; return memcmp(hdr->pakMagic, PAK_MAGIC, sizeof(hdr->pakMagic)) == 0; } /* * Checks if the given data is an EPK2 header */ -int compare_epk2_header(uint8_t *header, size_t headerSize){ - EPK_V2_HEADER_T *hdr = (EPK_V2_HEADER_T *)header; +bool compare_epk2_header(const uint8_t *header, size_t headerSize) { + const EPK_V2_HEADER_T *hdr = (const EPK_V2_HEADER_T *) header; return memcmp(hdr->epkMagic, EPK2_MAGIC, sizeof(hdr->epkMagic)) == 0; } @@ -49,7 +49,7 @@ MFILE *isFileEPK2(const char *epk_file) { } // check if the epk magic is present (decrypted) - if(compare_epk2_header((uint8_t *)&(epk2->epkHeader), sizeof(EPK_V2_HEADER_T))){ + if (compare_epk2_header((const uint8_t *) &(epk2->epkHeader), sizeof(EPK_V2_HEADER_T))) { goto checkOk; } diff --git a/src/epk3.c b/src/epk3.c index bbc6ea2e..deda3710 100644 --- a/src/epk3.c +++ b/src/epk3.c @@ -18,17 +18,16 @@ /* * Check for epk3 files with an additional heading signature (whole file signature?) */ -int compare_epk3_new_header(uint8_t *header, size_t headerSize){ - EPK_V3_HEADER_T *hdr = (EPK_V3_HEADER_T *)(header + SIGNATURE_SIZE); +bool compare_epk3_new_header(const uint8_t *header, size_t headerSize) { + const EPK_V3_HEADER_T *hdr = (const EPK_V3_HEADER_T *) (header + SIGNATURE_SIZE); return memcmp(hdr->epkMagic, EPK3_MAGIC, sizeof(hdr->epkMagic)) == 0; } /* * Checks if the given data is an EPK3 header */ -int compare_epk3_header(uint8_t *header, size_t headerSize){ - EPK_V3_HEADER_T *hdr = (EPK_V3_HEADER_T *)header; - +bool compare_epk3_header(const uint8_t *header, size_t headerSize) { + const EPK_V3_HEADER_T *hdr = (const EPK_V3_HEADER_T *) header; return memcmp(hdr->epkMagic, EPK3_MAGIC, sizeof(hdr->epkMagic)) == 0; } @@ -47,7 +46,7 @@ MFILE *isFileEPK3(const char *epk_file) { } // check if the epk magic is present (decrypted) - if(compare_epk3_header((uint8_t *)&(head->epkHeader), sizeof(EPK_V3_HEADER_T))){ + if (compare_epk3_header((const uint8_t *) &(head->epkHeader), sizeof(EPK_V3_HEADER_T))) { goto checkOk; } diff --git a/src/mediatek_pkg.c b/src/mediatek_pkg.c index 214eb1e1..fc5a69ec 100644 --- a/src/mediatek_pkg.c +++ b/src/mediatek_pkg.c @@ -32,30 +32,30 @@ static int mtkpkg_variant_flags = NEW; static struct mtkupg_header packageHeader; static bool was_decrypted = false; -int compare_pkg_header(uint8_t *header, size_t headerSize){ - struct mtkupg_header *hdr = (struct mtkupg_header *)header; +static bool compare_pkg_header(const uint8_t *header, size_t headerSize) { + const struct mtkupg_header *hdr = (const struct mtkupg_header *) header; if( !strncmp(hdr->vendor_magic, HISENSE_PKG_MAGIC, strlen(HISENSE_PKG_MAGIC)) ){ printf("[+] Found HISENSE Package\n"); - return 1; + return true; } if( !strncmp(hdr->vendor_magic, SHARP_PKG_MAGIC, strlen(SHARP_PKG_MAGIC)) ){ printf("[+] Found SHARP Package\n"); mtkpkg_variant_flags |= SHARP; - return 1; + return true; } if( !strncmp(hdr->vendor_magic, TPV_PKG_MAGIC, strlen(TPV_PKG_MAGIC)) || !strncmp(hdr->vendor_magic, TPV_PKG_MAGIC2,strlen(TPV_PKG_MAGIC2)) ){ printf("[+] Found PHILIPS(TPV) Package\n"); - return 1; + return true; } if( !strncmp(hdr->vendor_magic, PHILIPS_PKG_MAGIC, strlen(PHILIPS_PKG_MAGIC)) || !strncmp(hdr->vendor_magic, PHILIPS_PKG_MAGIC2, strlen(PHILIPS_PKG_MAGIC2)) ){ printf("[+] Found PHILIPS Package\n"); - return 1; + return true; } if( !strncmp(hdr->mtk_magic, MTK_FIRMWARE_MAGIC, strlen(MTK_FIRMWARE_MAGIC)) ){ @@ -63,18 +63,15 @@ int compare_pkg_header(uint8_t *header, size_t headerSize){ member_size(struct mtkupg_header, vendor_magic), hdr->vendor_magic ); - return 1; + return true; } - return 0; + return false; } -int compare_content_header(uint8_t *header, size_t headerSize){ - struct mtkpkg_data *data = (struct mtkpkg_data *)header; - if ( !strncmp(data->header.mtk_reserved, MTK_RESERVED_MAGIC, strlen(MTK_RESERVED_MAGIC)) ){ - return 1; - } - return 0; +static bool compare_content_header(const uint8_t *header, size_t headerSize) { + const struct mtkpkg_data *data = (const struct mtkpkg_data *) header; + return strncmp(data->header.mtk_reserved, MTK_RESERVED_MAGIC, strlen(MTK_RESERVED_MAGIC)) == 0; } bool is_known_partition(struct mtkpkg *pak){ @@ -500,8 +497,8 @@ void extract_mtk_pkg(const char *pkgFile, config_opts_t *config_opts){ dataSize, &(dataKey->key), (void *)&iv_tmp, AES_DECRYPT ); - int success = compare_content_header(pkgData, sizeof(struct mtkpkg_data)); - if(!success){ + + if(!compare_content_header(pkgData, sizeof(struct mtkpkg_data))){ fprintf(stderr, "[!] WARNING: MTK Crypted header not found, continuing anyways...\n"); } } diff --git a/src/util_crypto.c b/src/util_crypto.c index e8f1e06c..421ddbd6 100644 --- a/src/util_crypto.c +++ b/src/util_crypto.c @@ -52,7 +52,6 @@ static FILE *open_key_file(void) { KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, int key_type, void **dataOut, bool verbose){ AES_KEY aesKey; - int found = 0; if(keyFileName == NULL){ err_exit("No key file selected!\n"); @@ -134,7 +133,7 @@ KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompar break; } - found = fCompare(tmp_data, in_data_size) > 0; + bool found = fCompare(tmp_data, in_data_size); if(found && dataOut != NULL){ *dataOut = tmp_data; From 94e5c081603b31012269c6afff192771e4fbbe10 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Wed, 3 Jan 2024 22:16:32 -0500 Subject: [PATCH 11/27] change some types Mostly relatively straightforward type fixes/changes, including some format specifier incompatibility. --- include/epk.h | 4 ++-- include/main.h | 2 +- include/util_crypto.h | 2 +- src/epk.c | 14 +++++++------- src/mediatek_pkg.c | 4 ++-- src/util_crypto.c | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/epk.h b/include/epk.h index 54646458..f789a463 100644 --- a/include/epk.h +++ b/include/epk.h @@ -40,7 +40,7 @@ typedef enum { #define EPKV1_VERSION_FORMAT "%02" PRIx8 ".%02" PRIx8 ".%02" PRIx8 bool isEpkVersionString(const char *str); -int wrap_verifyimage(void *signature, void *data, size_t signSize, char *config_dir, SIG_TYPE_T sigType); -int wrap_decryptimage(void *src, size_t datalen, void *dest, char *config_dir, FILE_TYPE_T type, FILE_TYPE_T *outType); +int wrap_verifyimage(const void *signature, const void *data, size_t signSize, const char *config_dir, SIG_TYPE_T sigType); +int wrap_decryptimage(const void *src, size_t datalen, void *dest, const char *config_dir, FILE_TYPE_T type, FILE_TYPE_T *outType); void extractEPKfile(const char *epk_file, config_opts_t *config_opts); #endif diff --git a/include/main.h b/include/main.h index e280293d..d414d367 100644 --- a/include/main.h +++ b/include/main.h @@ -6,5 +6,5 @@ #ifndef __MAIN_H #define __MAIN_H #include "config.h" -int handle_file(const char *file, config_opts_t *config_opts); +int handle_file(const char *file, const config_opts_t *config_opts); #endif //__MAIN_H diff --git a/include/util_crypto.h b/include/util_crypto.h index 3fd39493..c2fe86b2 100644 --- a/include/util_crypto.h +++ b/include/util_crypto.h @@ -31,7 +31,7 @@ typedef struct { } KeyPair; KeyPair *find_AES_key( - uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, + const uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, int key_type, void **dataOut, bool verbose ); diff --git a/src/epk.c b/src/epk.c index 1d6b68bd..6f721f8f 100644 --- a/src/epk.c +++ b/src/epk.c @@ -55,7 +55,7 @@ static bool compare_epak_header(const uint8_t *header, size_t headerSize) { /* * Loads the specified Public Key for Signature verification */ -int SWU_CryptoInit_PEM(char *configuration_dir, char *pem_file) { +static int SWU_CryptoInit_PEM(const char *configuration_dir, const char *pem_file) { OpenSSL_add_all_digests(); ERR_load_CRYPTO_strings(); char *pem_file_name; @@ -80,7 +80,7 @@ int SWU_CryptoInit_PEM(char *configuration_dir, char *pem_file) { /* * Verifies the signature of the given data against the loaded public key */ -int API_SWU_VerifyImage(void *signature, void* data, size_t imageSize, SIG_TYPE_T sigType) { +static int API_SWU_VerifyImage(const void *signature, const void *data, size_t imageSize, SIG_TYPE_T sigType) { size_t hashSize; unsigned int sigSize; const EVP_MD *algo; @@ -131,8 +131,8 @@ int API_SWU_VerifyImage(void *signature, void* data, size_t imageSize, SIG_TYPE_ /* * Wrapper for signature verification. Retries by decrementing size if it fails */ -int wrap_SWU_VerifyImage( - void *signature, void* data, +static int wrap_SWU_VerifyImage( + const void *signature, const void *data, size_t signedSize, size_t *effectiveSignedSize, SIG_TYPE_T sigType ){ size_t curSize = signedSize; @@ -159,7 +159,7 @@ int wrap_SWU_VerifyImage( /* * High level wrapper for signature verification */ -int wrap_verifyimage(void *signature, void *data, size_t signSize, char *config_dir, SIG_TYPE_T sigType){ +int wrap_verifyimage(const void *signature, const void *data, size_t signSize, const char *config_dir, SIG_TYPE_T sigType){ size_t effectiveSignedSize; int result = -1; if(!sigCheckAvailable){ @@ -204,7 +204,7 @@ int wrap_verifyimage(void *signature, void *data, size_t signSize, char *config_ /* * Decrypts the given data against the loaded AES key, with ECB mode */ -void decryptImage(void *srcaddr, size_t len, void *dstaddr) { +static void decryptImage(const void *srcaddr, size_t len, void *dstaddr) { unsigned int remaining = len; while (remaining >= AES_BLOCK_SIZE) { @@ -223,7 +223,7 @@ void decryptImage(void *srcaddr, size_t len, void *dstaddr) { * The comparison function is selected from the passed file type * For EPK comparison, outType is used to store the detected type (EPK v2 or EPK v3) */ -int wrap_decryptimage(void *src, size_t datalen, void *dest, char *config_dir, FILE_TYPE_T type, FILE_TYPE_T *outType){ +int wrap_decryptimage(const void *src, size_t datalen, void *dest, const char *config_dir, FILE_TYPE_T type, FILE_TYPE_T *outType){ CompareFunc compareFunc = NULL; switch(type){ case EPK: diff --git a/src/mediatek_pkg.c b/src/mediatek_pkg.c index fc5a69ec..c2a90d5a 100644 --- a/src/mediatek_pkg.c +++ b/src/mediatek_pkg.c @@ -292,8 +292,8 @@ void extract_lzhs_fs(MFILE *mf, const char *dest_file, config_opts_t *config_opt struct lzhs_header *main_hdr = (struct lzhs_header *)data; struct lzhs_header *seg_hdr = (struct lzhs_header *)(data + sizeof(*main_hdr)); - printf("\n[0x%08X] segment #%u (compressed='%u bytes', uncompressed='%u bytes')\n", - moff(mf, main_hdr), + printf("\n[0x%08jX] segment #%u (compressed='%u bytes', uncompressed='%u bytes')\n", + (intmax_t) moff(mf, main_hdr), main_hdr->checksum, seg_hdr->compressedSize, seg_hdr->uncompressedSize); diff --git a/src/util_crypto.c b/src/util_crypto.c index 421ddbd6..008fa5ce 100644 --- a/src/util_crypto.c +++ b/src/util_crypto.c @@ -50,7 +50,7 @@ static FILE *open_key_file(void) { return NULL; } -KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, int key_type, void **dataOut, bool verbose){ +KeyPair *find_AES_key(const uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, int key_type, void **dataOut, bool verbose){ AES_KEY aesKey; if(keyFileName == NULL){ From cb9a7451af75fd682ae10b7ff5f7e39c8238a4ea Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Wed, 10 Jan 2024 16:42:08 -0500 Subject: [PATCH 12/27] epk.c: remove redundant comparisons --- src/epk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/epk.c b/src/epk.c index 6f721f8f..b6158dab 100644 --- a/src/epk.c +++ b/src/epk.c @@ -176,7 +176,7 @@ int wrap_verifyimage(const void *signature, const void *data, size_t signSize, c } else { struct dirent* hFile; while ((hFile = readdir(dirFile)) != NULL) { - if (!strcmp(hFile->d_name, ".") || !strcmp(hFile->d_name, "..") || hFile->d_name[0] == '.') continue; + if (hFile->d_name[0] == '.') continue; if (strstr(hFile->d_name, ".pem") || strstr(hFile->d_name, ".PEM")) { printf("Trying RSA key: %s...\n", hFile->d_name); SWU_CryptoInit_PEM(config_dir, hFile->d_name); From 8a3de8c1e617d743b3b6e86bbb96fcb5d4ce7d17 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:34:56 -0500 Subject: [PATCH 13/27] epk.c: skip obvious non-files in RSA key search --- src/epk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/epk.c b/src/epk.c index b6158dab..d206ce16 100644 --- a/src/epk.c +++ b/src/epk.c @@ -177,6 +177,7 @@ int wrap_verifyimage(const void *signature, const void *data, size_t signSize, c struct dirent* hFile; while ((hFile = readdir(dirFile)) != NULL) { if (hFile->d_name[0] == '.') continue; + if ((hFile->d_type != DT_REG) && (hFile->d_type != DT_LNK) && (hFile->d_type != DT_UNKNOWN)) continue; if (strstr(hFile->d_name, ".pem") || strstr(hFile->d_name, ".PEM")) { printf("Trying RSA key: %s...\n", hFile->d_name); SWU_CryptoInit_PEM(config_dir, hFile->d_name); From 09a409e9c92980243b463dfc052e912ffc882b7d Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:35:23 -0400 Subject: [PATCH 14/27] EPKv3 minor changes to PAK extraction --- src/epk3.c | 50 +++++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/src/epk3.c b/src/epk3.c index deda3710..fc524ed6 100644 --- a/src/epk3.c +++ b/src/epk3.c @@ -68,7 +68,8 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ epk3_union *epk3 = mdata(epk, epk3_union); - size_t headerSize, signed_size, sigSize, extraSegmentSize; + size_t headerSize, signed_size, sigSize; + size_t extraSegmentSize; /* size of additional data in new format */ SIG_TYPE_T sigType; { switch(epkType){ @@ -115,16 +116,14 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ ); } - int result = wrap_decryptimage( + if (!wrap_decryptimage( epkHeader, headerSize, epkHeader, config_opts->dest_dir, EPK_V3, NULL - ); - - if(result < 0){ + )) { return; } @@ -209,16 +208,14 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ /* Decrypt packageInfo */ - result = wrap_decryptimage( + if (!wrap_decryptimage( packageInfo, epkHeader->old.packageInfoSize, packageInfo, config_opts->dest_dir, RAW, NULL - ); - - if(result < 0){ + )) { return; } @@ -236,7 +233,7 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ dataPtr += epkHeader->old.packageInfoSize; - int packageInfoCount; + unsigned int packageInfoCount; switch(epkType){ case EPK_V3: @@ -254,43 +251,44 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ ); } - printf("\nPAK '%s' contains %" PRIu32 " segment(s), size %" PRIu32 " bytes:\n", + printf("\nPAK '%s' contains %" PRIu32 " segment%s, size %" PRIu32 " bytes:\n", pak->packageName, pak->segmentInfo.segmentCount, + (pak->segmentInfo.segmentCount == 1) ? "" : "s", pak->packageSize ); - char *pakFileName; + char *pakFileName = NULL; asprintf(&pakFileName, "%s/%s.pak", config_opts->dest_dir, pak->packageName); MFILE *pakFile = mfopen(pakFileName, "w+"); if(!pakFile){ err_exit("Cannot open '%s' for writing\n", pakFileName); } + mfile_map(pakFile, pak->packageSize); printf("Saving partition (%s) to file %s\n", pak->packageName, pakFileName); PACKAGE_SEGMENT_INFO_T segmentInfo = pak->segmentInfo; - uint segNo; - for(segNo = segmentInfo.segmentIndex; + for(uint segNo = segmentInfo.segmentIndex; segNo < segmentInfo.segmentCount; segNo++, pak++, i++ ){ + const void *sigPtr = (void *) dataPtr; dataPtr += sigSize; if(config_opts->enableSignatureChecking) { wrap_verifyimage( - (void *)(dataPtr - sigSize), - (void *)dataPtr, + sigPtr, + (const void *)dataPtr, pak->segmentInfo.segmentSize + extraSegmentSize, config_opts->config_dir, sigType ); } - printf(" segment #%u (name='%s', version='%s', offset='0x%jx', size='%" PRIu32 " bytes')\n", segNo + 1, pak->packageName, @@ -299,16 +297,14 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ pak->segmentInfo.segmentSize ); - result = wrap_decryptimage( - (void *)dataPtr, - pak->segmentInfo.segmentSize, - (void *)dataPtr, - config_opts->dest_dir, - RAW, - NULL - ); - - if(result < 0){ + if (!wrap_decryptimage( + (void *)dataPtr, + pak->segmentInfo.segmentSize, + (void *)dataPtr, + config_opts->dest_dir, + RAW, + NULL + )) { return; } From fee8734bdac2240c5f07a6b16c3de0bb9129e080 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Wed, 10 Jan 2024 19:22:58 -0500 Subject: [PATCH 15/27] epk.c: have SWU_CryptoInit_PEM() return the key --- src/epk.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/epk.c b/src/epk.c index d206ce16..cef42f3e 100644 --- a/src/epk.c +++ b/src/epk.c @@ -55,26 +55,35 @@ static bool compare_epak_header(const uint8_t *header, size_t headerSize) { /* * Loads the specified Public Key for Signature verification */ -static int SWU_CryptoInit_PEM(const char *configuration_dir, const char *pem_file) { +static EVP_PKEY *SWU_CryptoInit_PEM(const char *configuration_dir, const char *pem_file) { OpenSSL_add_all_digests(); ERR_load_CRYPTO_strings(); - char *pem_file_name; - asprintf(&pem_file_name, "%s/%s", configuration_dir, pem_file); + + char *pem_file_name = NULL; + int ret = asprintf(&pem_file_name, "%s/%s", configuration_dir, pem_file); + if (ret == -1) { + err_exit("Error in %s: Failed to allocate memory for PEM file path: %s\n\n", __func__, strerror(errno)); + return NULL; + } + FILE *pubKeyFile = fopen(pem_file_name, "r"); + free(pem_file_name); + if (pubKeyFile == NULL) { printf("Error: Can't open PEM file %s\n\n", pem_file); - return 1; + return NULL; } - EVP_PKEY *gpPubKey = PEM_read_PUBKEY(pubKeyFile, NULL, NULL, NULL); - _gpPubKey = gpPubKey; - if (_gpPubKey == NULL) { + + EVP_PKEY *pPubKey = PEM_read_PUBKEY(pubKeyFile, NULL, NULL, NULL); + if (pPubKey == NULL) { printf("Error: Can't read PEM signature from file %s\n\n", pem_file); - fclose(pubKeyFile); - return 1; + } else { + ERR_clear_error(); } + fclose(pubKeyFile); - ERR_clear_error(); - return 0; + + return pPubKey; } /* @@ -180,7 +189,9 @@ int wrap_verifyimage(const void *signature, const void *data, size_t signSize, c if ((hFile->d_type != DT_REG) && (hFile->d_type != DT_LNK) && (hFile->d_type != DT_UNKNOWN)) continue; if (strstr(hFile->d_name, ".pem") || strstr(hFile->d_name, ".PEM")) { printf("Trying RSA key: %s...\n", hFile->d_name); - SWU_CryptoInit_PEM(config_dir, hFile->d_name); + EVP_PKEY *key = SWU_CryptoInit_PEM(config_dir, hFile->d_name); + if (key == NULL) continue; + _gpPubKey = key; /* TODO: this doesn't need to be global */ result = wrap_SWU_VerifyImage(signature, data, signSize, &effectiveSignedSize, sigType); if(result > -1){ sigCheckAvailable = 1; From ea06bda78580cff96d0e1dd2b0bd1d2d4f7328c3 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Wed, 10 Jan 2024 19:38:17 -0500 Subject: [PATCH 16/27] epk.c: fix bug in signature verification EVP_VerifyFinal() returns -1 on error, and therefore so did API_SWU_VerifyImage(). The check in wrap_SWU_VerifyImage() would treat a return value of -1 as success, meaning it could treat an invalid signature as having been successfully verified. --- src/epk.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/epk.c b/src/epk.c index cef42f3e..949367d1 100644 --- a/src/epk.c +++ b/src/epk.c @@ -89,7 +89,7 @@ static EVP_PKEY *SWU_CryptoInit_PEM(const char *configuration_dir, const char *p /* * Verifies the signature of the given data against the loaded public key */ -static int API_SWU_VerifyImage(const void *signature, const void *data, size_t imageSize, SIG_TYPE_T sigType) { +static bool API_SWU_VerifyImage(const void *signature, const void *data, size_t imageSize, SIG_TYPE_T sigType) { size_t hashSize; unsigned int sigSize; const EVP_MD *algo; @@ -107,7 +107,7 @@ static int API_SWU_VerifyImage(const void *signature, const void *data, size_t i break; default: printf("Invalid sigType: %d\n", sigType); - return 0; + return false; } unsigned char md_value[hashSize]; @@ -116,11 +116,11 @@ static int API_SWU_VerifyImage(const void *signature, const void *data, size_t i EVP_MD_CTX *ctx1, *ctx2; if ((ctx1 = EVP_MD_CTX_new()) == NULL) - return 0; + return false; if ((ctx2 = EVP_MD_CTX_new()) == NULL) { EVP_MD_CTX_free(ctx1); - return 0; + return false; } EVP_DigestInit(ctx1, algo); @@ -134,7 +134,7 @@ static int API_SWU_VerifyImage(const void *signature, const void *data, size_t i EVP_MD_CTX_free(ctx2); EVP_MD_CTX_free(ctx1); - return result; + return (result == 1); } /* @@ -145,7 +145,7 @@ static int wrap_SWU_VerifyImage( size_t signedSize, size_t *effectiveSignedSize, SIG_TYPE_T sigType ){ size_t curSize = signedSize; - int verified; + bool verified; //int skipped = 0; while (curSize > 0) { verified = API_SWU_VerifyImage(signature, data, curSize, sigType); From fefba475ae235d1b4c37002ac48741ca2cef0666 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Wed, 10 Jan 2024 19:58:28 -0500 Subject: [PATCH 17/27] epk.c: streamline API_SWU_VerifyImage() --- src/epk.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/epk.c b/src/epk.c index 949367d1..998729cc 100644 --- a/src/epk.c +++ b/src/epk.c @@ -94,7 +94,7 @@ static bool API_SWU_VerifyImage(const void *signature, const void *data, size_t unsigned int sigSize; const EVP_MD *algo; - switch(sigType) { + switch (sigType) { case SIG_SHA1: hashSize = 0x40; sigSize = SIGNATURE_SIZE; @@ -112,27 +112,24 @@ static bool API_SWU_VerifyImage(const void *signature, const void *data, size_t unsigned char md_value[hashSize]; unsigned int md_len = 0; - int result = 0; - EVP_MD_CTX *ctx1, *ctx2; - if ((ctx1 = EVP_MD_CTX_new()) == NULL) - return false; - - if ((ctx2 = EVP_MD_CTX_new()) == NULL) { - EVP_MD_CTX_free(ctx1); + EVP_MD_CTX *ctx; + if ((ctx = EVP_MD_CTX_new()) == NULL) { return false; } - EVP_DigestInit(ctx1, algo); - EVP_DigestUpdate(ctx1, data, imageSize); - EVP_DigestFinal(ctx1, md_value, &md_len); - EVP_DigestInit(ctx2, algo); - EVP_DigestUpdate(ctx2, md_value, md_len); + EVP_DigestInit(ctx, algo); + EVP_DigestUpdate(ctx, data, imageSize); + EVP_DigestFinal(ctx, md_value, &md_len); + + EVP_MD_CTX_reset(ctx); + + EVP_DigestInit(ctx, algo); + EVP_DigestUpdate(ctx, md_value, md_len); - result = EVP_VerifyFinal(ctx2, signature, sigSize, _gpPubKey); + int result = EVP_VerifyFinal(ctx, signature, sigSize, _gpPubKey); - EVP_MD_CTX_free(ctx2); - EVP_MD_CTX_free(ctx1); + EVP_MD_CTX_free(ctx); return (result == 1); } From 1728669fd225cc28b0540e84fa13ec158cd1dd38 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Wed, 10 Jan 2024 20:14:59 -0500 Subject: [PATCH 18/27] epk.c: dont mix EVP_Digest and EVP_Verify --- src/epk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/epk.c b/src/epk.c index 998729cc..0c0668c2 100644 --- a/src/epk.c +++ b/src/epk.c @@ -124,8 +124,8 @@ static bool API_SWU_VerifyImage(const void *signature, const void *data, size_t EVP_MD_CTX_reset(ctx); - EVP_DigestInit(ctx, algo); - EVP_DigestUpdate(ctx, md_value, md_len); + EVP_VerifyInit(ctx, algo); + EVP_VerifyUpdate(ctx, md_value, md_len); int result = EVP_VerifyFinal(ctx, signature, sigSize, _gpPubKey); From e18f937144746f6a505d555936d37a6521687d08 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Thu, 11 Jan 2024 23:29:07 -0500 Subject: [PATCH 19/27] epk.c: show errors in API_SWU_VerifyImage() --- src/epk.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/epk.c b/src/epk.c index 0c0668c2..761051a8 100644 --- a/src/epk.c +++ b/src/epk.c @@ -129,9 +129,17 @@ static bool API_SWU_VerifyImage(const void *signature, const void *data, size_t int result = EVP_VerifyFinal(ctx, signature, sigSize, _gpPubKey); + /* I hope this can't affect OpenSSL's error queue. */ EVP_MD_CTX_free(ctx); - return (result == 1); + if (result == 1) { + return true; + } else if (result != 0) { + fprintf(stderr, "Error: EVP_VerifyFinal failed in %s:\n", __func__); + ERR_print_errors_fp(stderr); + } + + return false; } /* From 49e0ee56fb0d24209f4c1c1f1ce1586f6f0a252c Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Fri, 12 Jan 2024 01:04:04 -0500 Subject: [PATCH 20/27] epk.c: use EVP_DigestVerify() for second hash --- src/epk.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/epk.c b/src/epk.c index 761051a8..15bfd431 100644 --- a/src/epk.c +++ b/src/epk.c @@ -122,12 +122,8 @@ static bool API_SWU_VerifyImage(const void *signature, const void *data, size_t EVP_DigestUpdate(ctx, data, imageSize); EVP_DigestFinal(ctx, md_value, &md_len); - EVP_MD_CTX_reset(ctx); - - EVP_VerifyInit(ctx, algo); - EVP_VerifyUpdate(ctx, md_value, md_len); - - int result = EVP_VerifyFinal(ctx, signature, sigSize, _gpPubKey); + EVP_DigestVerifyInit(ctx, NULL, algo, NULL, _gpPubKey); + int result = EVP_DigestVerify(ctx, signature, sigSize, md_value, md_len); /* I hope this can't affect OpenSSL's error queue. */ EVP_MD_CTX_free(ctx); From c24a71050af56678bc55c028e11b5608006c0370 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Fri, 12 Jan 2024 01:30:23 -0500 Subject: [PATCH 21/27] epk3.c: add default cases to placate clang These probably shouldn't even be switches. --- src/epk3.c | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/epk3.c b/src/epk3.c index fc524ed6..4cbf6f17 100644 --- a/src/epk3.c +++ b/src/epk3.c @@ -71,30 +71,28 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ size_t headerSize, signed_size, sigSize; size_t extraSegmentSize; /* size of additional data in new format */ SIG_TYPE_T sigType; - { - switch(epkType){ - case EPK_V3: - headerSize = sizeof(EPK_V3_HEADER_T); - signed_size = ( - sizeof(epk3->old.head.epkHeader) + - sizeof(epk3->old.head.crc32Info) + - sizeof(epk3->old.head.reserved) - ); - sigType = SIG_SHA1; - sigSize = SIGNATURE_SIZE; - extraSegmentSize = 0; - break; - case EPK_V3_NEW: - headerSize = sizeof(EPK_V3_NEW_HEADER_T); - signed_size = headerSize; - sigType = SIG_SHA256; - sigSize = SIGNATURE_SIZE_NEW; - /* each segment has an index value */ - extraSegmentSize = sizeof(uint32_t); - break; - default: - err_exit("Unsupported EPK3 variant\n"); - } + switch(epkType){ + case EPK_V3: + headerSize = sizeof(EPK_V3_HEADER_T); + signed_size = ( + sizeof(epk3->old.head.epkHeader) + + sizeof(epk3->old.head.crc32Info) + + sizeof(epk3->old.head.reserved) + ); + sigType = SIG_SHA1; + sigSize = SIGNATURE_SIZE; + extraSegmentSize = 0; + break; + case EPK_V3_NEW: + headerSize = sizeof(EPK_V3_NEW_HEADER_T); + signed_size = headerSize; + sigType = SIG_SHA256; + sigSize = SIGNATURE_SIZE_NEW; + /* each segment has an index value */ + extraSegmentSize = sizeof(uint32_t); + break; + default: + err_exit("Unsupported EPK3 variant\n"); } EPK_V3_HEADER_UNION *epkHeader; @@ -147,6 +145,8 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ pak = &(packageInfo->new.packages[0]); sigPtr = epk3->new.packageInfo_signature; break; + default: + err_exit("Unsupported EPK3 variant\n"); } if(config_opts->enableSignatureChecking){ @@ -242,6 +242,8 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ case EPK_V3_NEW: packageInfoCount = packageInfo->new.packageInfoCount; break; + default: + err_exit("Unsupported EPK3 variant\n"); } for(uint i = 0; i Date: Fri, 12 Jan 2024 01:54:21 -0500 Subject: [PATCH 22/27] epk1.c: fix memory leak --- src/epk1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/epk1.c b/src/epk1.c index b2ea2fcb..f9f3236a 100644 --- a/src/epk1.c +++ b/src/epk1.c @@ -121,6 +121,7 @@ void extract_epk1_file(const char *epk_file, config_opts_t *config_opts) { if (pakRecord->offset == 0) { offset += 8; index--; + free(pakRecord); continue; } From 7a1a8bcb935cc61a6f96c22578a0136785f22c34 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sat, 2 Mar 2024 21:35:11 -0500 Subject: [PATCH 23/27] mediatek: simplify is_mtk_pkg() logic --- src/mediatek_pkg.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/mediatek_pkg.c b/src/mediatek_pkg.c index c2a90d5a..8b2f9593 100644 --- a/src/mediatek_pkg.c +++ b/src/mediatek_pkg.c @@ -104,18 +104,14 @@ MFILE *is_mtk_pkg(const char *pkgfile){ void *decryptedHeader = NULL; KeyPair *headerKey = NULL; - do { - if((headerKey = find_AES_key(data, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, false)) != NULL){ - break; - } - + if((headerKey = find_AES_key(data, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, false)) == NULL){ /* It failed, but we want to check for Philips. * Philips has an additional 0x80 header before the normal PKG one */ if((headerKey = find_AES_key(data + PHILIPS_HEADER_SIZE, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, false)) != NULL){ mtkpkg_variant_flags |= PHILIPS; } - } while(0); + } if(headerKey != NULL){ was_decrypted = true; From d7f8f3a35e1cd75e045b55b8d2ec7482843d2290 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sat, 25 May 2024 14:57:11 -0400 Subject: [PATCH 24/27] make some of the EPKv1 code a bit less scary --- src/epk1.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/epk1.c b/src/epk1.c index f9f3236a..ae5b6826 100644 --- a/src/epk1.c +++ b/src/epk1.c @@ -38,26 +38,26 @@ bool isFileEPK1(const char *epk_file) { } } -void printHeaderInfo(struct epk1Header_t *epakHeader) { +static void printHeaderInfo(const struct epk1Header_t *epakHeader) { printf("\nFirmware otaID: %s\n", epakHeader->otaID); printf("Firmware version: " EPKV1_VERSION_FORMAT "\n", epakHeader->fwVer[2], epakHeader->fwVer[1], epakHeader->fwVer[0]); printf("PAK count: %d\n", epakHeader->pakCount); printf("PAKs total size: %d\n", epakHeader->fileSize); } -void printNewHeaderInfo(struct epk1NewHeader_t *epakHeader) { +static void printNewHeaderInfo(const struct epk1NewHeader_t *epakHeader) { printf("\nFirmware otaID: %s\n", epakHeader->otaID); printf("Firmware version: " EPKV1_VERSION_FORMAT "\n", epakHeader->fwVer[2], epakHeader->fwVer[1], epakHeader->fwVer[0]); printf("PAK count: %d\n", epakHeader->pakCount); printf("PAKs total size: %d\n", epakHeader->fileSize); } -void constructVerString(char *fw_version, struct epk1Header_t *epakHeader) { - sprintf(fw_version, EPKV1_VERSION_FORMAT "-%s", epakHeader->fwVer[2], epakHeader->fwVer[1], epakHeader->fwVer[0], epakHeader->otaID); +static void constructVerString(char *fw_version, size_t buflen, const struct epk1Header_t *epakHeader) { + snprintf(fw_version, buflen, EPKV1_VERSION_FORMAT "-%s", epakHeader->fwVer[2], epakHeader->fwVer[1], epakHeader->fwVer[0], epakHeader->otaID); } -void constructNewVerString(char *fw_version, struct epk1NewHeader_t *epakHeader) { - sprintf(fw_version, EPKV1_VERSION_FORMAT "-%s", epakHeader->fwVer[2], epakHeader->fwVer[1], epakHeader->fwVer[0], epakHeader->otaID); +static void constructNewVerString(char *fw_version, size_t buflen, const struct epk1NewHeader_t *epakHeader) { + snprintf(fw_version, buflen, EPKV1_VERSION_FORMAT "-%s", epakHeader->fwVer[2], epakHeader->fwVer[1], epakHeader->fwVer[0], epakHeader->otaID); } void extract_epk1_file(const char *epk_file, config_opts_t *config_opts) { @@ -79,7 +79,7 @@ void extract_epk1_file(const char *epk_file, config_opts_t *config_opts) { err_exit("\nCannot mmap input file (%s). Aborting\n\n", strerror(errno)); } - char verString[12]; + char verString[12] = { '\0' }; int index; uint32_t pakcount = ((struct epk1Header_t *)buffer)->pakCount; if (pakcount >> 8 != 0) { @@ -102,7 +102,7 @@ void extract_epk1_file(const char *epk_file, config_opts_t *config_opts) { printf("Note: Padding byte is not zero (0x%" PRIx8 ")!\n", fwVer->pad); } - sprintf(verString, EPKV1_VERSION_FORMAT, fwVer->major, fwVer->minor1, fwVer->minor2); + snprintf(verString, sizeof(verString) - 1, EPKV1_VERSION_FORMAT, fwVer->major, fwVer->minor1, fwVer->minor2); printf("Firmware version: %s\n", verString); printf("PAK count: %d\n", epakHeader->pakCount); printf("PAKs total size: %d\n", epakHeader->fileSize); @@ -136,11 +136,11 @@ void extract_epk1_file(const char *epk_file, config_opts_t *config_opts) { SWAP(pakHeader->pakSize); pakHeader = (struct pakHeader_t *)(buffer + pakRecord->offset); - char pakName[PAKNAME_LEN + 1] = ""; - sprintf(pakName, "%.*s", PAKNAME_LEN, pakHeader->pakName); + char pakName[PAKNAME_LEN + 1] = { '\0' }; + snprintf(pakName, sizeof(pakName) - 1, "%.*s", PAKNAME_LEN, pakHeader->pakName); - char filename[PATH_MAX + 1] = ""; - int filename_len = snprintf(filename, PATH_MAX + 1, "%s/%s.pak", config_opts->dest_dir, pakName); + char filename[PATH_MAX + 1] = { '\0' }; + int filename_len = snprintf(filename, sizeof(filename), "%s/%s.pak", config_opts->dest_dir, pakName); if (filename_len > PATH_MAX) { err_exit("Error in %s: filename too long (%d > %d)\n", __func__, filename_len, PATH_MAX); @@ -169,7 +169,7 @@ void extract_epk1_file(const char *epk_file, config_opts_t *config_opts) { printf("\nFirmware type is EPK1...\n"); struct epk1Header_t *epakHeader = (struct epk1Header_t *)buffer; printHeaderInfo(epakHeader); - constructVerString(verString, epakHeader); + constructVerString(verString, sizeof(verString), epakHeader); asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, verString); createFolder(config_opts->dest_dir); @@ -178,10 +178,10 @@ void extract_epk1_file(const char *epk_file, config_opts_t *config_opts) { struct pakHeader_t *pakHeader; pakHeader = (struct pakHeader_t *)(buffer + pakRecord.offset); - char pakName[PAKNAME_LEN + 1] = ""; - sprintf(pakName, "%.*s", PAKNAME_LEN, pakHeader->pakName); + char pakName[PAKNAME_LEN + 1] = { '\0' }; + snprintf(pakName, sizeof(pakName) - 1, "%.*s", PAKNAME_LEN, pakHeader->pakName); - char filename[PATH_MAX + 1] = ""; + char filename[PATH_MAX + 1] = { '\0' }; int filename_len = snprintf(filename, PATH_MAX + 1, "%s/%s.pak", config_opts->dest_dir, pakName); if (filename_len > PATH_MAX) { @@ -206,7 +206,7 @@ void extract_epk1_file(const char *epk_file, config_opts_t *config_opts) { printf("\nFirmware type is EPK1(new)...\n"); struct epk1NewHeader_t *epakHeader = (struct epk1NewHeader_t *)(buffer); printNewHeaderInfo(epakHeader); - constructNewVerString(verString, epakHeader); + constructNewVerString(verString, sizeof(verString), epakHeader); asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, verString); createFolder(config_opts->dest_dir); @@ -214,11 +214,11 @@ void extract_epk1_file(const char *epk_file, config_opts_t *config_opts) { struct pakRec_t pakRecord = epakHeader->pakRecs[index]; struct pakHeader_t *pakHeader = (struct pakHeader_t *)(buffer + pakRecord.offset); - char pakName[PAKNAME_LEN + 1] = ""; - sprintf(pakName, "%.*s", PAKNAME_LEN, pakHeader->pakName); + char pakName[PAKNAME_LEN + 1] = { '\0' }; + snprintf(pakName, sizeof(pakName) - 1, "%.*s", PAKNAME_LEN, pakHeader->pakName); - char filename[PATH_MAX + 1] = ""; - int filename_len = snprintf(filename, PATH_MAX + 1, "%s/%s.pak", config_opts->dest_dir, pakName); + char filename[PATH_MAX + 1] = { '\0' }; + int filename_len = snprintf(filename, sizeof(filename), "%s/%s.pak", config_opts->dest_dir, pakName); if (filename_len > PATH_MAX) { err_exit("Error in %s: filename too long (%d > %d)\n", __func__, filename_len, PATH_MAX); From c4eaa8a511fb70d122d0650b5cb94b73c0649d16 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 21 Jul 2024 17:35:19 -0400 Subject: [PATCH 25/27] fix crashes on empty input Added size checks to the following functions: - is_mtk_pkg - is_philips_fusion1 - is_nfsb - is_lz4 - is_cramfs_image (exited rather than crashing) - symfile_load These checks are incredibly basic and likely to miss many issues, but they at least stop crashes on zero-length files. --- src/cramfs/uncramfs.c | 5 +++++ src/mediatek_pkg.c | 10 ++++++++++ src/philips.c | 9 ++++++++- src/symfile.c | 5 +++++ src/util.c | 18 ++++++++++++++++-- 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/cramfs/uncramfs.c b/src/cramfs/uncramfs.c index 6b9923b1..bbcfae90 100644 --- a/src/cramfs/uncramfs.c +++ b/src/cramfs/uncramfs.c @@ -628,6 +628,11 @@ int is_cramfs_image(char const *imagefile, char *endian) { perror(imagefile); exit(1); } + + if (st.st_size < sizeof(struct cramfs_super)) { + return 0; + } + // Map the cramfs image fd = open(imagefile, O_RDONLY); fslen_ub = st.st_size; diff --git a/src/mediatek_pkg.c b/src/mediatek_pkg.c index 8b2f9593..52f8d670 100644 --- a/src/mediatek_pkg.c +++ b/src/mediatek_pkg.c @@ -100,6 +100,11 @@ MFILE *is_mtk_pkg(const char *pkgfile){ err_exit("Cannot open file %s\n", pkgfile); } + if (msize(mf) < sizeof(struct mtkupg_header)) { + mclose(mf); + return NULL; + } + uint8_t *data = mdata(mf, uint8_t); void *decryptedHeader = NULL; KeyPair *headerKey = NULL; @@ -183,6 +188,11 @@ MFILE *is_lzhs_fs(const char *pkg){ uint8_t *data = mdata(mf, uint8_t); + if (msize(mf) < (SHARP_PKG_HEADER_SIZE)) { + goto fail; + } + + off_t start = MTK_EXT_LZHS_OFFSET; if(is_nfsb_mem(mf, SHARP_PKG_HEADER_SIZE)){ start += SHARP_PKG_HEADER_SIZE; diff --git a/src/philips.c b/src/philips.c index a0a5c773..0bb93a27 100644 --- a/src/philips.c +++ b/src/philips.c @@ -19,8 +19,15 @@ MFILE *is_philips_fusion1(const char *filename){ if(!mf){ err_exit("mfopen failed for %s\n", filename); } + + const size_t magic_len = strlen(PHILIPS_FUSION1_MAGIC); + if (msize(mf) < magic_len) { + mclose(mf); + return NULL; + } + uint8_t *data = mdata(mf, uint8_t); - if(!memcmp(data, PHILIPS_FUSION1_MAGIC, strlen(PHILIPS_FUSION1_MAGIC))){ + if(!memcmp(data, PHILIPS_FUSION1_MAGIC, magic_len)){ return mf; } mclose(mf); diff --git a/src/symfile.c b/src/symfile.c index 7d37596f..346d3bfa 100644 --- a/src/symfile.c +++ b/src/symfile.c @@ -79,6 +79,11 @@ int symfile_load(const char *fname) { return -1; } + if (st_buf.st_size < sizeof(*header)) { + close(fd); + return -1; + } + p = mmap(NULL, st_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); header = p; p += sizeof(*header); diff --git a/src/util.c b/src/util.c index ef524ad9..d71d46a8 100644 --- a/src/util.c +++ b/src/util.c @@ -250,8 +250,10 @@ MFILE *is_lz4(const char *lz4file) { if (!file){ err_exit("Can't open file %s\n\n", lz4file); } - if(!memcmp(mdata(file, uint8_t), "LZ4P", 4)) + + if ((msize(file) >= 4) && (memcmp(mdata(file, uint8_t), "LZ4P", 4) == 0)) { return file; + } mclose(file); return NULL; @@ -260,6 +262,11 @@ MFILE *is_lz4(const char *lz4file) { bool is_nfsb_mem(MFILE *file, off_t offset){ uint8_t *data = &(mdata(file, uint8_t))[offset]; + const off_t remaining_size = msize(file) - offset; + if (remaining_size < 4) { + return false; + } + if(memcmp(data, "NFSB", 4) != 0){ return false; } @@ -276,6 +283,11 @@ bool is_nfsb_mem(MFILE *file, off_t offset){ for(int i=0; i remaining_size) { + /* Not enough data present to match this */ + continue; + } + if(memcmp(data + offsets[j], algos[i], lengths[i]) == 0){ return true; } @@ -291,8 +303,10 @@ MFILE *is_nfsb(const char *filename) { err_exit("Can't open file %s\n\n", filename); } - if(is_nfsb_mem(file, 0)) + /* is_nfsb_mem() won't read beyond end of file */ + if (is_nfsb_mem(file, 0)) { return file; + } mclose(file); return NULL; From 2148ebbd1df44d13fdcef1d0426d4ff4bb792c0d Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sat, 30 Nov 2024 21:29:33 -0500 Subject: [PATCH 26/27] lzo-lg.c: avoid warning --- src/lzo-lg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lzo-lg.c b/src/lzo-lg.c index 32835de4..27762436 100644 --- a/src/lzo-lg.c +++ b/src/lzo-lg.c @@ -247,7 +247,6 @@ int do_decompress(FILE * fi, FILE * fo) { unsigned char m[sizeof(magic)]; lzo_uint32 flags, UNUSED(decomp_size); int method; - int level; lzo_uint block_size; lzo_uint32 checksum; @@ -287,7 +286,8 @@ int do_decompress(FILE * fi, FILE * fo) { } } - level = xgetc(fi); + /* level is not used */ + (void) xgetc(fi); block_size = xread32(fi); if (block_size < 1024 || block_size > 8 * 1024 * 1024L) { From e5f5cff8b63f63b0301c804ffb301f1ef3755e61 Mon Sep 17 00:00:00 2001 From: throwaway96 <68320646+throwaway96@users.noreply.github.com> Date: Sun, 22 Mar 2026 01:33:28 -0400 Subject: [PATCH 27/27] epk.c: fix bugs and refactor Bug fixes in wrap_decryptimage(): - Fix leak of KeyPair returned by find_AES_key() - Fix leak of decryptedData when type == EPK - Fix potential NULL dereference of decryptedData Bug fixes in extractEPKfile(): - Fix missing mclose() on error Refactoring: - Remove wrap_decryptimage() outType parameter - Change return types to bool - Change global variables to function-scope statics - Pass aesKey explicitly to decryptImage() --- include/epk.h | 4 +- src/epk.c | 126 ++++++++++++++++++++++++++++++-------------------- src/epk2.c | 13 ++---- src/epk3.c | 9 ++-- 4 files changed, 86 insertions(+), 66 deletions(-) diff --git a/include/epk.h b/include/epk.h index f789a463..f579ab88 100644 --- a/include/epk.h +++ b/include/epk.h @@ -40,7 +40,7 @@ typedef enum { #define EPKV1_VERSION_FORMAT "%02" PRIx8 ".%02" PRIx8 ".%02" PRIx8 bool isEpkVersionString(const char *str); -int wrap_verifyimage(const void *signature, const void *data, size_t signSize, const char *config_dir, SIG_TYPE_T sigType); -int wrap_decryptimage(const void *src, size_t datalen, void *dest, const char *config_dir, FILE_TYPE_T type, FILE_TYPE_T *outType); +bool wrap_verifyimage(const void *signature, const void *data, size_t signSize, const char *config_dir, SIG_TYPE_T sigType); +bool wrap_decryptimage(const void *src, size_t datalen, void *dest, const char *config_dir, FILE_TYPE_T type); void extractEPKfile(const char *epk_file, config_opts_t *config_opts); #endif diff --git a/src/epk.c b/src/epk.c index 15bfd431..0cf26710 100644 --- a/src/epk.c +++ b/src/epk.c @@ -23,10 +23,6 @@ #include "util_crypto.h" static EVP_PKEY *_gpPubKey; -static AES_KEY *aesKey; -static int keyFound = 0; -static int sigCheckAvailable = 0; -static int firstAttempt = 1; /* * Determines the format of an EPK header @@ -141,7 +137,7 @@ static bool API_SWU_VerifyImage(const void *signature, const void *data, size_t /* * Wrapper for signature verification. Retries by decrementing size if it fails */ -static int wrap_SWU_VerifyImage( +static bool wrap_SWU_VerifyImage( const void *signature, const void *data, size_t signedSize, size_t *effectiveSignedSize, SIG_TYPE_T sigType ){ @@ -156,28 +152,34 @@ static int wrap_SWU_VerifyImage( } //printf("Success!\nDigital signature is OK. Signed bytes: %d\n", curSize); //printf("Subtracted: %d\n", skipped); - return 0; + return true; } else { //skipped++; } curSize--; } //printf("Failed\n"); - return -1; + return false; } /* * High level wrapper for signature verification + * + * Note that the signature covers the ciphertext, so verification must be performed before decryption. */ -int wrap_verifyimage(const void *signature, const void *data, size_t signSize, const char *config_dir, SIG_TYPE_T sigType){ +bool wrap_verifyimage(const void *signature, const void *data, size_t signSize, const char *config_dir, SIG_TYPE_T sigType){ + static bool firstAttempt = true; + static bool sigCheckAvailable = false; size_t effectiveSignedSize; - int result = -1; + bool result = false; + if(!sigCheckAvailable){ // No key available, fail early if(!firstAttempt){ - return -1; + return false; } - firstAttempt = 0; + firstAttempt = false; + printf("Verifying %zu bytes\n", signSize); DIR* dirFile = opendir(config_dir); @@ -194,8 +196,8 @@ int wrap_verifyimage(const void *signature, const void *data, size_t signSize, c if (key == NULL) continue; _gpPubKey = key; /* TODO: this doesn't need to be global */ result = wrap_SWU_VerifyImage(signature, data, signSize, &effectiveSignedSize, sigType); - if(result > -1){ - sigCheckAvailable = 1; + if(result){ + sigCheckAvailable = true; break; } } @@ -206,7 +208,7 @@ int wrap_verifyimage(const void *signature, const void *data, size_t signSize, c result = wrap_SWU_VerifyImage(signature, data, signSize, &effectiveSignedSize, sigType); } - if (result < 0) { + if (!result) { fprintf(stderr, "WARNING: Cannot verify digital signature (maybe you don't have proper PEM file)\n\n"); } else { printf("Succesfully verified 0x%zx out of 0x%zx bytes\n", effectiveSignedSize, signSize); @@ -217,7 +219,7 @@ int wrap_verifyimage(const void *signature, const void *data, size_t signSize, c /* * Decrypts the given data against the loaded AES key, with ECB mode */ -static void decryptImage(const void *srcaddr, size_t len, void *dstaddr) { +static void decryptImage(const void *srcaddr, size_t len, void *dstaddr, const AES_KEY *aesKey) { unsigned int remaining = len; while (remaining >= AES_BLOCK_SIZE) { @@ -232,12 +234,14 @@ static void decryptImage(const void *srcaddr, size_t len, void *dstaddr) { } /* - * Identifies correct key for decryption (if not previously identified) and decrypts data - * The comparison function is selected from the passed file type - * For EPK comparison, outType is used to store the detected type (EPK v2 or EPK v3) + * Identifies correct key for decryption (if not previously identified) and decrypts data. + * If type is not RAW, validation will be performed after decryption. + * + * Returns true on successful decryption. */ -int wrap_decryptimage(const void *src, size_t datalen, void *dest, const char *config_dir, FILE_TYPE_T type, FILE_TYPE_T *outType){ +bool wrap_decryptimage(const void *src, size_t datalen, void *dest, const char *config_dir, FILE_TYPE_T type) { CompareFunc compareFunc = NULL; + switch(type){ case EPK: compareFunc = compare_epak_header; @@ -257,43 +261,49 @@ int wrap_decryptimage(const void *src, size_t datalen, void *dest, const char *c err_exit("Error in %s: file type %d not handled\n", __func__, type); } - bool decrypted = false; - uint8_t *decryptedData = NULL; - - // Check if we need decryption + // Check if it's not encrypted if(type != RAW && compareFunc(src, datalen)){ - decrypted = true; - return decrypted; + /* XXX: This doesn't seem right. Don't we want the plaintext to end up in dest? */ + return true; } - if(!keyFound){ + static bool keyFound = false; + static AES_KEY aesKey; + + bool decrypted = false; + + if (!keyFound) { printf("Trying known AES keys...\n"); + void *decryptedData = NULL; KeyPair *keyPair = find_AES_key(src, datalen, compareFunc, KEY_ECB, (void **)&decryptedData, true); - decrypted = keyFound = (keyPair != NULL); - if(decrypted){ - aesKey = &(keyPair->key); - } - if(decrypted && type != EPK){ + + if (keyPair != NULL) { + /* Store the AES key for future calls */ + aesKey = keyPair->key; + free(keyPair); + + decrypted = keyFound = true; + memcpy(dest, decryptedData, datalen); free(decryptedData); } } else { - decryptImage(src, datalen, dest); - if(type == RAW) + decryptImage(src, datalen, dest, &aesKey); + + if (type == RAW) { + /* There is no way to check RAW, so assume it's good */ decrypted = true; - else + } else { decrypted = compareFunc(dest, datalen); + } } - if (!decrypted){ + + if (!decrypted) { PERROR("Cannot decrypt EPK content (proper AES key is missing).\n"); - return -1; - } else if(type == EPK){ - if(outType != NULL){ - *outType = get_epak_header_type(decryptedData, datalen); - } + return false; } - return decrypted; + return true; } /* @@ -320,24 +330,40 @@ void extractEPKfile(const char *epk_file, config_opts_t *config_opts){ struct epk2_structure *epk2 = mdata(epk, struct epk2_structure); EPK_V2_HEADER_T *epkHeader = &(epk2->epkHeader); - int result; FILE_TYPE_T epkType; - if(compare_epk2_header((uint8_t *)epkHeader, sizeof(*epkHeader))){ + + if(compare_epk2_header((const uint8_t *) epkHeader, sizeof(*epkHeader))){ epkType = EPK_V2; } else { + /* We need to decrypt the header before determining EPK version */ printf("\nTrying to decrypt EPK header...\n"); - /* Detect if the file is EPK v2 or EPK v3 */ - result = wrap_decryptimage( - epkHeader, - sizeof(EPK_V2_HEADER_T), + /* + * Since all we want is to find out whether the file is EPK v2 or EPK v3, + * we supply a temporary buffer + */ + const size_t buf_len = sizeof(EPK_V2_HEADER_T); + void *dest_buf = calloc(1, buf_len); + if (dest_buf == NULL) { + err_exit("Memory allocation failed in %s\n", __func__); + } + + bool result = wrap_decryptimage( epkHeader, + buf_len, + dest_buf, config_opts->config_dir, - EPK, - &epkType + EPK ); - if(result < 0){ + + if (!result) { + /* Error message already printed by wrap_decryptimage() */ + (void) mclose(epk); + free(dest_buf); return; } + + epkType = get_epak_header_type(dest_buf, buf_len); + free(dest_buf); } switch(epkType){ diff --git a/src/epk2.c b/src/epk2.c index d216141f..b31dbfaf 100644 --- a/src/epk2.c +++ b/src/epk2.c @@ -111,11 +111,10 @@ void extractEPK2(MFILE *epk, config_opts_t *config_opts) { sizeof(EPK_V2_HEADER_T), epkHeader, config_opts->dest_dir, - EPK_V2, - NULL + EPK_V2 ); - if(result < 0){ + if(!result){ return; } @@ -211,11 +210,10 @@ void extractEPK2(MFILE *epk, config_opts_t *config_opts) { sizeof(PAK_V2_HEADER_T), &(pak->pakHeader), config_opts->config_dir, - (FILE_TYPE_T)PAK_V2, - NULL + (FILE_TYPE_T)PAK_V2 ); - if(result < 0){ + if(!result){ return; } @@ -243,8 +241,7 @@ void extractEPK2(MFILE *epk, config_opts_t *config_opts) { pak->pakHeader.segmentSize, &(pak->pData), config_opts->config_dir, - (FILE_TYPE_T)RAW, - NULL + (FILE_TYPE_T)RAW ); mwrite(&(pak->pData), pakContentSize, 1, outFile); //write the decrypted data diff --git a/src/epk3.c b/src/epk3.c index 4cbf6f17..51f8c87e 100644 --- a/src/epk3.c +++ b/src/epk3.c @@ -119,8 +119,7 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ headerSize, epkHeader, config_opts->dest_dir, - EPK_V3, - NULL + EPK_V3 )) { return; } @@ -213,8 +212,7 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ epkHeader->old.packageInfoSize, packageInfo, config_opts->dest_dir, - RAW, - NULL + RAW )) { return; } @@ -304,8 +302,7 @@ void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ pak->segmentInfo.segmentSize, (void *)dataPtr, config_opts->dest_dir, - RAW, - NULL + RAW )) { return; }