Skip to content

Instantly share code, notes, and snippets.

@ITotalJustice
Last active November 15, 2019 21:07
Show Gist options
  • Save ITotalJustice/d0383d0af4581f559cbfe12ea964307a to your computer and use it in GitHub Desktop.
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
#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