void exefs_print(exefs_context* ctx) { u32 i; char sectname[9]; u32 sectoffset; u32 sectsize; fprintf(stdout, "\nExeFS:\n"); for(i=0; i<8; i++) { exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + i); memset(sectname, 0, sizeof(sectname)); memcpy(sectname, section->name, 8); sectoffset = getle32(section->offset); sectsize = getle32(section->size); if (sectsize) { fprintf(stdout, "Section name: %s\n", sectname); fprintf(stdout, "Section offset: 0x%08x\n", sectoffset + 0x200); fprintf(stdout, "Section size: 0x%08x\n", sectsize); if (ctx->hashcheck[i] == Good) memdump(stdout, "Section hash (GOOD): ", ctx->header.hashes[7-i], 0x20); else if (ctx->hashcheck[i] == Fail) memdump(stdout, "Section hash (FAIL): ", ctx->header.hashes[7-i], 0x20); else memdump(stdout, "Section hash: ", ctx->header.hashes[7-i], 0x20); } } }
void ncch_get_counter(ctr_ncchheader header, unsigned char counter[16], unsigned char type) { unsigned int version = getle16(header.version); unsigned int mediaunitsize = 0x200; unsigned char* partitionid = header.partitionid; unsigned int i; unsigned int x = 0; for(i = 0; i < 16; i++) counter[i] = 0x00; if (version == 2 || version == 0) { for(i=0; i<8; i++) counter[i] = partitionid[7-i]; counter[8] = type; } else if (version == 1) { if (type == NCCHTYPE_EXHEADER) x = 0x200; else if (type == NCCHTYPE_EXEFS) x = getle32(header.exefsoffset) * mediaunitsize; else if (type == NCCHTYPE_ROMFS) x = getle32(header.romfsoffset) * mediaunitsize; for(i=0; i<8; i++) counter[i] = partitionid[i]; for(i=0; i<4; i++) counter[12+i] = x>>((3-i)*8); } }
u32 IdentifyImage(const char* path) { u8 header[0x200]; FIL file; if (f_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 0; f_lseek(&file, 0); f_sync(&file); UINT fsize = f_size(&file); UINT bytes_read; if ((f_read(&file, header, 0x200, &bytes_read) != FR_OK) || (bytes_read != 0x200)) { f_close(&file); return 0; } f_close(&file); if ((getbe32(header + 0x100) == 0x4E435344) && (getbe64(header + 0x110) == (u64) 0x0104030301000000) && (getbe64(header + 0x108) == (u64) 0) && (fsize >= 0x8FC8000)) { return IMG_NAND; } else if (getbe16(header + 0x1FE) == 0x55AA) { // migt be FAT or MBR if ((strncmp((char*) header + 0x36, "FAT12 ", 8) == 0) || (strncmp((char*) header + 0x36, "FAT16 ", 8) == 0) || (strncmp((char*) header + 0x36, "FAT ", 8) == 0) || (strncmp((char*) header + 0x52, "FAT32 ", 8) == 0)) { return IMG_FAT; // this is an actual FAT header } else if (((getle32(header + 0x1BE + 0x8) + getle32(header + 0x1BE + 0xC)) < (fsize / 0x200)) && // check file size (getle32(header + 0x1BE + 0x8) > 0) && (getle32(header + 0x1BE + 0xC) >= 0x800) && // check first partition sanity ((header[0x1BE + 0x4] == 0x1) || (header[0x1BE + 0x4] == 0x4) || (header[0x1BE + 0x4] == 0x6) || // filesystem type (header[0x1BE + 0x4] == 0xB) || (header[0x1BE + 0x4] == 0xC) || (header[0x1BE + 0x4] == 0xE))) { return IMG_FAT; // this might be an MBR -> give it the benefit of doubt } } return 0; }
int firm_verify(firm_context* ctx, u32 flags) { unsigned int i; u32 offset; u32 size; u8 buffer[16 * 1024]; u8 hash[0x20]; for(i=0; i<4; i++) { firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + i); offset = getle32(section->offset); size = getle32(section->size); if (size == 0) return 0; fseek(ctx->file, ctx->offset + offset, SEEK_SET); ctr_sha_256_init(&ctx->sha); while(size) { u32 max = sizeof(buffer); if (max > size) max = size; if (max != fread(buffer, 1, max, ctx->file)) { fprintf(stdout, "Error reading input file\n"); goto clean; } ctr_sha_256_update(&ctx->sha, buffer, max); size -= max; } ctr_sha_256_finish(&ctx->sha, hash); if (memcmp(hash, section->hash, 0x20) == 0) ctx->hashcheck[i] = Good; else ctx->hashcheck[i] = Fail; } clean: return 0; }
void romfs_print(romfs_context* ctx) { u32 i; fprintf(stdout, "\nRomFS:\n"); fprintf(stdout, "Header size: 0x%08X\n", getle32(ctx->infoheader.headersize)); for(i=0; i<4; i++) { fprintf(stdout, "Section %d offset: 0x%08"PRIX64"\n", i, ctx->offset + 0x1000 + getle32(ctx->infoheader.section[i].offset)); fprintf(stdout, "Section %d size: 0x%08X\n", i, getle32(ctx->infoheader.section[i].size)); } fprintf(stdout, "Data offset: 0x%08"PRIX64"\n", ctx->offset + 0x1000 + getle32(ctx->infoheader.dataoffset)); }
int exefs_verify(exefs_context* ctx, u32 index, u32 flags) { exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + index); u32 offset; u32 size; u8 buffer[16 * 1024]; u8 hash[0x20]; offset = getle32(section->offset) + sizeof(exefs_header); size = getle32(section->size); if (size == 0) return 0; fseek(ctx->file, ctx->offset + offset, SEEK_SET); ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); ctr_add_counter(&ctx->aes, offset / 0x10); ctr_sha_256_init(&ctx->sha); while(size) { u32 max = sizeof(buffer); if (max > size) max = size; if (max != fread(buffer, 1, max, ctx->file)) { fprintf(stdout, "Error reading input file\n"); goto clean; } if (ctx->encrypted) ctr_crypt_counter(&ctx->aes, buffer, buffer, max); ctr_sha_256_update(&ctx->sha, buffer, max); size -= max; } ctr_sha_256_finish(&ctx->sha, hash); if (memcmp(hash, ctx->header.hashes[7-index], 0x20) == 0) return 1; clean: return 0; }
void ivfc_print(ivfc_context* ctx) { u32 i; ivfc_header* header = &ctx->header; fprintf(stdout, "\nIVFC:\n"); fprintf(stdout, "Header: %.4s\n", header->magic); fprintf(stdout, "Id: %08x\n", getle32(header->id)); for(i=0; i<ctx->levelcount; i++) { ivfc_level* level = ctx->level + i; fprintf(stdout, "\n"); if (level->hashcheck == Unchecked) fprintf(stdout, "Level %d: \n", i); else fprintf(stdout, "Level %d (%s): \n", i, level->hashcheck == Good? "GOOD" : "FAIL"); fprintf(stdout, " Data offset: 0x%08"PRIx64"\n", ctx->offset + level->dataoffset); fprintf(stdout, " Data size: 0x%08"PRIx64"\n", level->datasize); fprintf(stdout, " Hash offset: 0x%08"PRIx64"\n", ctx->offset + level->hashoffset); fprintf(stdout, " Hash block size: 0x%08x\n", level->hashblocksize); } }
u32 CheckEmuNand(void) { u8* buffer = BUFFER_ADDRESS; u32 nand_size_sectors = getMMCDevice(0)->total_size; u32 nand_offset; if (emunand_no > 0) { if (nand_size_sectors > EMUNAND_MULTI_OFFSET_O3DS) { nand_offset = EMUNAND_MULTI_OFFSET_N3DS * (emunand_no - 1 ); } else { nand_offset = EMUNAND_MULTI_OFFSET_O3DS * (emunand_no - 1 ); } } else { nand_offset = 0; } // check the MBR for presence of EmuNAND sdmmc_sdcard_readsectors(0, 1, buffer); if (nand_offset+nand_size_sectors > getle32(buffer + 0x1BE + 0x8)) return EMUNAND_NOT_READY; // check for Gateway type EmuNAND sdmmc_sdcard_readsectors(nand_offset+nand_size_sectors, 1, buffer); if (memcmp(buffer + 0x100, "NCSD", 4) == 0) return EMUNAND_GATEWAY; // check for RedNAND type EmuNAND sdmmc_sdcard_readsectors(nand_offset + 1, 1, buffer); if (memcmp(buffer + 0x100, "NCSD", 4) == 0) return EMUNAND_REDNAND; // EmuNAND ready but not set up return EMUNAND_READY; }
void tik_print(tik_context* ctx) { int i; eticket* tik = &ctx->tik; fprintf(stdout, "\nTicket content:\n"); fprintf(stdout, "Signature Type: %08x\n" "Issuer: %s\n", getle32(tik->sig_type), tik->issuer ); fprintf(stdout, "Signature:\n"); hexdump(tik->signature, 0x100); fprintf(stdout, "\n"); memdump(stdout, "Encrypted Titlekey: ", tik->encrypted_title_key, 0x10); if (settings_get_common_keyX(ctx->usersettings)) memdump(stdout, "Decrypted Titlekey: ", ctx->titlekey, 0x10); memdump(stdout, "Ticket ID: ", tik->ticket_id, 0x08); fprintf(stdout, "Ticket Version: %d\n", getle16(tik->ticket_version)); memdump(stdout, "Title ID: ", tik->title_id, 0x08); fprintf(stdout, "Common Key Index: %d\n", tik->commonkey_idx); fprintf(stdout, "Content permission map:\n"); for(i = 0; i < 0x40; i++) { printf(" %02x", tik->content_permissions[i]); if ((i+1) % 8 == 0) printf("\n"); } printf("\n"); }
void ncsd_process(ncsd_context* ctx, u32 actions) { fseek(ctx->file, ctx->offset, SEEK_SET); fread(&ctx->header, 1, 0x200, ctx->file); if (getle32(ctx->header.magic) != MAGIC_NCSD) { fprintf(stdout, "Error, NCSD segment corrupted\n"); return; } if (actions & VerifyFlag) { if (ctx->usersettings) ctx->headersigcheck = ncsd_signature_verify(&ctx->header, &ctx->usersettings->keys.ncsdrsakey); } if (actions & InfoFlag) ncsd_print(ctx); ncch_set_file(&ctx->ncch, ctx->file); ncch_set_offset(&ctx->ncch, 0x4000); ncch_set_size(&ctx->ncch, ctx->size - 0x4000); ncch_set_usersettings(&ctx->ncch, ctx->usersettings); ncch_process(&ctx->ncch, actions); }
void ncsd_process(ncsd_context* ctx, u32 actions) { fseeko64(ctx->file, ctx->offset, SEEK_SET); fread(&ctx->header, 1, 0x200, ctx->file); if (getle32(ctx->header.magic) != MAGIC_NCSD) { fprintf(stdout, "Error, NCSD segment corrupted\n"); return; } if (actions & VerifyFlag) { if (ctx->usersettings) ctx->headersigcheck = ncsd_signature_verify(&ctx->header, &ctx->usersettings->keys.ncsdrsakey); } if (actions & InfoFlag) ncsd_print(ctx); if(ctx->ncch_index > 7 || ctx->header.partitiongeometry[ctx->ncch_index].size == 0) { fprintf(stderr," ERROR NCSD partition %d, does not exist\n",ctx->ncch_index); return; } ncch_set_file(&ctx->ncch, ctx->file); ncch_set_offset(&ctx->ncch, ctx->header.partitiongeometry[ctx->ncch_index].offset * ncsd_get_mediaunit_size(ctx)); ncch_set_size(&ctx->ncch, ctx->header.partitiongeometry[ctx->ncch_index].size * ncsd_get_mediaunit_size(ctx)); ncch_set_usersettings(&ctx->ncch, ctx->usersettings); ncch_process(&ctx->ncch, actions); }
void keyset_parse_seeddb(keyset* keys, char* path) { //keyset_parse_key128(&keys->seed, keytext, keylen); FILE* fp = fopen(path, "rb"); if (fp == NULL) { printf("[ERROR] Failed to load SeedDB (failed to open file)\n"); return; } seeddb_header hdr; fread(&hdr, sizeof(seeddb_header), 1, fp); keys->seed_num = getle32(hdr.n_entries); for (u32 i = 0; i < 0xC; i++) { if (hdr.padding[i] != 0x00) { printf("[ERROR] SeedDB is corrupt. (padding malformed)\n"); return; } } keys->seed_db = (seeddb_entry*)calloc(keys->seed_num, sizeof(seeddb_entry)); fread(keys->seed_db, keys->seed_num * sizeof(seeddb_entry), 1, fp); }
uint32_t getsize(int fd) { int len; uint8_t buf[4]; len=read(fd, buf, 4); return getle32(buf); }
int main(int argc, char *argv[]) { uint32_t olen; long ilen; unsigned long offs; FILE *f; if (argc < 2) { fprintf(stderr, "Usage: %s compressed_file\n", argv[0]); return 1; } /* Get the information for the compressed kernel image first */ f = fopen(argv[1], "r"); if (!f) { perror(argv[1]); return 1; } if (fseek(f, -4L, SEEK_END)) { perror(argv[1]); } fread(&olen, sizeof olen, 1, f); ilen = ftell(f); olen = getle32(&olen); fclose(f); /* * Now we have the input (compressed) and output (uncompressed) * sizes, compute the necessary decompression offset... */ offs = (olen > ilen) ? olen - ilen : 0; offs += olen >> 12; /* Add 8 bytes for each 32K block */ offs += 64*1024 + 128; /* Add 64K + 128 bytes slack */ offs = (offs+4095) & ~4095; /* Round to a 4K boundary */ printf(".section \".rodata..compressed\",\"a\",@progbits\n"); printf(".globl z_input_len\n"); printf("z_input_len = %lu\n", ilen); printf(".globl z_output_len\n"); printf("z_output_len = %lu\n", (unsigned long)olen); printf(".globl z_extract_offset\n"); printf("z_extract_offset = 0x%lx\n", offs); /* z_extract_offset_negative allows simplification of head_32.S */ printf(".globl z_extract_offset_negative\n"); printf("z_extract_offset_negative = -0x%lx\n", offs); printf(".globl input_data, input_data_end\n"); printf("input_data:\n"); printf(".incbin \"%s\"\n", argv[1]); printf("input_data_end:\n"); return 0; }
void romfs_visit_file(romfs_context* ctx, u32 fileoffset, u32 depth, u32 actions, const oschar_t* rootpath) { u32 siblingoffset = 0; oschar_t* currentpath = NULL; romfs_fileentry* entry = &ctx->fileentry; if (!romfs_fileblock_readentry(ctx, fileoffset, entry)) return; // fprintf(stdout, "%08X %08X %016llX %016llX %08X ", // getle32(entry->parentdiroffset), getle32(entry->siblingoffset), ctx->datablockoffset+getle64(entry->dataoffset), // getle64(entry->datasize), getle32(entry->unknown)); // fwprintf(stdout, L"%ls\n", entry->name); if (rootpath && os_strlen(rootpath)) { currentpath = os_AppendUTF16StrToPath(rootpath, (const utf16char_t*)entry->name); if (currentpath) { fputs("Saving ", stdout); os_fputs(currentpath, stdout); fputs("...\n", stdout); romfs_extract_datafile(ctx, getle64(entry->dataoffset), getle64(entry->datasize), currentpath); } else { fputs("Error creating file in root ", stderr); os_fputs(rootpath, stderr); fputs("\n", stderr); return; } } else { currentpath = os_CopyConvertUTF16Str((const utf16char_t*)entry->name); if (settings_get_list_romfs_files(ctx->usersettings)) { u32 i; for(i=0; i<depth; i++) printf(" "); os_fputs(currentpath, stdout); fputs("\n", stdout); } free(currentpath); currentpath = NULL; } siblingoffset = getle32(entry->siblingoffset); if (siblingoffset != (~0)) romfs_visit_file(ctx, siblingoffset, depth, actions, rootpath); free(currentpath); }
int check_riff(avi_context *ac, uint8_t *buf, int len) { uint32_t tag; int c = 0; if (len < 12) return -1; tag = getle32(buf); if (tag != TAG_IT('R','I','F','F')) return -1; c+=4; ac->riff_end = getle32(buf+c); c+=4; tag = getle32(buf+c); if (tag != TAG_IT('A','V','I',' ') && tag != TAG_IT('A','V','I','X') ) return -1; return c+4; }
uint8_t* decryptFirmTitleNcch(uint8_t* title, unsigned int size){ ctr_ncchheader NCCH; uint8_t CTR[16]; PartitionInfo INFO; NCCH = *((ctr_ncchheader*)title); if(memcmp(NCCH.magic, "NCCH", 4) != 0) return NULL; ncch_get_counter(NCCH, CTR, 2); INFO.ctr = CTR; INFO.buffer = title + getle32(NCCH.exefsoffset)*0x200; INFO.keyY = NCCH.signature; INFO.size = size; INFO.keyslot = 0x2C; DecryptPartition(&INFO); uint8_t* firm = (uint8_t*)(INFO.buffer + 0x200); return firm; }
void ncsd_print(ncsd_context* ctx) { char magic[5]; ctr_ncsdheader* header = &ctx->header; unsigned int i; unsigned int mediaunitsize = (unsigned int) ncsd_get_mediaunit_size(ctx); memcpy(magic, header->magic, 4); magic[4] = 0; fprintf(stdout, "Header: %s\n", magic); if (ctx->headersigcheck == Unchecked) memdump(stdout, "Signature: ", header->signature, 0x100); else if (ctx->headersigcheck == Good) memdump(stdout, "Signature (GOOD): ", header->signature, 0x100); else memdump(stdout, "Signature (FAIL): ", header->signature, 0x100); fprintf(stdout, "Media size: 0x%08x\n", getle32(header->mediasize)); fprintf(stdout, "Media id: %016"PRIx64"\n", getle64(header->mediaid)); //memdump(stdout, "Partition FS type: ", header->partitionfstype, 8); //memdump(stdout, "Partition crypt type: ", header->partitioncrypttype, 8); //memdump(stdout, "Partition offset/size: ", header->partitionoffsetandsize, 0x40); fprintf(stdout, "\n"); for(i=0; i<8; i++) { u32 partitionoffset = header->partitiongeometry[i].offset * mediaunitsize; u32 partitionsize = header->partitiongeometry[i].size * mediaunitsize; if (partitionsize != 0) { fprintf(stdout, "Partition %d \n", i); memdump(stdout, " Id: ", header->partitionid+i*8, 8); fprintf(stdout, " Area: 0x%08X-0x%08X\n", partitionoffset, partitionoffset+partitionsize); fprintf(stdout, " Filesystem: %02X\n", header->partitionfstype[i]); fprintf(stdout, " Encryption: %02X\n", header->partitioncrypttype[i]); fprintf(stdout, "\n"); } } memdump(stdout, "Extended header hash: ", header->extendedheaderhash, 0x20); memdump(stdout, "Additional header size: ", header->additionalheadersize, 4); memdump(stdout, "Sector zero offset: ", header->sectorzerooffset, 4); memdump(stdout, "Flags: ", header->flags, 8); fprintf(stdout, " > Mediaunit size: 0x%X\n", mediaunitsize); fprintf(stdout, " > Mediatype: %s\n", ncsd_print_mediatype(header->flags[5])); fprintf(stdout, " > Card Device: %s\n", ncsd_print_carddevice(header->flags[3] | header->flags[7])); }
int layout_addsection(u32 sectionid, u8 *section_payload, u32 section_payloadsize) { if(layout_pos+8+section_payloadsize > filebuf_size) { printf("This additional layout section is too large.\n"); return 5; } putle32(&filebuf[layout_pos+0], sectionid); putle32(&filebuf[layout_pos+4], 8+section_payloadsize); if(section_payload)memcpy(&filebuf[layout_pos+8], section_payload, section_payloadsize); layout_pos+= 8+section_payloadsize; putle32(layout_header->total_sections, getle32(layout_header->total_sections) + 1); return 0; }
void firm_print(firm_context* ctx) { u32 i; u32 address; u32 type; u32 offset; u32 size; u32 entrypointarm11 = getle32(ctx->header.entrypointarm11); u32 entrypointarm9 = getle32(ctx->header.entrypointarm9); fprintf(stdout, "\nFIRM:\n"); if (ctx->headersigcheck == Unchecked) memdump(stdout, "Signature: ", ctx->header.signature, 0x100); else if (ctx->headersigcheck == Good) memdump(stdout, "Signature (GOOD): ", ctx->header.signature, 0x100); else memdump(stdout, "Signature (FAIL): ", ctx->header.signature, 0x100); fprintf(stdout, "\n"); fprintf(stdout, "Entrypoint ARM9: 0x%08X\n", entrypointarm9); fprintf(stdout, "Entrypoint ARM11: 0x%08X\n", entrypointarm11); fprintf(stdout, "\n"); for(i=0; i<4; i++) { firm_sectionheader* section = (firm_sectionheader*)(ctx->header.section + i); offset = getle32(section->offset); size = getle32(section->size); address = getle32(section->address); type = getle32(section->type); if (size) { fprintf(stdout, "Section %d \n", i); fprintf(stdout, " Type: %s\n", type==0? "ARM9" : type==1? "ARM11" : "UNKNOWN"); fprintf(stdout, " Address: 0x%08X\n", address); fprintf(stdout, " Offset: 0x%08X\n", offset); fprintf(stdout, " Size: 0x%08X\n", size); if (ctx->hashcheck[i] == Good) memdump(stdout, " Hash (GOOD): ", section->hash, 0x20); else if (ctx->hashcheck[i] == Fail) memdump(stdout, " Hash (FAIL): ", section->hash, 0x20); else memdump(stdout, " Hash: ", section->hash, 0x20); } } }
int romfs_fileblock_readentry(romfs_context* ctx, u32 fileoffset, romfs_fileentry* entry) { u32 size_without_name = sizeof(romfs_fileentry) - ROMFS_MAXNAMESIZE; u32 namesize; if (!ctx->fileblock) return 0; if (!romfs_fileblock_read(ctx, fileoffset, size_without_name, entry)) return 0; namesize = getle32(entry->namesize); if (namesize > (ROMFS_MAXNAMESIZE-2)) namesize = (ROMFS_MAXNAMESIZE-2); memset(entry->name + namesize, 0, 2); if (!romfs_fileblock_read(ctx, fileoffset + size_without_name, namesize, entry->name)) return 0; return 1; }
u32 SeekTitleInNandDb(u32* tid_low, u32* tmd_id, TitleListInfo* title_info) { PartitionInfo* ctrnand_info = GetPartitionInfo(P_CTRNAND); u8* titledb = (u8*) 0x20316000; u32 offset_db; u32 size_db; if (SeekFileInNand(&offset_db, &size_db, "DBS TITLE DB ", ctrnand_info) != 0) return 1; // database not found if (size_db != 0x64C00) return 1; // bad database size if (DecryptNandToMem(titledb, offset_db, size_db, ctrnand_info) != 0) return 1; u8* entry_table = titledb + 0x39A80; u8* info_data = titledb + 0x44B80; if ((getle32(entry_table + 0) != 2) || (getle32(entry_table + 4) != 3)) return 1; // magic number not found *tid_low = 0; for (u32 i = 0; i < 1000; i++) { u8* entry = entry_table + 0xA8 + (0x2C * i); u8* info = info_data + (0x80 * i); u32 r; if (getle32(entry + 0xC) != title_info->tid_high) continue; // not a title id match if (getle32(entry + 0x4) != 1) continue; // not an active entry if ((getle32(entry + 0x18) - i != 0x162) || (getle32(entry + 0x1C) != 0x80) || (getle32(info + 0x08) != 0x40)) continue; // fishy title info / offset for (r = 0; r < 6; r++) { if ((title_info->tid_low[r] != 0) && (getle32(entry + 0x8) == title_info->tid_low[r])) break; } if (r >= 6) continue; *tmd_id = getle32(info + 0x14); *tid_low = title_info->tid_low[r]; break; } return (*tid_low) ? 0 : 1; }
u32 CheckEmuNand(void) { u8* buffer = BUFFER_ADDRESS; u32 nand_size_sectors = getMMCDevice(0)->total_size; // check the MBR for presence of EmuNAND sdmmc_sdcard_readsectors(0, 1, buffer); if (nand_size_sectors > getle32(buffer + 0x1BE + 0x8)) return EMUNAND_NOT_READY; // check for Gateway type EmuNAND sdmmc_sdcard_readsectors(nand_size_sectors, 1, buffer); if (memcmp(buffer + 0x100, "NCSD", 4) == 0) return EMUNAND_GATEWAY; // check for RedNAND type EmuNAND sdmmc_sdcard_readsectors(1, 1, buffer); if (memcmp(buffer + 0x100, "NCSD", 4) == 0) return EMUNAND_REDNAND; // EmuNAND ready but not set up return EMUNAND_READY; }
void firm_process(firm_context* ctx, u32 actions) { u32 i; fseek(ctx->file, ctx->offset, SEEK_SET); fread(&ctx->header, 1, sizeof(firm_header), ctx->file); if (getle32(ctx->header.magic) != MAGIC_FIRM) { fprintf(stdout, "Error, FIRM segment corrupted\n"); return; } if (actions & VerifyFlag) { firm_verify(ctx, actions); firm_signature_verify(ctx); } if (actions & InfoFlag) { firm_print(ctx); } if (actions & ExtractFlag) { filepath* dirpath = settings_get_firm_dir_path(ctx->usersettings); if (dirpath && dirpath->valid) { makedir(dirpath->pathname); for(i=0; i<4; i++) firm_save(ctx, i, actions); } } }
uint8_t* decryptFirmTitleNcch(uint8_t* title, size_t *size) { const size_t sector = 512; const size_t header = 512; ctr_ncchheader NCCH; uint8_t CTR[16]; PartitionInfo INFO; NCCH = *((ctr_ncchheader*)title); if(memcmp(NCCH.magic, "NCCH", 4) != 0) return NULL; ncch_get_counter(NCCH, CTR, 2); INFO.ctr = CTR; INFO.buffer = title + getle32(NCCH.exefsoffset)*sector; INFO.keyY = NCCH.signature; INFO.size = getle32(NCCH.exefssize)*sector; INFO.keyslot = 0x2C; DecryptPartition(&INFO); if (size != NULL) *size = INFO.size - header; uint8_t* firm = (uint8_t*)(INFO.buffer + header); if (getMpInfo() == MPINFO_KTR) if (decryptFirmKtrArm9(firm)) return NULL; return firm; }
void ivfc_process(ivfc_context* ctx, u32 actions) { ivfc_fseek(ctx, ctx->offset); ivfc_fread(ctx, &ctx->header, 1, sizeof(ivfc_header)); if (getle32(ctx->header.magic) != MAGIC_IVFC) { fprintf(stdout, "Error, IVFC segment corrupted\n"); return; } if (getle32(ctx->header.id) == 0x10000) { ctx->levelcount = 3; ctx->level[2].hashblocksize = 1 << getle32(ctx->header.level3.blocksize); ctx->level[1].hashblocksize = 1 << getle32(ctx->header.level2.blocksize); ctx->level[0].hashblocksize = 1 << getle32(ctx->header.level1.blocksize); ctx->bodyoffset = align64(IVFC_HEADER_SIZE + getle32(ctx->header.masterhashsize), ctx->level[2].hashblocksize); ctx->bodysize = getle64(ctx->header.level3.hashdatasize); ctx->level[2].dataoffset = ctx->bodyoffset; ctx->level[2].datasize = align64(ctx->bodysize, ctx->level[2].hashblocksize); ctx->level[0].dataoffset = ctx->level[2].dataoffset + ctx->level[2].datasize; ctx->level[0].datasize = align64(getle64(ctx->header.level1.hashdatasize), ctx->level[0].hashblocksize); ctx->level[1].dataoffset = ctx->level[0].dataoffset + ctx->level[0].datasize; ctx->level[1].datasize = align64(getle64(ctx->header.level2.hashdatasize), ctx->level[1].hashblocksize); ctx->level[0].hashoffset = IVFC_HEADER_SIZE; ctx->level[1].hashoffset = ctx->level[0].dataoffset; ctx->level[2].hashoffset = ctx->level[1].dataoffset; } if (actions & VerifyFlag) ivfc_verify(ctx, actions); if (actions & InfoFlag) ivfc_print(ctx); }
void romfs_process(romfs_context* ctx, u32 actions) { u32 dirblockoffset = 0; u32 dirblocksize = 0; u32 fileblockoffset = 0; u32 fileblocksize = 0; ivfc_set_offset(&ctx->ivfc, ctx->offset); ivfc_set_size(&ctx->ivfc, ctx->size); ivfc_set_file(&ctx->ivfc, ctx->file); ivfc_set_usersettings(&ctx->ivfc, ctx->usersettings); ivfc_set_counter(&ctx->ivfc, ctx->counter); ivfc_set_key(&ctx->ivfc, ctx->key); ivfc_set_encrypted(&ctx->ivfc, ctx->encrypted); ivfc_process(&ctx->ivfc, actions); romfs_fseek(ctx, ctx->offset); romfs_fread(ctx, &ctx->header, 1, sizeof(romfs_header)); if (getle32(ctx->header.magic) != MAGIC_IVFC) { fprintf(stdout, "Error, RomFS corrupted\n"); return; } ctx->infoblockoffset = (u32) (ctx->offset + 0x1000); romfs_fseek(ctx, ctx->infoblockoffset); romfs_fread(ctx, &ctx->infoheader, 1, sizeof(romfs_infoheader)); if (getle32(ctx->infoheader.headersize) != sizeof(romfs_infoheader)) { fprintf(stderr, "Error, info header mismatch\n"); return; } dirblockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.section[1].offset); dirblocksize = getle32(ctx->infoheader.section[1].size); fileblockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.section[3].offset); fileblocksize = getle32(ctx->infoheader.section[3].size); u32 hdrsize = getle32(ctx->infoheader.dataoffset); u8 *block = malloc(hdrsize); romfs_fseek(ctx, ctx->infoblockoffset); romfs_fread(ctx, block, hdrsize, 1); ctx->dirblock = malloc(dirblocksize); ctx->dirblocksize = dirblocksize; if(ctx->dirblock) memcpy(ctx->dirblock, block + getle32(ctx->infoheader.section[1].offset), dirblocksize); ctx->fileblock = malloc(fileblocksize); ctx->fileblocksize = fileblocksize; if (ctx->fileblock) memcpy(ctx->fileblock, block + getle32(ctx->infoheader.section[3].offset), fileblocksize); free(block); ctx->datablockoffset = ctx->infoblockoffset + getle32(ctx->infoheader.dataoffset); if (actions & InfoFlag) romfs_print(ctx); if (settings_get_romfs_dir_path(ctx->usersettings)->valid) ctx->extractdir = os_CopyConvertCharStr(settings_get_romfs_dir_path(ctx->usersettings)->pathname); else ctx->extractdir = NULL; romfs_visit_dir(ctx, 0, 0, actions, ctx->extractdir); free(ctx->extractdir); }
void romfs_visit_dir(romfs_context* ctx, u32 diroffset, u32 depth, u32 actions, const oschar_t* rootpath) { u32 siblingoffset; u32 childoffset; u32 fileoffset; oschar_t* currentpath; romfs_direntry* entry = &ctx->direntry; if (!romfs_dirblock_readentry(ctx, diroffset, entry)) return; // fprintf(stdout, "%08X %08X %08X %08X %08X ", // getle32(entry->parentoffset), getle32(entry->siblingoffset), getle32(entry->childoffset), // getle32(entry->fileoffset), getle32(entry->weirdoffset)); // fwprintf(stdout, L"%ls\n", entry->name); if (rootpath && os_strlen(rootpath)) { if (utf16_strlen((const utf16char_t*)entry->name) > 0) currentpath = os_AppendUTF16StrToPath(rootpath, (const utf16char_t*)entry->name); else // root dir, use the provided extract path instead of the empty root name. currentpath = os_CopyStr(rootpath); if (currentpath) { os_makedir(currentpath); } else { fputs("Error creating directory in root ", stderr); os_fputs(rootpath, stderr); fputs("\n", stderr); return; } } else { currentpath = os_CopyConvertUTF16Str((const utf16char_t*)entry->name); if (settings_get_list_romfs_files(ctx->usersettings)) { u32 i; for(i=0; i<depth; i++) printf(" "); os_fputs(currentpath, stdout); fputs("\n", stdout); } free(currentpath); currentpath = NULL; } siblingoffset = getle32(entry->siblingoffset); childoffset = getle32(entry->childoffset); fileoffset = getle32(entry->fileoffset); if (fileoffset != (~0)) romfs_visit_file(ctx, fileoffset, depth+1, actions, currentpath); if (childoffset != (~0)) romfs_visit_dir(ctx, childoffset, depth+1, actions, currentpath); if (siblingoffset != (~0)) romfs_visit_dir(ctx, siblingoffset, depth, actions, rootpath); free(currentpath); }
void exefs_save(exefs_context* ctx, u32 index, u32 flags) { exefs_sectionheader* section = (exefs_sectionheader*)(ctx->header.section + index); char outfname[MAX_PATH]; char name[64]; u32 offset; u32 size; FILE* fout; u32 compressedsize = 0; u32 decompressedsize = 0; u8* compressedbuffer = 0; u8* decompressedbuffer = 0; filepath* dirpath = 0; offset = getle32(section->offset) + sizeof(exefs_header); size = getle32(section->size); dirpath = settings_get_exefs_dir_path(ctx->usersettings); if (size == 0 || dirpath == 0 || dirpath->valid == 0) return; if (size >= ctx->size) { fprintf(stderr, "Error, ExeFS section %d size invalid\n", index); return; } memset(name, 0, sizeof(name)); memcpy(name, section->name, 8); memcpy(outfname, dirpath->pathname, MAX_PATH); strcat(outfname, "/"); if (name[0] == '.') strcat(outfname, name+1); else strcat(outfname, name); strcat(outfname, ".bin"); fout = fopen(outfname, "wb"); if (fout == 0) { fprintf(stderr, "Error, failed to create file %s\n", outfname); goto clean; } fseek(ctx->file, ctx->offset + offset, SEEK_SET); ctr_init_counter(&ctx->aes, ctx->key, ctx->counter); ctr_add_counter(&ctx->aes, offset / 0x10); if (index == 0 && (ctx->compressedflag || (flags & CompressCodeFlag)) && ((flags & RawFlag) == 0)) { fprintf(stdout, "Decompressing section %s to %s...\n", name, outfname); compressedsize = size; compressedbuffer = malloc(compressedsize); if (compressedbuffer == 0) { fprintf(stdout, "Error allocating memory\n"); goto clean; } if (compressedsize != fread(compressedbuffer, 1, compressedsize, ctx->file)) { fprintf(stdout, "Error reading input file\n"); goto clean; } if (ctx->encrypted) ctr_crypt_counter(&ctx->aes, compressedbuffer, compressedbuffer, compressedsize); decompressedsize = lzss_get_decompressed_size(compressedbuffer, compressedsize); decompressedbuffer = malloc(decompressedsize); if (decompressedbuffer == 0) { fprintf(stdout, "Error allocating memory\n"); goto clean; } if (0 == lzss_decompress(compressedbuffer, compressedsize, decompressedbuffer, decompressedsize)) goto clean; if (decompressedsize != fwrite(decompressedbuffer, 1, decompressedsize, fout)) { fprintf(stdout, "Error writing output file\n"); goto clean; } } else { u8 buffer[16 * 1024]; fprintf(stdout, "Saving section %s to %s...\n", name, outfname); while(size) { u32 max = sizeof(buffer); if (max > size) max = size; if (max != fread(buffer, 1, max, ctx->file)) { fprintf(stdout, "Error reading input file\n"); goto clean; } if (ctx->encrypted) ctr_crypt_counter(&ctx->aes, buffer, buffer, max); if (max != fwrite(buffer, 1, max, fout)) { fprintf(stdout, "Error writing output file\n"); goto clean; } size -= max; } } clean: free(compressedbuffer); free(decompressedbuffer); return; }
uint32_t getsize_buf(uint8_t *buf) { return getle32(buf); }