diff --git a/aes.c b/aes.c index 7f2b042..ffd6421 100644 --- a/aes.c +++ b/aes.c @@ -8,24 +8,24 @@ /* Allocate a new context. */ aes_ctx_t *new_aes_ctx(const void *key, unsigned int key_size, aes_mode_t mode) { aes_ctx_t *ctx; - + if ((ctx = malloc(sizeof(*ctx))) == NULL) { FATAL_ERROR("Failed to allocate aes_ctx_t!"); } mbedtls_cipher_init(&ctx->cipher_dec); mbedtls_cipher_init(&ctx->cipher_enc); - + if (mbedtls_cipher_setup(&ctx->cipher_dec, mbedtls_cipher_info_from_type(mode)) || mbedtls_cipher_setup(&ctx->cipher_enc, mbedtls_cipher_info_from_type(mode))) { FATAL_ERROR("Failed to set up AES context!"); } - + if (mbedtls_cipher_setkey(&ctx->cipher_dec, key, key_size * 8, AES_DECRYPT) || mbedtls_cipher_setkey(&ctx->cipher_enc, key, key_size * 8, AES_ENCRYPT)) { FATAL_ERROR("Failed to set key for AES context!"); } - + return ctx; } @@ -35,7 +35,7 @@ void free_aes_ctx(aes_ctx_t *ctx) { if (ctx == NULL) { return; } - + mbedtls_cipher_free(&ctx->cipher_dec); mbedtls_cipher_free(&ctx->cipher_enc); free(ctx); @@ -65,17 +65,17 @@ void aes_calculate_cmac(void *dst, void *src, size_t size, const void *key) { /* Encrypt with context. */ void aes_encrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) { size_t out_len = 0; - + /* Prepare context */ mbedtls_cipher_reset(&ctx->cipher_enc); - + /* XTS doesn't need per-block updating */ if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_XTS) mbedtls_cipher_update(&ctx->cipher_enc, (const unsigned char * )src, l, (unsigned char *)dst, &out_len); else { unsigned int blk_size = mbedtls_cipher_get_block_size(&ctx->cipher_enc); - + /* Do per-block updating */ for (int offset = 0; (unsigned int)offset < l; offset += blk_size) { @@ -83,15 +83,15 @@ void aes_encrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) { mbedtls_cipher_update(&ctx->cipher_enc, (const unsigned char * )src + offset, len, (unsigned char *)dst + offset, &out_len); } } - + /* Flush all data */ mbedtls_cipher_finish(&ctx->cipher_enc, NULL, NULL); } /* Decrypt with context. */ -void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) +void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) { - bool src_equals_dst = false; + bool src_equals_dst = false; if (src == dst) { @@ -105,17 +105,17 @@ void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) } size_t out_len = 0; - + /* Prepare context */ mbedtls_cipher_reset(&ctx->cipher_dec); - + /* XTS doesn't need per-block updating */ if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_dec) == MBEDTLS_MODE_XTS) mbedtls_cipher_update(&ctx->cipher_dec, (const unsigned char * )src, l, (unsigned char *)dst, &out_len); else { unsigned int blk_size = mbedtls_cipher_get_block_size(&ctx->cipher_dec); - + /* Do per-block updating */ for (int offset = 0; (unsigned int)offset < l; offset += blk_size) { @@ -123,7 +123,7 @@ void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) mbedtls_cipher_update(&ctx->cipher_dec, (const unsigned char * )src + offset, len, (unsigned char *)dst + offset, &out_len); } } - + /* Flush all data */ mbedtls_cipher_finish(&ctx->cipher_dec, NULL, NULL); diff --git a/bktr.c b/bktr.c index c2d9b19..fbc4815 100644 --- a/bktr.c +++ b/bktr.c @@ -12,20 +12,20 @@ bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uin fprintf(stderr, "Too big offset looked up in BKTR relocation table!\n"); exit(EXIT_FAILURE); } - + uint32_t bucket_num = 0; for (unsigned int i = 1; i < block->num_buckets; i++) { if (block->bucket_virtual_offsets[i] <= offset) { bucket_num++; } } - + bktr_relocation_bucket_t *bucket = bktr_get_relocation_bucket(block, bucket_num); - + if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */ return &bucket->entries[0]; } - + /* Binary search. */ uint32_t low = 0, high = bucket->num_entries - 1; while (low <= high) { @@ -55,20 +55,20 @@ bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uin if (offset >= last_bucket->entries[last_bucket->num_entries].offset) { return &last_bucket->entries[last_bucket->num_entries]; } - + uint32_t bucket_num = 0; for (unsigned int i = 1; i < block->num_buckets; i++) { if (block->bucket_physical_offsets[i] <= offset) { bucket_num++; } } - + bktr_subsection_bucket_t *bucket = bktr_get_subsection_bucket(block, bucket_num); - + if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */ return &bucket->entries[0]; } - + /* Binary search. */ uint32_t low = 0, high = bucket->num_entries - 1; while (low <= high) { diff --git a/extkeys.c b/extkeys.c index 254ae4d..ca4bed7 100644 --- a/extkeys.c +++ b/extkeys.c @@ -178,7 +178,7 @@ void parse_hex_key(unsigned char *key, const char *hex, unsigned int len) { void extkeys_parse_titlekeys(hactool_settings_t *settings, FILE *f) { char *key, *value; int ret; - + while ((ret = get_kv(f, &key, &value)) != 1 && ret != -2) { if (ret == 0) { if (key == NULL || value == NULL) { @@ -186,7 +186,7 @@ void extkeys_parse_titlekeys(hactool_settings_t *settings, FILE *f) { } unsigned char rights_id[0x10]; unsigned char titlekey[0x10]; - + bool should_ignore_key = false; if (strlen(key) != 0x20) { should_ignore_key = true; @@ -214,7 +214,7 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) { char *key, *value; int ret; nca_keyset_t *keyset = &settings->keyset; - + while ((ret = get_kv(f, &key, &value)) != 1 && ret != -2) { if (ret == 0) { if (key == NULL || value == NULL) { @@ -225,7 +225,7 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) { parse_hex_key(keyset->aes_kek_generation_source, value, sizeof(keyset->aes_kek_generation_source)); matched_key = 1; } else if (strcmp(key, "aes_key_generation_source") == 0) { - parse_hex_key(keyset->aes_key_generation_source, value, sizeof(keyset->aes_key_generation_source)); + parse_hex_key(keyset->aes_key_generation_source, value, sizeof(keyset->aes_key_generation_source)); matched_key = 1; } else if (strcmp(key, "key_area_key_application_source") == 0) { parse_hex_key(keyset->key_area_key_application_source, value, sizeof(keyset->key_area_key_application_source)); @@ -307,28 +307,28 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) { matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "keyblob_key_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->keyblob_keys[i], value, sizeof(keyset->keyblob_keys[i])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "keyblob_mac_key_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->keyblob_mac_keys[i], value, sizeof(keyset->keyblob_mac_keys[i])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "encrypted_keyblob_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->encrypted_keyblobs[i], value, sizeof(keyset->encrypted_keyblobs[i])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "keyblob_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->keyblobs[i], value, sizeof(keyset->keyblobs[i])); @@ -343,21 +343,21 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) { matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "tsec_root_key_%02"PRIx32, i - 6); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->tsec_root_keys[i - 6], value, sizeof(keyset->tsec_root_keys[i - 6])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "master_kek_source_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->master_kek_sources[i], value, sizeof(keyset->master_kek_sources[i])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "package1_mac_key_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->package1_mac_keys[i], value, sizeof(keyset->package1_mac_keys[i])); @@ -365,56 +365,56 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) { break; } } - for (unsigned int i = 0; i < 0x20 && !matched_key; i++) { + for (unsigned int i = 0; i < 0x20 && !matched_key; i++) { snprintf(test_name, sizeof(test_name), "master_kek_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->master_keks[i], value, sizeof(keyset->master_keks[i])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "master_key_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->master_keys[i], value, sizeof(keyset->master_keys[i])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "package1_key_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->package1_keys[i], value, sizeof(keyset->package1_keys[i])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "package2_key_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->package2_keys[i], value, sizeof(keyset->package2_keys[i])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "titlekek_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->titlekeks[i], value, sizeof(keyset->titlekeks[i])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "key_area_key_application_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->key_area_keys[i][0], value, sizeof(keyset->key_area_keys[i][0])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "key_area_key_ocean_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->key_area_keys[i][1], value, sizeof(keyset->key_area_keys[i][1])); matched_key = 1; break; } - + snprintf(test_name, sizeof(test_name), "key_area_key_system_%02"PRIx32, i); if (strcmp(key, test_name) == 0) { parse_hex_key(keyset->key_area_keys[i][2], value, sizeof(keyset->key_area_keys[i][2])); @@ -444,7 +444,7 @@ void settings_add_titlekey(hactool_settings_t *settings, const unsigned char *ri fprintf(stderr, " already has a corresponding titlekey!\n"); exit(EXIT_FAILURE); } - + /* Ensure enough space for keys. */ if (settings->known_titlekeys.count == 0) { settings->known_titlekeys.titlekeys = malloc(1 * sizeof(titlekey_entry_t)); @@ -456,9 +456,9 @@ void settings_add_titlekey(hactool_settings_t *settings, const unsigned char *ri fprintf(stderr, "Failed to allocate titlekey list!\n"); exit(EXIT_FAILURE); } - + titlekey_entry_t *new_key = &settings->known_titlekeys.titlekeys[settings->known_titlekeys.count++]; - + memcpy(new_key->rights_id, rights_id, 0x10); memcpy(new_key->titlekey, titlekey, 0x10); } @@ -469,7 +469,7 @@ titlekey_entry_t *settings_get_titlekey(hactool_settings_t *settings, const unsi return &settings->known_titlekeys.titlekeys[i]; } } - + return NULL; } diff --git a/hfs0.c b/hfs0.c index 072c9ed..328c565 100644 --- a/hfs0.c +++ b/hfs0.c @@ -3,13 +3,13 @@ void hfs0_process(hfs0_ctx_t *ctx) { /* Read *just* safe amount. */ - hfs0_header_t raw_header; + hfs0_header_t raw_header; fseeko64(ctx->file, ctx->offset, SEEK_SET); if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) { fprintf(stderr, "Failed to read HFS0 header!\n"); exit(EXIT_FAILURE); } - + if (raw_header.magic != MAGIC_HFS0) { memdump(stdout, "Sanity: ", &raw_header, sizeof(raw_header)); printf("Error: HFS0 is corrupt!\n"); @@ -22,16 +22,16 @@ void hfs0_process(hfs0_ctx_t *ctx) { fprintf(stderr, "Failed to allocate HFS0 header!\n"); exit(EXIT_FAILURE); } - + fseeko64(ctx->file, ctx->offset, SEEK_SET); if (fread(ctx->header, 1, header_size, ctx->file) != header_size) { fprintf(stderr, "Failed to read HFS0 header!\n"); exit(EXIT_FAILURE); } - + /* Weak file validation. */ uint64_t max_size = 0x1ULL; - max_size <<= 48; /* Switch file sizes are capped at 48 bits. */ + max_size <<= 48; /* Switch file sizes are capped at 48 bits. */ uint64_t cur_ofs = 0; for (unsigned int i = 0; i < ctx->header->num_files; i++) { hfs0_file_entry_t *cur_file = hfs0_get_file_entry(ctx->header, i); @@ -41,11 +41,11 @@ void hfs0_process(hfs0_ctx_t *ctx) { } cur_ofs += cur_file->size; } - + if (ctx->tool_ctx->action & ACTION_INFO) { hfs0_print(ctx); } - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { hfs0_save(ctx); } diff --git a/kip.c b/kip.c index caca212..7493b53 100644 --- a/kip.c +++ b/kip.c @@ -6,13 +6,13 @@ void ini1_process(ini1_ctx_t *ctx) { /* Read *just* safe amount. */ - ini1_header_t raw_header; + ini1_header_t raw_header; fseeko64(ctx->file, 0, SEEK_SET); if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) { fprintf(stderr, "Failed to read INI1 header!\n"); exit(EXIT_FAILURE); } - + if (raw_header.magic != MAGIC_INI1 || raw_header.num_processes > INI1_MAX_KIPS) { printf("Error: INI1 is corrupt!\n"); exit(EXIT_FAILURE); @@ -23,13 +23,13 @@ void ini1_process(ini1_ctx_t *ctx) { fprintf(stderr, "Failed to allocate INI1 header!\n"); exit(EXIT_FAILURE); } - + fseeko64(ctx->file, 0, SEEK_SET); if (fread(ctx->header, 1, raw_header.size, ctx->file) != raw_header.size) { fprintf(stderr, "Failed to read INI1!\n"); exit(EXIT_FAILURE); } - + uint64_t offset = 0; for (unsigned int i = 0; i < ctx->header->num_processes; i++) { ctx->kips[i].tool_ctx = ctx->tool_ctx; @@ -40,11 +40,11 @@ void ini1_process(ini1_ctx_t *ctx) { } offset += kip1_get_size(&ctx->kips[i]); } - + if (ctx->tool_ctx->action & ACTION_INFO) { ini1_print(ctx); } - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { ini1_save(ctx); } @@ -109,7 +109,7 @@ char *kip1_get_json(kip1_ctx_t *ctx) { cJSON *kip_json = cJSON_CreateObject(); char *output_str = NULL; char work_buffer[0x300] = {0}; - + /* Add KIP1 header fields. */ strcpy(work_buffer, ctx->header->name); cJSON_AddStringToObject(kip_json, "name", work_buffer); @@ -118,13 +118,13 @@ char *kip1_get_json(kip1_ctx_t *ctx) { cJSON_AddNumberToObject(kip_json, "main_thread_priority", ctx->header->main_thread_priority); cJSON_AddNumberToObject(kip_json, "default_cpu_id", ctx->header->default_core); cJSON_AddNumberToObject(kip_json, "process_category", ctx->header->process_category); - + /* Add KAC. */ cJSON *kac_json = kac_get_json(ctx->header->capabilities, sizeof(ctx->header->capabilities) / sizeof(uint32_t)); cJSON_AddItemToObject(kip_json, "kernel_capabilities", kac_json); - + output_str = cJSON_Print(kip_json); - + cJSON_Delete(kip_json); return output_str; } @@ -133,11 +133,11 @@ static void kip1_blz_uncompress(void *hdr_end) { uint32_t addl_size = ((uint32_t *)hdr_end)[-1]; uint32_t header_size = ((uint32_t *)hdr_end)[-2]; uint32_t cmp_and_hdr_size = ((uint32_t *)hdr_end)[-3]; - + unsigned char *cmp_start = (unsigned char *)(((uintptr_t)hdr_end) - cmp_and_hdr_size); uint32_t cmp_ofs = cmp_and_hdr_size - header_size; uint32_t out_ofs = cmp_and_hdr_size + addl_size; - + while (out_ofs) { unsigned char control = cmp_start[--cmp_ofs]; for (unsigned int i = 0; i < 8; i++) { @@ -155,7 +155,7 @@ static void kip1_blz_uncompress(void *hdr_end) { seg_size = out_ofs; } out_ofs -= seg_size; - + for (unsigned int j = 0; j < seg_size; j++) { cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs]; } @@ -182,7 +182,7 @@ static void *kip1_uncompress(kip1_ctx_t *ctx, uint64_t *size) { new_header.section_headers[i].compressed_size = new_header.section_headers[i].out_size; } new_header.flags &= 0xF8; - + *size = kip1_get_size_from_header(&new_header); unsigned char *new_kip = calloc(1, *size); if (new_kip == NULL) { @@ -190,7 +190,7 @@ static void *kip1_uncompress(kip1_ctx_t *ctx, uint64_t *size) { exit(EXIT_FAILURE); } *((kip1_header_t *)new_kip) = new_header; - + uint64_t new_offset = 0x100; uint64_t old_offset = 0x100; for (unsigned int i = 0; i < 3; i++) { @@ -200,19 +200,19 @@ static void *kip1_uncompress(kip1_ctx_t *ctx, uint64_t *size) { new_offset += ctx->header->section_headers[i].out_size; old_offset += ctx->header->section_headers[i].compressed_size; } - + return new_kip; } void kip1_process(kip1_ctx_t *ctx) { /* Read *just* safe amount. */ - kip1_header_t raw_header; + kip1_header_t raw_header; fseeko64(ctx->file, 0, SEEK_SET); if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) { fprintf(stderr, "Failed to read KIP1 header!\n"); exit(EXIT_FAILURE); } - + if (raw_header.magic != MAGIC_KIP1) { printf("Error: KIP1 is corrupt!\n"); exit(EXIT_FAILURE); @@ -224,17 +224,17 @@ void kip1_process(kip1_ctx_t *ctx) { fprintf(stderr, "Failed to allocate KIP1!\n"); exit(EXIT_FAILURE); } - + fseeko64(ctx->file, 0, SEEK_SET); if (fread(ctx->header, 1, size, ctx->file) != size) { fprintf(stderr, "Failed to read KIP1!\n"); exit(EXIT_FAILURE); } - + if (ctx->tool_ctx->action & ACTION_INFO) { kip1_print(ctx, 0); } - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { kip1_save(ctx); } diff --git a/main.c b/main.c index 0b4733c..8d0aa6e 100644 --- a/main.c +++ b/main.c @@ -19,7 +19,7 @@ static const char *prog_name = "hactool"; /* Print usage. Taken largely from ctrtool. */ static void usage(void) { - fprintf(stderr, + fprintf(stderr, "hactool (c) SciresM.\n" "Built: %s %s\n" "\n" @@ -56,7 +56,7 @@ static void usage(void) { " --baseromfs Set Base RomFS to use with update partitions.\n" " --basenca Set Base NCA to use with update partitions.\n" " --basefake Use a fake Base RomFS with update partitions (all reads will return 0xCC).\n" - " --onlyupdated Ignore non-updated files in update partitions.\n" + " --onlyupdated Ignore non-updated files in update partitions.\n" "NPDM options:\n" " --json=file Specify file path for saving JSON representation of program permissions to.\n" "KIP1 options:\n" @@ -124,7 +124,7 @@ int main(int argc, char **argv) { filepath_init(&keypath); nca_ctx.tool_ctx = &tool_ctx; nca_ctx.is_cli_target = true; - + nca_ctx.tool_ctx->file_type = FILETYPE_NCA; base_ctx.file_type = FILETYPE_NCA; @@ -134,7 +134,7 @@ int main(int argc, char **argv) { while (1) { int option_index; int c; - static struct option long_options[] = + static struct option long_options[] = { {"extract", 0, NULL, 'x'}, {"info", 0, NULL, 'i'}, @@ -192,7 +192,7 @@ int main(int argc, char **argv) { if (c == -1) break; - switch (c) + switch (c) { case 'i': nca_ctx.tool_ctx->action |= ACTION_INFO; @@ -219,9 +219,9 @@ int main(int argc, char **argv) { } else if (!strcmp(optarg, "pfs0") || !strcmp(optarg, "exefs")) { nca_ctx.tool_ctx->file_type = FILETYPE_PFS0; } else if (!strcmp(optarg, "romfs")) { - nca_ctx.tool_ctx->file_type = FILETYPE_ROMFS; + nca_ctx.tool_ctx->file_type = FILETYPE_ROMFS; } else if (!strcmp(optarg, "nca0_romfs") || !strcmp(optarg, "nca0romfs") || !strcmp(optarg, "betaromfs") || !strcmp(optarg, "beta_romfs")) { - nca_ctx.tool_ctx->file_type = FILETYPE_NCA0_ROMFS; + nca_ctx.tool_ctx->file_type = FILETYPE_NCA0_ROMFS; } else if (!strcmp(optarg, "hfs0")) { nca_ctx.tool_ctx->file_type = FILETYPE_HFS0; } else if (!strcmp(optarg, "xci") || !strcmp(optarg, "gamecard") || !strcmp(optarg, "gc")) { @@ -256,19 +256,19 @@ int main(int argc, char **argv) { case 7: filepath_set(&nca_ctx.tool_ctx->settings.section_dir_paths[3], optarg); break; case 8: nca_ctx.tool_ctx->settings.exefs_path.enabled = 1; - filepath_set(&nca_ctx.tool_ctx->settings.exefs_path.path, optarg); + filepath_set(&nca_ctx.tool_ctx->settings.exefs_path.path, optarg); break; case 9: nca_ctx.tool_ctx->settings.romfs_path.enabled = 1; - filepath_set(&nca_ctx.tool_ctx->settings.romfs_path.path, optarg); + filepath_set(&nca_ctx.tool_ctx->settings.romfs_path.path, optarg); break; case 10: nca_ctx.tool_ctx->settings.exefs_dir_path.enabled = 1; - filepath_set(&nca_ctx.tool_ctx->settings.exefs_dir_path.path, optarg); + filepath_set(&nca_ctx.tool_ctx->settings.exefs_dir_path.path, optarg); break; case 11: nca_ctx.tool_ctx->settings.romfs_dir_path.enabled = 1; - filepath_set(&nca_ctx.tool_ctx->settings.romfs_dir_path.path, optarg); + filepath_set(&nca_ctx.tool_ctx->settings.romfs_dir_path.path, optarg); break; case 12: parse_hex_key(nca_ctx.tool_ctx->settings.cli_titlekey, optarg, 16); @@ -314,43 +314,43 @@ int main(int argc, char **argv) { break; case 17: tool_ctx.settings.out_dir_path.enabled = 1; - filepath_set(&tool_ctx.settings.out_dir_path.path, optarg); + filepath_set(&tool_ctx.settings.out_dir_path.path, optarg); break; case 18: - filepath_set(&nca_ctx.tool_ctx->settings.plaintext_path, optarg); + filepath_set(&nca_ctx.tool_ctx->settings.plaintext_path, optarg); break; case 19: - filepath_set(&nca_ctx.tool_ctx->settings.header_path, optarg); + filepath_set(&nca_ctx.tool_ctx->settings.header_path, optarg); break; case 20: - filepath_set(&tool_ctx.settings.pfs0_dir_path, optarg); + filepath_set(&tool_ctx.settings.pfs0_dir_path, optarg); break; case 21: - filepath_set(&tool_ctx.settings.hfs0_dir_path, optarg); + filepath_set(&tool_ctx.settings.hfs0_dir_path, optarg); break; case 22: - filepath_set(&tool_ctx.settings.rootpt_dir_path, optarg); + filepath_set(&tool_ctx.settings.rootpt_dir_path, optarg); break; case 23: - filepath_set(&tool_ctx.settings.update_dir_path, optarg); + filepath_set(&tool_ctx.settings.update_dir_path, optarg); break; case 24: - filepath_set(&tool_ctx.settings.normal_dir_path, optarg); + filepath_set(&tool_ctx.settings.normal_dir_path, optarg); break; case 25: - filepath_set(&tool_ctx.settings.secure_dir_path, optarg); + filepath_set(&tool_ctx.settings.secure_dir_path, optarg); break; case 26: - filepath_set(&tool_ctx.settings.logo_dir_path, optarg); + filepath_set(&tool_ctx.settings.logo_dir_path, optarg); break; case 27: - filepath_set(&tool_ctx.settings.pk11_dir_path, optarg); + filepath_set(&tool_ctx.settings.pk11_dir_path, optarg); break; case 28: - filepath_set(&tool_ctx.settings.pk21_dir_path, optarg); + filepath_set(&tool_ctx.settings.pk21_dir_path, optarg); break; case 29: - filepath_set(&tool_ctx.settings.ini1_dir_path, optarg); + filepath_set(&tool_ctx.settings.ini1_dir_path, optarg); break; case 30: tool_ctx.action |= ACTION_EXTRACTINI1; @@ -386,13 +386,13 @@ int main(int argc, char **argv) { parse_hex_key(nca_ctx.tool_ctx->settings.keygen_tsec, optarg, 16); break; case 37: - filepath_set(&tool_ctx.settings.npdm_json_path, optarg); + filepath_set(&tool_ctx.settings.npdm_json_path, optarg); break; case 38: tool_ctx.action |= ACTION_SAVEINIJSON; break; case 39: - filepath_set(&nca_ctx.tool_ctx->settings.uncompressed_path, optarg); + filepath_set(&nca_ctx.tool_ctx->settings.uncompressed_path, optarg); break; case 40: nca_ctx.tool_ctx->settings.skip_key_warnings = 1; @@ -405,7 +405,7 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } } - + /* Try to populate default keyfile. */ FILE *keyfile = NULL; if (keypath.valid == VALIDITY_VALID) { @@ -432,7 +432,7 @@ int main(int argc, char **argv) { pki_derive_keys(&tool_ctx.settings.keyset); fclose(keyfile); } - + /* Try to load titlekeys. */ FILE *titlekeyfile = open_key_file("title"); if (titlekeyfile != NULL) { @@ -445,7 +445,7 @@ int main(int argc, char **argv) { } else if (tool_ctx.file_type != FILETYPE_BOOT0 && ((optind < argc) || (argc == 1))) { usage(); } - + /* Special case NAX0. */ if (tool_ctx.file_type == FILETYPE_NAX0) { nax0_ctx_t nax_ctx; @@ -453,10 +453,10 @@ int main(int argc, char **argv) { filepath_set(&nax_ctx.base_path, input_name); nax_ctx.tool_ctx = &tool_ctx; nax0_process(&nax_ctx); - + if (nax_ctx.aes_ctx) { free_aes_ctx(nax_ctx.aes_ctx); - } + } if (nax_ctx.num_files) { for (unsigned int i = 0; i < nax_ctx.num_files; i++) { fclose(nax_ctx.files[i]); @@ -467,13 +467,13 @@ int main(int argc, char **argv) { } printf("Done!\n"); return EXIT_SUCCESS; - } - + } + if ((tool_ctx.file = fopen(input_name, "rb")) == NULL && tool_ctx.file_type != FILETYPE_BOOT0) { fprintf(stderr, "unable to open %s: %s\n", input_name, strerror(errno)); return EXIT_FAILURE; } - + switch (tool_ctx.file_type) { case FILETYPE_NCA: { if (nca_ctx.tool_ctx->base_nca_ctx != NULL) { @@ -497,18 +497,18 @@ int main(int argc, char **argv) { nca_ctx.file = tool_ctx.file; nca_process(&nca_ctx); nca_free_section_contexts(&nca_ctx); - + if (nca_ctx.tool_ctx->base_file_type == BASEFILE_FAKE) { nca_ctx.tool_ctx->base_file = NULL; } - + if (nca_ctx.tool_ctx->base_file != NULL) { fclose(nca_ctx.tool_ctx->base_file); if (nca_ctx.tool_ctx->base_file_type == BASEFILE_NCA) { nca_free_section_contexts(nca_ctx.tool_ctx->base_nca_ctx); free(nca_ctx.tool_ctx->base_nca_ctx); } - } + } break; } case FILETYPE_PFS0: { @@ -699,7 +699,7 @@ int main(int argc, char **argv) { usage(); } } - + if (tool_ctx.settings.known_titlekeys.titlekeys != NULL) { free(tool_ctx.settings.known_titlekeys.titlekeys); } diff --git a/nax0.c b/nax0.c index 06d260c..3693c96 100644 --- a/nax0.c +++ b/nax0.c @@ -8,7 +8,7 @@ static size_t nax0_read(nax0_ctx_t *ctx, uint64_t offset, void *dst, size_t size fseeko64(ctx->files[0], offset, SEEK_SET); return fread(dst, 1, size, ctx->files[0]); } - + FILE *which = ctx->files[offset / 0xFFFF0000ULL]; uint64_t offset_in_file = offset % 0xFFFF0000ULL; fseeko64(which, offset_in_file, SEEK_SET); @@ -61,15 +61,15 @@ void nax0_process(nax0_ctx_t *ctx) { } } } - + nax0_read(ctx, 0, &ctx->header, sizeof(ctx->header)); if (ctx->header.magic != MAGIC_NAX0) { printf("Error: File has invalid NAX0 magic!\n"); return; } - + memcpy(ctx->encrypted_keys, ctx->header.keys, sizeof(ctx->header.keys)); - + int found = 0; for (ctx->k = 0; ctx->k < 2; ctx->k++) { unsigned char nax_specific_keys[2][0x10]; @@ -79,7 +79,7 @@ void nax0_process(nax0_ctx_t *ctx) { aes_decrypt(nax_k_ctx, ctx->header.keys[i], ctx->encrypted_keys[i], 0x10); free_aes_ctx(nax_k_ctx); } - + unsigned char validation_mac[0x20]; sha256_get_buffer_hmac(validation_mac, &ctx->header.magic, 0x60, ctx->tool_ctx->settings.keyset.sd_card_keys[ctx->k] + 0x10, 0x10); if (memcmp(ctx->header.hmac_header, validation_mac, 0x20) == 0) { @@ -87,18 +87,18 @@ void nax0_process(nax0_ctx_t *ctx) { break; } } - + if (!found) { printf("Error: NAX0 key derivation failed. Check SD card seed and relative path?\n"); return; } - + ctx->aes_ctx = new_aes_ctx(ctx->header.keys, 0x20, AES_MODE_XTS); - + if (ctx->tool_ctx->action & ACTION_INFO) { nax0_print(ctx); } - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { nax0_save(ctx); } diff --git a/nca.h b/nca.h index c1dccc9..9ffb1d6 100644 --- a/nca.h +++ b/nca.h @@ -165,7 +165,7 @@ typedef struct { typedef struct nca_ctx { FILE *file; /* File for this NCA. */ - size_t file_size; + size_t file_size; unsigned char crypto_type; int has_rights_id; int is_decrypted; diff --git a/nca0_romfs.c b/nca0_romfs.c index 8930ff2..a65a6b7 100644 --- a/nca0_romfs.c +++ b/nca0_romfs.c @@ -16,7 +16,7 @@ static void nca0_romfs_visit_file(nca0_romfs_ctx_t *ctx, uint32_t file_offset, f if (entry->name_size) { filepath_append_n(cur_path, entry->name_size, "%s", entry->name); } - + /* If we're extracting... */ if ((ctx->tool_ctx->action & ACTION_LISTROMFS) == 0) { printf("Saving %s...\n", cur_path->char_path); @@ -99,14 +99,14 @@ void nca0_romfs_process(nca0_romfs_ctx_t *ctx) { fprintf(stderr, "NCA0 RomFS is corrupt?\n"); return; } - + /* If there's ever anything meaningful to print about RomFS, uncomment and implement. * * if (ctx->tool_ctx->action & ACTION_INFO) { * nca0_romfs_print(ctx); * } */ - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { nca0_romfs_save(ctx); } diff --git a/nca0_romfs.h b/nca0_romfs.h index 35b5417..2f48ce6 100644 --- a/nca0_romfs.h +++ b/nca0_romfs.h @@ -27,7 +27,7 @@ typedef struct { uint32_t block_size; /* In bytes. */ uint32_t always_2; uint64_t hash_table_offset; /* Normally zero. */ - uint64_t hash_table_size; + uint64_t hash_table_size; uint64_t romfs_offset; uint64_t romfs_size; uint8_t _0x48[0xF0]; diff --git a/nso.c b/nso.c index 4dfbb31..84184cd 100644 --- a/nso.c +++ b/nso.c @@ -15,7 +15,7 @@ static void *nso_uncompress(nso0_ctx_t *ctx) { new_header.segments[1].align_or_total_size = 0; /* Clear compression flags. */ new_header.flags &= 0xF8; - + uint64_t size = nso_get_size(&new_header); nso0_header_t *new_nso = calloc(1, size); if (new_nso == NULL) { @@ -23,7 +23,7 @@ static void *nso_uncompress(nso0_ctx_t *ctx) { exit(EXIT_FAILURE); } *((nso0_header_t *)new_nso) = new_header; - + for (unsigned int segment = 0; segment < 3; segment++) { char *src = (char *)ctx->header + ctx->header->segments[segment].file_off; char *dst = (char *)new_nso + new_header.segments[segment].file_off; @@ -45,19 +45,19 @@ static void *nso_uncompress(nso0_ctx_t *ctx) { } } } - + return new_nso; } void nso0_process(nso0_ctx_t *ctx) { /* Read *just* safe amount. */ - nso0_header_t raw_header; + nso0_header_t raw_header; fseeko64(ctx->file, 0, SEEK_SET); if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) { fprintf(stderr, "Failed to read NSO0 header!\n"); exit(EXIT_FAILURE); } - + if (raw_header.magic != MAGIC_NSO0) { printf("Error: NSO0 is corrupt!\n"); exit(EXIT_FAILURE); @@ -69,19 +69,19 @@ void nso0_process(nso0_ctx_t *ctx) { fprintf(stderr, "Failed to allocate NSO0!\n"); exit(EXIT_FAILURE); } - + fseeko64(ctx->file, 0, SEEK_SET); if (fread(ctx->header, 1, size, ctx->file) != size) { fprintf(stderr, "Failed to read NSO0!\n"); exit(EXIT_FAILURE); } - + ctx->uncompressed_header = nso_uncompress(ctx); - + if (ctx->tool_ctx->action & ACTION_INFO) { nso0_print(ctx); } - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { nso0_save(ctx); } @@ -111,7 +111,7 @@ void nso0_print(nso0_ctx_t *ctx) { void nso0_save(nso0_ctx_t *ctx) { filepath_t *uncmp_path = &ctx->tool_ctx->settings.uncompressed_path; - if (ctx->tool_ctx->file_type == FILETYPE_NSO0 && uncmp_path->valid == VALIDITY_VALID) { + if (ctx->tool_ctx->file_type == FILETYPE_NSO0 && uncmp_path->valid == VALIDITY_VALID) { FILE *f_uncmp = os_fopen(uncmp_path->os_path, OS_MODE_WRITE); if (f_uncmp == NULL) { fprintf(stderr, "Failed to open %s!\n", uncmp_path->char_path); diff --git a/packages.c b/packages.c index 5ee4b36..f7d051e 100644 --- a/packages.c +++ b/packages.c @@ -11,7 +11,7 @@ void pk11_process(pk11_ctx_t *ctx) { fprintf(stderr, "Failed to read PK11 Stage 1!\n"); exit(EXIT_FAILURE); } - + /* Check if PK11 was built in 2016. */ /* This is a heuristic to detect an older layout for the PK11 binary. */ if (ctx->stage1.build_date[0] == '2' && ctx->stage1.build_date[1] == '0' && ctx->stage1.build_date[2] == '1' && ctx->stage1.build_date[3] == '6') { @@ -19,18 +19,18 @@ void pk11_process(pk11_ctx_t *ctx) { } else { ctx->is_pilot = 0; } - + ctx->pk11 = malloc(ctx->stage1.pk11_size); if (ctx->pk11 == NULL) { fprintf(stderr, "Failed to allocate PK11!\n"); exit(EXIT_FAILURE); } - + if (fread(ctx->pk11, 1, ctx->stage1.pk11_size, ctx->file) != ctx->stage1.pk11_size) { fprintf(stderr, "Failed to read PK11!\n"); exit(EXIT_FAILURE); } - + aes_ctx_t *crypt_ctx = NULL; pk11_t dec_header; for (unsigned int i = 0; i < 0x20; i++) { @@ -44,26 +44,26 @@ void pk11_process(pk11_ctx_t *ctx) { free_aes_ctx(crypt_ctx); crypt_ctx = NULL; } - + if (crypt_ctx == NULL) { fprintf(stderr, "Failed to decrypt PK11! Is correct key present?\n"); exit(EXIT_FAILURE); } - + aes_setiv(crypt_ctx, ctx->stage1.ctr, 0x10); aes_decrypt(crypt_ctx, ctx->pk11, ctx->pk11, ctx->stage1.pk11_size); - + uint64_t pk11_size = 0x20 + ctx->pk11->warmboot_size + ctx->pk11->nx_bootloader_size + ctx->pk11->secmon_size; pk11_size = align64(pk11_size, 0x10); if (pk11_size != ctx->stage1.pk11_size) { fprintf(stderr, "PK11 seems corrupt!\n"); exit(EXIT_FAILURE); } - + if (ctx->tool_ctx->action & ACTION_INFO) { pk11_print(ctx); } - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { pk11_save(ctx); } @@ -92,7 +92,7 @@ void pk11_save(pk11_ctx_t *ctx) { } if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) { os_makedir(dirpath->os_path); - + /* Save Decrypted.bin */ printf("Saving decrypted binary to %s/Decrypted.bin\n", dirpath->char_path); char *decrypted_bin = malloc(sizeof(ctx->stage1) + ctx->stage1.pk11_size); @@ -104,28 +104,28 @@ void pk11_save(pk11_ctx_t *ctx) { memcpy(decrypted_bin + sizeof(ctx->stage1), ctx->pk11, ctx->stage1.pk11_size); save_buffer_to_directory_file(decrypted_bin, sizeof(ctx->stage1) + ctx->stage1.pk11_size, dirpath, "Decrypted.bin"); free(decrypted_bin); - + /* Save Warmboot.bin */ printf("Saving Warmboot.bin to %s/Warmboot.bin...\n", dirpath->char_path); save_buffer_to_directory_file(pk11_get_warmboot_bin(ctx), ctx->pk11->warmboot_size, dirpath, "Warmboot.bin"); - + /* Save NX_Bootloader.bin */ printf("Saving NX_Bootloader.bin to %s/NX_Bootloader.bin...\n", dirpath->char_path); save_buffer_to_directory_file(pk11_get_nx_bootloader(ctx), ctx->pk11->nx_bootloader_size, dirpath, "NX_Bootloader.bin"); - + /* Save Secure_Monitor.bin */ printf("Saving Secure_Monitor.bin to %s/Secure_Monitor.bin...\n", dirpath->char_path); save_buffer_to_directory_file(pk11_get_secmon(ctx), ctx->pk11->secmon_size, dirpath, "Secure_Monitor.bin"); } } -void pk21_process(pk21_ctx_t *ctx) { +void pk21_process(pk21_ctx_t *ctx) { fseeko64(ctx->file, 0, SEEK_SET); if (fread(&ctx->header, 1, sizeof(ctx->header), ctx->file) != sizeof(ctx->header)) { fprintf(stderr, "Failed to read PK21 Header!\n"); exit(EXIT_FAILURE); } - + bool is_encrypted = false; for (unsigned int i = 0; i < 0x100; i++) { if (ctx->header.signature[i] != 0) { @@ -133,7 +133,7 @@ void pk21_process(pk21_ctx_t *ctx) { } } is_encrypted &= ctx->header.magic != MAGIC_PK21; - + if (is_encrypted) { if (rsa2048_pss_verify(&ctx->header.ctr, 0x100, ctx->header.signature, ctx->tool_ctx->settings.keyset.package2_fixed_key_modulus)) { ctx->signature_validity = VALIDITY_VALID; @@ -143,21 +143,21 @@ void pk21_process(pk21_ctx_t *ctx) { } else { ctx->signature_validity = VALIDITY_UNCHECKED; } - - + + /* Nintendo, what the fuck? */ ctx->package_size = ctx->header.ctr_dwords[0] ^ ctx->header.ctr_dwords[2] ^ ctx->header.ctr_dwords[3]; if (ctx->package_size > 0x7FC000) { fprintf(stderr, "Error: Package2 Header is corrupt!\n"); exit(EXIT_FAILURE); } - + aes_ctx_t *crypt_ctx = NULL; if (is_encrypted) { unsigned char ctr[0x10]; pk21_header_t temp_header; memcpy(ctr, ctx->header.ctr, sizeof(ctr)); - + for (unsigned int i = 0; i < 0x20; i++) { ctx->key_rev = i; memcpy(&temp_header, &ctx->header, sizeof(temp_header)); @@ -172,29 +172,29 @@ void pk21_process(pk21_ctx_t *ctx) { free_aes_ctx(crypt_ctx); crypt_ctx = NULL; } - + if (crypt_ctx == NULL) { fprintf(stderr, "Failed to decrypt PK21! Is correct key present?\n"); exit(EXIT_FAILURE); } } - + if (ctx->package_size != 0x200 + ctx->header.section_sizes[0] + ctx->header.section_sizes[1] + ctx->header.section_sizes[2]) { fprintf(stderr, "Error: Package2 Header is corrupt!\n"); exit(EXIT_FAILURE); } - + ctx->sections = malloc(ctx->package_size); if (ctx->sections == NULL) { fprintf(stderr, "Failed to allocate sections!\n"); exit(EXIT_FAILURE); } - + if (fread(ctx->sections, 1, ctx->package_size - 0x200, ctx->file) != ctx->package_size - 0x200) { fprintf(stderr, "Failed to read PK21 Sections!\n"); exit(EXIT_FAILURE); } - + uint64_t offset = 0; for (unsigned int i = 0; i < 3; i++) { unsigned char calc_hash[0x20]; @@ -206,11 +206,11 @@ void pk21_process(pk21_ctx_t *ctx) { } if (is_encrypted) { aes_setiv(crypt_ctx, ctx->header.section_ctrs[i], 0x10); - aes_decrypt(crypt_ctx, ctx->sections + offset, ctx->sections + offset, ctx->header.section_sizes[i]); + aes_decrypt(crypt_ctx, ctx->sections + offset, ctx->sections + offset, ctx->header.section_sizes[i]); } offset += ctx->header.section_sizes[i]; } - + ctx->ini1_ctx.tool_ctx = ctx->tool_ctx; /* Support 8.0.0 INI1 embedded in Kernel */ if (ctx->header.section_sizes[1] > 0) { @@ -237,11 +237,11 @@ void pk21_process(pk21_ctx_t *ctx) { offset += kip1_get_size(&ctx->ini1_ctx.kips[i]); } } - + if (ctx->tool_ctx->action & ACTION_INFO) { pk21_print(ctx); } - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { pk21_save(ctx); } @@ -271,10 +271,10 @@ void pk21_print(pk21_ctx_t *ctx) { } else { memdump(stdout, " Signature: ", &ctx->header.signature, 0x100); } - + /* What the fuck? */ printf(" Header Version: %02"PRIx32"\n", (ctx->header.ctr_dwords[1] ^ (ctx->header.ctr_dwords[1] >> 16) ^ (ctx->header.ctr_dwords[1] >> 24)) & 0xFF); - + bool is_ini1_embedded = ctx->header.section_sizes[1] == 0; for (unsigned int i = 0; i < 3; i++) { printf(" Section %"PRId32" (%s):\n", i, pk21_get_section_name(i, is_ini1_embedded)); @@ -291,7 +291,7 @@ void pk21_print(pk21_ctx_t *ctx) { printf(" Load Address: %08"PRIx32"\n", ctx->header.section_offsets[i] + 0x80000000); printf(" Size: %08"PRIx32"\n", ctx->header.section_sizes[i]); } - + printf("\n"); ini1_print(&ctx->ini1_ctx); } @@ -307,7 +307,7 @@ void pk21_save(pk21_ctx_t *ctx) { } if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) { os_makedir(dirpath->os_path); - + /* Save Decrypted.bin */ printf("Saving decrypted binary to %s/Decrypted.bin\n", dirpath->char_path); char *decrypted_bin = malloc(ctx->package_size); @@ -319,11 +319,11 @@ void pk21_save(pk21_ctx_t *ctx) { memcpy(decrypted_bin + sizeof(ctx->header), ctx->sections, ctx->package_size - 0x200); save_buffer_to_directory_file(decrypted_bin, ctx->package_size, dirpath, "Decrypted.bin"); free(decrypted_bin); - + /* Save Kernel.bin */ printf("Saving Kernel.bin to %s/Kernel.bin...\n", dirpath->char_path); save_buffer_to_directory_file(ctx->sections, ctx->header.section_sizes[0], dirpath, "Kernel.bin"); - + /* Save INI1.bin */ printf("Saving INI1.bin to %s/INI1.bin...\n", dirpath->char_path); if (ctx->header.section_sizes[1] > 0) diff --git a/pfs0.c b/pfs0.c index 00b4e91..3cc11fb 100644 --- a/pfs0.c +++ b/pfs0.c @@ -3,13 +3,13 @@ void pfs0_process(pfs0_ctx_t *ctx) { /* Read *just* safe amount. */ - pfs0_header_t raw_header; + pfs0_header_t raw_header; fseeko64(ctx->file, 0, SEEK_SET); if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) { fprintf(stderr, "Failed to read PFS0 header!\n"); exit(EXIT_FAILURE); } - + if (raw_header.magic != MAGIC_PFS0) { printf("Error: PFS0 is corrupt!\n"); exit(EXIT_FAILURE); @@ -21,16 +21,16 @@ void pfs0_process(pfs0_ctx_t *ctx) { fprintf(stderr, "Failed to allocate PFS0 header!\n"); exit(EXIT_FAILURE); } - + fseeko64(ctx->file, 0, SEEK_SET); if (fread(ctx->header, 1, header_size, ctx->file) != header_size) { fprintf(stderr, "Failed to read PFS0 header!\n"); exit(EXIT_FAILURE); } - + /* Weak file validation. */ uint64_t max_size = 0x1ULL; - max_size <<= 48; /* Switch file sizes are capped at 48 bits. */ + max_size <<= 48; /* Switch file sizes are capped at 48 bits. */ uint64_t cur_ofs = 0; for (unsigned int i = 0; i < ctx->header->num_files; i++) { pfs0_file_entry_t *cur_file = pfs0_get_file_entry(ctx->header, i); @@ -58,11 +58,11 @@ void pfs0_process(pfs0_ctx_t *ctx) { } } } - + if (ctx->tool_ctx->action & ACTION_INFO) { pfs0_print(ctx); } - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { pfs0_save(ctx); } diff --git a/pfs0.h b/pfs0.h index 75b6248..ad1652e 100644 --- a/pfs0.h +++ b/pfs0.h @@ -26,7 +26,7 @@ typedef struct { uint32_t block_size; /* In bytes. */ uint32_t always_2; uint64_t hash_table_offset; /* Normally zero. */ - uint64_t hash_table_size; + uint64_t hash_table_size; uint64_t pfs0_offset; uint64_t pfs0_size; uint8_t _0x48[0xF0]; diff --git a/romfs.c b/romfs.c index 39abff0..d16055e 100644 --- a/romfs.c +++ b/romfs.c @@ -96,14 +96,14 @@ void romfs_process(romfs_ctx_t *ctx) { exit(EXIT_FAILURE); } } - + /* If there's ever anything meaningful to print about RomFS, uncomment and implement. * * if (ctx->tool_ctx->action & ACTION_INFO) { * romfs_print(ctx); * } */ - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { romfs_save(ctx); } diff --git a/rsa.c b/rsa.c index 120a496..7fd0310 100644 --- a/rsa.c +++ b/rsa.c @@ -11,7 +11,7 @@ static void calculate_mgf1_and_xor(unsigned char *data, size_t data_size, const void *h_src, size_t h_src_size) { unsigned char h_buf[RSA_2048_BYTES] = {0}; memcpy(h_buf, h_src, h_src_size); - + unsigned char mgf1_buf[0x20]; size_t ofs = 0; unsigned int seed = 0; @@ -34,7 +34,7 @@ int rsa2048_pss_verify(const void *data, size_t len, const unsigned char *signat mbedtls_mpi modulus_mpi; mbedtls_mpi e_mpi; mbedtls_mpi message_mpi; - + mbedtls_mpi_init(&signature_mpi); mbedtls_mpi_init(&modulus_mpi); mbedtls_mpi_init(&e_mpi); @@ -44,7 +44,7 @@ int rsa2048_pss_verify(const void *data, size_t len, const unsigned char *signat unsigned char m_buf[RSA_2048_BYTES]; unsigned char h_buf[0x24]; const unsigned char E[3] = {1, 0, 1}; - + mbedtls_mpi_read_binary(&e_mpi, E, 3); mbedtls_mpi_read_binary(&signature_mpi, signature, RSA_2048_BYTES); mbedtls_mpi_read_binary(&modulus_mpi, modulus, RSA_2048_BYTES); @@ -77,7 +77,7 @@ int rsa2048_pss_verify(const void *data, size_t len, const unsigned char *signat if (m_buf[i] != 0) { return false; } - } + } if (m_buf[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) { return false; } @@ -98,7 +98,7 @@ int rsa2048_pkcs1_verify(const void *data, size_t len, const unsigned char *sign mbedtls_mpi modulus_mpi; mbedtls_mpi e_mpi; mbedtls_mpi message_mpi; - + mbedtls_mpi_init(&signature_mpi); mbedtls_mpi_init(&modulus_mpi); mbedtls_mpi_init(&e_mpi); @@ -108,7 +108,7 @@ int rsa2048_pkcs1_verify(const void *data, size_t len, const unsigned char *sign unsigned char m_buf[RSA_2048_BYTES]; unsigned char h_buf[0x20]; const unsigned char E[3] = {1, 0, 1}; - + mbedtls_mpi_read_binary(&e_mpi, E, 3); mbedtls_mpi_read_binary(&signature_mpi, signature, RSA_2048_BYTES); mbedtls_mpi_read_binary(&modulus_mpi, modulus, RSA_2048_BYTES); @@ -122,27 +122,27 @@ int rsa2048_pkcs1_verify(const void *data, size_t len, const unsigned char *sign mbedtls_mpi_free(&modulus_mpi); mbedtls_mpi_free(&e_mpi); mbedtls_mpi_free(&message_mpi); - + /* For RSA-2048, this prefix is just a constant. */ const unsigned char pkcs1_hash_prefix[0xE0] = { - 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x31, 0x30, + 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; - + sha256_hash_buffer(h_buf, data, len); - + return memcmp(pkcs1_hash_prefix, m_buf, 0xE0) == 0 && memcmp(&m_buf[0xE0], h_buf, 0x20) == 0; } @@ -152,7 +152,7 @@ int rsa2048_oaep_decrypt_verify(void *out, size_t max_out_len, const unsigned ch mbedtls_mpi modulus_mpi; mbedtls_mpi exp_mpi; mbedtls_mpi message_mpi; - + mbedtls_mpi_init(&signature_mpi); mbedtls_mpi_init(&modulus_mpi); mbedtls_mpi_init(&exp_mpi); @@ -160,7 +160,7 @@ int rsa2048_oaep_decrypt_verify(void *out, size_t max_out_len, const unsigned ch mbedtls_mpi_lset(&message_mpi, RSA_2048_BITS); unsigned char m_buf[RSA_2048_BYTES]; - + mbedtls_mpi_read_binary(&exp_mpi, exponent, exponent_len); mbedtls_mpi_read_binary(&signature_mpi, signature, RSA_2048_BYTES); mbedtls_mpi_read_binary(&modulus_mpi, modulus, RSA_2048_BYTES); @@ -174,7 +174,7 @@ int rsa2048_oaep_decrypt_verify(void *out, size_t max_out_len, const unsigned ch mbedtls_mpi_free(&modulus_mpi); mbedtls_mpi_free(&exp_mpi); mbedtls_mpi_free(&message_mpi); - + /* There's no automated PSS verification as far as I can tell. */ if (m_buf[0] != 0x00) { return false; @@ -190,7 +190,7 @@ int rsa2048_oaep_decrypt_verify(void *out, size_t max_out_len, const unsigned ch if (memcmp(db, label_hash, 0x20) != 0) { return false; } - + /* Validate message prefix. */ const unsigned char *data = db + 0x20; size_t remaining = RSA_2048_BYTES - 0x20 - 1 - 0x20; diff --git a/settings.h b/settings.h index 4e5c9a9..ce76d02 100644 --- a/settings.h +++ b/settings.h @@ -20,9 +20,9 @@ typedef struct { unsigned char tsec_key[0x10]; /* TSEC key for use in key derivation. NOTE: CONSOLE UNIQUE. */ unsigned char device_key[0x10]; /* Device key used to derive some FS keys. NOTE: CONSOLE UNIQUE. */ unsigned char keyblob_keys[0x20][0x10]; /* Actual keys used to decrypt keyblobs. NOTE: CONSOLE UNIQUE.*/ - unsigned char keyblob_mac_keys[0x20][0x10]; /* Keys used to validate keyblobs. NOTE: CONSOLE UNIQUE. */ - unsigned char encrypted_keyblobs[0x20][0xB0]; /* Actual encrypted keyblobs (EKS). NOTE: CONSOLE UNIQUE. */ - unsigned char keyblobs[0x20][0x90]; /* Actual decrypted keyblobs (EKS). */ + unsigned char keyblob_mac_keys[0x20][0x10]; /* Keys used to validate keyblobs. NOTE: CONSOLE UNIQUE. */ + unsigned char encrypted_keyblobs[0x20][0xB0]; /* Actual encrypted keyblobs (EKS). NOTE: CONSOLE UNIQUE. */ + unsigned char keyblobs[0x20][0x90]; /* Actual decrypted keyblobs (EKS). */ unsigned char keyblob_key_sources[0x20][0x10]; /* Seeds for keyblob keys. */ unsigned char keyblob_mac_key_source[0x10]; /* Seed for keyblob MAC key derivation. */ unsigned char tsec_root_kek[0x10]; /* Used to generate TSEC root keys. */ diff --git a/sha.c b/sha.c index 1e88678..41b6bdc 100644 --- a/sha.c +++ b/sha.c @@ -7,21 +7,21 @@ /* Allocate new context. */ sha_ctx_t *new_sha_ctx(hash_type_t type, int hmac) { sha_ctx_t *ctx; - + if ((ctx = malloc(sizeof(*ctx))) == NULL) { FATAL_ERROR("Failed to allocate sha_ctx_t!"); } - + mbedtls_md_init(&ctx->digest); - + if (mbedtls_md_setup(&ctx->digest, mbedtls_md_info_from_type(type), hmac)) { FATAL_ERROR("Failed to set up hash context!"); } - + if (mbedtls_md_starts(&ctx->digest)) { FATAL_ERROR("Failed to start hash context!"); } - + return ctx; } @@ -31,7 +31,7 @@ void free_sha_ctx(sha_ctx_t *ctx) { if (ctx == NULL) { return; } - + mbedtls_md_free(&ctx->digest); free(ctx); } @@ -57,29 +57,29 @@ void sha256_hash_buffer(unsigned char *digest, const void *data, size_t l) { /* SHA256-HMAC digest. */ void sha256_get_buffer_hmac(void *digest, const void *secret, size_t s_l, const void *data, size_t d_l) { sha_ctx_t *ctx; - + if ((ctx = malloc(sizeof(*ctx))) == NULL) { FATAL_ERROR("Failed to allocate sha_ctx_t!"); } - + mbedtls_md_init(&ctx->digest); - + if (mbedtls_md_setup(&ctx->digest, mbedtls_md_info_from_type(HASH_TYPE_SHA256), 1)) { FATAL_ERROR("Failed to set up hash context!"); } - + if (mbedtls_md_hmac_starts(&ctx->digest, secret, s_l)) { FATAL_ERROR("Failed to set up HMAC secret context!"); } - + if (mbedtls_md_hmac_update(&ctx->digest, data, d_l)) { FATAL_ERROR("Failed processing HMAC input!"); } - + if (mbedtls_md_hmac_finish(&ctx->digest, digest)) { FATAL_ERROR("Failed getting HMAC output!"); } - + mbedtls_md_free(&ctx->digest); free(ctx); } diff --git a/xci.c b/xci.c index dceb7e0..ab257a4 100644 --- a/xci.c +++ b/xci.c @@ -7,21 +7,21 @@ /* However, it (and other XCI keys) can be dumped with a GCD attack on two signatures. */ /* Contact SciresM for details, if curious. */ static const unsigned char xci_header_pubk[0x100] = { - 0x98, 0xC7, 0x26, 0xB6, 0x0D, 0x0A, 0x50, 0xA7, 0x39, 0x21, 0x0A, 0xE3, 0x2F, 0xE4, 0x3E, 0x2E, - 0x5B, 0xA2, 0x86, 0x75, 0xAA, 0x5C, 0xEE, 0x34, 0xF1, 0xA3, 0x3A, 0x7E, 0xBD, 0x90, 0x4E, 0xF7, - 0x8D, 0xFA, 0x17, 0xAA, 0x6B, 0xC6, 0x36, 0x6D, 0x4C, 0x9A, 0x6D, 0x57, 0x2F, 0x80, 0xA2, 0xBC, - 0x38, 0x4D, 0xDA, 0x99, 0xA1, 0xD8, 0xC3, 0xE2, 0x99, 0x79, 0x36, 0x71, 0x90, 0x20, 0x25, 0x9D, - 0x4D, 0x11, 0xB8, 0x2E, 0x63, 0x6B, 0x5A, 0xFA, 0x1E, 0x9C, 0x04, 0xD1, 0xC5, 0xF0, 0x9C, 0xB1, - 0x0F, 0xB8, 0xC1, 0x7B, 0xBF, 0xE8, 0xB0, 0xD2, 0x2B, 0x47, 0x01, 0x22, 0x6B, 0x23, 0xC9, 0xD0, - 0xBC, 0xEB, 0x75, 0x6E, 0x41, 0x7D, 0x4C, 0x26, 0xA4, 0x73, 0x21, 0xB4, 0xF0, 0x14, 0xE5, 0xD9, - 0x8D, 0xB3, 0x64, 0xEE, 0xA8, 0xFA, 0x84, 0x1B, 0xB8, 0xB8, 0x7C, 0x88, 0x6B, 0xEF, 0xCC, 0x97, - 0x04, 0x04, 0x9A, 0x67, 0x2F, 0xDF, 0xEC, 0x0D, 0xB2, 0x5F, 0xB5, 0xB2, 0xBD, 0xB5, 0x4B, 0xDE, - 0x0E, 0x88, 0xA3, 0xBA, 0xD1, 0xB4, 0xE0, 0x91, 0x81, 0xA7, 0x84, 0xEB, 0x77, 0x85, 0x8B, 0xEF, - 0xA5, 0xE3, 0x27, 0xB2, 0xF2, 0x82, 0x2B, 0x29, 0xF1, 0x75, 0x2D, 0xCE, 0xCC, 0xAE, 0x9B, 0x8D, - 0xED, 0x5C, 0xF1, 0x8E, 0xDB, 0x9A, 0xD7, 0xAF, 0x42, 0x14, 0x52, 0xCD, 0xE3, 0xC5, 0xDD, 0xCE, - 0x08, 0x12, 0x17, 0xD0, 0x7F, 0x1A, 0xAA, 0x1F, 0x7D, 0xE0, 0x93, 0x54, 0xC8, 0xBC, 0x73, 0x8A, - 0xCB, 0xAD, 0x6E, 0x93, 0xE2, 0x19, 0x72, 0x6B, 0xD3, 0x45, 0xF8, 0x73, 0x3D, 0x2B, 0x6A, 0x55, - 0xD2, 0x3A, 0x8B, 0xB0, 0x8A, 0x42, 0xE3, 0x3D, 0xF1, 0x92, 0x23, 0x42, 0x2E, 0xBA, 0xCC, 0x9C, + 0x98, 0xC7, 0x26, 0xB6, 0x0D, 0x0A, 0x50, 0xA7, 0x39, 0x21, 0x0A, 0xE3, 0x2F, 0xE4, 0x3E, 0x2E, + 0x5B, 0xA2, 0x86, 0x75, 0xAA, 0x5C, 0xEE, 0x34, 0xF1, 0xA3, 0x3A, 0x7E, 0xBD, 0x90, 0x4E, 0xF7, + 0x8D, 0xFA, 0x17, 0xAA, 0x6B, 0xC6, 0x36, 0x6D, 0x4C, 0x9A, 0x6D, 0x57, 0x2F, 0x80, 0xA2, 0xBC, + 0x38, 0x4D, 0xDA, 0x99, 0xA1, 0xD8, 0xC3, 0xE2, 0x99, 0x79, 0x36, 0x71, 0x90, 0x20, 0x25, 0x9D, + 0x4D, 0x11, 0xB8, 0x2E, 0x63, 0x6B, 0x5A, 0xFA, 0x1E, 0x9C, 0x04, 0xD1, 0xC5, 0xF0, 0x9C, 0xB1, + 0x0F, 0xB8, 0xC1, 0x7B, 0xBF, 0xE8, 0xB0, 0xD2, 0x2B, 0x47, 0x01, 0x22, 0x6B, 0x23, 0xC9, 0xD0, + 0xBC, 0xEB, 0x75, 0x6E, 0x41, 0x7D, 0x4C, 0x26, 0xA4, 0x73, 0x21, 0xB4, 0xF0, 0x14, 0xE5, 0xD9, + 0x8D, 0xB3, 0x64, 0xEE, 0xA8, 0xFA, 0x84, 0x1B, 0xB8, 0xB8, 0x7C, 0x88, 0x6B, 0xEF, 0xCC, 0x97, + 0x04, 0x04, 0x9A, 0x67, 0x2F, 0xDF, 0xEC, 0x0D, 0xB2, 0x5F, 0xB5, 0xB2, 0xBD, 0xB5, 0x4B, 0xDE, + 0x0E, 0x88, 0xA3, 0xBA, 0xD1, 0xB4, 0xE0, 0x91, 0x81, 0xA7, 0x84, 0xEB, 0x77, 0x85, 0x8B, 0xEF, + 0xA5, 0xE3, 0x27, 0xB2, 0xF2, 0x82, 0x2B, 0x29, 0xF1, 0x75, 0x2D, 0xCE, 0xCC, 0xAE, 0x9B, 0x8D, + 0xED, 0x5C, 0xF1, 0x8E, 0xDB, 0x9A, 0xD7, 0xAF, 0x42, 0x14, 0x52, 0xCD, 0xE3, 0xC5, 0xDD, 0xCE, + 0x08, 0x12, 0x17, 0xD0, 0x7F, 0x1A, 0xAA, 0x1F, 0x7D, 0xE0, 0x93, 0x54, 0xC8, 0xBC, 0x73, 0x8A, + 0xCB, 0xAD, 0x6E, 0x93, 0xE2, 0x19, 0x72, 0x6B, 0xD3, 0x45, 0xF8, 0x73, 0x3D, 0x2B, 0x6A, 0x55, + 0xD2, 0x3A, 0x8B, 0xB0, 0x8A, 0x42, 0xE3, 0x3D, 0xF1, 0x92, 0x23, 0x42, 0x2E, 0xBA, 0xCC, 0x9C, 0x9A, 0xC1, 0xDD, 0x62, 0x86, 0x9C, 0x2E, 0xE1, 0x2D, 0x6F, 0x62, 0x67, 0x51, 0x08, 0x0E, 0xCF }; @@ -31,12 +31,12 @@ void xci_process(xci_ctx_t *ctx) { fprintf(stderr, "Failed to read XCI header!\n"); return; } - + if (ctx->header.magic != MAGIC_HEAD) { fprintf(stderr, "Error: XCI header is corrupt!\n"); exit(EXIT_FAILURE); } - + if (ctx->tool_ctx->action & ACTION_VERIFY) { if (rsa2048_pkcs1_verify(&ctx->header.magic, 0x100, ctx->header.header_sig, xci_header_pubk)) { ctx->header_sig_validity = VALIDITY_VALID; @@ -44,31 +44,31 @@ void xci_process(xci_ctx_t *ctx) { ctx->header_sig_validity = VALIDITY_INVALID; } } - + ctx->hfs0_hash_validity = check_memory_hash_table(ctx->file, ctx->header.hfs0_header_hash, ctx->header.hfs0_offset, ctx->header.hfs0_header_size, ctx->header.hfs0_header_size, 0); if (ctx->hfs0_hash_validity != VALIDITY_VALID) { fprintf(stderr, "Error: XCI partition is corrupt!\n"); exit(EXIT_FAILURE); } - + hactool_ctx_t blank_ctx; memset(&blank_ctx, 0, sizeof(blank_ctx)); blank_ctx.action = ctx->tool_ctx->action & ~(ACTION_EXTRACT | ACTION_INFO); - + ctx->partition_ctx.file = ctx->file; ctx->partition_ctx.offset = ctx->header.hfs0_offset; ctx->partition_ctx.tool_ctx = &blank_ctx; ctx->partition_ctx.name = "rootpt"; hfs0_process(&ctx->partition_ctx); - + if (ctx->partition_ctx.header->num_files > 4) { fprintf(stderr, "Error: Invalid XCI partition!\n"); - exit(EXIT_FAILURE); + exit(EXIT_FAILURE); } - + for (unsigned int i = 0; i < ctx->partition_ctx.header->num_files; i++) { hfs0_ctx_t *cur_ctx = NULL; - + hfs0_file_entry_t *cur_file = hfs0_get_file_entry(ctx->partition_ctx.header, i); char *cur_name = hfs0_get_file_name(ctx->partition_ctx.header, i); if (!strcmp(cur_name, "update") && ctx->update_ctx.file == NULL) { @@ -79,20 +79,20 @@ void xci_process(xci_ctx_t *ctx) { cur_ctx = &ctx->secure_ctx; } else if (!strcmp(cur_name, "logo") && ctx->logo_ctx.file == NULL) { cur_ctx = &ctx->logo_ctx; - } - + } + if (cur_ctx == NULL) { fprintf(stderr, "Unknown XCI partition: %s\n", cur_name); exit(EXIT_FAILURE); } - + cur_ctx->name = cur_name; cur_ctx->offset = ctx->partition_ctx.offset + hfs0_get_header_size(ctx->partition_ctx.header) + cur_file->offset; cur_ctx->tool_ctx = &blank_ctx; cur_ctx->file = ctx->file; hfs0_process(cur_ctx); } - + for (unsigned int i = 0; i < 0x10; i++) { ctx->iv[i] = ctx->header.reversed_iv[0xF-i]; } @@ -111,12 +111,12 @@ void xci_process(xci_ctx_t *ctx) { } else { ctx->has_decrypted_header = 0; } - + if (ctx->tool_ctx->action & ACTION_INFO) { xci_print(ctx); } - + if (ctx->tool_ctx->action & ACTION_EXTRACT) { xci_save(ctx); } @@ -130,7 +130,7 @@ void xci_save(xci_ctx_t *ctx) { os_makedir(dirpath->os_path); for (unsigned int i = 0; i < ctx->partition_ctx.header->num_files; i++) { hfs0_ctx_t *cur_ctx = NULL; - + char *cur_name = hfs0_get_file_name(ctx->partition_ctx.header, i); if (!strcmp(cur_name, "update")) { cur_ctx = &ctx->update_ctx; @@ -199,7 +199,7 @@ void xci_save(xci_ctx_t *ctx) { hfs0_save_file(&ctx->logo_ctx, i, &ctx->tool_ctx->settings.logo_dir_path); } printf("\n"); - } + } } } @@ -250,7 +250,7 @@ static void xci_print_hfs0(hfs0_ctx_t *ctx) { print_magic(" Magic: ", ctx->header->magic); printf(" Offset: %012"PRIx64"\n", ctx->offset); printf(" Number of files: %"PRId32"\n", ctx->header->num_files); - + if (ctx->header->num_files > 0 && (ctx->header->num_files < 100 || ctx->tool_ctx->action & ACTION_VERIFY)) { printf(" Files:"); for (unsigned int i = 0; i < ctx->header->num_files; i++) { @@ -264,7 +264,7 @@ static void xci_print_hfs0(hfs0_ctx_t *ctx) { } } } - + void xci_print(xci_ctx_t *ctx) { printf("\nXCI:\n"); print_magic("Magic: ", ctx->header.magic); @@ -278,10 +278,10 @@ void xci_print(xci_ctx_t *ctx) { } else { memdump(stdout, "Header Signature: ", &ctx->header.header_sig, 0x100); } - + printf("Cartridge Type: %s\n", xci_get_cartridge_type(ctx)); printf("Cartridge Size: %012"PRIx64"\n", media_to_real(ctx->header.cart_size + 1)); - + memdump(stdout, "Header IV: ", ctx->iv, 0x10); memdump(stdout, "Encrypted Header: ", ctx->header.encrypted_data, 0x70); if (ctx->has_decrypted_header) { @@ -294,7 +294,7 @@ void xci_print(xci_ctx_t *ctx) { printf(" Write Time Wait1: %08"PRIx32"\n", gc_info->write_time_wait_1); printf(" Write Time Wait2: %08"PRIx32"\n", gc_info->write_time_wait_2); printf(" Firmware Mode: %08"PRIx32"\n", gc_info->firmware_mode); - + // decode version uint32_t ver[4] = {0}; ver[0] = ((gc_info->cup_version >> 26) & 0x3f); @@ -314,16 +314,16 @@ void xci_print(xci_ctx_t *ctx) { printf("Root Partition:\n"); } xci_print_hfs0(&ctx->partition_ctx); - + printf("Update Partition:\n"); xci_print_hfs0(&ctx->update_ctx); - + printf("Normal Partition:\n"); xci_print_hfs0(&ctx->normal_ctx); - + printf("Secure Partition:\n"); xci_print_hfs0(&ctx->secure_ctx); - + /* Ensure that Logo partition exists. */ if (ctx->partition_ctx.header->num_files == 4) { printf("Logo Partition:\n");