int ExtractCCIPartitions(CCI_CONTEXT *ctx) { FILE *cci = fopen(ctx->cci_file.argument,"rb"); if(cci == NULL) return Fail; chdir(ctx->outfile.argument); u64 chunk_size = ctx->ncsd_struct->MEDIA_UNIT_SIZE; u8 *chunk = malloc(chunk_size); for(int i = 0; i < 8; i++){ if(ctx->ncsd_struct->partition_data[i].active == True){ char output[1024]; memset(&output,0,1024); switch(ctx->ncsd_struct->partition_data[i].content_type){ case CXI : snprintf(output,1024,"%s_%d_APPDATA.cxi",ctx->ncsd_struct->partition_data[i].product_code,i); break; case CFA_Manual : snprintf(output,1024,"%s_%d_MANUAL.cfa",ctx->ncsd_struct->partition_data[i].product_code,i); break; case CFA_DLPChild : snprintf(output,1024,"%s_%d_DLP.cfa",ctx->ncsd_struct->partition_data[i].product_code,i); break; case CFA_Update : snprintf(output,1024,"%s_%d_UPDATEDATA.cfa",ctx->ncsd_struct->partition_data[i].product_code,i); break; case CFA_Simple : snprintf(output,1024,"%s_%d.cfa",ctx->ncsd_struct->partition_data[i].product_code,i); break; default: snprintf(output,1024,"%s_%d.bin",ctx->ncsd_struct->partition_data[i].product_code,i); break; } FILE *out = fopen(output,"wb"); if(out == NULL){ fclose(cci); return Fail; } printf("[+] Writing '%s'\n",output); u64 size = ctx->ncsd_struct->partition_data[i].size; u64 chunk_num = (size/chunk_size); u64 in_offset = ctx->ncsd_struct->partition_data[i].offset; u64 out_offset = 0; for(u64 i = 0; i < chunk_num; i++){ fseek_64(cci,in_offset,SEEK_SET); fseek_64(out,out_offset,SEEK_SET); fread(chunk,chunk_size,1,cci); fwrite(chunk,chunk_size,1,out); in_offset += chunk_size; out_offset += chunk_size; } fclose(out); } } free(chunk); fclose(cci); return 0; }
void WriteCciDataToOutput(cci_settings *set) { // NCSD Header WriteBuffer(set->headers.ccihdr.buffer, set->headers.ccihdr.size, 0, set->out); // Card Info Header WriteBuffer(set->headers.cardinfohdr.buffer, set->headers.cardinfohdr.size, set->headers.ccihdr.size, set->out); // Dummy data between header and first NCCH u64 len = set->content.cOffset[0] - (set->headers.ccihdr.size + set->headers.cardinfohdr.size); u8 *dummy_data = malloc(len); if(set->headers.cardinfohdr.size > sizeof(cardinfo_hdr)) // additional debug header data exists memset(dummy_data, 0x00, len); else // normal production cci image memset(dummy_data, 0xff, len); WriteBuffer(dummy_data, len, (set->headers.ccihdr.size + set->headers.cardinfohdr.size),set->out); free(dummy_data); // NCCH Partitions u8 *ncch; for(int i = 0; i < CCI_MAX_CONTENT; i++){ if(set->content.active[i]){ ncch = set->content.data + set->content.dOffset[i]; WriteBuffer(ncch, set->content.dSize[i], set->content.cOffset[i], set->out); } } // Cci Padding if(set->options.padCci){ fseek_64(set->out,set->romInfo.usedSize); // Determining Size of Padding u64 len = set->romInfo.mediaSize - set->romInfo.usedSize; // Create Padding chunk u8 *pad = malloc(set->romInfo.blockSize); memset(pad,0xff,set->romInfo.blockSize); // Writing Dummy Bytes to file for(u64 i = 0; i < len; i += set->romInfo.blockSize) fwrite(pad,set->romInfo.blockSize,1,set->out); free(pad); } return; }
int RestoreCCI(CCI_CONTEXT *ctx) { printf("[+] Restoring CCI\n"); if(ctx->ncsd_struct->CCI_FILE_STATUS == IS_S_TRIM){ printf("[!] Update Data has been removed, CCI cannot be restored\n"); return Fail; } if(TruncateFile_u64(ctx->cci_file.argument,ctx->ncsd_struct->MEDIA_SIZE) != 0){ printf("[!] Failed to Restore CCI\n"); return Fail; } FILE *cci = fopen(ctx->cci_file.argument,"rb+"); fseek_64(cci,ctx->ncsd_struct->CCI_IMAGE_SIZE,SEEK_SET); WriteDummyBytes(cci,0xff,(ctx->ncsd_struct->MEDIA_SIZE - ctx->ncsd_struct->CCI_IMAGE_SIZE)); fclose(cci); return 0; }
void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file) { fseek_64(file,offset,SEEK_SET); fread(outbuff,size,1,file); }
//IO Related void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output) { fseek_64(output,offset,SEEK_SET); fwrite(buffer,size,1,output); }
int GetNCSDData(CCI_CONTEXT *ctx) { // Opening CCI FILE *cci = fopen(ctx->cci_file.argument,"rb"); if(ctx->ncsd_struct == NULL) return Fail; memset(ctx->ncsd_struct,0x0,sizeof(NCSD_STRUCT)); // Getting File Size of CCI File ctx->ncsd_struct->CCI_FILE_SIZE = GetFileSize_u64(ctx->cci_file.argument); NCSD_HEADER header; CARD_INFO_HEADER card_info; DEV_CARD_INFO_HEADER dev_card_info; // Reading CCI Header Sections fseek(cci,0x0,SEEK_SET); fread(&ctx->ncsd_struct->signature,0x100,1,cci); fseek(cci,0x100,SEEK_SET); fread(&header,sizeof(NCSD_HEADER),1,cci); fseek(cci,0x200,SEEK_SET); fread(&card_info,sizeof(CARD_INFO_HEADER),1,cci); fseek(cci,0x1200,SEEK_SET); fread(&dev_card_info,sizeof(DEV_CARD_INFO_HEADER),1,cci); // Checking CCI Magic if(u8_to_u32(header.magic,BE) != NCSD_MAGIC){ printf("[!] NCSD File is corrupt\n"); goto fail; } // Checking Media Type to see if suitable for CCI if(header.partition_flags[MEDIA_TYPE_INDEX] != CARD1 && header.partition_flags[MEDIA_TYPE_INDEX] != CARD2){ printf("[!] NCSD File is not CCI\n"); goto fail; } // Determining Media Unit Size ctx->ncsd_struct->MEDIA_UNIT_SIZE = 0x200*pow(2,header.partition_flags[MEDIA_UNIT_SIZE]); // Media Size ctx->ncsd_struct->MEDIA_SIZE = u8_to_u32(header.media_size,LE)*(ctx->ncsd_struct->MEDIA_UNIT_SIZE); // Get Writable Address ctx->ncsd_struct->WRITABLE_ADDRESS = u8_to_u32(card_info.writable_address,LE)*(ctx->ncsd_struct->MEDIA_UNIT_SIZE); ctx->ncsd_struct->CARD2_MAX_SAVEDATA_SIZE = ctx->ncsd_struct->MEDIA_SIZE - ctx->ncsd_struct->WRITABLE_ADDRESS; // Getting CCI Image Size by summing total size of NCSD Partitions u32 tmp = u8_to_u32(header.offsetsize_table[0].offset,LE); for(int i = 0; i < 8; i++){ tmp += u8_to_u32(header.offsetsize_table[i].size,LE); if (i == 6) ctx->ncsd_struct->CCI_S_TRIM_SIZE = tmp*ctx->ncsd_struct->MEDIA_UNIT_SIZE; // The Update Partition is always in Partition 7, so this size doesn't include Partition 7 } ctx->ncsd_struct->CCI_IMAGE_SIZE = tmp*ctx->ncsd_struct->MEDIA_UNIT_SIZE; // Comparing CCI File Size, with calculated size ctx->ncsd_struct->CCI_FILE_STATUS = 0; if(ctx->ncsd_struct->CCI_FILE_SIZE == ctx->ncsd_struct->MEDIA_SIZE) ctx->ncsd_struct->CCI_FILE_STATUS = IS_FULL; else if(ctx->ncsd_struct->CCI_FILE_SIZE == ctx->ncsd_struct->CCI_IMAGE_SIZE) ctx->ncsd_struct->CCI_FILE_STATUS = IS_TRIM; else if(ctx->ncsd_struct->CCI_FILE_SIZE == ctx->ncsd_struct->CCI_S_TRIM_SIZE) ctx->ncsd_struct->CCI_FILE_STATUS = IS_S_TRIM; else { /* printf("CCI_FILE_SIZE = 0x%llx\n",ctx->ncsd_struct->CCI_FILE_SIZE); printf("MEDIA_SIZE = 0x%llx\n",ctx->ncsd_struct->MEDIA_SIZE); printf("CCI_IMAGE_SIZE = 0x%llx\n",ctx->ncsd_struct->CCI_IMAGE_SIZE); printf("CCI_S_TRIM_SIZE = 0x%llx\n",ctx->ncsd_struct->CCI_S_TRIM_SIZE); */ ctx->ncsd_struct->CCI_FILE_STATUS = IS_MALFORMED; goto fail; } // Storing Partition Offsets ctx->ncsd_struct->partition_count = 0; for(int i = 0; i < 8; i++){ ctx->ncsd_struct->partition_data[i].offset = u8_to_u32(header.offsetsize_table[i].offset,LE)*ctx->ncsd_struct->MEDIA_UNIT_SIZE; ctx->ncsd_struct->partition_data[i].size = u8_to_u32(header.offsetsize_table[i].size,LE)*ctx->ncsd_struct->MEDIA_UNIT_SIZE; if(ctx->ncsd_struct->partition_data[i].offset != 0 && ctx->ncsd_struct->partition_data[i].size != 0) ctx->ncsd_struct->partition_data[i].active = True; ctx->ncsd_struct->partition_data[i].title_id = u8_to_u64(header.partition_id_table[i],LE); ctx->ncsd_struct->partition_data[i].fs_type = header.partitions_fs_type[i]; ctx->ncsd_struct->partition_data[i].crypto_type = header.partitions_crypto_type[i]; // Checking to see if partition actually exists if(ctx->ncsd_struct->partition_data[i].offset >= ctx->ncsd_struct->CCI_FILE_SIZE){ ctx->ncsd_struct->partition_data[i].active = False; break; } if(ctx->ncsd_struct->partition_data[i].active) ctx->ncsd_struct->partition_count++; } // Exit if no CXI found if(!ctx->ncsd_struct->partition_data[0].active){ printf("[!] CXI Not Found\n"); goto fail; } // Getting Data from CXI NCCH_HEADER cxi_header; fseek_64(cci,(ctx->ncsd_struct->partition_data[0].offset + 0x100),SEEK_SET); fread(&cxi_header,sizeof(NCCH_HEADER),1,cci); if(u8_to_u32(cxi_header.magic,BE) != NCCH_MAGIC){ printf("[!] CXI is Corrupt\n"); goto fail; } // Must have ExeFS region to be CXI if((cxi_header.flags[MEDIA_TYPE_INDEX] & ExeFS) != ExeFS){ printf("[!] CXI Not Found\n"); goto fail; } ctx->ncsd_struct->partition_data[0].content_type = CXI; // Getting Product Code fseek_64(cci,(ctx->ncsd_struct->partition_data[0].offset + 0x150),SEEK_SET); fread(ctx->ncsd_struct->partition_data[0].product_code,16,1,cci); // Checking 'other flag' for crypto settings if((cxi_header.flags[OtherFlag] & 1) == 1){ if((cxi_header.flags[OtherFlag] & 4) == 4) ctx->ncsd_struct->partition_data[0].ncch_crypto_key = no_crypto; else if ((cxi_header.program_id[4] && 0x10) == 0x10) ctx->ncsd_struct->partition_data[0].ncch_crypto_key = fixed_system; else ctx->ncsd_struct->partition_data[0].ncch_crypto_key = fixed_zeros; } else if(!cxi_header.flags[OtherFlag]){ ctx->ncsd_struct->partition_data[0].ncch_crypto_key = secure_key; if(cxi_header.flags[SecureCryptoType2Flag]) ctx->ncsd_struct->partition_data[0].ncch_crypto_key = secure_key2; } // Getting SDK Version u32 CXI_Media_Unit_Size = 0x200*pow(2,cxi_header.flags[MEDIA_UNIT_SIZE]); u64 plain_region_offset = ctx->ncsd_struct->partition_data[0].offset + u8_to_u32(cxi_header.plain_region_offset,LE)*CXI_Media_Unit_Size; u64 plain_region_size = u8_to_u32(cxi_header.plain_region_size,LE)*CXI_Media_Unit_Size; int result = GetSDKVersion(cci,plain_region_offset,plain_region_size,ctx->ncsd_struct); // If that failed, attempt to guess SDK version if(result){ strcpy(ctx->ncsd_struct->SDK_PATCH,"Release"); memset(&ctx->ncsd_struct->SDK_VER,0,3); ctx->ncsd_struct->SDK_VER[0] = 1; if(header.partition_flags[MEDIA_CARD_DEVICE_OLD]) ctx->ncsd_struct->SDK_VER[0] = 2; if(header.partition_flags[MEDIA_CARD_DEVICE]) ctx->ncsd_struct->SDK_VER[0] = 3; if(u8_to_u32(cxi_header.logo_region_offset,LE) || u8_to_u32(cxi_header.logo_region_size,LE)) ctx->ncsd_struct->SDK_VER[0] = 5; if(cxi_header.flags[SecureCryptoType2Flag]) ctx->ncsd_struct->SDK_VER[0] = 6; } // Getting Data from remaining CFA partitions for(int i = 1; i < 8; i++){ u8 magic[4]; fseek_64(cci,(ctx->ncsd_struct->partition_data[i].offset + 0x100),SEEK_SET); fread(&magic,4,1,cci); if(u8_to_u32(magic,BE) == NCCH_MAGIC){ u8 flags[8]; u8 ProgramID[8]; fseek_64(cci,(ctx->ncsd_struct->partition_data[i].offset + 0x188),SEEK_SET); fread(&flags,8,1,cci); fseek_64(cci,(ctx->ncsd_struct->partition_data[i].offset + 0x118),SEEK_SET); fread(&ProgramID,8,1,cci); if( (flags[NCCH_Type] & ExeFS) != ExeFS && (flags[NCCH_Type] & RomFS) == RomFS ){ if((flags[NCCH_Type] & Manual) == Manual && (flags[NCCH_Type] & SystemUpdate) != SystemUpdate) ctx->ncsd_struct->partition_data[i].content_type = CFA_Manual; else if((flags[NCCH_Type] & Child) == Child) ctx->ncsd_struct->partition_data[i].content_type = CFA_DLPChild; else if((flags[NCCH_Type] & SystemUpdate) == SystemUpdate && (flags[NCCH_Type] & Manual) != Manual) ctx->ncsd_struct->partition_data[i].content_type = CFA_Update; else ctx->ncsd_struct->partition_data[i].content_type = CFA_Simple; } else if((flags[NCCH_Type] & ExeFS) == ExeFS) ctx->ncsd_struct->partition_data[i].content_type = CXI; else ctx->ncsd_struct->partition_data[i].content_type = _unknown; // Checking 'other flag' for crypto settings if((flags[OtherFlag] & 1) == 1){ if((flags[OtherFlag] & 4) == 4) ctx->ncsd_struct->partition_data[i].ncch_crypto_key = no_crypto; else if ((ProgramID[4] && 0x10) == 0x10) ctx->ncsd_struct->partition_data[i].ncch_crypto_key = fixed_system; else ctx->ncsd_struct->partition_data[i].ncch_crypto_key = fixed_zeros; } else if(!flags[OtherFlag]){ ctx->ncsd_struct->partition_data[i].ncch_crypto_key = secure_key; if(flags[SecureCryptoType2Flag]) ctx->ncsd_struct->partition_data[i].ncch_crypto_key = secure_key2; } fseek_64(cci,(ctx->ncsd_struct->partition_data[i].offset + 0x150),SEEK_SET); fread(ctx->ncsd_struct->partition_data[i].product_code,16,1,cci); } else ctx->ncsd_struct->partition_data[i].content_type = _unknown; } if(ctx->flags[info]) PrintNCSDHeaderData(ctx->ncsd_struct,&header,&card_info,&dev_card_info); if(ctx->flags[part_info]) PrintCCIPartitionData(ctx->ncsd_struct,&header,&card_info,&dev_card_info); fclose(cci); return 0; fail: fclose(cci); return Fail; }
int GetSDKVersion(FILE *cxi, u64 plain_region_offset, u64 plain_region_size, NCSD_STRUCT *ctx) { // Counting Strings in Plain Region int string_count = 0; fseek_64(cxi,plain_region_offset,SEEK_SET); while (ftell(cxi) <= (u32)(plain_region_offset+plain_region_size)){ if(fgetc(cxi) == '[') string_count++; } // Storing Plain Region Strings fseek_64(cxi,plain_region_offset,SEEK_SET); char tmp = '\0'; int j = 0; char MiddleWareString[string_count][100]; memset(&MiddleWareString,0,100*string_count*sizeof(char)); for(int i = 0; i < string_count; i++){ while(tmp != '[') tmp = fgetc(cxi); tmp = fgetc(cxi); while(tmp != ']') { MiddleWareString[i][j] = tmp; tmp = fgetc(cxi); j++; } MiddleWareString[i][j] = '\0'; j = 0; } //printf("Total MDW Strings: %d\n",string_count); // Checking Plain Region Strings int found_sdk_ver = 0; char SDK_VER[3][4]; char FW_VER[3][4]; for(int i = 0; i < string_count; i++){ //printf(" %s\n",MiddleWareString[i]); if(strncmp("SDK+NINTENDO:DEBUG",MiddleWareString[i],18) == 0) ctx->BUILD_TYPE = 1; else if(strncmp("SDK+NINTENDO:CTR_SDK-",MiddleWareString[i],21) == 0 && !found_sdk_ver){ found_sdk_ver = true; int set = 0; memset(&SDK_VER,0,4*3*sizeof(char)); int len = strlen(MiddleWareString[i]); for(int k = 21, ver_str = 0; k < len; k++){ //printf(" %c\n",MiddleWareString[i][k]); if(MiddleWareString[i][k] == '_'){ if(set < 3){ SDK_VER[set][ver_str] = '\0'; } else{ ctx->SDK_PATCH[ver_str] = '\0'; } ver_str = 0; set++; k++; } if(set < 3) SDK_VER[set][ver_str] = MiddleWareString[i][k]; else ctx->SDK_PATCH[ver_str] = MiddleWareString[i][k]; ver_str++; } } else if(strncmp("SDK+NINTENDO:Firmware-",MiddleWareString[i],22) == 0){ int set = 0; memset(&FW_VER,0,4*3*sizeof(char)); int len = strlen(MiddleWareString[i]); for(int k = 22, ver_str = 0; k < len; k++){ //printf(" %c\n",MiddleWareString[i][k]); if(MiddleWareString[i][k] == '_'){ FW_VER[set][ver_str] = '\0'; ver_str = 0; set++; k++; } FW_VER[set][ver_str] = MiddleWareString[i][k]; ver_str++; } } } if(!found_sdk_ver) return 1; if(strcmp(ctx->SDK_PATCH,"none") == 0) strcpy(ctx->SDK_PATCH,"Release"); for(int i = 0; i < 3; i++){ ctx->SDK_VER[i] = strtol(SDK_VER[i],NULL,10); } for(int i = 0; i < 3; i++){ ctx->FW_VER[i] = strtol(FW_VER[i],NULL,10); } return 0; }
int GetNCSDData(USER_CONTEXT *ctx, NCSD_STRUCT *ncsd_struct, FILE *ncsd) { if(ncsd_struct == NULL) return Fail; memset(ncsd_struct,0x0,sizeof(NCSD_STRUCT)); NCSD_HEADER header; CARD_INFO_HEADER card_info; DEV_CARD_INFO_HEADER dev_card_info; fseek(ncsd,0x0,SEEK_SET); fread(&ncsd_struct->signature,0x100,1,ncsd); fseek(ncsd,0x100,SEEK_SET); fread(&header,sizeof(NCSD_HEADER),1,ncsd); fseek(ncsd,0x200,SEEK_SET); fread(&card_info,sizeof(CARD_INFO_HEADER),1,ncsd); fseek(ncsd,0x1200,SEEK_SET); fread(&dev_card_info,sizeof(DEV_CARD_INFO_HEADER),1,ncsd); ctr_sha(&header,sizeof(NCSD_HEADER),ncsd_struct->ncsd_header_hash,CTR_SHA_256); if(u8_to_u32(header.magic,BE) != NCSD_MAGIC){ printf("[!] ROM is Corrupt\n"); return Fail; } ncsd_struct->sig_valid = ctr_rsa(ncsd_struct->ncsd_header_hash,ncsd_struct->signature,ctx->keys.NcsdCfa.n,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY); u32 media_size = ((header.partition_flags[6] + 1)*0x200); ncsd_struct->rom_size = u8_to_u32(header.rom_size,LE)*media_size; ncsd_struct->used_rom_size = 0; if(ncsd_struct->used_rom_size == 0){ u32 tmp = u8_to_u32(header.offsetsize_table[0].offset,LE); for(int i = 0; i < 8; i++){ tmp += u8_to_u32(header.offsetsize_table[i].size,LE); } ncsd_struct->used_rom_size = tmp*media_size; } for(int i = 0; i < 8; i++){ ncsd_struct->partition_data[i].offset = u8_to_u32(header.offsetsize_table[i].offset,LE)*media_size; ncsd_struct->partition_data[i].size = u8_to_u32(header.offsetsize_table[i].size,LE)*media_size; if(ncsd_struct->partition_data[i].offset != 0 && ncsd_struct->partition_data[i].size != 0) ncsd_struct->partition_data[i].active = True; ncsd_struct->partition_data[i].title_id = u8_to_u64(header.partition_id_table[i],LE); ncsd_struct->partition_data[i].fs_type = header.partitions_fs_type[i]; ncsd_struct->partition_data[i].crypto_type = header.partitions_crypto_type[i]; u8 magic[4]; fseek_64(ncsd,(ncsd_struct->partition_data[i].offset + 0x100),SEEK_SET); fread(&magic,4,1,ncsd); if(u8_to_u32(magic,BE) == NCCH_MAGIC){ u8 flags[8]; u8 flag_bool[8]; fseek_64(ncsd,(ncsd_struct->partition_data[i].offset + 0x188),SEEK_SET); fread(&flags,8,1,ncsd); resolve_flag(flags[5],flag_bool); if(flag_bool[1] == False && flag_bool[0] == True){ if(flag_bool[2] == False && flag_bool[3] == True) ncsd_struct->partition_data[i].content_type = CFA_Manual; else if(flag_bool[2] == True && flag_bool[3] == True) ncsd_struct->partition_data[i].content_type = CFA_DLPChild; else if(flag_bool[2] == True && flag_bool[3] == False) ncsd_struct->partition_data[i].content_type = CFA_Update; else ncsd_struct->partition_data[i].content_type = _unknown; } else if(flag_bool[1] == True) ncsd_struct->partition_data[i].content_type = CXI; else ncsd_struct->partition_data[i].content_type = _unknown; } else ncsd_struct->partition_data[i].content_type = _unknown; } if(u8_to_u64(card_info.cver_title_id,LE) == 0){ u8 stock_title_key[0x10] = {0x6E, 0xC7, 0x5F, 0xB2, 0xE2, 0xB4, 0x87, 0x46, 0x1E, 0xDD, 0xCB, 0xB8, 0x97, 0x11, 0x92, 0xBA}; if(memcmp(dev_card_info.TitleKey,stock_title_key,0x10) == 0) ncsd_struct->type = dev_external_SDK; else ncsd_struct->type = dev_internal_SDK; } else ncsd_struct->type = retail; /** if(ncsd_struct->type != retail){ u8 iv[16]; u8 key[16]; memset(&iv,0x0,16); memset(&key,0x0,16); //iv[0] = header.partition_flags[7]; //memcpy(iv+11,header.partition_flags,5); u8 tmp[16] = {0xB2, 0x57, 0xA7, 0xC0, 0x24, 0xC8, 0xC1, 0xB0, 0x75, 0x91, 0xC4, 0xC5, 0x1D, 0x96, 0x67, 0x4F}; memcpy(iv,tmp,16); memcpy(key,common_dpki_aesKey,16); ctr_aes_context aes; memset(&aes,0x0,sizeof(ctr_aes_context)); memdump(stdout,"ENC Title Key: ",dev_card_info.TitleKey,0x10); ctr_init_aes_cbc(&aes,key,iv,DEC); ctr_aes_cbc(&aes,dev_card_info.TitleKey,dev_card_info.TitleKey,0x10,DEC); memdump(stdout,"DEC Title Key: ",dev_card_info.TitleKey,0x10); } **/ /** for(int i = 0; i < 8; i++){ if(ncsd_struct->partition_data[i].active == True){ ncsd_struct->partition_data[i].sig_valid = VerifyNCCHSection(ctx,dev_card_info.TitleKey,ncsd_struct->partition_data[i].offset,ncsd); } } **/ ncsd_struct->valid = True; if(ctx->flags[info]) PrintNCSDData(ncsd_struct,&header,&card_info,&dev_card_info); return 0; }