mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
RomFS file entry patching working.
This commit is contained in:
parent
5631046a67
commit
18531961ca
4 changed files with 322 additions and 74 deletions
179
source/main.c
179
source/main.c
|
@ -113,6 +113,7 @@ int main(int argc, char *argv[])
|
|||
u64 romfs_size = 0;
|
||||
RomFileSystemFileEntry *romfs_file_entry = NULL;
|
||||
RomFileSystemContext romfs_ctx = {0};
|
||||
RomFileSystemFileEntryPatch romfs_patch = {0};
|
||||
|
||||
buf = malloc(0x400000);
|
||||
if (!buf)
|
||||
|
@ -172,15 +173,6 @@ int main(int argc, char *argv[])
|
|||
printf("romfs initialize ctx succeeded\n");
|
||||
consoleUpdate(NULL);
|
||||
|
||||
if (romfsGetTotalDataSize(&romfs_ctx, &romfs_size))
|
||||
{
|
||||
printf("romfs size succeeded: 0x%lX\n", romfs_size);
|
||||
} else {
|
||||
printf("romfs size failed\n");
|
||||
}
|
||||
|
||||
consoleUpdate(NULL);
|
||||
|
||||
tmp_file = fopen("sdmc:/nxdt_test/romfs_ctx.bin", "wb");
|
||||
if (tmp_file)
|
||||
{
|
||||
|
@ -200,9 +192,9 @@ int main(int argc, char *argv[])
|
|||
fwrite(romfs_ctx.dir_table, 1, romfs_ctx.dir_table_size, tmp_file);
|
||||
fclose(tmp_file);
|
||||
tmp_file = NULL;
|
||||
printf("dir table saved\n");
|
||||
printf("romfs dir table saved\n");
|
||||
} else {
|
||||
printf("dir table not saved\n");
|
||||
printf("romfs dir table not saved\n");
|
||||
}
|
||||
|
||||
consoleUpdate(NULL);
|
||||
|
@ -213,40 +205,9 @@ int main(int argc, char *argv[])
|
|||
fwrite(romfs_ctx.file_table, 1, romfs_ctx.file_table_size, tmp_file);
|
||||
fclose(tmp_file);
|
||||
tmp_file = NULL;
|
||||
printf("file table saved\n");
|
||||
printf("romfs file table saved\n");
|
||||
} else {
|
||||
printf("file table not saved\n");
|
||||
}
|
||||
|
||||
consoleUpdate(NULL);
|
||||
|
||||
romfs_file_entry = romfsGetFileEntryByPath(&romfs_ctx, "/control.nacp");
|
||||
if (!romfs_file_entry)
|
||||
{
|
||||
printf("romfs get file entry by path failed\n");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
printf("romfs get file entry by path success: %s | %p\n", romfs_file_entry->name, romfs_file_entry);
|
||||
consoleUpdate(NULL);
|
||||
|
||||
if (romfsReadFileEntryData(&romfs_ctx, romfs_file_entry, buf, romfs_file_entry->size, 0))
|
||||
{
|
||||
printf("romfs read file entry success\n");
|
||||
consoleUpdate(NULL);
|
||||
|
||||
tmp_file = fopen("sdmc:/nxdt_test/control.nacp", "wb");
|
||||
if (tmp_file)
|
||||
{
|
||||
fwrite(buf, 1, romfs_file_entry->size, tmp_file);
|
||||
fclose(tmp_file);
|
||||
tmp_file = NULL;
|
||||
printf("romfs file entry data saved\n");
|
||||
} else {
|
||||
printf("romfs file entry data not saved\n");
|
||||
}
|
||||
} else {
|
||||
printf("romfs read file entry failed\n");
|
||||
printf("romfs file table not saved\n");
|
||||
}
|
||||
|
||||
consoleUpdate(NULL);
|
||||
|
@ -270,6 +231,134 @@ int main(int argc, char *argv[])
|
|||
printf("romfs read fs data failed\n");
|
||||
}
|
||||
|
||||
if (romfsGetTotalDataSize(&romfs_ctx, &romfs_size))
|
||||
{
|
||||
printf("romfs size succeeded: 0x%lX\n", romfs_size);
|
||||
} else {
|
||||
printf("romfs size failed\n");
|
||||
}
|
||||
|
||||
consoleUpdate(NULL);
|
||||
|
||||
romfs_file_entry = romfsGetFileEntryByPath(&romfs_ctx, "/control.nacp");
|
||||
if (!romfs_file_entry)
|
||||
{
|
||||
printf("romfs get file entry by path failed\n");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
printf("romfs get file entry by path success: %s | %p\n", romfs_file_entry->name, romfs_file_entry);
|
||||
consoleUpdate(NULL);
|
||||
|
||||
if (!romfsReadFileEntryData(&romfs_ctx, romfs_file_entry, buf, romfs_file_entry->size, 0))
|
||||
{
|
||||
printf("romfs read file entry failed\n");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
printf("romfs read file entry success\n");
|
||||
consoleUpdate(NULL);
|
||||
|
||||
tmp_file = fopen("sdmc:/nxdt_test/control.nacp", "wb");
|
||||
if (tmp_file)
|
||||
{
|
||||
fwrite(buf, 1, romfs_file_entry->size, tmp_file);
|
||||
fclose(tmp_file);
|
||||
tmp_file = NULL;
|
||||
printf("romfs file entry data saved\n");
|
||||
} else {
|
||||
printf("romfs file entry data not saved\n");
|
||||
}
|
||||
|
||||
consoleUpdate(NULL);
|
||||
|
||||
NacpStruct *nacp_data = (NacpStruct*)buf;
|
||||
memset(nacp_data->lang, 0, MEMBER_SIZE(NacpStruct, lang));
|
||||
for(u8 i = 0; i < 16; i++)
|
||||
{
|
||||
sprintf(nacp_data->lang[i].name, "nxdumptool");
|
||||
sprintf(nacp_data->lang[i].author, "DarkMatterCore");
|
||||
}
|
||||
|
||||
tmp_file = fopen("sdmc:/nxdt_test/control_mod.nacp", "wb");
|
||||
if (tmp_file)
|
||||
{
|
||||
fwrite(buf, 1, romfs_file_entry->size, tmp_file);
|
||||
fclose(tmp_file);
|
||||
tmp_file = NULL;
|
||||
printf("romfs file entry mod data saved\n");
|
||||
} else {
|
||||
printf("romfs file entry mod data not saved\n");
|
||||
}
|
||||
|
||||
consoleUpdate(NULL);
|
||||
|
||||
if (!romfsGenerateFileEntryPatch(&romfs_ctx, romfs_file_entry, buf, MEMBER_SIZE(NacpStruct, lang), 0, &romfs_patch))
|
||||
{
|
||||
printf("romfs file entry patch failed\n");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
printf("romfs file entry patch success\n");
|
||||
consoleUpdate(NULL);
|
||||
|
||||
tmp_file = fopen("sdmc:/nxdt_test/romfs_patch.bin", "wb");
|
||||
if (tmp_file)
|
||||
{
|
||||
fwrite(&romfs_patch, 1, sizeof(RomFileSystemFileEntryPatch), tmp_file);
|
||||
fclose(tmp_file);
|
||||
tmp_file = NULL;
|
||||
printf("romfs patch saved\n");
|
||||
} else {
|
||||
printf("romfs patch not saved\n");
|
||||
}
|
||||
|
||||
for(u8 i = 0; i < (NCA_IVFC_HASH_DATA_LAYER_COUNT + 1); i++)
|
||||
{
|
||||
NcaHashInfoLayerPatch *layer_patch = (i < NCA_IVFC_HASH_DATA_LAYER_COUNT ? &(romfs_patch.cur_format_patch.hash_data_layer_patch[i]) : &(romfs_patch.cur_format_patch.hash_target_layer_patch));
|
||||
if (!layer_patch->size || !layer_patch->data) continue;
|
||||
|
||||
char path[64];
|
||||
sprintf(path, "sdmc:/nxdt_test/romfs_patch_l%u.bin", i);
|
||||
|
||||
tmp_file = fopen(path, "wb");
|
||||
if (tmp_file)
|
||||
{
|
||||
fwrite(layer_patch->data, 1, layer_patch->size, tmp_file);
|
||||
fclose(tmp_file);
|
||||
tmp_file = NULL;
|
||||
printf("romfs patch #%u saved\n", i);
|
||||
} else {
|
||||
printf("romfs 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);
|
||||
tmp_file = NULL;
|
||||
printf("nca header mod saved\n");
|
||||
} else {
|
||||
printf("nca header mod not saved\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -287,6 +376,8 @@ out2:
|
|||
|
||||
if (tmp_file) fclose(tmp_file);
|
||||
|
||||
romfsFreeFileEntryPatch(&romfs_patch);
|
||||
|
||||
romfsFreeContext(&romfs_ctx);
|
||||
|
||||
if (serviceIsActive(&(ncm_storage.s))) ncmContentStorageClose(&ncm_storage);
|
||||
|
|
189
source/nca.c
189
source/nca.c
|
@ -137,7 +137,7 @@ bool ncaEncryptHeader(NcaContext *ctx)
|
|||
{
|
||||
case NcaVersion_Nca3:
|
||||
crypt_res = aes128XtsNintendoCrypt(&hdr_aes_ctx, ctx->header.fs_headers, ctx->header.fs_headers, NCA_FULL_HEADER_LENGTH - NCA_HEADER_LENGTH, 2, NCA_AES_XTS_SECTOR_SIZE, true);
|
||||
if (crypt_res != NCA_FULL_HEADER_LENGTH)
|
||||
if (crypt_res != (NCA_FULL_HEADER_LENGTH - NCA_HEADER_LENGTH))
|
||||
{
|
||||
LOGFILE("Error encrypting NCA3 \"%s\" FS section headers!", ctx->content_id_str);
|
||||
return false;
|
||||
|
@ -485,8 +485,8 @@ bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *da
|
|||
}
|
||||
|
||||
/* Reencrypt hash target layer block */
|
||||
out->hash_target_layer_patch.data = _ncaGenerateEncryptedFsSectionBlock(ctx, hash_target_block, hash_target_size, hash_target_start_offset, &(out->hash_target_layer_patch.size), \
|
||||
&(out->hash_target_layer_patch.offset), false);
|
||||
out->hash_target_layer_patch.data = _ncaGenerateEncryptedFsSectionBlock(ctx, hash_target_block + hash_target_data_offset, data_size, hash_target_layer_offset + data_offset, \
|
||||
&(out->hash_target_layer_patch.size), &(out->hash_target_layer_patch.offset), false);
|
||||
if (!out->hash_target_layer_patch.data)
|
||||
{
|
||||
LOGFILE("Failed to generate encrypted HierarchicalSha256 hash target layer block!");
|
||||
|
@ -505,22 +505,183 @@ bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *da
|
|||
success = true;
|
||||
|
||||
exit:
|
||||
mutexUnlock(&g_ncaCryptoBufferMutex);
|
||||
|
||||
if (hash_target_block) free(hash_target_block);
|
||||
|
||||
if (hash_data_layer) free(hash_data_layer);
|
||||
|
||||
if (!success) ncaFreeHierarchicalSha256Patch(out);
|
||||
|
||||
mutexUnlock(&g_ncaCryptoBufferMutex);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void *data, u64 data_size, u64 data_offset, NcaHierarchicalIntegrityPatch *out)
|
||||
{
|
||||
mutexLock(&g_ncaCryptoBufferMutex);
|
||||
|
||||
NcaContext *nca_ctx = NULL;
|
||||
bool success = false;
|
||||
|
||||
u8 *cur_data = NULL;
|
||||
u64 cur_data_offset = data_offset;
|
||||
u64 cur_data_size = data_size;
|
||||
|
||||
u8 *hash_data_block = NULL, *hash_target_block = NULL;
|
||||
|
||||
if (!ctx || !(nca_ctx = (NcaContext*)ctx->nca_ctx) || !ctx->header || ctx->header->hash_type != NcaHashType_HierarchicalIntegrity || !data || !data_size || !out || \
|
||||
data_offset >= ctx->header->hash_info.hierarchical_integrity.hash_target_layer_info.size || \
|
||||
(data_offset + data_size) > ctx->header->hash_info.hierarchical_integrity.hash_target_layer_info.size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Process each IVFC layer */
|
||||
for(u8 i = (NCA_IVFC_HASH_DATA_LAYER_COUNT + 1); i > 0; i--)
|
||||
{
|
||||
NcaHierarchicalIntegrityLayerInfo *cur_layer_info = (i > NCA_IVFC_HASH_DATA_LAYER_COUNT ? &(ctx->header->hash_info.hierarchical_integrity.hash_target_layer_info) : \
|
||||
&(ctx->header->hash_info.hierarchical_integrity.hash_data_layer_info[i - 1]));
|
||||
|
||||
NcaHierarchicalIntegrityLayerInfo *parent_layer_info = (i > 1 ? &(ctx->header->hash_info.hierarchical_integrity.hash_data_layer_info[i - 2]) : NULL);
|
||||
|
||||
NcaHashInfoLayerPatch *cur_layer_patch = (i > NCA_IVFC_HASH_DATA_LAYER_COUNT ? &(out->hash_target_layer_patch) : &(out->hash_data_layer_patch[i - 1]));
|
||||
|
||||
if (!cur_layer_info->size || !cur_layer_info->block_size || (parent_layer_info && (!parent_layer_info->size || !parent_layer_info->block_size)))
|
||||
{
|
||||
LOGFILE("Invalid HierarchicalIntegrity parent/child layer!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Calculate required offsets and sizes */
|
||||
u64 hash_block_size = NCA_IVFC_BLOCK_SIZE(cur_layer_info->block_size);
|
||||
|
||||
u64 hash_data_layer_offset = 0;
|
||||
u64 hash_data_start_offset = 0, hash_data_end_offset = 0, hash_data_size = 0;
|
||||
|
||||
u64 hash_target_layer_offset = cur_layer_info->offset, hash_target_layer_size = cur_layer_info->size;
|
||||
u64 hash_target_start_offset = 0, hash_target_end_offset = 0, hash_target_size = 0, hash_target_data_offset = 0;
|
||||
|
||||
if (parent_layer_info)
|
||||
{
|
||||
/* HierarchicalIntegrity layer from L1 to L5 */
|
||||
hash_data_layer_offset = parent_layer_info->offset;
|
||||
|
||||
hash_data_start_offset = ((cur_data_offset / hash_block_size) * SHA256_HASH_SIZE);
|
||||
hash_data_end_offset = (((cur_data_offset + cur_data_size) / hash_block_size) * SHA256_HASH_SIZE);
|
||||
hash_data_size = (hash_data_end_offset != hash_data_start_offset ? (hash_data_end_offset - hash_data_start_offset) : SHA256_HASH_SIZE);
|
||||
|
||||
hash_target_start_offset = (hash_target_layer_offset + ALIGN_DOWN(cur_data_offset, hash_block_size));
|
||||
hash_target_end_offset = (hash_target_layer_offset + ALIGN_UP(cur_data_offset + cur_data_size, hash_block_size));
|
||||
hash_target_size = (hash_target_end_offset - hash_target_start_offset);
|
||||
} else {
|
||||
/* HierarchicalIntegrity master layer */
|
||||
/* The master hash is calculated over the whole layer and saved to the NCA FS header */
|
||||
hash_target_start_offset = hash_target_layer_offset;
|
||||
hash_target_end_offset = (hash_target_layer_offset + hash_target_layer_size);
|
||||
hash_target_size = hash_target_layer_size;
|
||||
}
|
||||
|
||||
hash_target_data_offset = (cur_data_offset - ALIGN_DOWN(cur_data_offset, hash_block_size));
|
||||
|
||||
/* Allocate memory for our hash target layer block */
|
||||
hash_target_block = calloc(hash_target_size, sizeof(u8));
|
||||
if (!hash_target_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes for the HierarchicalIntegrity hash target layer block!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Adjust hash target layer end offset and size if needed to avoid read errors */
|
||||
if (hash_target_end_offset > (hash_target_layer_offset + hash_target_layer_size))
|
||||
{
|
||||
hash_target_end_offset = (hash_target_layer_offset + hash_target_layer_size);
|
||||
hash_target_size = (hash_target_end_offset - hash_target_start_offset);
|
||||
}
|
||||
|
||||
/* Read hash target layer block */
|
||||
if (!_ncaReadFsSection(ctx, hash_target_block, hash_target_size, hash_target_start_offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read HierarchicalIntegrity hash target layer block!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Replace hash target layer block data */
|
||||
memcpy(hash_target_block + hash_target_data_offset, (i > NCA_IVFC_HASH_DATA_LAYER_COUNT ? data : cur_data), cur_data_size);
|
||||
|
||||
if (parent_layer_info)
|
||||
{
|
||||
/* Allocate memory for our hash data layer block */
|
||||
hash_data_block = calloc(hash_data_size, sizeof(u8));
|
||||
if (!hash_data_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes for the HierarchicalIntegrity hash data layer block!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Read hash target layer block */
|
||||
if (!_ncaReadFsSection(ctx, hash_data_block, hash_data_size, hash_data_layer_offset + hash_data_start_offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read HierarchicalIntegrity hash data layer block!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Recalculate hashes */
|
||||
/* Size isn't truncated for blocks smaller than the hash block size, unlike HierarchicalSha256, so we just keep using the same hash block size throughout the loop */
|
||||
/* For these specific cases, the rest of the block should be filled with zeroes (already taken care of by using calloc()) */
|
||||
for(u64 i = 0, j = 0; i < hash_target_size; i += hash_block_size, j++) sha256CalculateHash(hash_data_block + (j * SHA256_HASH_SIZE), hash_target_block + i, hash_block_size);
|
||||
} else {
|
||||
/* Recalculate master hash from hash info block */
|
||||
sha256CalculateHash(ctx->header->hash_info.hierarchical_integrity.master_hash, hash_target_block, hash_target_size);
|
||||
}
|
||||
|
||||
/* Reencrypt hash target layer block */
|
||||
cur_layer_patch->data = _ncaGenerateEncryptedFsSectionBlock(ctx, hash_target_block + hash_target_data_offset, cur_data_size, hash_target_layer_offset + cur_data_offset, \
|
||||
&(cur_layer_patch->size), &(cur_layer_patch->offset), false);
|
||||
if (!cur_layer_patch->data)
|
||||
{
|
||||
LOGFILE("Failed to generate encrypted HierarchicalIntegrity hash target layer block!");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Free hash target layer block */
|
||||
free(hash_target_block);
|
||||
hash_target_block = NULL;
|
||||
|
||||
if (parent_layer_info)
|
||||
{
|
||||
/* Free previous layer data if necessary */
|
||||
if (cur_data) free(cur_data);
|
||||
|
||||
/* Prepare data for the next target layer */
|
||||
cur_data = hash_data_block;
|
||||
cur_data_offset = hash_data_start_offset;
|
||||
cur_data_size = hash_data_size;
|
||||
hash_data_block = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Recalculate FS header hash */
|
||||
sha256CalculateHash(nca_ctx->header.fs_hashes[ctx->section_num].hash, ctx->header, sizeof(NcaFsHeader));
|
||||
|
||||
/* Enable the 'dirty_header' flag */
|
||||
nca_ctx->dirty_header = true;
|
||||
|
||||
success = true;
|
||||
|
||||
exit:
|
||||
if (hash_data_block) free(hash_data_block);
|
||||
|
||||
if (hash_target_block) free(hash_target_block);
|
||||
|
||||
if (cur_data) free(cur_data);
|
||||
|
||||
if (!success) ncaFreeHierarchicalIntegrityPatch(out);
|
||||
|
||||
mutexUnlock(&g_ncaCryptoBufferMutex);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static size_t aes128XtsNintendoCrypt(Aes128XtsContext *ctx, void *dst, const void *src, size_t size, u64 sector, size_t sector_size, bool encrypt)
|
||||
{
|
||||
|
@ -1016,13 +1177,13 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
success = true;
|
||||
|
||||
exit:
|
||||
if (lock) mutexUnlock(&g_ncaCryptoBufferMutex);
|
||||
|
||||
if (!success && out)
|
||||
{
|
||||
free(out);
|
||||
out = NULL;
|
||||
}
|
||||
|
||||
if (lock) mutexUnlock(&g_ncaCryptoBufferMutex);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
|
22
source/nca.h
22
source/nca.h
|
@ -328,13 +328,13 @@ bool ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size, u64 of
|
|||
/// Returns a pointer to a heap-allocated buffer used to encrypt the input plaintext data, based on the encryption type used by the input NCA FS section, as well as its offset and size.
|
||||
/// Input offset must be relative to the start of the NCA FS section.
|
||||
/// Output size and offset are guaranteed to be aligned to the AES sector size used by the encryption type from the FS section.
|
||||
/// Output offset is relative to the start of the NCA content file, making it easier to use the output encrypted block to replace data in-place while writing a NCA.
|
||||
/// Output offset is relative to the start of the NCA content file, making it easier to use the output encrypted block to seamlessly replace data while dumping a NCA.
|
||||
void *ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const void *data, u64 data_size, u64 data_offset, u64 *out_block_size, u64 *out_block_offset);
|
||||
|
||||
/// Generates HierarchicalSha256 FS section patch data, which can be used to replace NCA data in content dumping operations.
|
||||
/// Input offset must be relative to the start of the HierarchicalSha256 hash target layer (actual underlying FS).
|
||||
/// 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 not capable of generating more than one patch per HierarchicalSha256 FS section.
|
||||
/// As such, this function is not designed to generate more than one patch per HierarchicalSha256 FS section.
|
||||
bool ncaGenerateHierarchicalSha256Patch(NcaFsSectionContext *ctx, const void *data, u64 data_size, u64 data_offset, NcaHierarchicalSha256Patch *out);
|
||||
|
||||
/// Cleanups a previously generated NcaHierarchicalSha256Patch.
|
||||
|
@ -346,23 +346,23 @@ NX_INLINE void ncaFreeHierarchicalSha256Patch(NcaHierarchicalSha256Patch *patch)
|
|||
memset(patch, 0, sizeof(NcaHierarchicalSha256Patch));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Generates HierarchicalIntegrity FS section patch data, which can be used to replace NCA data in content dumping operations.
|
||||
/// Input offset must be relative to the start of the HierarchicalIntegrity hash target layer (actual underlying FS).
|
||||
/// 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 not designed to generate more than one patch per HierarchicalIntegrity FS section.
|
||||
bool ncaGenerateHierarchicalIntegrityPatch(NcaFsSectionContext *ctx, const void *data, u64 data_size, u64 data_offset, NcaHierarchicalIntegrityPatch *out);
|
||||
|
||||
/// Cleanups a previously generated NcaHierarchicalIntegrityPatch.
|
||||
NX_INLINE void ncaFreeHierarchicalIntegrityPatch(NcaHierarchicalIntegrityPatch *patch)
|
||||
{
|
||||
if (!patch) return;
|
||||
|
||||
for(u8 i = 0; i < NCA_IVFC_HASH_DATA_LAYER_COUNT; i++)
|
||||
for(u8 i = 0; i < (NCA_IVFC_HASH_DATA_LAYER_COUNT + 1); i++)
|
||||
{
|
||||
if (patch->hash_data_layer_patch[i].data) free(patch->hash_data_layer_patch[i].data);
|
||||
NcaHashInfoLayerPatch *layer_patch = (i < NCA_IVFC_HASH_DATA_LAYER_COUNT ? &(patch->hash_data_layer_patch[i]) : &(patch->hash_target_layer_patch));
|
||||
if (layer_patch->data) free(layer_patch->data);
|
||||
}
|
||||
|
||||
if (patch->hash_target_layer_patch.data) free(patch->hash_target_layer_patch.data);
|
||||
memset(patch, 0, sizeof(NcaHierarchicalIntegrityPatch));
|
||||
}
|
||||
|
||||
|
@ -413,7 +413,6 @@ NX_INLINE bool ncaValidateHierarchicalSha256Offsets(NcaHierarchicalSha256 *hiera
|
|||
{
|
||||
if (!hierarchical_sha256 || !section_size || !hierarchical_sha256->hash_block_size || hierarchical_sha256->layer_count != NCA_HIERARCHICAL_SHA256_LAYER_COUNT) return false;
|
||||
|
||||
/* Validate layer offsets and sizes */
|
||||
for(u8 i = 0; i < NCA_HIERARCHICAL_SHA256_LAYER_COUNT; i++)
|
||||
{
|
||||
NcaHierarchicalSha256LayerInfo *layer_info = (i == 0 ? &(hierarchical_sha256->hash_data_layer_info) : &(hierarchical_sha256->hash_target_layer_info));
|
||||
|
@ -428,7 +427,6 @@ NX_INLINE bool ncaValidateHierarchicalIntegrityOffsets(NcaHierarchicalIntegrity
|
|||
if (!hierarchical_integrity || !section_size || __builtin_bswap32(hierarchical_integrity->magic) != NCA_IVFC_MAGIC || !hierarchical_integrity->master_hash_size || \
|
||||
hierarchical_integrity->layer_count != NCA_IVFC_LAYER_COUNT) return false;
|
||||
|
||||
/* Validate layer offsets and sizes */
|
||||
for(u8 i = 0; i < (NCA_IVFC_HASH_DATA_LAYER_COUNT + 1); i++)
|
||||
{
|
||||
NcaHierarchicalIntegrityLayerInfo *layer_info = (i < NCA_IVFC_HASH_DATA_LAYER_COUNT ? &(hierarchical_integrity->hash_data_layer_info[i]) : &(hierarchical_integrity->hash_target_layer_info));
|
||||
|
|
|
@ -490,14 +490,12 @@ bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEnt
|
|||
if (ctx->nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs)
|
||||
{
|
||||
out->use_old_format_patch = true;
|
||||
|
||||
success = ncaGenerateHierarchicalSha256Patch(ctx->nca_fs_ctx, data, data_size, fs_offset, &(out->old_format_patch));
|
||||
if (!success) LOGFILE("Failed to generate 0x%lX bytes HierarchicalSha256 patch at offset 0x%lX for RomFS file entry!", data_size, fs_offset);
|
||||
} else {
|
||||
out->use_old_format_patch = false;
|
||||
|
||||
success = true;
|
||||
|
||||
success = ncaGenerateHierarchicalIntegrityPatch(ctx->nca_fs_ctx, data, data_size, fs_offset, &(out->cur_format_patch));
|
||||
if (!success) LOGFILE("Failed to generate 0x%lX bytes HierarchicalIntegrity patch at offset 0x%lX for RomFS file entry!", data_size, fs_offset);
|
||||
}
|
||||
|
||||
return success;
|
||||
|
|
Loading…
Reference in a new issue