Add JSON output for KIP1/INI, fix encrypted package2 input

This commit is contained in:
Michael Scire 2018-05-02 22:09:11 -06:00
parent cdbcdf0d4a
commit d2d9146f68
7 changed files with 89 additions and 9 deletions

60
kip.c
View file

@ -2,6 +2,7 @@
#include <stdio.h>
#include "kip.h"
#include "npdm.h"
#include "cJSON.h"
void ini1_process(ini1_ctx_t *ctx) {
/* Read *just* safe amount. */
@ -79,10 +80,55 @@ void ini1_save(ini1_ctx_t *ctx) {
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);
if (ctx->tool_ctx->action & ACTION_SAVEINIJSON) {
printf("SAVING INI JSON!\n");
memset(&padded_name, 0, sizeof(padded_name));
memcpy(&padded_name, ctx->kips[i].header->name, sizeof(ctx->kips[i].header->name));
strcat(padded_name, ".json");
filepath_t json_path;
filepath_init(&json_path);
filepath_copy(&json_path, dirpath);
filepath_append(&json_path, padded_name);
FILE *f_json = os_fopen(json_path.os_path, OS_MODE_WRITE);
if (f_json == NULL) {
fprintf(stderr, "Failed to open %s!\n", json_path.char_path);
return;
}
const char *json = kip1_get_json(&ctx->kips[i]);
if (fwrite(json, 1, strlen(json), f_json) != strlen(json)) {
fprintf(stderr, "Failed to write JSON file!\n");
exit(EXIT_FAILURE);
}
fclose(f_json);
}
}
}
}
const char *kip1_get_json(kip1_ctx_t *ctx) {
cJSON *kip_json = cJSON_CreateObject();
const char *output_str = NULL;
char work_buffer[0x300] = {0};
/* Add KIP1 header fields. */
strcpy(work_buffer, ctx->header->name);
cJSON_AddStringToObject(kip_json, "name", work_buffer);
cJSON_AddU64ToObject(kip_json, "title_id", ctx->header->title_id);
cJSON_AddU32ToObject(kip_json, "main_thread_stack_size", ctx->header->section_headers[1].attribute);
cJSON_AddNumberToObject(kip_json, "main_thread_priority", ctx->header->main_thread_priority);
cJSON_AddNumberToObject(kip_json, "default_cpu_id", ctx->header->default_core);
cJSON_AddNumberToObject(kip_json, "process_category", ctx->header->process_category);
/* Add KAC. */
cJSON *kac_json = kac_get_json(ctx->header->capabilities, sizeof(ctx->header->capabilities) / sizeof(uint32_t));
cJSON_AddItemToObject(kip_json, "kernel_capabilities", kac_json);
output_str = cJSON_Print(kip_json);
cJSON_Delete(kip_json);
return output_str;
}
void kip1_process(kip1_ctx_t *ctx) {
/* Read *just* safe amount. */
kip1_header_t raw_header;
@ -143,4 +189,18 @@ void kip1_print(kip1_ctx_t *ctx, int suppress) {
void kip1_save(kip1_ctx_t *ctx) {
/* Do nothing. */
filepath_t *json_path = &ctx->tool_ctx->settings.npdm_json_path;
if (ctx->tool_ctx->file_type == FILETYPE_KIP1 && json_path->valid == VALIDITY_VALID) {
FILE *f_json = os_fopen(json_path->os_path, OS_MODE_WRITE);
if (f_json == NULL) {
fprintf(stderr, "Failed to open %s!\n", json_path->char_path);
return;
}
const char *json = kip1_get_json(ctx);
if (fwrite(json, 1, strlen(json), f_json) != strlen(json)) {
fprintf(stderr, "Failed to write JSON file!\n");
exit(EXIT_FAILURE);
}
fclose(f_json);
}
}

1
kip.h
View file

@ -54,6 +54,7 @@ void ini1_process(ini1_ctx_t *ctx);
void ini1_print(ini1_ctx_t *ctx);
void ini1_save(ini1_ctx_t *ctx);
const char *kip1_get_json(kip1_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);

9
main.c
View file

@ -54,8 +54,8 @@ static void usage(void) {
" --basenca Set Base NCA to use with update partitions.\n"
" --basefake Use a fake Base RomFS with update partitions (all reads will return 0xCC).\n"
" --onlyupdated Ignore non-updated files in update partitions.\n"
"NPDM options:\n"
" --json=file Specify file path for saving JSON representation of NPDM to.\n"
"NPDM/KIP1 options:\n"
" --json=file Specify file path for saving JSON representation of program permissions to.\n"
"PFS0 options:\n"
" --pfs0dir=dir Specify PFS0 directory path.\n"
" --outdir=dir Specify PFS0 directory path. Overrides previous path, if present.\n"
@ -85,6 +85,7 @@ static void usage(void) {
"INI1 options:\n"
" --ini1dir=dir Specify INI1 directory path.\n"
" --outdir=dir Specify INI1 directory path. Overrides previous path, if present.\n"
" --saveini1json Enable generation of JSON descriptors for all INI1 members.\n"
"NAX0 options:\n"
" --sdseed=seed Set console unique seed for SD card NAX0 encryption.\n"
" --sdpath=path Set relative path for NAX0 key derivation (ex: /registered/000000FF/cafebabecafebabecafebabecafebabe.nca).\n"
@ -166,6 +167,7 @@ int main(int argc, char **argv) {
{"sbk", 1, NULL, 34},
{"tseckey", 1, NULL, 35},
{"json", 1, NULL, 36},
{"saveini1json", 0, NULL, 37},
{NULL, 0, NULL, 0},
};
@ -359,6 +361,9 @@ int main(int argc, char **argv) {
case 36:
filepath_set(&tool_ctx.settings.npdm_json_path, optarg);
break;
case 37:
tool_ctx.action |= ACTION_SAVEINIJSON;
break;
default:
usage();
return EXIT_FAILURE;

16
npdm.c
View file

@ -677,21 +677,27 @@ void npdm_save(npdm_t *npdm, hactool_ctx_t *tool_ctx) {
}
}
void cJSON_AddU8ToObject(cJSON *obj, char *name, unsigned int val) {
void cJSON_AddU8ToObject(cJSON *obj, char *name, uint8_t val) {
char buf[0x20] = {0};
snprintf(buf, sizeof(buf), "0x%02x", val);
snprintf(buf, sizeof(buf), "0x%02"PRIx8, val);
cJSON_AddStringToObject(obj, name, buf);
}
void cJSON_AddU16ToObject(cJSON *obj, char *name, uint16_t val) {
char buf[0x20] = {0};
snprintf(buf, sizeof(buf), "0x%04x", val & 0xFFFF);
snprintf(buf, sizeof(buf), "0x%04"PRIx16, val & 0xFFFF);
cJSON_AddStringToObject(obj, name, buf);
}
void cJSON_AddU32ToObject(cJSON *obj, char *name, uint32_t val) {
char buf[0x20] = {0};
snprintf(buf, sizeof(buf), "0x%08"PRIx16, val);
cJSON_AddStringToObject(obj, name, buf);
}
void cJSON_AddU64ToObject(cJSON *obj, char *name, uint64_t val) {
char buf[0x20] = {0};
snprintf(buf, sizeof(buf), "0x%016llx", val);
snprintf(buf, sizeof(buf), "0x%016"PRIx64, val);
cJSON_AddStringToObject(obj, name, buf);
}
@ -835,7 +841,7 @@ const char *npdm_get_json(npdm_t *npdm) {
cJSON_AddU64ToObject(npdm_json, "title_id", aci0->title_id);
cJSON_AddU64ToObject(npdm_json, "title_id_range_min", acid->title_id_range_min);
cJSON_AddU64ToObject(npdm_json, "title_id_range_max", acid->title_id_range_max);
cJSON_AddU64ToObject(npdm_json, "main_thread_stack_size", npdm->main_stack_size);
cJSON_AddU32ToObject(npdm_json, "main_thread_stack_size", npdm->main_stack_size);
cJSON_AddNumberToObject(npdm_json, "main_thread_priority", npdm->main_thread_prio);
cJSON_AddNumberToObject(npdm_json, "default_cpu_id", npdm->default_cpuid);
cJSON_AddNumberToObject(npdm_json, "process_category", npdm->process_category);

8
npdm.h
View file

@ -4,6 +4,7 @@
#include "types.h"
#include "utils.h"
#include "settings.h"
#include "cJSON.h"
#define MAGIC_META 0x4154454D
#define MAGIC_ACID 0x44494341
@ -140,4 +141,11 @@ char *npdm_get_proc_category(int process_category);
void kac_print(uint32_t *descriptors, uint32_t num_descriptors);
const char *npdm_get_json(npdm_t *npdm);
void cJSON_AddU8ToObject(cJSON *obj, char *name, uint8_t val);
void cJSON_AddU16ToObject(cJSON *obj, char *name, uint16_t val);
void cJSON_AddU32ToObject(cJSON *obj, char *name, uint32_t val);
void cJSON_AddU64ToObject(cJSON *obj, char *name, uint64_t val);
cJSON *kac_get_json(uint32_t *descriptors, uint32_t num_descriptors);
#endif

View file

@ -132,7 +132,7 @@ void pk21_process(pk21_ctx_t *ctx) {
is_encrypted = true;
}
}
is_encrypted &= ctx->header.magic == MAGIC_PK21;
is_encrypted &= ctx->header.magic != MAGIC_PK21;
if (is_encrypted) {
if (rsa2048_pss_verify(&ctx->header.ctr, 0x100, ctx->header.signature, ctx->tool_ctx->settings.keyset.package2_fixed_key_modulus)) {
@ -178,7 +178,6 @@ void pk21_process(pk21_ctx_t *ctx) {
exit(EXIT_FAILURE);
}
}
if (ctx->package_size != 0x200 + ctx->header.section_sizes[0] + ctx->header.section_sizes[1] + ctx->header.section_sizes[2]) {
fprintf(stderr, "Error: Package2 Header is corrupt!\n");

View file

@ -111,6 +111,7 @@ enum hactool_file_type
#define ACTION_DEV (1<<5)
#define ACTION_EXTRACTINI1 (1<<6)
#define ACTION_ONLYUPDATEDROMFS (1<<7)
#define ACTION_SAVEINIJSON (1<<0)
struct nca_ctx; /* This will get re-defined by nca.h. */