diff --git a/source/main.c b/source/main.c index fa83e39..790e3b0 100644 --- a/source/main.c +++ b/source/main.c @@ -26,7 +26,7 @@ #include #include "nca.h" -#include "pfs.h" +#include "romfs.h" #include "rsa.h" @@ -92,9 +92,8 @@ int main(int argc, char *argv[]) } }; - u64 pfs_size = 0; - PartitionFileSystemContext pfs_ctx = {0}; - PartitionFileSystemEntry *pfs_entry = NULL; + u64 romfs_size = 0; + RomFileSystemContext romfs_ctx = {0}; buf = malloc(0x400000); if (!buf) @@ -145,210 +144,71 @@ int main(int argc, char *argv[]) consoleUpdate(NULL); - tmp_file = fopen("sdmc:/nxdt_test/section0.bin", "wb"); - if (tmp_file) + if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_contexts[1]))) { - u64 blksize = 0x400000; - u64 total = nca_ctx->fs_contexts[0].section_size; - - printf("nca section0 created: 0x%lX\n", total); - consoleUpdate(NULL); - - for(u64 curpos = 0; curpos < total; curpos += blksize) - { - if (blksize > (total - curpos)) blksize = (total - curpos); - - if (!ncaReadFsSection(&(nca_ctx->fs_contexts[0]), buf, blksize, curpos)) - { - printf("nca read section failed\n"); - goto out2; - } - - fwrite(buf, 1, blksize, tmp_file); - } - - fclose(tmp_file); - tmp_file = NULL; - - printf("nca read section0 success\n"); - } else { - printf("nca section0 not created\n"); - } - - consoleUpdate(NULL); - - if (!pfsInitializeContext(&pfs_ctx, &(nca_ctx->fs_contexts[0]))) - { - printf("pfs initialize ctx failed\n"); + printf("romfs initialize ctx failed\n"); goto out2; } - printf("pfs initialize ctx succeeded\n"); + printf("romfs initialize ctx succeeded\n"); consoleUpdate(NULL); - if (pfsGetTotalDataSize(&pfs_ctx, &pfs_size)) + if (romfsGetTotalDataSize(&romfs_ctx, &romfs_size)) { - printf("pfs size succeeded: 0x%lX\n", pfs_size); + printf("romfs size succeeded: 0x%lX\n", romfs_size); } else { - printf("pfs size failed\n"); + printf("romfs size failed\n"); } consoleUpdate(NULL); - tmp_file = fopen("sdmc:/nxdt_test/pfs_ctx.bin", "wb"); + tmp_file = fopen("sdmc:/nxdt_test/romfs_ctx.bin", "wb"); if (tmp_file) { - fwrite(&pfs_ctx, 1, sizeof(PartitionFileSystemContext), tmp_file); + fwrite(&romfs_ctx, 1, sizeof(RomFileSystemContext), tmp_file); fclose(tmp_file); tmp_file = NULL; - printf("pfs ctx saved\n"); + printf("romfs ctx saved\n"); } else { - printf("pfs ctx not saved\n"); + printf("romfs ctx not saved\n"); } consoleUpdate(NULL); - tmp_file = fopen("sdmc:/nxdt_test/pfs_header.bin", "wb"); + tmp_file = fopen("sdmc:/nxdt_test/dir_table.bin", "wb"); if (tmp_file) { - fwrite(pfs_ctx.header, 1, pfs_ctx.header_size, tmp_file); + fwrite(romfs_ctx.dir_table, 1, romfs_ctx.dir_table_size, tmp_file); fclose(tmp_file); tmp_file = NULL; - printf("pfs header saved\n"); + printf("dir table saved\n"); } else { - printf("pfs header not saved\n"); + printf("dir table not saved\n"); } consoleUpdate(NULL); - tmp_file = fopen("sdmc:/nxdt_test/pfs.bin", "wb"); + tmp_file = fopen("sdmc:/nxdt_test/file_table.bin", "wb"); if (tmp_file) { - u64 blksize = 0x400000; - u64 total = pfs_ctx.size; - - printf("pfs created: 0x%lX\n", total); - consoleUpdate(NULL); - - for(u64 curpos = 0; curpos < total; curpos += blksize) - { - if (blksize > (total - curpos)) blksize = (total - curpos); - - if (!pfsReadPartitionData(&pfs_ctx, buf, blksize, curpos)) - { - printf("pfs read partition failed\n"); - goto out2; - } - - fwrite(buf, 1, blksize, tmp_file); - } - + fwrite(romfs_ctx.file_table, 1, romfs_ctx.file_table_size, tmp_file); fclose(tmp_file); tmp_file = NULL; - - printf("pfs read partition success\n"); + printf("file table saved\n"); } else { - printf("pfs not created\n"); + printf("file table not saved\n"); } consoleUpdate(NULL); - pfs_entry = pfsGetEntryByName(&pfs_ctx, "main.npdm"); - if (!pfs_entry) - { - printf("pfs get entry by name failed\n"); - goto out2; - } - printf("pfs get entry by name succeeded\n"); - consoleUpdate(NULL); - tmp_file = fopen("sdmc:/nxdt_test/main.npdm", "wb"); - if (tmp_file) - { - printf("main.npdm created. Target size -> 0x%lX\n", pfs_entry->size); - consoleUpdate(NULL); - - if (!pfsReadEntryData(&pfs_ctx, pfs_entry, buf, pfs_entry->size, 0)) - { - printf("pfs read entry data failed\n"); - goto out2; - } - - fwrite(buf, 1, pfs_entry->size, tmp_file); - fclose(tmp_file); - tmp_file = NULL; - - printf("pfs read main.npdm success\n"); - } else { - printf("main.npdm not created\n"); - } - consoleUpdate(NULL); - u32 acid_offset = 0; - memcpy(&acid_offset, buf + 0x78, sizeof(u32)); - PartitionFileSystemModifiedBlockInfo pfs_block_info = {0}; - if (pfsGenerateModifiedEntryData(&pfs_ctx, pfs_entry, rsa2048GetCustomAcidPublicKey(), RSA2048_SIGNATURE_SIZE, acid_offset + RSA2048_SIGNATURE_SIZE, &pfs_block_info)) - { - printf("pfs mod data success | hbo: 0x%lX | hbs: 0x%lX | dbo: 0x%lX | dbs: 0x%lX\n", pfs_block_info.hash_block_offset, pfs_block_info.hash_block_size, pfs_block_info.data_block_offset, pfs_block_info.data_block_size); - - consoleUpdate(NULL); - - tmp_file = fopen("sdmc:/nxdt_test/pfs_mod.bin", "wb"); - if (tmp_file) - { - fwrite(&pfs_block_info, 1, sizeof(PartitionFileSystemModifiedBlockInfo), tmp_file); - fclose(tmp_file); - tmp_file = NULL; - printf("pfs mod data saved\n"); - } else { - printf("pfs mod data not saved\n"); - } - - consoleUpdate(NULL); - - tmp_file = fopen("sdmc:/nxdt_test/pfs_hash_mod.bin", "wb"); - if (tmp_file) - { - fwrite(pfs_block_info.hash_block, 1, pfs_block_info.hash_block_size, tmp_file); - fclose(tmp_file); - tmp_file = NULL; - printf("pfs hash mod data saved\n"); - } else { - printf("pfs hash mod data not saved\n"); - } - - consoleUpdate(NULL); - - tmp_file = fopen("sdmc:/nxdt_test/pfs_data_mod.bin", "wb"); - if (tmp_file) - { - fwrite(pfs_block_info.data_block, 1, pfs_block_info.data_block_size, tmp_file); - fclose(tmp_file); - tmp_file = NULL; - printf("pfs data mod data saved\n"); - } else { - printf("pfs data mod data not saved\n"); - } - - consoleUpdate(NULL); - - tmp_file = fopen("sdmc:/nxdt_test/new_nca_ctx.bin", "wb"); - if (tmp_file) - { - fwrite(nca_ctx, 1, sizeof(NcaContext), tmp_file); - fclose(tmp_file); - tmp_file = NULL; - printf("nca ctx saved\n"); - } else { - printf("nca ctx not saved\n"); - } - } else { - printf("pfs mod data failed\n"); - } + + out2: while(appletMainLoop()) @@ -360,7 +220,7 @@ out2: if (tmp_file) fclose(tmp_file); - pfsFreeContext(&pfs_ctx); + romfsFreeContext(&romfs_ctx); if (serviceIsActive(&(ncm_storage.s))) ncmContentStorageClose(&ncm_storage); diff --git a/source/nca.h b/source/nca.h index 8519d8c..60073c6 100644 --- a/source/nca.h +++ b/source/nca.h @@ -370,7 +370,7 @@ NX_INLINE bool ncaValidateHierarchicalSha256Offsets(NcaHierarchicalSha256 *hiera NX_INLINE bool ncaValidateHierarchicalIntegrityOffsets(NcaHierarchicalIntegrity *hierarchical_integrity, u64 section_size) { if (!hierarchical_integrity || !section_size || __builtin_bswap32(hierarchical_integrity->magic) != NCA_IVFC_MAGIC || !hierarchical_integrity->master_hash_size || \ - hierarchical_integrity->layer_count != NCA_IVFC_HASH_DATA_LAYER_COUNT) return false; + hierarchical_integrity->layer_count < NCA_IVFC_HASH_DATA_LAYER_COUNT) return false; /* Validate layer offsets and sizes */ for(u8 i = 0; i < (NCA_IVFC_HASH_DATA_LAYER_COUNT + 1); i++) diff --git a/source/pfs.c b/source/pfs.c index 3cadd42..ad7c944 100644 --- a/source/pfs.c +++ b/source/pfs.c @@ -134,7 +134,7 @@ bool pfsReadEntryData(PartitionFileSystemContext *ctx, PartitionFileSystemEntry return true; } -bool pfsGenerateModifiedEntryData(PartitionFileSystemContext *ctx, PartitionFileSystemEntry *fs_entry, const void *data, u64 data_size, u64 data_offset, PartitionFileSystemModifiedBlockInfo *out) +bool pfsGenerateEntryPatch(PartitionFileSystemContext *ctx, PartitionFileSystemEntry *fs_entry, const void *data, u64 data_size, u64 data_offset, PartitionFileSystemPatchInfo *out) { NcaContext *nca_ctx = NULL; diff --git a/source/pfs.h b/source/pfs.h index f6a93de..f6a4a79 100644 --- a/source/pfs.h +++ b/source/pfs.h @@ -52,10 +52,10 @@ typedef struct { u64 hash_block_offset; ///< New hash block offset (relative to the start of the NCA content file). u64 hash_block_size; ///< New hash block size. u8 *hash_block; ///< New hash block contents. - u64 data_block_offset; ///< New data block offset. + u64 data_block_offset; ///< New data block offset (relative to the start of the NCA content file). u64 data_block_size; ///< New data block size. u8 *data_block; ///< New data block contents. -} PartitionFileSystemModifiedBlockInfo; +} PartitionFileSystemPatchInfo; /// Initializes a partition FS context. bool pfsInitializeContext(PartitionFileSystemContext *out, NcaFsSectionContext *nca_fs_ctx); @@ -78,7 +78,7 @@ bool pfsReadEntryData(PartitionFileSystemContext *ctx, PartitionFileSystemEntry /// Input offset must be relative to the start of the partition FS entry data. /// Bear in mind that this function recalculates both the NcaHashInfo block master hash and the NCA FS header hash from the NCA header, and enables the 'dirty_header' flag from the NCA context. /// As such, this function is only capable of modifying a single file from a partition FS in a NCA content file. -bool pfsGenerateModifiedEntryData(PartitionFileSystemContext *ctx, PartitionFileSystemEntry *fs_entry, const void *data, u64 data_size, u64 data_offset, PartitionFileSystemModifiedBlockInfo *out); +bool pfsGenerateEntryPatch(PartitionFileSystemContext *ctx, PartitionFileSystemEntry *fs_entry, const void *data, u64 data_size, u64 data_offset, PartitionFileSystemPatchInfo *out); /// Miscellaneous functions. diff --git a/source/romfs.c b/source/romfs.c index 43dab43..23abb56 100644 --- a/source/romfs.c +++ b/source/romfs.c @@ -86,7 +86,7 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_ } /* Read directory entries table */ - dir_table_offset = (out->offset + (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.directory_entry_offset : out->header.cur_format.directory_entry_offset)); + dir_table_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.directory_entry_offset : out->header.cur_format.directory_entry_offset); out->dir_table_size = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.directory_entry_size : out->header.cur_format.directory_entry_size); if (dir_table_offset >= out->size || !out->dir_table_size || (dir_table_offset + out->dir_table_size) > out->size) @@ -102,14 +102,14 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_ return false; } - if (!ncaReadFsSection(nca_fs_ctx, out->dir_table, out->dir_table_size, dir_table_offset)) + if (!ncaReadFsSection(nca_fs_ctx, out->dir_table, out->dir_table_size, out->offset + dir_table_offset)) { LOGFILE("Failed to read RomFS directory entries table!"); return false; } /* Read file entries table */ - file_table_offset = (out->offset + (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.file_entry_offset : out->header.cur_format.file_entry_offset)); + file_table_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.file_entry_offset : out->header.cur_format.file_entry_offset); out->file_table_size = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.file_entry_size : out->header.cur_format.file_entry_size); if (file_table_offset >= out->size || !out->file_table_size || (file_table_offset + out->file_table_size) > out->size) @@ -125,14 +125,14 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_ return false; } - if (!ncaReadFsSection(nca_fs_ctx, out->file_table, out->file_table_size, file_table_offset)) + if (!ncaReadFsSection(nca_fs_ctx, out->file_table, out->file_table_size, out->offset + file_table_offset)) { LOGFILE("Failed to read RomFS file entries table!"); return false; } - /* Calculate file data body offset */ - out->body_offset = (out->offset + (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.body_offset : out->header.cur_format.body_offset)); + /* Get file data body offset */ + out->body_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.body_offset : out->header.cur_format.body_offset); if (out->body_offset >= out->size) { LOGFILE("Invalid RomFS file data body!"); @@ -142,20 +142,35 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_ return true; } +bool romfsReadFileSystemData(RomFileSystemContext *ctx, void *out, u64 read_size, u64 offset) +{ + if (!ctx || !ctx->nca_fs_ctx || !ctx->size || !out || !read_size || offset >= ctx->size || (offset + read_size) > ctx->size) + { + LOGFILE("Invalid parameters!"); + return false; + } + + /* Read filesystem data */ + if (!ncaReadFsSection(ctx->nca_fs_ctx, out, read_size, ctx->offset + offset)) + { + LOGFILE("Failed to read RomFS data!"); + return false; + } + + return true; +} + bool romfsReadFileEntryData(RomFileSystemContext *ctx, RomFileSystemFileEntry *file_entry, void *out, u64 read_size, u64 offset) { - if (!ctx || !ctx->nca_fs_ctx || !ctx->size || !ctx->body_offset || !file_entry || !file_entry->size || file_entry->offset >= ctx->size || (file_entry->offset + file_entry->size) > ctx->size || \ + if (!ctx || !ctx->body_offset || !file_entry || !file_entry->size || file_entry->offset >= ctx->size || (file_entry->offset + file_entry->size) > ctx->size || \ !out || !read_size || offset >= file_entry->size || (offset + read_size) > file_entry->size) { LOGFILE("Invalid parameters!"); return false; } - /* Calculate offset relative to the start of the NCA FS section */ - u64 section_offset = (ctx->body_offset + file_entry->offset + offset); - /* Read entry data */ - if (!ncaReadFsSection(ctx->nca_fs_ctx, out, read_size, section_offset)) + if (!romfsReadFileSystemData(ctx, out, read_size, ctx->body_offset + file_entry->offset + offset)) { LOGFILE("Failed to read RomFS file entry data!"); return false; diff --git a/source/romfs.h b/source/romfs.h index 7d0a2fc..c8ba35d 100644 --- a/source/romfs.h +++ b/source/romfs.h @@ -99,7 +99,7 @@ typedef struct { RomFileSystemDirectoryEntry *dir_table; ///< RomFS directory entries table. u64 file_table_size; ///< RomFS file entries table size. RomFileSystemFileEntry *file_table; ///< RomFS file entries table. - u64 body_offset; ///< RomFS file data body offset (relative to the start of the NCA FS section). + u64 body_offset; ///< RomFS file data body offset (relative to the start of the RomFS). } RomFileSystemContext; /// Initializes a RomFS context. @@ -114,6 +114,9 @@ NX_INLINE void romfsFreeContext(RomFileSystemContext *ctx) memset(ctx, 0, sizeof(RomFileSystemContext)); } +/// Reads raw filesystem data using a RomFS context. +bool romfsReadFileSystemData(RomFileSystemContext *ctx, void *out, u64 read_size, u64 offset); + /// Reads data from a previously retrieved RomFileSystemFileEntry using a RomFS context. bool romfsReadFileEntryData(RomFileSystemContext *ctx, RomFileSystemFileEntry *file_entry, void *out, u64 read_size, u64 offset); @@ -125,16 +128,16 @@ bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, u32 dir_entry_offset, /// Miscellaneous functions. -NX_INLINE RomFileSystemDirectoryEntry *romfsGetDirectoryEntry(RomFileSystemContext *ctx, u32 file_entry_offset) +NX_INLINE RomFileSystemDirectoryEntry *romfsGetDirectoryEntry(RomFileSystemContext *ctx, u32 dir_entry_offset) { - if (!ctx || !ctx->dir_table || file_entry_offset >= ctx->dir_table_size) return NULL; - return (RomFileSystemDirectoryEntry*)((u8*)ctx->dir_table + file_entry_offset); + if (!ctx || !ctx->dir_table || (dir_entry_offset + sizeof(RomFileSystemDirectoryEntry)) > ctx->dir_table_size) return NULL; + return (RomFileSystemDirectoryEntry*)((u8*)ctx->dir_table + dir_entry_offset); } -NX_INLINE RomFileSystemFileEntry *romfsGetFileEntry(RomFileSystemContext *ctx, u32 dir_entry_offset) +NX_INLINE RomFileSystemFileEntry *romfsGetFileEntry(RomFileSystemContext *ctx, u32 file_entry_offset) { - if (!ctx || !ctx->file_table || dir_entry_offset >= ctx->file_table_size) return NULL; - return (RomFileSystemFileEntry*)((u8*)ctx->file_table + dir_entry_offset); + if (!ctx || !ctx->file_table || (file_entry_offset + sizeof(RomFileSystemFileEntry)) > ctx->file_table_size) return NULL; + return (RomFileSystemFileEntry*)((u8*)ctx->file_table + file_entry_offset); } #endif /* __ROMFS_H__ */