Implement XCI logo partition extraction.

Simplify fseek handling with large file support.
This commit is contained in:
hexkyz 2018-05-31 20:54:17 +01:00
parent 9d9b781aa3
commit af428a1bde
5 changed files with 60 additions and 45 deletions

56
main.c
View File

@ -73,6 +73,7 @@ static void usage(void) {
" --updatedir=dir Specify XCI update HFS0 directory path.\n"
" --normaldir=dir Specify XCI normal HFS0 directory path.\n"
" --securedir=dir Specify XCI secure HFS0 directory path.\n"
" --logodir=dir Specify XCI logo HFS0 directory path.\n"
" --outdir=dir Specify XCI directory path. Overrides previous paths, if present.\n"
"Package1 options:\n"
" --package1dir=dir Specify Package1 directory path.\n"
@ -156,18 +157,19 @@ int main(int argc, char **argv) {
{"updatedir", 1, NULL, 23},
{"normaldir", 1, NULL, 24},
{"securedir", 1, NULL, 25},
{"package1dir", 1, NULL, 26},
{"package2dir", 1, NULL, 27},
{"ini1dir", 1, NULL, 28},
{"extractini1", 0, NULL, 29},
{"basefake", 0, NULL, 30},
{"onlyupdated", 0, NULL, 31},
{"sdseed", 1, NULL, 32},
{"sdpath", 1, NULL, 33},
{"sbk", 1, NULL, 34},
{"tseckey", 1, NULL, 35},
{"json", 1, NULL, 36},
{"saveini1json", 0, NULL, 37},
{"logodir", 1, NULL, 26},
{"package1dir", 1, NULL, 27},
{"package2dir", 1, NULL, 28},
{"ini1dir", 1, NULL, 29},
{"extractini1", 0, NULL, 30},
{"basefake", 0, NULL, 31},
{"onlyupdated", 0, NULL, 32},
{"sdseed", 1, NULL, 33},
{"sdpath", 1, NULL, 34},
{"sbk", 1, NULL, 35},
{"tseckey", 1, NULL, 36},
{"json", 1, NULL, 37},
{"saveini1json", 0, NULL, 38},
{NULL, 0, NULL, 0},
};
@ -317,18 +319,21 @@ int main(int argc, char **argv) {
filepath_set(&tool_ctx.settings.secure_dir_path, optarg);
break;
case 26:
filepath_set(&tool_ctx.settings.pk11_dir_path, optarg);
filepath_set(&tool_ctx.settings.logo_dir_path, optarg);
break;
case 27:
filepath_set(&tool_ctx.settings.pk21_dir_path, optarg);
filepath_set(&tool_ctx.settings.pk11_dir_path, optarg);
break;
case 28:
filepath_set(&tool_ctx.settings.ini1_dir_path, optarg);
filepath_set(&tool_ctx.settings.pk21_dir_path, optarg);
break;
case 29:
tool_ctx.action |= ACTION_EXTRACTINI1;
filepath_set(&tool_ctx.settings.ini1_dir_path, optarg);
break;
case 30:
tool_ctx.action |= ACTION_EXTRACTINI1;
break;
case 31:
if (nca_ctx.tool_ctx->base_file != NULL) {
usage();
return EXIT_FAILURE;
@ -336,10 +341,10 @@ int main(int argc, char **argv) {
nca_ctx.tool_ctx->base_file_type = BASEFILE_FAKE;
nca_ctx.tool_ctx->base_file++; /* Guarantees base_file != NULL. I'm so sorry. */
break;
case 31:
case 32:
tool_ctx.action |= ACTION_ONLYUPDATEDROMFS;
break;
case 32:
case 33:
parse_hex_key(nca_ctx.tool_ctx->settings.sdseed, optarg, 16);
nca_ctx.tool_ctx->settings.has_sdseed = 1;
for (unsigned int key = 0; key < 2; key++) {
@ -349,19 +354,19 @@ int main(int argc, char **argv) {
}
pki_derive_keys(&tool_ctx.settings.keyset);
break;
case 33:
case 34:
filepath_set(&tool_ctx.settings.nax0_sd_path, optarg);
break;
case 34:
case 35:
parse_hex_key(nca_ctx.tool_ctx->settings.keygen_sbk, optarg, 16);
break;
case 35:
case 36:
parse_hex_key(nca_ctx.tool_ctx->settings.keygen_tsec, optarg, 16);
break;
case 36:
case 37:
filepath_set(&tool_ctx.settings.npdm_json_path, optarg);
break;
case 37:
case 38:
tool_ctx.action |= ACTION_SAVEINIJSON;
break;
default:
@ -449,14 +454,11 @@ int main(int argc, char **argv) {
printf("Done!\n");
return EXIT_SUCCESS;
}
if ((tool_ctx.file = fopen(input_name, "rb")) == NULL && tool_ctx.file_type != FILETYPE_BOOT0) {
fprintf(stderr, "unable to open %s: %s\n", input_name, strerror(errno));
return EXIT_FAILURE;
}
switch (tool_ctx.file_type) {
case FILETYPE_NCA: {

View File

@ -81,6 +81,7 @@ typedef struct {
filepath_t update_dir_path;
filepath_t normal_dir_path;
filepath_t secure_dir_path;
filepath_t logo_dir_path;
filepath_t header_path;
filepath_t nax0_path;
filepath_t nax0_sd_path;
@ -125,5 +126,4 @@ typedef struct {
uint32_t action;
} hactool_ctx_t;
#endif

11
utils.h
View File

@ -51,16 +51,9 @@ inline int fseeko64(FILE *__stream, long long __off, int __whence)
{
return _fseeki64(__stream, __off, __whence);
}
#elif __APPLE__ || __CYGWIN__
// OS X file I/O is 64bit
#define fseeko64 fseek
#elif __linux__ || __WIN32
extern int fseeko64 (FILE *__stream, _off64_t __off, int __whence);
#else
/* fseeko is guaranteed by POSIX, hopefully the OS made their off_t definition 64-bit;
* known sane on FreeBSD and OpenBSD.
*/
#define fseeko64 fseeko
/* off_t is 64-bit with large file support */
#define fseeko64 fseek
#endif
static inline uint64_t media_to_real(uint64_t media) {

31
xci.c
View File

@ -60,12 +60,12 @@ void xci_process(xci_ctx_t *ctx) {
ctx->partition_ctx.name = "rootpt";
hfs0_process(&ctx->partition_ctx);
if (ctx->partition_ctx.header->num_files != 3) {
if (ctx->partition_ctx.header->num_files > 4) {
fprintf(stderr, "Error: Invalid XCI partition!\n");
exit(EXIT_FAILURE);
}
for (unsigned int i = 0; i < 3; i++) {
for (unsigned int i = 0; i < ctx->partition_ctx.header->num_files; i++) {
hfs0_ctx_t *cur_ctx = NULL;
hfs0_file_entry_t *cur_file = hfs0_get_file_entry(ctx->partition_ctx.header, i);
@ -76,6 +76,8 @@ void xci_process(xci_ctx_t *ctx) {
cur_ctx = &ctx->normal_ctx;
} else if (!strcmp(cur_name, "secure") && ctx->secure_ctx.file == NULL) {
cur_ctx = &ctx->secure_ctx;
} else if (!strcmp(cur_name, "logo") && ctx->logo_ctx.file == NULL) {
cur_ctx = &ctx->logo_ctx;
}
if (cur_ctx == NULL) {
@ -109,7 +111,7 @@ void xci_save(xci_ctx_t *ctx) {
printf("Extracting XCI...\n");
filepath_t *dirpath = &ctx->tool_ctx->settings.out_dir_path.path;
os_makedir(dirpath->os_path);
for (unsigned int i = 0; i < 3; i++) {
for (unsigned int i = 0; i < ctx->partition_ctx.header->num_files; i++) {
hfs0_ctx_t *cur_ctx = NULL;
char *cur_name = hfs0_get_file_name(ctx->partition_ctx.header, i);
@ -119,9 +121,11 @@ void xci_save(xci_ctx_t *ctx) {
cur_ctx = &ctx->normal_ctx;
} else if (!strcmp(cur_name, "secure")) {
cur_ctx = &ctx->secure_ctx;
} else if (!strcmp(cur_name, "logo")) {
cur_ctx = &ctx->logo_ctx;
}
if (cur_ctx == NULL) {
fprintf(stderr, "Unkown XCI partition found in extraction: %s\n", cur_name);
fprintf(stderr, "Unknown XCI partition found in extraction: %s\n", cur_name);
exit(EXIT_FAILURE);
}
filepath_t partition_dirpath;
@ -163,13 +167,22 @@ void xci_save(xci_ctx_t *ctx) {
}
/* Save Secure Partition. */
if (ctx->tool_ctx->settings.secure_dir_path.valid == VALIDITY_VALID) {
printf("Saving Secure Partition...\n");
printf("Saving Secure Partition...\n");
os_makedir(ctx->tool_ctx->settings.secure_dir_path.os_path);
for (uint32_t i = 0; i < ctx->secure_ctx.header->num_files; i++) {
hfs0_save_file(&ctx->secure_ctx, i, &ctx->tool_ctx->settings.secure_dir_path);
}
printf("\n");
}
}
/* Save Logo Partition. */
if (ctx->tool_ctx->settings.logo_dir_path.valid == VALIDITY_VALID) {
printf("Saving Logo Partition...\n");
os_makedir(ctx->tool_ctx->settings.logo_dir_path.os_path);
for (uint32_t i = 0; i < ctx->logo_ctx.header->num_files; i++) {
hfs0_save_file(&ctx->logo_ctx, i, &ctx->tool_ctx->settings.logo_dir_path);
}
printf("\n");
}
}
}
@ -238,4 +251,10 @@ void xci_print(xci_ctx_t *ctx) {
printf("Secure Partition:\n");
xci_print_hfs0(&ctx->secure_ctx);
/* Ensure that Logo partition exists. */
if (ctx->partition_ctx.header->num_files == 4) {
printf("Logo Partition:\n");
xci_print_hfs0(&ctx->logo_ctx);
}
}

5
xci.h
View File

@ -10,11 +10,12 @@
#define MAGIC_HEAD 0x44414548 /* "HEAD" */
typedef enum {
CARTSIZE_1GB = 0xFA,
CARTSIZE_2GB = 0xF8,
CARTSIZE_4GB = 0xF0,
CARTSIZE_8GB = 0xE0,
CARTSIZE_16GB = 0xE1,
/* CARTSIZE_32GB = 0xE2? */
CARTSIZE_32GB = 0xE2
} cartridge_type_t;
typedef struct {
@ -49,6 +50,7 @@ typedef struct {
hfs0_ctx_t normal_ctx;
hfs0_ctx_t update_ctx;
hfs0_ctx_t secure_ctx;
hfs0_ctx_t logo_ctx;
hactool_ctx_t *tool_ctx;
unsigned char iv[0x10];
/* TODO: Header decryption. */
@ -60,5 +62,4 @@ void xci_process(xci_ctx_t *ctx);
void xci_save(xci_ctx_t *ctx);
void xci_print(xci_ctx_t *ctx);
#endif