From efb9b2d103381695eff41ea5fd3d0af4b5cc2704 Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Thu, 30 Apr 2020 07:24:08 -0400 Subject: [PATCH] BKTR finished. --- source/bktr.c | 44 ++++----- source/bktr.h | 14 +-- source/main.c | 254 +++++++++++++++++++++----------------------------- 3 files changed, 138 insertions(+), 174 deletions(-) diff --git a/source/bktr.c b/source/bktr.c index b3a1e85..8f6498b 100644 --- a/source/bktr.c +++ b/source/bktr.c @@ -126,9 +126,8 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct } BktrIndirectStorageBucket *last_indirect_bucket = bktrGetIndirectStorageBucket(out->indirect_block, out->indirect_block->bucket_count - 1); - last_indirect_bucket->indirect_storage_entries[last_indirect_bucket->entry_count].virtual_offset = out->indirect_block->virtual_size; - BktrAesCtrExStorageBucket *last_aes_ctr_ex_bucket = bktrGetAesCtrExStorageBucket(out->aes_ctr_ex_block, out->aes_ctr_ex_block->bucket_count - 1); + last_indirect_bucket->indirect_storage_entries[last_indirect_bucket->entry_count].virtual_offset = out->indirect_block->virtual_size; last_aes_ctr_ex_bucket->aes_ctr_ex_storage_entries[last_aes_ctr_ex_bucket->entry_count].offset = patch_info->indirect_offset; last_aes_ctr_ex_bucket->aes_ctr_ex_storage_entries[last_aes_ctr_ex_bucket->entry_count].generation = update_nca_fs_ctx->header->generation; last_aes_ctr_ex_bucket->aes_ctr_ex_storage_entries[last_aes_ctr_ex_bucket->entry_count + 1].offset = update_nca_fs_ctx->section_size; @@ -170,7 +169,7 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct goto exit; } - if (!bktrPhysicalSectionRead(out, &(out->patch_romfs_ctx.dir_table), out->patch_romfs_ctx.dir_table_size, out->patch_romfs_ctx.offset + dir_table_offset)) + if (!bktrPhysicalSectionRead(out, out->patch_romfs_ctx.dir_table, out->patch_romfs_ctx.dir_table_size, out->patch_romfs_ctx.offset + dir_table_offset)) { LOGFILE("Failed to read update NCA RomFS directory entries table!"); goto exit; @@ -193,7 +192,7 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct goto exit; } - if (!bktrPhysicalSectionRead(out, &(out->patch_romfs_ctx.file_table), out->patch_romfs_ctx.file_table_size, out->patch_romfs_ctx.offset + file_table_offset)) + if (!bktrPhysicalSectionRead(out, out->patch_romfs_ctx.file_table, out->patch_romfs_ctx.file_table_size, out->patch_romfs_ctx.offset + file_table_offset)) { LOGFILE("Failed to read update NCA RomFS file entries table!"); goto exit; @@ -259,7 +258,7 @@ static bool bktrPhysicalSectionRead(BktrContext *ctx, void *out, u64 read_size, u64 section_offset = 0, indirect_block_size = 0; /* Determine which FS section to use + the actual offset to start reading from */ - /* No better way to do this than to make all BKTR addresses virtual */ + /* There's no better way to do this than making all BKTR addresses virtual */ indirect_entry = bktrGetIndirectStorageEntry(ctx->indirect_block, offset); if (!indirect_entry) { @@ -267,27 +266,30 @@ static bool bktrPhysicalSectionRead(BktrContext *ctx, void *out, u64 read_size, return false; } + next_indirect_entry = (indirect_entry + 1); section_offset = (offset - indirect_entry->virtual_offset + indirect_entry->physical_offset); /* Perform read operation */ bool success = false; - next_indirect_entry = (indirect_entry + 1); if ((offset + read_size) <= next_indirect_entry->virtual_offset) { - /* Easy path: read only within the current indirect storage entry */ + /* Read only within the current indirect storage entry */ /* If we're not dealing with an indirect storage entry with a patch index, just retrieve the data from the base RomFS */ if (indirect_entry->indirect_storage_index == BktrIndirectStorageIndex_Patch) { success = bktrAesCtrExStorageRead(ctx, out, read_size, offset, section_offset); + if (!success) LOGFILE("Failed to read 0x%lX bytes block from BKTR AesCtrEx storage at offset 0x%lX!", read_size, section_offset); } else { success = ncaReadFsSection(ctx->base_romfs_ctx.nca_fs_ctx, out, read_size, section_offset); + if (!success) LOGFILE("Failed to read 0x%lX bytes block from base RomFS at offset 0x%lX!", read_size, section_offset); } } else { - /* Handle read that spans multiple indirect storage entries */ + /* Handle reads that span multiple indirect storage entries */ indirect_block_size = (next_indirect_entry->virtual_offset - offset); - success = (bktrReadFileSystemData(ctx, out, indirect_block_size, offset) && \ - bktrReadFileSystemData(ctx, (u8*)out + indirect_block_size, read_size - indirect_block_size, offset + indirect_block_size)); + success = (bktrPhysicalSectionRead(ctx, out, indirect_block_size, offset) && \ + bktrPhysicalSectionRead(ctx, (u8*)out + indirect_block_size, read_size - indirect_block_size, offset + indirect_block_size)); + if (!success) LOGFILE("Failed to read 0x%lX bytes block from multiple BKTR indirect storage entries at offset 0x%lX!", read_size, section_offset); } return success; @@ -310,19 +312,20 @@ static bool bktrAesCtrExStorageRead(BktrContext *ctx, void *out, u64 read_size, return false; } + next_aes_ctr_ex_entry = (aes_ctr_ex_entry + 1); + /* Perform read operation */ bool success = false; - next_aes_ctr_ex_entry = (aes_ctr_ex_entry + 1); if ((section_offset + read_size) <= next_aes_ctr_ex_entry->offset) { - /* Read AesCtrEx storage entry data */ + /* Read only within the current AesCtrEx storage entry */ success = ncaReadAesCtrExStorageFromBktrSection(ctx->patch_romfs_ctx.nca_fs_ctx, out, read_size, section_offset, aes_ctr_ex_entry->generation); } else { /* Handle read that spans multiple AesCtrEx storage entries */ u64 aes_ctr_ex_block_size = (next_aes_ctr_ex_entry->offset - section_offset); - success = (bktrReadFileSystemData(ctx, out, aes_ctr_ex_block_size, virtual_offset) && \ - bktrReadFileSystemData(ctx, (u8*)out + aes_ctr_ex_block_size, read_size - aes_ctr_ex_block_size, virtual_offset + aes_ctr_ex_block_size)); + success = (bktrPhysicalSectionRead(ctx, out, aes_ctr_ex_block_size, virtual_offset) && \ + bktrPhysicalSectionRead(ctx, (u8*)out + aes_ctr_ex_block_size, read_size - aes_ctr_ex_block_size, virtual_offset + aes_ctr_ex_block_size)); } return success; @@ -331,12 +334,12 @@ static bool bktrAesCtrExStorageRead(BktrContext *ctx, void *out, u64 read_size, NX_INLINE BktrIndirectStorageBucket *bktrGetIndirectStorageBucket(BktrIndirectStorageBlock *block, u32 bucket_num) { if (!block || bucket_num >= block->bucket_count) return NULL; - return (BktrIndirectStorageBucket*)((u8*)block->indirect_storage_buckets + ((sizeof(BktrIndirectStorageBucket) + sizeof(BktrIndirectStorageEntry)) * bucket_num)); + return (BktrIndirectStorageBucket*)((u8*)block->indirect_storage_buckets + ((sizeof(BktrIndirectStorageBucket) + sizeof(BktrIndirectStorageEntry)) * (u64)bucket_num)); } static BktrIndirectStorageEntry *bktrGetIndirectStorageEntry(BktrIndirectStorageBlock *block, u64 offset) { - if (!block || offset >= block->virtual_size) + if (!block || !block->bucket_count || offset >= block->virtual_size) { LOGFILE("Invalid parameters!"); return NULL; @@ -384,12 +387,12 @@ static BktrIndirectStorageEntry *bktrGetIndirectStorageEntry(BktrIndirectStorage NX_INLINE BktrAesCtrExStorageBucket *bktrGetAesCtrExStorageBucket(BktrAesCtrExStorageBlock *block, u32 bucket_num) { if (!block || bucket_num >= block->bucket_count) return NULL; - return (BktrAesCtrExStorageBucket*)((u8*)block->aes_ctr_ex_storage_buckets + ((sizeof(BktrAesCtrExStorageBucket) + sizeof(BktrAesCtrExStorageEntry)) * bucket_num)); + return (BktrAesCtrExStorageBucket*)((u8*)block->aes_ctr_ex_storage_buckets + ((sizeof(BktrAesCtrExStorageBucket) + sizeof(BktrAesCtrExStorageEntry)) * (u64)bucket_num)); } static BktrAesCtrExStorageEntry *bktrGetAesCtrExStorageEntry(BktrAesCtrExStorageBlock *block, u64 offset) { - if (!block || offset >= block->physical_size) + if (!block || !block->bucket_count || offset >= block->physical_size) { LOGFILE("Invalid parameters!"); return NULL; @@ -398,9 +401,8 @@ static BktrAesCtrExStorageEntry *bktrGetAesCtrExStorageEntry(BktrAesCtrExStorage u32 bucket_num = 0; BktrAesCtrExStorageBucket *last_bucket = NULL, *bucket = NULL; - /* If offset is past the virtual, we're reading from the BKTR_HEADER subsection */ last_bucket = bktrGetAesCtrExStorageBucket(block, block->bucket_count - 1); - if (!last_bucket) + if (!last_bucket || !last_bucket->entry_count) { LOGFILE("Error retrieving last BKTR AesCtrEx storage bucket!"); return NULL; @@ -414,7 +416,7 @@ static BktrAesCtrExStorageEntry *bktrGetAesCtrExStorageEntry(BktrAesCtrExStorage } bucket = bktrGetAesCtrExStorageBucket(block, bucket_num); - if (!bucket) + if (!bucket || !bucket->entry_count) { LOGFILE("Error retrieving BKTR AesCtrEx storage bucket #%u!", bucket_num); return NULL; diff --git a/source/bktr.h b/source/bktr.h index a29c1fe..ccd54ca 100644 --- a/source/bktr.h +++ b/source/bktr.h @@ -25,13 +25,13 @@ typedef enum { BktrIndirectStorageIndex_Original = 0, BktrIndirectStorageIndex_Patch = 1 -} BktrIndirectStorageIndex; +} PACKED BktrIndirectStorageIndex; typedef struct { u64 virtual_offset; u64 physical_offset; u32 indirect_storage_index; ///< BktrIndirectStorageIndex. -} BktrIndirectStorageEntry; +} PACKED BktrIndirectStorageEntry; typedef struct { u32 index; @@ -39,7 +39,7 @@ typedef struct { u64 end_offset; BktrIndirectStorageEntry indirect_storage_entries[0x3FF0 / sizeof(BktrIndirectStorageEntry)]; u8 reserved[0x3FF0 % sizeof(BktrIndirectStorageEntry)]; -} BktrIndirectStorageBucket; +} PACKED BktrIndirectStorageBucket; typedef struct { u32 index; @@ -47,20 +47,20 @@ typedef struct { u64 virtual_size; u64 virtual_offsets[0x3FF0 / sizeof(u64)]; BktrIndirectStorageBucket indirect_storage_buckets[]; -} BktrIndirectStorageBlock; +} PACKED BktrIndirectStorageBlock; typedef struct { u64 offset; u32 size; u32 generation; -} BktrAesCtrExStorageEntry; +} PACKED BktrAesCtrExStorageEntry; typedef struct { u32 index; u32 entry_count; u64 end_offset; BktrAesCtrExStorageEntry aes_ctr_ex_storage_entries[0x3FF]; -} BktrAesCtrExStorageBucket; +} PACKED BktrAesCtrExStorageBucket; typedef struct { u32 index; @@ -68,7 +68,7 @@ typedef struct { u64 physical_size; u64 physical_offsets[0x3FF0 / sizeof(u64)]; BktrAesCtrExStorageBucket aes_ctr_ex_storage_buckets[]; -} BktrAesCtrExStorageBlock; +} PACKED BktrAesCtrExStorageBlock; typedef struct { RomFileSystemContext base_romfs_ctx; ///< Base NCA RomFS context. diff --git a/source/main.c b/source/main.c index 13da35c..a40a184 100644 --- a/source/main.c +++ b/source/main.c @@ -25,10 +25,7 @@ #include -#include "nca.h" -#include "pfs.h" -#include "romfs.h" -#include "rsa.h" +#include "bktr.h" @@ -63,10 +60,13 @@ int main(int argc, char *argv[]) u8 *buf = NULL; FILE *tmp_file = NULL; - Ticket tik = {0}; - NcaContext *nca_ctx = NULL; + Ticket base_tik = {0}, update_tik = {0}; + NcaContext *base_nca_ctx = NULL, *update_nca_ctx = NULL; NcmContentStorage ncm_storage = {0}; + BktrContext bktr_ctx = {0}; + RomFileSystemFileEntry *bktr_file_entry = NULL; + Result rc = 0; mkdir("sdmc:/nxdt_test", 0744); @@ -75,8 +75,8 @@ int main(int argc, char *argv[]) .c = { 0x01, 0x00, 0x82, 0x40, 0x0B, 0xCC, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 } // Untitled Goose Game };*/ - // Untitled Goose Game's Program NCA - NcmPackagedContentInfo content_info = { + // Untitled Goose Game's Base Program NCA + NcmPackagedContentInfo base_program_content_info = { .hash = { 0x8E, 0xF9, 0x20, 0xD4, 0x5E, 0xE1, 0x9E, 0xD1, 0xD2, 0x04, 0xC4, 0xC8, 0x22, 0x50, 0x79, 0xE8, 0xD3, 0xE2, 0xE2, 0xA0, 0x66, 0xFD, 0x2B, 0xB6, 0x5C, 0x73, 0xF6, 0x89, 0xE2, 0x25, 0x0A, 0x82 @@ -93,27 +93,23 @@ int main(int argc, char *argv[]) } }; - // Untitled Goose Game's Control NCA - /*NcmPackagedContentInfo content_info = { + // Untitled Goose Game's Update Program NCA + NcmPackagedContentInfo update_program_content_info = { .hash = { - 0xCE, 0x6E, 0x17, 0x1F, 0x93, 0x2D, 0x29, 0x28, 0xC1, 0x62, 0x94, 0x5B, 0x86, 0x2C, 0x42, 0x93, - 0xAC, 0x2C, 0x0D, 0x3E, 0xD7, 0xCE, 0x07, 0xA2, 0x34, 0x33, 0x43, 0xD9, 0x21, 0x8A, 0xA3, 0xFE + 0xDB, 0xEE, 0x62, 0x0E, 0x8F, 0x64, 0x37, 0xE4, 0x8A, 0x5C, 0x63, 0x61, 0xE8, 0xD2, 0x32, 0x6A, + 0x21, 0x0D, 0x79, 0x50, 0x3A, 0xAF, 0x0D, 0x66, 0x76, 0xE2, 0xBC, 0x84, 0xF7, 0x0A, 0x21, 0xE2 }, .info = { .content_id = { - .c = { 0xCE, 0x6E, 0x17, 0x1F, 0x93, 0x2D, 0x29, 0x28, 0xC1, 0x62, 0x94, 0x5B, 0x86, 0x2C, 0x42, 0x93 } + .c = { 0xDB, 0xEE, 0x62, 0x0E, 0x8F, 0x64, 0x37, 0xE4, 0x8A, 0x5C, 0x63, 0x61, 0xE8, 0xD2, 0x32, 0x6A } }, .size = { - 0x00, 0x74, 0x0A, 0x00, 0x00, 0x00 + 0x00, 0xF4, 0xA0, 0x0E, 0x00, 0x00 }, - .content_type = NcmContentType_Control, + .content_type = NcmContentType_Program, .id_offset = 0 } - };*/ - - PartitionFileSystemEntry *pfs_entry = NULL; - PartitionFileSystemContext pfs_ctx = {0}; - NcaHierarchicalSha256Patch pfs_patch = {0}; + }; buf = malloc(0x400000); if (!buf) @@ -125,14 +121,24 @@ int main(int argc, char *argv[]) printf("read buf succeeded\n"); consoleUpdate(NULL); - nca_ctx = calloc(1, sizeof(NcaContext)); - if (!nca_ctx) + base_nca_ctx = calloc(1, sizeof(NcaContext)); + if (!base_nca_ctx) { - printf("nca ctx buf failed\n"); + printf("base nca ctx buf failed\n"); goto out2; } - printf("nca ctx buf succeeded\n"); + printf("base nca ctx buf succeeded\n"); + consoleUpdate(NULL); + + update_nca_ctx = calloc(1, sizeof(NcaContext)); + if (!update_nca_ctx) + { + printf("update nca ctx buf failed\n"); + goto out2; + } + + printf("update nca ctx buf succeeded\n"); consoleUpdate(NULL); rc = ncmOpenContentStorage(&ncm_storage, NcmStorageId_SdCard); @@ -145,171 +151,127 @@ int main(int argc, char *argv[]) printf("ncm open storage succeeded\n"); consoleUpdate(NULL); - if (!ncaInitializeContext(nca_ctx, NcmStorageId_SdCard, &ncm_storage, 0, &content_info, &tik)) + if (!ncaInitializeContext(base_nca_ctx, NcmStorageId_SdCard, &ncm_storage, 0, &base_program_content_info, &base_tik)) { - printf("nca initialize ctx failed\n"); + printf("base nca initialize ctx failed\n"); goto out2; } - tmp_file = fopen("sdmc:/nxdt_test/nca_ctx.bin", "wb"); + tmp_file = fopen("sdmc:/nxdt_test/base_nca_ctx.bin", "wb"); if (tmp_file) { - fwrite(nca_ctx, 1, sizeof(NcaContext), tmp_file); + fwrite(base_nca_ctx, 1, sizeof(NcaContext), tmp_file); fclose(tmp_file); tmp_file = NULL; - printf("nca ctx saved\n"); + printf("base nca ctx saved\n"); } else { - printf("nca ctx not saved\n"); + printf("base nca ctx not saved\n"); } consoleUpdate(NULL); - if (!pfsInitializeContext(&pfs_ctx, &(nca_ctx->fs_contexts[0]))) + if (!ncaInitializeContext(update_nca_ctx, NcmStorageId_SdCard, &ncm_storage, 0, &update_program_content_info, &update_tik)) { - printf("pfs initialize ctx failed\n"); + printf("update nca initialize ctx failed\n"); goto out2; } - printf("pfs initialize ctx succeeded\n"); - consoleUpdate(NULL); - - tmp_file = fopen("sdmc:/nxdt_test/pfs_ctx.bin", "wb"); + tmp_file = fopen("sdmc:/nxdt_test/update_nca_ctx.bin", "wb"); if (tmp_file) { - fwrite(&pfs_ctx, 1, sizeof(PartitionFileSystemContext), tmp_file); + fwrite(update_nca_ctx, 1, sizeof(NcaContext), tmp_file); fclose(tmp_file); tmp_file = NULL; - printf("pfs ctx saved\n"); + printf("update nca ctx saved\n"); } else { - printf("pfs ctx not saved\n"); + printf("update nca ctx not saved\n"); } consoleUpdate(NULL); - tmp_file = fopen("sdmc:/nxdt_test/pfs_header.bin", "wb"); - if (tmp_file) + if (!bktrInitializeContext(&bktr_ctx, &(base_nca_ctx->fs_contexts[1]), &(update_nca_ctx->fs_contexts[1]))) { - fwrite(pfs_ctx.header, 1, pfs_ctx.header_size, tmp_file); - fclose(tmp_file); - tmp_file = NULL; - printf("pfs header saved\n"); - } else { - printf("pfs header not saved\n"); - } - - consoleUpdate(NULL); - - pfs_entry = pfsGetEntryByName(&pfs_ctx, "main.npdm"); - if (!pfs_entry) - { - printf("pfs get entry by name failed\n"); + printf("bktr initialize ctx failed\n"); goto out2; } - printf("pfs get entry by name succeeded\n"); + printf("bktr initialize ctx succeeded\n"); consoleUpdate(NULL); - if (!pfsReadEntryData(&pfs_ctx, pfs_entry, buf, pfs_entry->size, 0)) + tmp_file = fopen("sdmc:/nxdt_test/bktr_ctx.bin", "wb"); + if (tmp_file) { - printf("pfs read entry data failed\n"); + fwrite(&bktr_ctx, 1, sizeof(BktrContext), tmp_file); + fclose(tmp_file); + tmp_file = NULL; + printf("bktr ctx saved\n"); + } else { + printf("bktr ctx not saved\n"); + } + + consoleUpdate(NULL); + + bktr_file_entry = bktrGetFileEntryByPath(&bktr_ctx, "/Data/resources.assets"); + if (!bktr_file_entry) + { + printf("bktr get file entry by path failed\n"); goto out2; } - printf("pfs read entry data succeeded\n"); + printf("bktr get file entry by path success: %.*s | 0x%lX\n", bktr_file_entry->name_length, bktr_file_entry->name, bktr_file_entry->size); consoleUpdate(NULL); - tmp_file = fopen("sdmc:/nxdt_test/main.npdm", "wb"); + /*tmp_file = fopen("sdmc:/nxdt_test/resources.assets", "wb"); if (tmp_file) { - fwrite(buf, 1, pfs_entry->size, tmp_file); - fclose(tmp_file); - tmp_file = NULL; - printf("main.npdm saved\n"); - } else { - printf("main.npdm not saved\n"); - } - - consoleUpdate(NULL); - - u32 acid_offset = 0; - memcpy(&acid_offset, buf + 0x78, sizeof(u32)); - memcpy(buf + acid_offset + RSA2048_SIGNATURE_SIZE, rsa2048GetCustomAcidPublicKey(), RSA2048_SIGNATURE_SIZE); - - tmp_file = fopen("sdmc:/nxdt_test/main_mod.npdm", "wb"); - if (tmp_file) - { - fwrite(buf, 1, pfs_entry->size, tmp_file); - fclose(tmp_file); - tmp_file = NULL; - printf("main_mod.npdm saved\n"); - } else { - printf("main_mod.npdm not saved\n"); - } - - consoleUpdate(NULL); - - if (!pfsGenerateEntryPatch(&pfs_ctx, pfs_entry, buf + acid_offset + RSA2048_SIGNATURE_SIZE, RSA2048_SIGNATURE_SIZE, acid_offset + RSA2048_SIGNATURE_SIZE, &pfs_patch)) - { - printf("pfs entry patch failed\n"); - goto out2; - } - - printf("pfs entry patch succeeded\n"); - consoleUpdate(NULL); - - tmp_file = fopen("sdmc:/nxdt_test/pfs_patch.bin", "wb"); - if (tmp_file) - { - fwrite(&pfs_patch, 1, sizeof(NcaHierarchicalSha256Patch), tmp_file); - fclose(tmp_file); - tmp_file = NULL; - printf("pfs patch saved\n"); - } else { - printf("pfs patch not saved\n"); - } - - for(u8 i = 0; i < 2; i++) - { - NcaHashInfoLayerPatch *layer_patch = (i == 0 ? &(pfs_patch.hash_data_layer_patch) : &(pfs_patch.hash_target_layer_patch)); - if (!layer_patch->size || !layer_patch->data) continue; - - char path[64]; - sprintf(path, "sdmc:/nxdt_test/pfs_patch_l%u.bin", i); - - tmp_file = fopen(path, "wb"); - if (tmp_file) + u64 curpos = 0, blksize = 0x400000; + for(curpos = 0; curpos < bktr_file_entry->size; curpos += blksize) { - fwrite(layer_patch->data, 1, layer_patch->size, tmp_file); - fclose(tmp_file); - tmp_file = NULL; - printf("pfs patch #%u saved\n", i); - } else { - printf("pfs patch #%u not saved\n", i); + if (blksize > (bktr_file_entry->size - curpos)) blksize = (bktr_file_entry->size - curpos); + + if (!bktrReadFileEntryData(&bktr_ctx, bktr_file_entry, buf, blksize, curpos)) break; + + fwrite(buf, 1, blksize, tmp_file); } - consoleUpdate(NULL); - } - - if (!ncaEncryptHeader(nca_ctx)) - { - printf("nca header mod not encrypted\n"); - goto out2; - } - - printf("nca header mod encrypted\n"); - consoleUpdate(NULL); - - tmp_file = fopen("sdmc:/nxdt_test/nca_header_mod.bin", "wb"); - if (tmp_file) - { - fwrite(&(nca_ctx->header), 1, sizeof(NcaHeader), tmp_file); fclose(tmp_file); tmp_file = NULL; - printf("nca header mod saved\n"); + + if (curpos < bktr_file_entry->size) + { + printf("resources.assets read error\n"); + } else { + printf("resources.assets saved\n"); + } } else { - printf("nca header mod not saved\n"); - } + printf("resources.assets not saved\n"); + }*/ + tmp_file = fopen("sdmc:/nxdt_test/romfs.bin", "wb"); + if (tmp_file) + { + u64 curpos = 0, blksize = 0x400000; + for(curpos = 0; curpos < bktr_ctx.size; curpos += blksize) + { + if (blksize > (bktr_ctx.size - curpos)) blksize = (bktr_ctx.size - curpos); + + if (!bktrReadFileSystemData(&bktr_ctx, buf, blksize, curpos)) break; + + fwrite(buf, 1, blksize, tmp_file); + } + + fclose(tmp_file); + tmp_file = NULL; + + if (curpos < bktr_ctx.size) + { + printf("romfs read error\n"); + } else { + printf("romfs saved\n"); + } + } else { + printf("romfs not saved\n"); + } @@ -331,13 +293,13 @@ out2: if (tmp_file) fclose(tmp_file); - ncaFreeHierarchicalSha256Patch(&pfs_patch); - - pfsFreeContext(&pfs_ctx); + bktrFreeContext(&bktr_ctx); if (serviceIsActive(&(ncm_storage.s))) ncmContentStorageClose(&ncm_storage); - if (nca_ctx) free(nca_ctx); + if (update_nca_ctx) free(update_nca_ctx); + + if (base_nca_ctx) free(base_nca_ctx); if (buf) free(buf);