diff --git a/ctrtool/exefs.c b/ctrtool/exefs.c index 51e522f..465bc8b 100644 --- a/ctrtool/exefs.c +++ b/ctrtool/exefs.c @@ -315,7 +315,7 @@ void exefs_print(exefs_context* ctx) u32 sectsize; fprintf(stdout, "\nExeFS:\n"); - for(i=0; i<8; i++) + for(i=0; iheader.section + i); diff --git a/ctrtool/exefs.h b/ctrtool/exefs.h index 2d1c410..fd6e8f0 100644 --- a/ctrtool/exefs.h +++ b/ctrtool/exefs.h @@ -7,6 +7,7 @@ #include "filepath.h" #include "settings.h" +#define EXEFS_SECTION_NUM 8 typedef struct { @@ -18,9 +19,9 @@ typedef struct typedef struct { - exefs_sectionheader section[8]; + exefs_sectionheader section[EXEFS_SECTION_NUM]; u8 reserved[0x80]; - u8 hashes[8][0x20]; + u8 hashes[EXEFS_SECTION_NUM][0x20]; } exefs_header; typedef struct @@ -35,7 +36,7 @@ typedef struct exefs_header header; ctr_aes_context aes; ctr_sha256_context sha; - int hashcheck[8]; + int hashcheck[EXEFS_SECTION_NUM]; int compressedflag; int encrypted; } exefs_context; diff --git a/ctrtool/ncch.c b/ctrtool/ncch.c index 67e684b..7099788 100644 --- a/ctrtool/ncch.c +++ b/ctrtool/ncch.c @@ -182,6 +182,7 @@ void ncch_save(ncch_context* ctx, u32 type, u32 flags) FILE* fout = 0; filepath* path = 0; u8 buffer[16*1024]; + exefs_header exefs_hdr; if (0 == ncch_extract_prepare(ctx, type, flags)) @@ -215,22 +216,106 @@ void ncch_save(ncch_context* ctx, u32 type, u32 flags) case NCCHTYPE_PLAINRGN: fprintf(stdout, "Saving Plain Region...\n"); break; } - while(1) + // special crypto considerations for exefs when two keys are used + if (type == NCCHTYPE_EXEFS && ctx->header.flags[3] > 0 && ctx->encrypted) { u32 read_len; - if (0 == ncch_extract_buffer(ctx, buffer, sizeof(buffer), &read_len, type == NCCHTYPE_LOGO || type == NCCHTYPE_PLAINRGN)) + // read header + if (0 == ncch_extract_buffer(ctx, (u8*)&exefs_hdr, sizeof(exefs_hdr), &read_len, 0)) goto clean; - if (read_len == 0) - break; - - if (read_len != fwrite(buffer, 1, read_len, fout)) + if (read_len != fwrite(&exefs_hdr, 1, read_len, fout)) { fprintf(stdout, "Error writing output file\n"); goto clean; } + + for (int i = 0; i < 8; i++) + { + + // get section size + u32 section_size = getle32(exefs_hdr.section[i].size); + u32 section_padding = align(section_size, 0x200)-section_size; + + // skip empty sections + if (section_size == 0) + continue; + + // select correct key + if (strncmp((char*)exefs_hdr.section[i].name, "icon", 8) == 0 || strncmp((char*)exefs_hdr.section[i].name, "banner", 8) == 0) + ctr_init_key(&ctx->aes, ctx->key[0]); + else + ctr_init_key(&ctx->aes, ctx->key[1]); + + // set counter + u8 ctr[16]; + ncch_get_counter(ctx, ctr, NCCHTYPE_EXEFS); + ctr_init_counter(&ctx->aes, ctr); + ctr_add_counter(&ctx->aes, (getle32(exefs_hdr.section[i].offset) + sizeof(exefs_header)) / 0x10); + + // extract data + while (section_size > 0) + { + read_len = sizeof(buffer); + if (read_len > section_size) + read_len = section_size; + + + if (read_len != fread(buffer, 1, read_len, ctx->file)) + { + fprintf(stdout, "Error reading input file\n"); + goto clean; + } + + ctr_crypt_counter(&ctx->aes, buffer, buffer, read_len); + + if (read_len != fwrite(buffer, 1, read_len, fout)) + { + fprintf(stdout, "Error writing output file\n"); + goto clean; + } + + + section_size -= read_len; + } + + // skip the padding + if (section_padding) + { + fseeko64(ctx->file, section_padding, SEEK_CUR); + memset(buffer, 0, section_padding); + if (section_padding != fwrite(buffer, 1, section_padding, fout)) + { + fprintf(stdout, "Error writing output file\n"); + goto clean; + } + + } + + ctx->extractsize -= section_size + section_padding; + } } + else + { + while (1) + { + u32 read_len; + + if (0 == ncch_extract_buffer(ctx, buffer, sizeof(buffer), &read_len, (type == NCCHTYPE_LOGO || type == NCCHTYPE_PLAINRGN))) + goto clean; + + if (read_len == 0) + break; + + if (read_len != fwrite(buffer, 1, read_len, fout)) + { + fprintf(stdout, "Error writing output file\n"); + goto clean; + } + } + } + clean: if (fout) fclose(fout);