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 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 SeekFileInNand(u32* offset, u32* size, const char* path, PartitionInfo* partition) { // poor mans NAND FAT file seeker: // - path must be in FAT 8+3 format, without dots or slashes // example: DIR1_______DIR2_______FILENAMEEXT // - can't handle long filenames // - dirs must not exceed 1024 entries // - fragmentation not supported u8* buffer = BUFFER_ADDRESS; u32 p_size = partition->size; u32 p_offset = partition->offset; u32 fat_pos = 0; bool found = false; if (strnlen(path, 256) % (8+3) != 0) return 1; if (DecryptNandToMem(buffer, p_offset, NAND_SECTOR_SIZE, partition) != 0) return 1; // good FAT header description found here: http://www.compuphase.com/mbr_fat.htm u32 fat_start = NAND_SECTOR_SIZE * getle16(buffer + 0x0E); u32 fat_count = buffer[0x10]; u32 fat_size = NAND_SECTOR_SIZE * getle16(buffer + 0x16) * fat_count; u32 root_size = getle16(buffer + 0x11) * 0x20; u32 cluster_start = fat_start + fat_size + root_size; u32 cluster_size = buffer[0x0D] * NAND_SECTOR_SIZE; for (*offset = p_offset + fat_start + fat_size; strnlen(path, 256) >= 8+3; path += 8+3) { if (*offset - p_offset > p_size) return 1; found = false; if (DecryptNandToMem(buffer, *offset, cluster_size, partition) != 0) return 1; for (u32 i = 0x00; i < cluster_size; i += 0x20) { static const char zeroes[8+3] = { 0x00 }; // skip invisible, deleted and lfn entries if ((buffer[i] == '.') || (buffer[i] == 0xE5) || (buffer[i+0x0B] == 0x0F)) continue; else if (memcmp(buffer + i, zeroes, 8+3) == 0) return 1; u32 p; // search for path in fat folder structure, accept '?' wildcards for (p = 0; (p < 8+3) && (path[p] == '?' || buffer[i+p] == path[p]); p++); if (p != 8+3) continue; // entry found, store offset and move on fat_pos = getle16(buffer + i + 0x1A); *offset = p_offset + cluster_start + (fat_pos - 2) * cluster_size; *size = getle32(buffer + i + 0x1C); found = true; break; } if (!found) break; } // check for fragmentation if (found && (*size > cluster_size)) { if (fat_size / fat_count > 0x100000) // prevent buffer overflow return 1; // fishy FAT table size - should never happen if (DecryptNandToMem(buffer, p_offset + fat_start, fat_size / fat_count, partition) != 0) return 1; for (u32 i = 0; i < (*size - 1) / cluster_size; i++) { if (*(((u16*) buffer) + fat_pos + i) != fat_pos + i + 1) return 1; } // no need to check the files last FAT table entry } return (found) ? 0 : 1; }