BKTR finished.

This commit is contained in:
Pablo Curiel 2020-04-30 07:24:08 -04:00
parent 4774aeae9c
commit efb9b2d103
3 changed files with 138 additions and 174 deletions

View file

@ -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); 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); 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].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].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; 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; 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!"); LOGFILE("Failed to read update NCA RomFS directory entries table!");
goto exit; goto exit;
@ -193,7 +192,7 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
goto exit; 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!"); LOGFILE("Failed to read update NCA RomFS file entries table!");
goto exit; goto exit;
@ -259,7 +258,7 @@ static bool bktrPhysicalSectionRead(BktrContext *ctx, void *out, u64 read_size,
u64 section_offset = 0, indirect_block_size = 0; u64 section_offset = 0, indirect_block_size = 0;
/* Determine which FS section to use + the actual offset to start reading from */ /* 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); indirect_entry = bktrGetIndirectStorageEntry(ctx->indirect_block, offset);
if (!indirect_entry) if (!indirect_entry)
{ {
@ -267,27 +266,30 @@ static bool bktrPhysicalSectionRead(BktrContext *ctx, void *out, u64 read_size,
return false; return false;
} }
next_indirect_entry = (indirect_entry + 1);
section_offset = (offset - indirect_entry->virtual_offset + indirect_entry->physical_offset); section_offset = (offset - indirect_entry->virtual_offset + indirect_entry->physical_offset);
/* Perform read operation */ /* Perform read operation */
bool success = false; bool success = false;
next_indirect_entry = (indirect_entry + 1);
if ((offset + read_size) <= next_indirect_entry->virtual_offset) 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 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) if (indirect_entry->indirect_storage_index == BktrIndirectStorageIndex_Patch)
{ {
success = bktrAesCtrExStorageRead(ctx, out, read_size, offset, section_offset); 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 { } else {
success = ncaReadFsSection(ctx->base_romfs_ctx.nca_fs_ctx, out, read_size, section_offset); 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 { } 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); indirect_block_size = (next_indirect_entry->virtual_offset - offset);
success = (bktrReadFileSystemData(ctx, out, indirect_block_size, offset) && \ success = (bktrPhysicalSectionRead(ctx, out, indirect_block_size, offset) && \
bktrReadFileSystemData(ctx, (u8*)out + indirect_block_size, read_size - indirect_block_size, offset + indirect_block_size)); 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; return success;
@ -310,19 +312,20 @@ static bool bktrAesCtrExStorageRead(BktrContext *ctx, void *out, u64 read_size,
return false; return false;
} }
next_aes_ctr_ex_entry = (aes_ctr_ex_entry + 1);
/* Perform read operation */ /* Perform read operation */
bool success = false; bool success = false;
next_aes_ctr_ex_entry = (aes_ctr_ex_entry + 1);
if ((section_offset + read_size) <= next_aes_ctr_ex_entry->offset) 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); success = ncaReadAesCtrExStorageFromBktrSection(ctx->patch_romfs_ctx.nca_fs_ctx, out, read_size, section_offset, aes_ctr_ex_entry->generation);
} else { } else {
/* Handle read that spans multiple AesCtrEx storage entries */ /* Handle read that spans multiple AesCtrEx storage entries */
u64 aes_ctr_ex_block_size = (next_aes_ctr_ex_entry->offset - section_offset); 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) && \ success = (bktrPhysicalSectionRead(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)); 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; 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) NX_INLINE BktrIndirectStorageBucket *bktrGetIndirectStorageBucket(BktrIndirectStorageBlock *block, u32 bucket_num)
{ {
if (!block || bucket_num >= block->bucket_count) return NULL; 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) 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!"); LOGFILE("Invalid parameters!");
return NULL; return NULL;
@ -384,12 +387,12 @@ static BktrIndirectStorageEntry *bktrGetIndirectStorageEntry(BktrIndirectStorage
NX_INLINE BktrAesCtrExStorageBucket *bktrGetAesCtrExStorageBucket(BktrAesCtrExStorageBlock *block, u32 bucket_num) NX_INLINE BktrAesCtrExStorageBucket *bktrGetAesCtrExStorageBucket(BktrAesCtrExStorageBlock *block, u32 bucket_num)
{ {
if (!block || bucket_num >= block->bucket_count) return NULL; 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) 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!"); LOGFILE("Invalid parameters!");
return NULL; return NULL;
@ -398,9 +401,8 @@ static BktrAesCtrExStorageEntry *bktrGetAesCtrExStorageEntry(BktrAesCtrExStorage
u32 bucket_num = 0; u32 bucket_num = 0;
BktrAesCtrExStorageBucket *last_bucket = NULL, *bucket = NULL; 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); 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!"); LOGFILE("Error retrieving last BKTR AesCtrEx storage bucket!");
return NULL; return NULL;
@ -414,7 +416,7 @@ static BktrAesCtrExStorageEntry *bktrGetAesCtrExStorageEntry(BktrAesCtrExStorage
} }
bucket = bktrGetAesCtrExStorageBucket(block, bucket_num); bucket = bktrGetAesCtrExStorageBucket(block, bucket_num);
if (!bucket) if (!bucket || !bucket->entry_count)
{ {
LOGFILE("Error retrieving BKTR AesCtrEx storage bucket #%u!", bucket_num); LOGFILE("Error retrieving BKTR AesCtrEx storage bucket #%u!", bucket_num);
return NULL; return NULL;

View file

@ -25,13 +25,13 @@
typedef enum { typedef enum {
BktrIndirectStorageIndex_Original = 0, BktrIndirectStorageIndex_Original = 0,
BktrIndirectStorageIndex_Patch = 1 BktrIndirectStorageIndex_Patch = 1
} BktrIndirectStorageIndex; } PACKED BktrIndirectStorageIndex;
typedef struct { typedef struct {
u64 virtual_offset; u64 virtual_offset;
u64 physical_offset; u64 physical_offset;
u32 indirect_storage_index; ///< BktrIndirectStorageIndex. u32 indirect_storage_index; ///< BktrIndirectStorageIndex.
} BktrIndirectStorageEntry; } PACKED BktrIndirectStorageEntry;
typedef struct { typedef struct {
u32 index; u32 index;
@ -39,7 +39,7 @@ typedef struct {
u64 end_offset; u64 end_offset;
BktrIndirectStorageEntry indirect_storage_entries[0x3FF0 / sizeof(BktrIndirectStorageEntry)]; BktrIndirectStorageEntry indirect_storage_entries[0x3FF0 / sizeof(BktrIndirectStorageEntry)];
u8 reserved[0x3FF0 % sizeof(BktrIndirectStorageEntry)]; u8 reserved[0x3FF0 % sizeof(BktrIndirectStorageEntry)];
} BktrIndirectStorageBucket; } PACKED BktrIndirectStorageBucket;
typedef struct { typedef struct {
u32 index; u32 index;
@ -47,20 +47,20 @@ typedef struct {
u64 virtual_size; u64 virtual_size;
u64 virtual_offsets[0x3FF0 / sizeof(u64)]; u64 virtual_offsets[0x3FF0 / sizeof(u64)];
BktrIndirectStorageBucket indirect_storage_buckets[]; BktrIndirectStorageBucket indirect_storage_buckets[];
} BktrIndirectStorageBlock; } PACKED BktrIndirectStorageBlock;
typedef struct { typedef struct {
u64 offset; u64 offset;
u32 size; u32 size;
u32 generation; u32 generation;
} BktrAesCtrExStorageEntry; } PACKED BktrAesCtrExStorageEntry;
typedef struct { typedef struct {
u32 index; u32 index;
u32 entry_count; u32 entry_count;
u64 end_offset; u64 end_offset;
BktrAesCtrExStorageEntry aes_ctr_ex_storage_entries[0x3FF]; BktrAesCtrExStorageEntry aes_ctr_ex_storage_entries[0x3FF];
} BktrAesCtrExStorageBucket; } PACKED BktrAesCtrExStorageBucket;
typedef struct { typedef struct {
u32 index; u32 index;
@ -68,7 +68,7 @@ typedef struct {
u64 physical_size; u64 physical_size;
u64 physical_offsets[0x3FF0 / sizeof(u64)]; u64 physical_offsets[0x3FF0 / sizeof(u64)];
BktrAesCtrExStorageBucket aes_ctr_ex_storage_buckets[]; BktrAesCtrExStorageBucket aes_ctr_ex_storage_buckets[];
} BktrAesCtrExStorageBlock; } PACKED BktrAesCtrExStorageBlock;
typedef struct { typedef struct {
RomFileSystemContext base_romfs_ctx; ///< Base NCA RomFS context. RomFileSystemContext base_romfs_ctx; ///< Base NCA RomFS context.

View file

@ -25,10 +25,7 @@
#include <dirent.h> #include <dirent.h>
#include "nca.h" #include "bktr.h"
#include "pfs.h"
#include "romfs.h"
#include "rsa.h"
@ -63,10 +60,13 @@ int main(int argc, char *argv[])
u8 *buf = NULL; u8 *buf = NULL;
FILE *tmp_file = NULL; FILE *tmp_file = NULL;
Ticket tik = {0}; Ticket base_tik = {0}, update_tik = {0};
NcaContext *nca_ctx = NULL; NcaContext *base_nca_ctx = NULL, *update_nca_ctx = NULL;
NcmContentStorage ncm_storage = {0}; NcmContentStorage ncm_storage = {0};
BktrContext bktr_ctx = {0};
RomFileSystemFileEntry *bktr_file_entry = NULL;
Result rc = 0; Result rc = 0;
mkdir("sdmc:/nxdt_test", 0744); 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 .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 // Untitled Goose Game's Base Program NCA
NcmPackagedContentInfo content_info = { NcmPackagedContentInfo base_program_content_info = {
.hash = { .hash = {
0x8E, 0xF9, 0x20, 0xD4, 0x5E, 0xE1, 0x9E, 0xD1, 0xD2, 0x04, 0xC4, 0xC8, 0x22, 0x50, 0x79, 0xE8, 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 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 // Untitled Goose Game's Update Program NCA
/*NcmPackagedContentInfo content_info = { NcmPackagedContentInfo update_program_content_info = {
.hash = { .hash = {
0xCE, 0x6E, 0x17, 0x1F, 0x93, 0x2D, 0x29, 0x28, 0xC1, 0x62, 0x94, 0x5B, 0x86, 0x2C, 0x42, 0x93, 0xDB, 0xEE, 0x62, 0x0E, 0x8F, 0x64, 0x37, 0xE4, 0x8A, 0x5C, 0x63, 0x61, 0xE8, 0xD2, 0x32, 0x6A,
0xAC, 0x2C, 0x0D, 0x3E, 0xD7, 0xCE, 0x07, 0xA2, 0x34, 0x33, 0x43, 0xD9, 0x21, 0x8A, 0xA3, 0xFE 0x21, 0x0D, 0x79, 0x50, 0x3A, 0xAF, 0x0D, 0x66, 0x76, 0xE2, 0xBC, 0x84, 0xF7, 0x0A, 0x21, 0xE2
}, },
.info = { .info = {
.content_id = { .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 = { .size = {
0x00, 0x74, 0x0A, 0x00, 0x00, 0x00 0x00, 0xF4, 0xA0, 0x0E, 0x00, 0x00
}, },
.content_type = NcmContentType_Control, .content_type = NcmContentType_Program,
.id_offset = 0 .id_offset = 0
} }
};*/ };
PartitionFileSystemEntry *pfs_entry = NULL;
PartitionFileSystemContext pfs_ctx = {0};
NcaHierarchicalSha256Patch pfs_patch = {0};
buf = malloc(0x400000); buf = malloc(0x400000);
if (!buf) if (!buf)
@ -125,14 +121,24 @@ int main(int argc, char *argv[])
printf("read buf succeeded\n"); printf("read buf succeeded\n");
consoleUpdate(NULL); consoleUpdate(NULL);
nca_ctx = calloc(1, sizeof(NcaContext)); base_nca_ctx = calloc(1, sizeof(NcaContext));
if (!nca_ctx) if (!base_nca_ctx)
{ {
printf("nca ctx buf failed\n"); printf("base nca ctx buf failed\n");
goto out2; 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); consoleUpdate(NULL);
rc = ncmOpenContentStorage(&ncm_storage, NcmStorageId_SdCard); rc = ncmOpenContentStorage(&ncm_storage, NcmStorageId_SdCard);
@ -145,171 +151,127 @@ int main(int argc, char *argv[])
printf("ncm open storage succeeded\n"); printf("ncm open storage succeeded\n");
consoleUpdate(NULL); 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; 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) if (tmp_file)
{ {
fwrite(nca_ctx, 1, sizeof(NcaContext), tmp_file); fwrite(base_nca_ctx, 1, sizeof(NcaContext), tmp_file);
fclose(tmp_file); fclose(tmp_file);
tmp_file = NULL; tmp_file = NULL;
printf("nca ctx saved\n"); printf("base nca ctx saved\n");
} else { } else {
printf("nca ctx not saved\n"); printf("base nca ctx not saved\n");
} }
consoleUpdate(NULL); 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; goto out2;
} }
printf("pfs initialize ctx succeeded\n"); tmp_file = fopen("sdmc:/nxdt_test/update_nca_ctx.bin", "wb");
consoleUpdate(NULL);
tmp_file = fopen("sdmc:/nxdt_test/pfs_ctx.bin", "wb");
if (tmp_file) if (tmp_file)
{ {
fwrite(&pfs_ctx, 1, sizeof(PartitionFileSystemContext), tmp_file); fwrite(update_nca_ctx, 1, sizeof(NcaContext), tmp_file);
fclose(tmp_file); fclose(tmp_file);
tmp_file = NULL; tmp_file = NULL;
printf("pfs ctx saved\n"); printf("update nca ctx saved\n");
} else { } else {
printf("pfs ctx not saved\n"); printf("update nca ctx not saved\n");
} }
consoleUpdate(NULL); consoleUpdate(NULL);
tmp_file = fopen("sdmc:/nxdt_test/pfs_header.bin", "wb"); if (!bktrInitializeContext(&bktr_ctx, &(base_nca_ctx->fs_contexts[1]), &(update_nca_ctx->fs_contexts[1])))
if (tmp_file)
{ {
fwrite(pfs_ctx.header, 1, pfs_ctx.header_size, tmp_file); printf("bktr initialize ctx failed\n");
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");
goto out2; goto out2;
} }
printf("pfs get entry by name succeeded\n"); printf("bktr initialize ctx succeeded\n");
consoleUpdate(NULL); 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; 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); consoleUpdate(NULL);
tmp_file = fopen("sdmc:/nxdt_test/main.npdm", "wb"); /*tmp_file = fopen("sdmc:/nxdt_test/resources.assets", "wb");
if (tmp_file) if (tmp_file)
{ {
fwrite(buf, 1, pfs_entry->size, tmp_file); u64 curpos = 0, blksize = 0x400000;
fclose(tmp_file); for(curpos = 0; curpos < bktr_file_entry->size; curpos += blksize)
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)
{ {
fwrite(layer_patch->data, 1, layer_patch->size, tmp_file); if (blksize > (bktr_file_entry->size - curpos)) blksize = (bktr_file_entry->size - curpos);
fclose(tmp_file);
tmp_file = NULL; if (!bktrReadFileEntryData(&bktr_ctx, bktr_file_entry, buf, blksize, curpos)) break;
printf("pfs patch #%u saved\n", i);
} else { fwrite(buf, 1, blksize, tmp_file);
printf("pfs patch #%u not saved\n", i);
} }
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); fclose(tmp_file);
tmp_file = NULL; tmp_file = NULL;
printf("nca header mod saved\n");
} else {
printf("nca header mod not saved\n");
}
if (curpos < bktr_file_entry->size)
{
printf("resources.assets read error\n");
} else {
printf("resources.assets saved\n");
}
} else {
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); if (tmp_file) fclose(tmp_file);
ncaFreeHierarchicalSha256Patch(&pfs_patch); bktrFreeContext(&bktr_ctx);
pfsFreeContext(&pfs_ctx);
if (serviceIsActive(&(ncm_storage.s))) ncmContentStorageClose(&ncm_storage); 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); if (buf) free(buf);