Last active
November 15, 2019 21:07
-
-
Save ITotalJustice/d0383d0af4581f559cbfe12ea964307a to your computer and use it in GitHub Desktop.
Dump all .nca's inside from inside the secure, logo, normal and update from an xci
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> // you already know what this is for... | |
#include <stdbool.h> // for bools. | |
#include <stdlib.h> // for malloc. | |
#include <stdint.h> // for u_int64_t etc etc. | |
#include <string.h> // for strstr. | |
#include <sys/stat.h> // for mkdir. | |
#define HFS0_MAGIC 0x30534648 // HFS0 | |
#define HFS0_HEADER_OFFSET 0xF000 | |
#define BUFFER_SIZE 0x800000 //8MB | |
static FILE *g_file; | |
typedef struct | |
{ | |
u_int32_t magic; | |
u_int32_t total_files; | |
u_int32_t string_table_size; | |
u_int32_t padding; | |
} hfs0_header_t; | |
typedef struct | |
{ | |
u_int64_t data_offset; | |
u_int64_t data_size; | |
u_int32_t name_offset; | |
u_int32_t hash_size; | |
u_int64_t padding; | |
char hash[0x20]; // i think i use a char? maybe use an u_int_t[0x20]??? | |
} hfs0_file_table_t; | |
typedef struct | |
{ | |
char name[64]; | |
} hfs0_string_table_t; | |
typedef struct | |
{ | |
hfs0_header_t header; | |
hfs0_file_table_t *file_table; | |
hfs0_string_table_t *string_table; | |
u_int64_t file_table_offset; | |
size_t file_table_size; | |
u_int64_t string_table_offset; | |
u_int64_t raw_data_offset; | |
size_t raw_data_size; | |
} hfs0_structs_t; | |
bool hfs0_get_header(hfs0_structs_t *ptr, u_int64_t offset) | |
{ | |
// read the header. | |
fseek(g_file, offset, SEEK_SET); | |
fread(&ptr->header, sizeof(hfs0_header_t), 1, g_file); | |
if (ptr->header.magic != HFS0_MAGIC) | |
{ | |
printf("\ngot wrong magic %x16\n", ptr->header.magic); | |
fclose(g_file); | |
return false; | |
} | |
printf("\ngot correct magic %x16\n", ptr->header.magic); | |
return true; | |
} | |
void hfs0_populate_file_table(hfs0_structs_t *ptr) | |
{ | |
ptr->file_table = malloc(ptr->file_table_size); | |
fseek(g_file, ptr->file_table_offset, SEEK_SET); | |
fread(ptr->file_table, ptr->file_table_size, 1, g_file); | |
} | |
void hfs0_populate_string_table(hfs0_structs_t *ptr) | |
{ | |
ptr->string_table = malloc(ptr->header.total_files * sizeof(hfs0_string_table_t)); | |
char *data_temp = malloc(ptr->header.string_table_size); | |
fseek(g_file, ptr->string_table_offset, SEEK_SET); | |
fread(data_temp, ptr->header.string_table_size, 1, g_file); | |
for (u_int32_t i = 0; i < ptr->header.total_files; i++) | |
{ | |
u_int64_t offset = ptr->file_table[i].name_offset; | |
for (u_int8_t j = 0; ; j++, offset++) | |
{ | |
ptr->string_table[i].name[j] = data_temp[offset]; | |
if (ptr->string_table[i].name[j] == 0x00) | |
{ | |
printf("found string %s\n", ptr->string_table[i].name); | |
break; | |
} | |
} | |
} | |
free(data_temp); | |
} | |
void hfs0_populate_table_size_offsets(hfs0_structs_t *ptr, u_int64_t offset) | |
{ | |
ptr->file_table_offset = offset + sizeof(hfs0_header_t); | |
ptr->file_table_size = ptr->header.total_files * sizeof(hfs0_file_table_t); | |
ptr->string_table_offset = ptr->file_table_offset + ptr->file_table_size; | |
ptr->raw_data_offset = ptr->string_table_offset + ptr->header.string_table_size; | |
} | |
size_t hfs0_get_total_raw_data_size(hfs0_structs_t *ptr) | |
{ | |
size_t total_size = 0; | |
for (u_int32_t i = 0; i < ptr->header.total_files; i++) | |
total_size += ptr->file_table[i].data_size; | |
return total_size; | |
} | |
void hfs0_free_structs(hfs0_structs_t *ptr) | |
{ | |
free(ptr->file_table); | |
free(ptr->string_table); | |
} | |
bool hfs0_parse(hfs0_structs_t *ptr, u_int64_t offset) | |
{ | |
printf("\ngetting header\n"); | |
if (!hfs0_get_header(ptr, offset)) return false; | |
// we have enough info to get the offset and sizes of the file_table, string table and data. | |
printf("\npopulating table offsets / sizes\n"); | |
hfs0_populate_table_size_offsets(ptr, offset); | |
// populate the file table. | |
printf("\npopulating file table...\n"); | |
hfs0_populate_file_table(ptr); | |
// get the total raw data size | |
// this should be used to check against the total free space. | |
// if the total size needed is larger than the free space, cleanup then exit. | |
ptr->raw_data_size = hfs0_get_total_raw_data_size(ptr); | |
// populate the string table. | |
printf("\npopulating string table...\n"); | |
hfs0_populate_string_table(ptr); | |
return true; | |
} | |
void hfs0_extract_all(hfs0_structs_t *ptr) | |
{ | |
for (u_int32_t i = 0; i < ptr->header.total_files; i++) | |
{ | |
mkdir(ptr->string_table[i].name, 0777); | |
hfs0_structs_t temp; | |
hfs0_parse(&temp, ptr->raw_data_offset + ptr->file_table[i].data_offset); | |
for (u_int32_t j = 0; j < temp.header.total_files; j++) | |
{ | |
// create new file to dump data to. | |
char new_path[128]; | |
sprintf(new_path, "%s/%s", ptr->string_table[i].name, temp.string_table[j].name); | |
FILE *new_file = fopen(new_path, "wb"); | |
if (!new_file) | |
{ | |
printf("failed to create new file %s\n", temp.string_table[j].name); | |
break; | |
} | |
printf("now dumping %s of size %luMB\n", temp.string_table[j].name, temp.file_table[j].data_size / 0x100000); | |
fseek(g_file, temp.raw_data_offset + temp.file_table[j].data_offset, SEEK_SET); | |
// loop until data is dumped. | |
for (u_int64_t offset = 0, buf_size = BUFFER_SIZE; offset < temp.file_table[j].data_size; offset += buf_size) | |
{ | |
if (offset + buf_size > temp.file_table[j].data_size) buf_size = temp.file_table[j].data_size - offset; | |
void *buf = malloc(buf_size); | |
fread(buf, buf_size, 1, g_file); | |
fwrite(buf, buf_size, 1, new_file); | |
free(buf); | |
} | |
fclose(new_file); | |
} | |
hfs0_free_structs(&temp); | |
} | |
} | |
// START HERE // | |
int main(int argc, char *argv[]) | |
{ | |
if (argc < 2) | |
{ | |
printf("enter file name\n"); | |
return 1; | |
} | |
// create main struct on the stack which gets passed around the whole program. | |
hfs0_structs_t root; | |
if (!(g_file = fopen(argv[1], "rb"))) | |
{ | |
printf("could not open file %s\n", argv[1]); | |
return 1; | |
} | |
if (!hfs0_parse(&root, HFS0_HEADER_OFFSET)) return 1; | |
//time to dump it... | |
printf("\ndumping data...\n"); | |
hfs0_extract_all(&root); | |
// close file, free mem, exit! | |
printf("\nexit...\n"); | |
hfs0_free_structs(&root); | |
fclose(g_file); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment