mirror of
https://github.com/SciresM/hactool
synced 2024-11-22 20:13:08 +00:00
Finish Package2 support, add support for INI1, KIP1 (Closes #4)
This commit is contained in:
parent
9ddd0d070e
commit
3e1fddd9de
10 changed files with 335 additions and 11 deletions
6
Makefile
6
Makefile
|
@ -13,7 +13,7 @@ all:
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
|
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
hactool: sha.o aes.o extkeys.o rsa.o npdm.o bktr.o packages.o pki.o pfs0.o hfs0.o romfs.o utils.o nca.o xci.o main.o filepath.o ConvertUTF.o
|
hactool: sha.o aes.o extkeys.o rsa.o npdm.o bktr.o kip.o packages.o pki.o pfs0.o hfs0.o romfs.o utils.o nca.o xci.o main.o filepath.o ConvertUTF.o
|
||||||
$(CC) -o $@ $^ $(LDFLAGS) -L $(LIBDIR)
|
$(CC) -o $@ $^ $(LDFLAGS) -L $(LIBDIR)
|
||||||
|
|
||||||
aes.o: aes.h types.h
|
aes.o: aes.h types.h
|
||||||
|
@ -26,9 +26,11 @@ filepath.o: filepath.c types.h
|
||||||
|
|
||||||
hfs0.o: hfs0.h types.h
|
hfs0.o: hfs0.h types.h
|
||||||
|
|
||||||
|
kip.o: kip.h types.h
|
||||||
|
|
||||||
main.o: main.c pki.h types.h
|
main.o: main.c pki.h types.h
|
||||||
|
|
||||||
packages.o: packages.h aes.h types.h
|
packages.o: packages.h aes.h kip.h types.h
|
||||||
|
|
||||||
pfs0.o: pfs0.h types.h
|
pfs0.o: pfs0.h types.h
|
||||||
|
|
||||||
|
|
146
kip.c
Normal file
146
kip.c
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "kip.h"
|
||||||
|
#include "npdm.h"
|
||||||
|
|
||||||
|
void ini1_process(ini1_ctx_t *ctx) {
|
||||||
|
/* Read *just* safe amount. */
|
||||||
|
ini1_header_t raw_header;
|
||||||
|
fseeko64(ctx->file, 0, SEEK_SET);
|
||||||
|
if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) {
|
||||||
|
fprintf(stderr, "Failed to read INI1 header!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw_header.magic != MAGIC_INI1 || raw_header.num_processes > INI1_MAX_KIPS) {
|
||||||
|
printf("Error: INI1 is corrupt!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->header = malloc(raw_header.size);
|
||||||
|
if (ctx->header == NULL) {
|
||||||
|
fprintf(stderr, "Failed to allocate INI1 header!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fseeko64(ctx->file, 0, SEEK_SET);
|
||||||
|
if (fread(ctx->header, 1, raw_header.size, ctx->file) != raw_header.size) {
|
||||||
|
fprintf(stderr, "Failed to read INI1!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t offset = 0;
|
||||||
|
for (unsigned int i = 0; i < ctx->header->num_processes; i++) {
|
||||||
|
ctx->kips[i].tool_ctx = ctx->tool_ctx;
|
||||||
|
ctx->kips[i].header = (kip1_header_t *)&ctx->header->kip_data[offset];
|
||||||
|
if (ctx->kips[i].header->magic != MAGIC_KIP1) {
|
||||||
|
fprintf(stderr, "INI1 is corrupted!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
offset += kip1_get_size(&ctx->kips[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->tool_ctx->action & ACTION_INFO) {
|
||||||
|
ini1_print(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
|
||||||
|
ini1_save(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ini1_print(ini1_ctx_t *ctx) {
|
||||||
|
printf("INI1:\n");
|
||||||
|
printf(" Number of Processes: %02"PRIx32"\n", ctx->header->num_processes);
|
||||||
|
printf(" Size: %08"PRIx32"\n", ctx->header->size);
|
||||||
|
printf("\n");
|
||||||
|
for (unsigned int i = 0; i < ctx->header->num_processes; i++) {
|
||||||
|
printf("Process %02"PRIx32":\n", i);
|
||||||
|
kip1_print(&ctx->kips[i], 1);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ini1_save(ini1_ctx_t *ctx) {
|
||||||
|
filepath_t *dirpath;
|
||||||
|
if (ctx->tool_ctx->file_type == FILETYPE_INI1 && ctx->tool_ctx->settings.out_dir_path.enabled) {
|
||||||
|
dirpath = &ctx->tool_ctx->settings.out_dir_path.path;
|
||||||
|
}
|
||||||
|
if (dirpath == NULL || dirpath->valid != VALIDITY_VALID) {
|
||||||
|
dirpath = &ctx->tool_ctx->settings.ini1_dir_path;
|
||||||
|
}
|
||||||
|
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
||||||
|
os_makedir(dirpath->os_path);
|
||||||
|
for (unsigned int i = 0; i < ctx->header->num_processes; i++) {
|
||||||
|
char padded_name[0x20];
|
||||||
|
memset(&padded_name, 0, sizeof(padded_name));
|
||||||
|
memcpy(&padded_name, ctx->kips[i].header->name, sizeof(ctx->kips[i].header->name));
|
||||||
|
strcat(padded_name, ".kip1");
|
||||||
|
printf("Saving %s to %s/%s...\n", padded_name, dirpath->char_path, padded_name);
|
||||||
|
save_buffer_to_directory_file(ctx->kips[i].header, kip1_get_size(&ctx->kips[i]), dirpath, padded_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kip1_process(kip1_ctx_t *ctx) {
|
||||||
|
/* Read *just* safe amount. */
|
||||||
|
kip1_header_t raw_header;
|
||||||
|
fseeko64(ctx->file, 0, SEEK_SET);
|
||||||
|
if (fread(&raw_header, 1, sizeof(raw_header), ctx->file) != sizeof(raw_header)) {
|
||||||
|
fprintf(stderr, "Failed to read KIP1 header!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw_header.magic != MAGIC_KIP1) {
|
||||||
|
printf("Error: KIP1 is corrupt!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t size = kip1_get_size_from_header(&raw_header);
|
||||||
|
ctx->header = malloc(size);
|
||||||
|
if (ctx->header == NULL) {
|
||||||
|
fprintf(stderr, "Failed to allocate KIP1 header!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fseeko64(ctx->file, 0, SEEK_SET);
|
||||||
|
if (fread(ctx->header, 1, size, ctx->file) != size) {
|
||||||
|
fprintf(stderr, "Failed to read KIP1!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->tool_ctx->action & ACTION_INFO) {
|
||||||
|
kip1_print(ctx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->tool_ctx->action & ACTION_EXTRACT) {
|
||||||
|
kip1_save(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kip1_print(kip1_ctx_t *ctx, int suppress) {
|
||||||
|
if (!suppress) printf("KIP1:\n");
|
||||||
|
printf(" Title ID: %016"PRIx64"\n", ctx->header->title_id);
|
||||||
|
char padded_name[13];
|
||||||
|
memset(&padded_name, 0, sizeof(padded_name));
|
||||||
|
memcpy(&padded_name, ctx->header->name, sizeof(ctx->header->name));
|
||||||
|
printf(" Name: %s\n", padded_name);
|
||||||
|
printf(" Process Category: %s\n", npdm_get_proc_category(ctx->header->process_category));
|
||||||
|
printf(" Main Thread Priority: %"PRId8"\n", ctx->header->main_thread_priority);
|
||||||
|
printf(" Default CPU Core: %"PRId8"\n", ctx->header->default_core);
|
||||||
|
printf(" Is 64 Bit: %s\n", (ctx->header->flags & (1 << 3)) ? "True" : "False");
|
||||||
|
printf(" Is Address Space 64 Bit: %s\n", (ctx->header->flags & (1 << 4)) ? "True" : "False");
|
||||||
|
printf(" Sections:\n");
|
||||||
|
printf(" .text: %08"PRIx32"-%08"PRIx32"\n", ctx->header->section_headers[0].out_offset, ctx->header->section_headers[0].out_offset + align(ctx->header->section_headers[0].out_size, 0x1000));
|
||||||
|
printf(" .rodata: %08"PRIx32"-%08"PRIx32"\n", ctx->header->section_headers[1].out_offset, ctx->header->section_headers[1].out_offset + align(ctx->header->section_headers[1].out_size, 0x1000));
|
||||||
|
printf(" .rwdata: %08"PRIx32"-%08"PRIx32"\n", ctx->header->section_headers[2].out_offset, ctx->header->section_headers[2].out_offset + align(ctx->header->section_headers[2].out_size, 0x1000));
|
||||||
|
printf(" .bss: %08"PRIx32"-%08"PRIx32"\n", ctx->header->section_headers[3].out_offset, ctx->header->section_headers[3].out_offset + align(ctx->header->section_headers[3].out_size, 0x1000));
|
||||||
|
printf(" Kernel Access Control:\n");
|
||||||
|
kac_print(ctx->header->capabilities, 0x20);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void kip1_save(kip1_ctx_t *ctx) {
|
||||||
|
/* Do nothing. */
|
||||||
|
}
|
72
kip.h
Normal file
72
kip.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
#ifndef HACTOOL_KIP_H
|
||||||
|
#define HACTOOL_KIP_H
|
||||||
|
#include "types.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#define MAGIC_INI1 0x31494E49
|
||||||
|
#define MAGIC_KIP1 0x3150494B
|
||||||
|
#define INI1_MAX_KIPS 0x50
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t magic;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t num_processes;
|
||||||
|
uint32_t _0xC;
|
||||||
|
char kip_data[];
|
||||||
|
} ini1_header_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t out_offset;
|
||||||
|
uint32_t out_size;
|
||||||
|
uint32_t compressed_size;
|
||||||
|
uint32_t attribute;
|
||||||
|
} kip_section_header_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t magic;
|
||||||
|
char name[0xC];
|
||||||
|
uint64_t title_id;
|
||||||
|
uint32_t process_category;
|
||||||
|
uint8_t main_thread_priority;
|
||||||
|
uint8_t default_core;
|
||||||
|
uint8_t _0x1E;
|
||||||
|
uint8_t flags;
|
||||||
|
kip_section_header_t section_headers[6];
|
||||||
|
uint32_t capabilities[0x20];
|
||||||
|
unsigned char data[];
|
||||||
|
} kip1_header_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FILE *file;
|
||||||
|
hactool_ctx_t *tool_ctx;
|
||||||
|
kip1_header_t *header;
|
||||||
|
} kip1_ctx_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FILE *file;
|
||||||
|
hactool_ctx_t *tool_ctx;
|
||||||
|
ini1_header_t *header;
|
||||||
|
kip1_ctx_t kips[INI1_MAX_KIPS];
|
||||||
|
} ini1_ctx_t;
|
||||||
|
|
||||||
|
void ini1_process(ini1_ctx_t *ctx);
|
||||||
|
void ini1_print(ini1_ctx_t *ctx);
|
||||||
|
void ini1_save(ini1_ctx_t *ctx);
|
||||||
|
|
||||||
|
void kip1_process(kip1_ctx_t *ctx);
|
||||||
|
void kip1_print(kip1_ctx_t *ctx, int suppress);
|
||||||
|
void kip1_save(kip1_ctx_t *ctx);
|
||||||
|
|
||||||
|
static inline uint64_t kip1_get_size(kip1_ctx_t *ctx) {
|
||||||
|
/* Header + .text + .rodata + .rwdata */
|
||||||
|
return 0x100 + ctx->header->section_headers[0].compressed_size + ctx->header->section_headers[1].compressed_size + ctx->header->section_headers[2].compressed_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t kip1_get_size_from_header(kip1_header_t *header) {
|
||||||
|
/* Header + .text + .rodata + .rwdata */
|
||||||
|
return 0x100 + header->section_headers[0].compressed_size + header->section_headers[1].compressed_size + header->section_headers[2].compressed_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
46
main.c
46
main.c
|
@ -30,7 +30,7 @@ static void usage(void) {
|
||||||
" -y, --verify Verify hashes and signatures.\n"
|
" -y, --verify Verify hashes and signatures.\n"
|
||||||
" -d, --dev Decrypt with development keys instead of retail.\n"
|
" -d, --dev Decrypt with development keys instead of retail.\n"
|
||||||
" -k, --keyset Load keys from an external file.\n"
|
" -k, --keyset Load keys from an external file.\n"
|
||||||
" -t, --intype=type Specify input file type [nca, xci, pfs0, romfs, hfs0, npdm, pk11]\n"
|
" -t, --intype=type Specify input file type [nca, xci, pfs0, romfs, hfs0, npdm, pk11, pk21, ini1, kip1]\n"
|
||||||
" --titlekey=key Set title key for Rights ID crypto titles.\n"
|
" --titlekey=key Set title key for Rights ID crypto titles.\n"
|
||||||
" --contentkey=key Set raw key for NCA body decryption.\n"
|
" --contentkey=key Set raw key for NCA body decryption.\n"
|
||||||
"NCA options:\n"
|
"NCA options:\n"
|
||||||
|
@ -72,6 +72,12 @@ static void usage(void) {
|
||||||
"Package1 options:\n"
|
"Package1 options:\n"
|
||||||
" --package1dir=dir Specify Package1 directory path.\n"
|
" --package1dir=dir Specify Package1 directory path.\n"
|
||||||
" --outdir=dir Specify Package1 directory path. Overrides previous path, if present.\n"
|
" --outdir=dir Specify Package1 directory path. Overrides previous path, if present.\n"
|
||||||
|
"Package2 options:\n"
|
||||||
|
" --package2dir=dir Specify Package1 directory path.\n"
|
||||||
|
" --outdir=dir Specify Package1 directory path. Overrides previous path, if present.\n"
|
||||||
|
"INI1 options:\n"
|
||||||
|
" --ini1dir=dir Specify Package1 directory path.\n"
|
||||||
|
" --outdir=dir Specify Package1 directory path. Overrides previous path, if present.\n"
|
||||||
"\n", __TIME__, __DATE__, prog_name);
|
"\n", __TIME__, __DATE__, prog_name);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -137,6 +143,9 @@ int main(int argc, char **argv) {
|
||||||
{"normaldir", 1, NULL, 24},
|
{"normaldir", 1, NULL, 24},
|
||||||
{"securedir", 1, NULL, 25},
|
{"securedir", 1, NULL, 25},
|
||||||
{"package1dir", 1, NULL, 26},
|
{"package1dir", 1, NULL, 26},
|
||||||
|
{"package2dir", 1, NULL, 27},
|
||||||
|
{"ini1dir", 1, NULL, 28},
|
||||||
|
{"extractini1", 0, NULL, 29},
|
||||||
{NULL, 0, NULL, 0},
|
{NULL, 0, NULL, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -182,6 +191,10 @@ int main(int argc, char **argv) {
|
||||||
nca_ctx.tool_ctx->file_type = FILETYPE_PACKAGE1;
|
nca_ctx.tool_ctx->file_type = FILETYPE_PACKAGE1;
|
||||||
} else if (!strcmp(optarg, "package2") || !strcmp(optarg, "pk21")) {
|
} else if (!strcmp(optarg, "package2") || !strcmp(optarg, "pk21")) {
|
||||||
nca_ctx.tool_ctx->file_type = FILETYPE_PACKAGE2;
|
nca_ctx.tool_ctx->file_type = FILETYPE_PACKAGE2;
|
||||||
|
} else if (!strcmp(optarg, "ini1")) {
|
||||||
|
nca_ctx.tool_ctx->file_type = FILETYPE_INI1;
|
||||||
|
} else if (!strcmp(optarg, "kip1") || !strcmp(optarg, "kip")) {
|
||||||
|
nca_ctx.tool_ctx->file_type = FILETYPE_KIP1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0: filepath_set(&nca_ctx.tool_ctx->settings.section_paths[0], optarg); break;
|
case 0: filepath_set(&nca_ctx.tool_ctx->settings.section_paths[0], optarg); break;
|
||||||
|
@ -280,6 +293,15 @@ int main(int argc, char **argv) {
|
||||||
case 26:
|
case 26:
|
||||||
filepath_set(&tool_ctx.settings.pk11_dir_path, optarg);
|
filepath_set(&tool_ctx.settings.pk11_dir_path, optarg);
|
||||||
break;
|
break;
|
||||||
|
case 27:
|
||||||
|
filepath_set(&tool_ctx.settings.pk21_dir_path, optarg);
|
||||||
|
break;
|
||||||
|
case 28:
|
||||||
|
filepath_set(&tool_ctx.settings.ini1_dir_path, optarg);
|
||||||
|
break;
|
||||||
|
case 29:
|
||||||
|
tool_ctx.action |= ACTION_EXTRACTINI1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -445,6 +467,28 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case FILETYPE_INI1: {
|
||||||
|
ini1_ctx_t ini1_ctx;
|
||||||
|
memset(&ini1_ctx, 0, sizeof(ini1_ctx));
|
||||||
|
ini1_ctx.file = tool_ctx.file;
|
||||||
|
ini1_ctx.tool_ctx = &tool_ctx;
|
||||||
|
ini1_process(&ini1_ctx);
|
||||||
|
if (ini1_ctx.header) {
|
||||||
|
free(ini1_ctx.header);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FILETYPE_KIP1: {
|
||||||
|
kip1_ctx_t kip1_ctx;
|
||||||
|
memset(&kip1_ctx, 0, sizeof(kip1_ctx));
|
||||||
|
kip1_ctx.file = tool_ctx.file;
|
||||||
|
kip1_ctx.tool_ctx = &tool_ctx;
|
||||||
|
kip1_process(&kip1_ctx);
|
||||||
|
if (kip1_ctx.header) {
|
||||||
|
free(kip1_ctx.header);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case FILETYPE_XCI: {
|
case FILETYPE_XCI: {
|
||||||
xci_ctx_t xci_ctx;
|
xci_ctx_t xci_ctx;
|
||||||
memset(&xci_ctx, 0, sizeof(xci_ctx));
|
memset(&xci_ctx, 0, sizeof(xci_ctx));
|
||||||
|
|
2
nca.c
2
nca.c
|
@ -625,7 +625,7 @@ void nca_print_sections(nca_ctx_t *ctx) {
|
||||||
/* Print out information about the NCA. */
|
/* Print out information about the NCA. */
|
||||||
void nca_print(nca_ctx_t *ctx) {
|
void nca_print(nca_ctx_t *ctx) {
|
||||||
printf("\nNCA:\n");
|
printf("\nNCA:\n");
|
||||||
print_magic("Magic: ", ctx->header.magic);
|
print_magic("Magic: ", ctx->header.magic);
|
||||||
|
|
||||||
if (ctx->tool_ctx->action & ACTION_VERIFY && ctx->fixed_sig_validity != VALIDITY_UNCHECKED) {
|
if (ctx->tool_ctx->action & ACTION_VERIFY && ctx->fixed_sig_validity != VALIDITY_UNCHECKED) {
|
||||||
if (ctx->fixed_sig_validity == VALIDITY_VALID) {
|
if (ctx->fixed_sig_validity == VALIDITY_VALID) {
|
||||||
|
|
4
npdm.c
4
npdm.c
|
@ -212,8 +212,8 @@ const fs_perm_t fs_permissions_bool[MAX_FS_PERM_BOOL] = {
|
||||||
{"Unknown (0x1A)", 0x8000000000004020}
|
{"Unknown (0x1A)", 0x8000000000004020}
|
||||||
};
|
};
|
||||||
|
|
||||||
char *npdm_get_proc_category(npdm_t *npdm) {
|
char *npdm_get_proc_category(int process_category) {
|
||||||
switch (npdm->process_category) {
|
switch (process_category) {
|
||||||
case 0:
|
case 0:
|
||||||
return "Regular Title";
|
return "Regular Title";
|
||||||
case 1:
|
case 1:
|
||||||
|
|
3
npdm.h
3
npdm.h
|
@ -134,4 +134,7 @@ static inline npdm_aci0_t *npdm_get_aci0(npdm_t *npdm) {
|
||||||
|
|
||||||
void npdm_print(npdm_t *npdm, hactool_ctx_t *tool_ctx);
|
void npdm_print(npdm_t *npdm, hactool_ctx_t *tool_ctx);
|
||||||
|
|
||||||
|
char *npdm_get_proc_category(int process_category);
|
||||||
|
void kac_print(uint32_t *descriptors, uint32_t num_descriptors);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
58
packages.c
58
packages.c
|
@ -194,7 +194,20 @@ void pk21_process(pk21_ctx_t *ctx) {
|
||||||
offset += ctx->header.section_sizes[i];
|
offset += ctx->header.section_sizes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Parse INI1 */
|
ctx->ini1_ctx.tool_ctx = ctx->tool_ctx;
|
||||||
|
ctx->ini1_ctx.header = (ini1_header_t *)(ctx->sections + ctx->header.section_sizes[0]);
|
||||||
|
if (ctx->ini1_ctx.header->magic == MAGIC_INI1 && ctx->ini1_ctx.header->num_processes <= INI1_MAX_KIPS) {
|
||||||
|
offset = 0;
|
||||||
|
for (unsigned int i = 0; i < ctx->ini1_ctx.header->num_processes; i++) {
|
||||||
|
ctx->ini1_ctx.kips[i].tool_ctx = ctx->tool_ctx;
|
||||||
|
ctx->ini1_ctx.kips[i].header = (kip1_header_t *)&ctx->ini1_ctx.header->kip_data[offset];
|
||||||
|
if (ctx->ini1_ctx.kips[i].header->magic != MAGIC_KIP1) {
|
||||||
|
fprintf(stderr, "INI1 is corrupted!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
offset += kip1_get_size(&ctx->ini1_ctx.kips[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->tool_ctx->action & ACTION_INFO) {
|
if (ctx->tool_ctx->action & ACTION_INFO) {
|
||||||
pk21_print(ctx);
|
pk21_print(ctx);
|
||||||
|
@ -244,12 +257,49 @@ void pk21_print(pk21_ctx_t *ctx) {
|
||||||
printf(" Load Address: %08"PRIx32"\n", ctx->header.section_offsets[i] + 0x80000000);
|
printf(" Load Address: %08"PRIx32"\n", ctx->header.section_offsets[i] + 0x80000000);
|
||||||
printf(" Size: %08"PRIx32"\n", ctx->header.section_sizes[i]);
|
printf(" Size: %08"PRIx32"\n", ctx->header.section_sizes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
ini1_print(&ctx->ini1_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pk21_save(pk21_ctx_t *ctx) {
|
void pk21_save(pk21_ctx_t *ctx) {
|
||||||
printf("Saving PK21 currently not implemented.\n");
|
/* Extract to directory. */
|
||||||
/* TODO: Save sections + extract INI1 */
|
filepath_t *dirpath = NULL;
|
||||||
|
if (ctx->tool_ctx->file_type == FILETYPE_PACKAGE2 && ctx->tool_ctx->settings.out_dir_path.enabled) {
|
||||||
|
dirpath = &ctx->tool_ctx->settings.out_dir_path.path;
|
||||||
|
}
|
||||||
|
if (dirpath == NULL || dirpath->valid != VALIDITY_VALID) {
|
||||||
|
dirpath = &ctx->tool_ctx->settings.pk21_dir_path;
|
||||||
|
}
|
||||||
|
if (dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
||||||
|
os_makedir(dirpath->os_path);
|
||||||
|
|
||||||
|
/* Save Decrypted.bin */
|
||||||
|
printf("Saving decrypted binary to %s/Decrypted.bin\n", dirpath->char_path);
|
||||||
|
char *decrypted_bin = malloc(ctx->package_size);
|
||||||
|
if (decrypted_bin == NULL) {
|
||||||
|
fprintf(stderr, "Failed to allocate buffer!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
memcpy(decrypted_bin, &ctx->header, 0x200);
|
||||||
|
memcpy(decrypted_bin + sizeof(ctx->header), ctx->sections, ctx->package_size - 0x200);
|
||||||
|
save_buffer_to_directory_file(decrypted_bin, ctx->package_size, dirpath, "Decrypted.bin");
|
||||||
|
free(decrypted_bin);
|
||||||
|
|
||||||
|
/* Save Kernel.bin */
|
||||||
|
printf("Saving Kernel.bin to %s/Kernel.bin...\n", dirpath->char_path);
|
||||||
|
save_buffer_to_directory_file(ctx->sections, ctx->header.section_sizes[0], dirpath, "Kernel.bin");
|
||||||
|
|
||||||
|
/* Save INI1.bin */
|
||||||
|
printf("Saving INI1.bin to %s/INI1.bin...\n", dirpath->char_path);
|
||||||
|
save_buffer_to_directory_file(ctx->sections + ctx->header.section_sizes[0], ctx->header.section_sizes[1], dirpath, "INI1.bin");
|
||||||
|
}
|
||||||
|
if (ctx->ini1_ctx.header != NULL && (ctx->tool_ctx->action & ACTION_EXTRACTINI1 || ctx->tool_ctx->settings.ini1_dir_path.valid == VALIDITY_VALID)) {
|
||||||
|
filepath_t *ini1_dirpath = &ctx->tool_ctx->settings.ini1_dir_path;
|
||||||
|
if (ini1_dirpath->valid != VALIDITY_VALID && dirpath != NULL && dirpath->valid == VALIDITY_VALID) {
|
||||||
|
filepath_copy(ini1_dirpath, dirpath);
|
||||||
|
filepath_append(ini1_dirpath, "INI1");
|
||||||
|
}
|
||||||
|
ini1_save(&ctx->ini1_ctx);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -4,6 +4,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "kip.h"
|
||||||
|
|
||||||
#define MAGIC_PK11 0x31314B50
|
#define MAGIC_PK11 0x31314B50
|
||||||
#define MAGIC_PK21 0x31324B50
|
#define MAGIC_PK21 0x31324B50
|
||||||
|
@ -87,6 +88,7 @@ typedef struct {
|
||||||
validity_t section_validities[4];
|
validity_t section_validities[4];
|
||||||
unsigned char *sections;
|
unsigned char *sections;
|
||||||
pk21_header_t header;
|
pk21_header_t header;
|
||||||
|
ini1_ctx_t ini1_ctx;
|
||||||
} pk21_ctx_t;
|
} pk21_ctx_t;
|
||||||
|
|
||||||
void pk21_process(pk21_ctx_t *ctx);
|
void pk21_process(pk21_ctx_t *ctx);
|
||||||
|
|
|
@ -57,6 +57,8 @@ typedef struct {
|
||||||
filepath_t pfs0_dir_path;
|
filepath_t pfs0_dir_path;
|
||||||
filepath_t hfs0_dir_path;
|
filepath_t hfs0_dir_path;
|
||||||
filepath_t pk11_dir_path;
|
filepath_t pk11_dir_path;
|
||||||
|
filepath_t pk21_dir_path;
|
||||||
|
filepath_t ini1_dir_path;
|
||||||
filepath_t dec_nca_path;
|
filepath_t dec_nca_path;
|
||||||
filepath_t rootpt_dir_path;
|
filepath_t rootpt_dir_path;
|
||||||
filepath_t update_dir_path;
|
filepath_t update_dir_path;
|
||||||
|
@ -74,7 +76,9 @@ enum hactool_file_type
|
||||||
FILETYPE_XCI,
|
FILETYPE_XCI,
|
||||||
FILETYPE_NPDM,
|
FILETYPE_NPDM,
|
||||||
FILETYPE_PACKAGE1,
|
FILETYPE_PACKAGE1,
|
||||||
FILETYPE_PACKAGE2
|
FILETYPE_PACKAGE2,
|
||||||
|
FILETYPE_INI1,
|
||||||
|
FILETYPE_KIP1
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ACTION_INFO (1<<0)
|
#define ACTION_INFO (1<<0)
|
||||||
|
@ -83,6 +87,7 @@ enum hactool_file_type
|
||||||
#define ACTION_RAW (1<<3)
|
#define ACTION_RAW (1<<3)
|
||||||
#define ACTION_LISTROMFS (1<<4)
|
#define ACTION_LISTROMFS (1<<4)
|
||||||
#define ACTION_DEV (1<<5)
|
#define ACTION_DEV (1<<5)
|
||||||
|
#define ACTION_EXTRACTINI1 (1<<6)
|
||||||
|
|
||||||
struct nca_ctx; /* This will get re-defined by nca.h. */
|
struct nca_ctx; /* This will get re-defined by nca.h. */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue