mirror of
https://github.com/SciresM/hactool
synced 2024-11-21 19:53:01 +00:00
Fix regression causing segfault on remapped saves (#88)
* save: Find file by path, ignore fail on validate * save: Revert faulty semantics, fix wrong hash size * save: Add missing save type from help string * save: Fix bug in remap storage init
This commit is contained in:
parent
bea6345a48
commit
55b13f0d67
4 changed files with 41 additions and 25 deletions
|
@ -19,7 +19,7 @@ Options:
|
|||
-y, --verify Verify hashes and signatures.
|
||||
-d, --dev Decrypt with development keys instead of retail.
|
||||
-k, --keyset Load keys from an external file.
|
||||
-t, --intype=type Specify input file type [nca, xci, pfs0, romfs, hfs0, npdm, pk11, pk21, ini1, kip1, nax0, keygen]
|
||||
-t, --intype=type Specify input file type [nca, xci, pfs0, romfs, hfs0, npdm, pk11, pk21, ini1, kip1, nax0, save, keygen]
|
||||
--titlekey=key Set title key for Rights ID crypto titles.
|
||||
--contentkey=key Set raw key for NCA body decryption.
|
||||
--disablekeywarns Disables warning output when loading external keys.
|
||||
|
|
2
main.c
2
main.c
|
@ -34,7 +34,7 @@ static void usage(void) {
|
|||
" -y, --verify Verify hashes and signatures.\n"
|
||||
" -d, --dev Decrypt with development keys instead of retail.\n"
|
||||
" -k, --keyset Load keys from an external file.\n"
|
||||
" -t, --intype=type Specify input file type [nca, xci, pfs0, romfs, hfs0, npdm, pk11, pk21, ini1, kip1, nax0, keygen]\n"
|
||||
" -t, --intype=type Specify input file type [nca, xci, pfs0, romfs, hfs0, npdm, pk11, pk21, ini1, kip1, nax0, save, keygen]\n"
|
||||
" --titlekey=key Set title key for Rights ID crypto titles.\n"
|
||||
" --contentkey=key Set raw key for NCA body decryption.\n"
|
||||
" --disablekeywarns Disables warning output when loading external keys.\n"
|
||||
|
|
60
save.c
60
save.c
|
@ -1,3 +1,4 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "save.h"
|
||||
|
@ -68,27 +69,34 @@ uint32_t save_duplex_storage_read(duplex_storage_ctx_t *ctx, void *buffer, uint6
|
|||
}
|
||||
|
||||
remap_segment_ctx_t *save_remap_init_segments(remap_header_t *header, remap_entry_ctx_t *map_entries, uint32_t num_map_entries) {
|
||||
remap_segment_ctx_t *segments = malloc(sizeof(remap_segment_ctx_t) * header->map_segment_count);
|
||||
remap_segment_ctx_t *segments = calloc(1, sizeof(remap_segment_ctx_t) * header->map_segment_count);
|
||||
unsigned int entry_idx = 0;
|
||||
|
||||
for (unsigned int i = 0; i < header->map_segment_count; i++) {
|
||||
remap_segment_ctx_t *seg = &segments[i];
|
||||
seg->entries = malloc(sizeof(remap_entry_ctx_t));
|
||||
memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t));
|
||||
seg->entry_count = 0;
|
||||
remap_entry_ctx_t **ptr = malloc(sizeof(remap_entry_ctx_t *) * (seg->entry_count + 1));
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "Failed to allocate entries in remap storage!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
seg->entries = ptr;
|
||||
seg->entries[seg->entry_count++] = &map_entries[entry_idx];
|
||||
seg->offset = map_entries[entry_idx].virtual_offset;
|
||||
map_entries[entry_idx].segment = seg;
|
||||
seg->entry_count = 1;
|
||||
entry_idx++;
|
||||
map_entries[entry_idx++].segment = seg;
|
||||
|
||||
while (entry_idx < num_map_entries && map_entries[entry_idx - 1].virtual_offset_end == map_entries[entry_idx].virtual_offset) {
|
||||
map_entries[entry_idx].segment = seg;
|
||||
map_entries[entry_idx - 1].next = &map_entries[entry_idx];
|
||||
seg->entries = malloc(sizeof(remap_entry_ctx_t));
|
||||
memcpy(seg->entries, &map_entries[entry_idx], sizeof(remap_entry_ctx_t));
|
||||
seg->entry_count++;
|
||||
entry_idx++;
|
||||
ptr = realloc(seg->entries, sizeof(remap_entry_ctx_t *) * (seg->entry_count + 1));
|
||||
if (!ptr) {
|
||||
fprintf(stderr, "Failed to reallocate entries in remap storage!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
seg->entries = ptr;
|
||||
seg->entries[seg->entry_count++] = &map_entries[entry_idx++];
|
||||
}
|
||||
seg->length = seg->entries[seg->entry_count - 1].virtual_offset_end - seg->entries[0].virtual_offset;
|
||||
seg->length = seg->entries[seg->entry_count - 1]->virtual_offset_end - seg->entries[0]->virtual_offset;
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
@ -97,8 +105,8 @@ remap_entry_ctx_t *save_remap_get_map_entry(remap_storage_ctx_t *ctx, uint64_t o
|
|||
uint32_t segment_idx = (uint32_t)(offset >> (64 - ctx->header->segment_bits));
|
||||
if (segment_idx < ctx->header->map_segment_count) {
|
||||
for (unsigned int i = 0; i < ctx->segments[segment_idx].entry_count; i++)
|
||||
if (ctx->segments[segment_idx].entries[i].virtual_offset_end > offset)
|
||||
return &ctx->segments[segment_idx].entries[i];
|
||||
if (ctx->segments[segment_idx].entries[i]->virtual_offset_end > offset)
|
||||
return ctx->segments[segment_idx].entries[i];
|
||||
}
|
||||
fprintf(stderr, "Remap offset %"PRIx64" out of range!\n", offset);
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -178,7 +186,7 @@ void save_ivfc_storage_init(hierarchical_integrity_verification_storage_ctx_t *c
|
|||
uint32_t length;
|
||||
};
|
||||
|
||||
static struct salt_source_t salt_sources[6] = {
|
||||
static const struct salt_source_t salt_sources[6] = {
|
||||
{"HierarchicalIntegrityVerificationStorage::Master", 48},
|
||||
{"HierarchicalIntegrityVerificationStorage::L1", 44},
|
||||
{"HierarchicalIntegrityVerificationStorage::L2", 44},
|
||||
|
@ -272,7 +280,7 @@ void save_ivfc_storage_read(integrity_verification_storage_ctx_t *ctx, void *buf
|
|||
|
||||
sha_ctx_t *sha_ctx = new_sha_ctx(HASH_TYPE_SHA256, 0);
|
||||
sha_update(sha_ctx, ctx->salt, 0x20);
|
||||
sha_update(sha_ctx, data_buffer, count);
|
||||
sha_update(sha_ctx, data_buffer, ctx->sector_size);
|
||||
sha_get_hash(sha_ctx, hash);
|
||||
free_sha_ctx(sha_ctx);
|
||||
hash[0x1F] |= 0x80;
|
||||
|
@ -482,6 +490,18 @@ uint32_t save_fs_get_index_from_key(save_filesystem_list_ctx_t *ctx, save_entry_
|
|||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
int save_hierarchical_file_table_find_path_recursive(hierarchical_save_file_table_ctx_t *ctx, save_entry_key_t *key, char *path) {
|
||||
memcpy(key->name, path, SAVE_FS_LIST_MAX_NAME_LENGTH);
|
||||
key->parent = 0;
|
||||
char *pos = path;
|
||||
while (pos) {
|
||||
key->parent = save_fs_get_index_from_key(&ctx->directory_table, key, NULL);
|
||||
if (key->parent == 0xFFFFFFFF) return 0;
|
||||
pos = strchr(pos, '/');
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int save_hierarchical_file_table_find_next_file(hierarchical_save_file_table_ctx_t *ctx, save_find_position_t *position, save_file_info_t *info, char *name) {
|
||||
if (position->next_file == 0) {
|
||||
return 0;
|
||||
|
@ -627,7 +647,7 @@ void save_process(save_ctx_t *ctx) {
|
|||
ctx->data_remap_storage.type = STORAGE_BYTES;
|
||||
ctx->data_remap_storage.base_storage_offset = ctx->header.layout.file_map_data_offset;
|
||||
ctx->data_remap_storage.header = &ctx->header.main_remap_header;
|
||||
ctx->data_remap_storage.map_entries = malloc(sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count);
|
||||
ctx->data_remap_storage.map_entries = calloc(1, sizeof(remap_entry_ctx_t) * ctx->data_remap_storage.header->map_entry_count);
|
||||
ctx->data_remap_storage.file = ctx->file;
|
||||
fseeko64(ctx->file, ctx->header.layout.file_map_entry_offset, SEEK_SET);
|
||||
for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_entry_count; i++) {
|
||||
|
@ -763,15 +783,11 @@ void save_process_header(save_ctx_t *ctx) {
|
|||
|
||||
void save_free_contexts(save_ctx_t *ctx) {
|
||||
for (unsigned int i = 0; i < ctx->data_remap_storage.header->map_segment_count; i++) {
|
||||
for (unsigned int j = 0; j < ctx->data_remap_storage.segments[i].entry_count; j++) {
|
||||
free(&ctx->data_remap_storage.segments[i].entries[j]);
|
||||
}
|
||||
free(ctx->data_remap_storage.segments[i].entries);
|
||||
}
|
||||
free(ctx->data_remap_storage.segments);
|
||||
for (unsigned int i = 0; i < ctx->meta_remap_storage.header->map_segment_count; i++) {
|
||||
for (unsigned int j = 0; j < ctx->meta_remap_storage.segments[i].entry_count; j++) {
|
||||
free(&ctx->meta_remap_storage.segments[i].entries[j]);
|
||||
}
|
||||
free(ctx->meta_remap_storage.segments[i].entries);
|
||||
}
|
||||
free(ctx->meta_remap_storage.segments);
|
||||
free(ctx->data_remap_storage.map_entries);
|
||||
|
|
2
save.h
2
save.h
|
@ -146,7 +146,7 @@ struct remap_entry_ctx_t {
|
|||
struct remap_segment_ctx_t{
|
||||
uint64_t offset;
|
||||
uint64_t length;
|
||||
remap_entry_ctx_t *entries;
|
||||
remap_entry_ctx_t **entries;
|
||||
uint64_t entry_count;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue