mirror of
https://github.com/SciresM/hactool.git
synced 2024-11-23 12:39:45 +00:00
Implement XCI logo partition extraction.
Simplify fseek handling with large file support.
This commit is contained in:
parent
9d9b781aa3
commit
af428a1bde
56
main.c
56
main.c
@ -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: {
|
||||
|
@ -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
11
utils.h
@ -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
31
xci.c
@ -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
5
xci.h
@ -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
|
Loading…
Reference in New Issue
Block a user