int elf_ProcessHeader(elf_context *elf) { const elf_hdr *hdr = (const elf_hdr*)elf->file; /* Check conditions for valid CTR ELF */ if (u8_to_u32(hdr->magic, BE) != ELF_MAGIC) return NOT_ELF_FILE; if (hdr->bitFormat != elf_32_bit) return NOT_CTR_ARM_ELF; if (hdr->endianness != elf_little_endian) return NOT_CTR_ARM_ELF; if (u8_to_u16(hdr->targetArchitecture, LE) != elf_arm) return NOT_CTR_ARM_ELF; if (u8_to_u16(hdr->type, LE) != elf_executeable) return NON_EXECUTABLE_ELF; elf->phdrOffset = u8_to_u32(hdr->programHeaderTableOffset, LE); elf->segmentNum = u8_to_u16(hdr->programHeaderEntryCount, LE); elf->segments = calloc(elf->segmentNum, sizeof(elf_segment)); if (!elf->segments) { fprintf(stderr, "[ELF ERROR] Not enough memory\n"); return MEM_ERROR; } elf->shdrOffset = u8_to_u32(hdr->sectionHeaderTableOffset, LE); elf->shdrNameIndex = u8_to_u16(hdr->sectionHeaderNameEntryIndex, LE); elf->sectionNum = u8_to_u16(hdr->sectionHeaderEntryCount, LE); elf->sections = calloc(elf->sectionNum, sizeof(elf_section)); if (!elf->sections) { fprintf(stderr, "[ELF ERROR] Not enough memory\n"); return MEM_ERROR; } return 0; }
static int check (const uint8_t *input, size_t input_length, const uint32_t *expected, size_t expected_length) { size_t length; uint32_t *result; /* Test return conventions with resultbuf == NULL. */ result = u8_to_u32 (input, input_length, NULL, &length); if (!(result != NULL)) return 1; if (!(length == expected_length)) return 2; if (!(u32_cmp (result, expected, expected_length) == 0)) return 3; free (result); /* Test return conventions with resultbuf too small. */ if (expected_length > 0) { uint32_t *preallocated; length = expected_length - 1; preallocated = (uint32_t *) malloc (length * sizeof (uint32_t)); result = u8_to_u32 (input, input_length, preallocated, &length); if (!(result != NULL)) return 4; if (!(result != preallocated)) return 5; if (!(length == expected_length)) return 6; if (!(u32_cmp (result, expected, expected_length) == 0)) return 7; free (result); free (preallocated); } /* Test return conventions with resultbuf large enough. */ { uint32_t *preallocated; length = expected_length; preallocated = (uint32_t *) malloc (length * sizeof (uint32_t)); result = u8_to_u32 (input, input_length, preallocated, &length); if (!(result != NULL)) return 8; if (!(preallocated == NULL || result == preallocated)) return 9; if (!(length == expected_length)) return 10; if (!(u32_cmp (result, expected, expected_length) == 0)) return 11; free (preallocated); } return 0; }
void GetCertSigSectionSizes(u32 *SigSize, u32 *SigPadding, u8 *cert) { sig_types sig = (sig_types)u8_to_u32(cert,BE); switch(sig){ case RSA_4096_SHA1 : *SigSize = 0x200; *SigPadding = 0x3C; break; case RSA_2048_SHA1 : *SigSize = 0x100; *SigPadding = 0x3C; break; case ECC_SHA1 : *SigSize = 0x3C; *SigPadding = 0x40; break; case RSA_4096_SHA256 : *SigSize = 0x200; *SigPadding = 0x3C; break; case RSA_2048_SHA256 : *SigSize = 0x100; *SigPadding = 0x3C; break; case ECC_SHA256 : *SigSize = 0x3C; *SigPadding = 0x40; break; default : *SigSize = 0; *SigPadding = 0; break; } return; }
// Cert Sizes void GetCertSigSectionSizes(u32 *sign_size, u32 *sign_padlen, u8 *cert) { u32 sig = u8_to_u32(cert,BE); switch(sig){ case RSA_4096_SHA1 : *sign_size = 0x200; *sign_padlen = 0x3C; break; case RSA_2048_SHA1 : *sign_size = 0x100; *sign_padlen = 0x3C; break; case ECC_SHA1 : *sign_size = 0x3C; *sign_padlen = 0x40; break; case RSA_4096_SHA256 : *sign_size = 0x200; *sign_padlen = 0x3C; break; case RSA_2048_SHA256 : *sign_size = 0x100; *sign_padlen = 0x3C; break; case ECC_SHA256 : *sign_size = 0x3C; *sign_padlen = 0x40; break; default : *sign_size = 0; *sign_padlen = 0; break; } return; }
void GetCUPVersion(/*char *FW_STRING, */CARD_INFO_HEADER *card_info) { u8 MAJOR = 0; u8 MINOR = 0; u8 BUILD = 0; char REGION_CHAR = ' '; u16 CVer_ver = u8_to_u16(card_info->cver_title_version,LE); u32 CVer_UID = u8_to_u32(card_info->cver_title_id,LE); switch(CVer_UID){ case EUR_UPDATE : REGION_CHAR = 'E'; break; case JPN_UPDATE : REGION_CHAR = 'J'; break; case USA_UPDATE : REGION_CHAR = 'U'; break; case CHN_UPDATE : REGION_CHAR = 'C'; break; case KOR_UPDATE : REGION_CHAR = 'K'; break; case TWN_UPDATE : REGION_CHAR = 'T'; break; } switch(CVer_ver){ case 3088 : MAJOR = 3; MINOR = 0; BUILD = 0; break; default ://This tends to work most of the time, use above for manual overrides MAJOR = (CVer_ver & 0x7f00) >> 10; MINOR = (CVer_ver & 0x3f0) >> 4; //BUILD = CVer_ver & 0xf; break; } printf(" CUP Version: %d.%d.%d%c\n",MAJOR,MINOR,BUILD,REGION_CHAR); }
void GetMin3DSFW(char *FW_STRING, CARD_INFO_HEADER *card_info) { u8 MAJOR = 0; u8 MINOR = 0; u8 BUILD = 0; char REGION_CHAR = 'X'; u16 CVer_ver = u8_to_u16(card_info->cver_title_version,LE); u32 CVer_UID = u8_to_u32(card_info->cver_title_id,LE); switch(CVer_UID){ case EUR_ROM : REGION_CHAR = 'E'; break; case JPN_ROM : REGION_CHAR = 'J'; break; case USA_ROM : REGION_CHAR = 'U'; break; case CHN_ROM : REGION_CHAR = 'C'; break; case KOR_ROM : REGION_CHAR = 'K'; break; case TWN_ROM : REGION_CHAR = 'T'; break; } switch(CVer_ver){ case 3088 : MAJOR = 3; MINOR = 0; BUILD = 0; break; default : MAJOR = CVer_ver/1024; MINOR = (CVer_ver - 1024*(CVer_ver/1024))/0x10; break;//This tends to work 98% of the time, use above for manual overides } sprintf(FW_STRING,"%d.%d.%d-X%c",MAJOR,MINOR,BUILD,REGION_CHAR); }
void PrintNCSDHeaderData(NCSD_STRUCT *ctx, NCSD_HEADER *header, CARD_INFO_HEADER *card_info, DEV_CARD_INFO_HEADER *dev_card_info) { printf("[+] CCI Image Details\n"); u8 CardDevice = header->partition_flags[MEDIA_CARD_DEVICE_OLD] + header->partition_flags[MEDIA_CARD_DEVICE]; switch (header->partition_flags[MEDIA_TYPE_INDEX]){ case INNER_DEVICE: printf(" Media Type: INTERNAL_DEVICE\n"); break; case CARD1: printf(" Media Type: CARD1\n"); break; case CARD2: printf(" Media Type: CARD2\n > Writable Region:\n - Offset: 0x%llx\n - Size: 0x%llx (%lld MB)\n",ctx->WRITABLE_ADDRESS,ctx->CARD2_MAX_SAVEDATA_SIZE,(ctx->CARD2_MAX_SAVEDATA_SIZE/MB)); break; case EXTENDED_DEVICE: printf(" Media Type: EXTENDED_DEVICE\n"); break; } GetCHIPFullSize(ctx->MEDIA_SIZE,ctx->type); GetCCIDataSize(ctx->CCI_IMAGE_SIZE,ctx->type); GetCCIFileStatus(ctx->CCI_FILE_SIZE,ctx->CCI_FILE_STATUS,ctx->type); switch (CardDevice){ case CARD_DEVICE_NOR_FLASH: printf(" Additional Device: EEPROM\n"); break; case CARD_DEVICE_NONE: printf(" Additional Device: None\n"); break; case CARD_DEVICE_BT: printf(" Additional Device: BT\n"); break; } printf(" Partition Count: %d\n",ctx->partition_count); if(u8_to_u64(card_info->cver_title_id,LE) && u8_to_u16(card_info->cver_title_version,LE)){ //printf("CVer Title ID: %016llx\n",u8_to_u64(card_info->cver_title_id,LE)); //printf("CVer Title Ver: v%d\n",u8_to_u16(card_info->cver_title_version,LE)); GetCUPVersion(card_info); } if(!header->partition_flags[MEDIA_6X_SAVE_CRYPTO] && !header->partition_flags[MEDIA_CARD_DEVICE] && !header->partition_flags[MEDIA_CARD_DEVICE_OLD]){ printf(" Save Crypto: Repeating CTR Fail\n"); } else if(!header->partition_flags[MEDIA_6X_SAVE_CRYPTO] && (header->partition_flags[MEDIA_CARD_DEVICE] || header->partition_flags[MEDIA_CARD_DEVICE_OLD])){ printf(" Save Crypto: 2.2.0 KeyY Method\n"); } else if(header->partition_flags[MEDIA_6X_SAVE_CRYPTO] == 1 && !header->partition_flags[MEDIA_CARD_DEVICE_OLD]){ if(!header->partition_flags[MEDIA_CARD_DEVICE]){ printf(" Save Crypto: 2.2.0 KeyY Method\n"); } else if(header->partition_flags[MEDIA_CARD_DEVICE]){ printf(" Save Crypto: 6.0.0 KeyY Method\n"); } } printf("[+] CXI Partition\n"); printf(" Product Code: %.16s\n",card_info->partition_0_header.product_code); printf(" Company Code: %.2s\n",card_info->partition_0_header.maker_code); u32 UniqueID = u8_to_u32(&card_info->partition_0_header.program_id[1],LE)&0xffffff; printf(" Unique ID: %05x\n",UniqueID); printf(" Build Type: %s\n",ctx->BUILD_TYPE? "Debug or Development" : "Release"); printf(" SDK Version: %d.%d.%d %s\n",ctx->SDK_VER[0],ctx->SDK_VER[1],ctx->SDK_VER[2],ctx->SDK_PATCH); if(ctx->FW_VER[0] || ctx->FW_VER[1]) printf(" Req. Kernel Version: %d.%d-%d\n",ctx->FW_VER[0],ctx->FW_VER[1],ctx->FW_VER[2]); printf("[+] CFA Partitions\n"); for(int i = 1; i < 8; i++){ if(i == 1) printf(" E-Manual: %s\n",ctx->partition_data[i].active? "Yes" : "No"); else if(i == 2) printf(" DLP Child: %s\n",ctx->partition_data[i].active? "Yes" : "No"); else if(i == 7) printf(" Update Data: %s\n",ctx->partition_data[i].active? "Yes" : "No"); else{ if(ctx->partition_data[i].active) printf(" CFA %d: %s\n",i,ctx->partition_data[i].active? "Yes" : "No"); } } }
u32 GetExeFsSectionOffset(char *section, u8 *ExeFs) { exefs_hdr *hdr = (exefs_hdr*) ExeFs; for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){ if(strncmp(hdr->fileHdr[i].name,section,8) == 0){ return u8_to_u32(hdr->fileHdr[i].offset,LE) + sizeof(exefs_hdr); } } return 0; }
bool VerifyCert(u8 *cert, u8 *pubk) { if(!GetCertHdr(cert)) return false; u8 *signature = (cert+sizeof(u32)); u8 *data = (u8*)GetCertHdr(cert); u32 datasize = sizeof(cert_hdr) + GetCertPubkSectionSize(GetCertPubkType(cert)); return RsaSignVerify(data,datasize,signature,pubk,NULL,u8_to_u32(cert,BE),CTR_RSA_VERIFY); }
u8* GetExeFsSection(char *section, u8 *ExeFs) { exefs_hdr *hdr = (exefs_hdr*) ExeFs; for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){ if(strncmp(hdr->fileHdr[i].name,section,8) == 0){ u32 offset = u8_to_u32(hdr->fileHdr[i].offset,LE) + sizeof(exefs_hdr); return (u8*)(ExeFs+offset); } } return NULL; }
// Pubk pubk_types GetCertPubkType(u8 *cert) { u32 SigSize = 0; u32 SigPadding = 0; GetCertSigSectionSizes(&SigSize,&SigPadding,cert); if(!SigSize || !SigPadding) return 0; Cert_Struct *certcore = (Cert_Struct*)(cert+4+SigSize+SigPadding); return (pubk_types)u8_to_u32(certcore->KeyType,BE); }
u32 GetCertSize(u8 *cert) { u32 SigSize = 0; u32 SigPadding = 0; GetCertSigSectionSizes(&SigSize,&SigPadding,cert); if(!SigSize || !SigPadding) return 0; Cert_Struct *certcore = (Cert_Struct*)(cert+4+SigSize+SigPadding); u32 PubKSectionSize = GetCertPubkSectionSize((pubk_types)u8_to_u32(certcore->KeyType,BE)); return (4+SigSize+SigPadding+sizeof(Cert_Struct)+PubKSectionSize); }
void elf_PopulateSegments(elf_context *elf) { const elf_phdr *phdr = (const elf_phdr *)(elf->file + elf->phdrOffset); for (int i = 0; i < elf->segmentNum; i++) { elf->segments[i].type = u8_to_u32(phdr[i].type, LE); elf->segments[i].flags = u8_to_u32(phdr[i].flags, LE); elf->segments[i].fileOffset = u8_to_u32(phdr[i].offset, LE); elf->segments[i].fileSize = u8_to_u32(phdr[i].filesz, LE); elf->segments[i].ptr = elf->file + elf->segments[i].fileOffset; elf->segments[i].pAddr = u8_to_u32(phdr[i].paddr, LE); elf->segments[i].vAddr = u8_to_u32(phdr[i].vaddr, LE); elf->segments[i].memSize = u8_to_u32(phdr[i].memsz, LE); elf->segments[i].alignment = u8_to_u32(phdr[i].align, LE); } }
void elf_PopulateSections(elf_context *elf) { const elf_shdr *shdr = (const elf_shdr *)(elf->file + elf->shdrOffset); const char *nameTable = (const char*)(elf->file + u8_to_u32(shdr[elf->shdrNameIndex].offset, LE)); for (int i = 0; i < elf->sectionNum; i++) { elf->sections[i].name = nameTable + u8_to_u32(shdr[i].name, LE); elf->sections[i].type = u8_to_u32(shdr[i].type, LE); elf->sections[i].flags = u8_to_u32(shdr[i].flags, LE); elf->sections[i].fileOffset = u8_to_u32(shdr[i].offset, LE); elf->sections[i].size = u8_to_u32(shdr[i].size, LE); elf->sections[i].ptr = elf->file + elf->sections[i].fileOffset; elf->sections[i].vAddr = u8_to_u32(shdr[i].addr, LE); elf->sections[i].alignment = u8_to_u32(shdr[i].addralign, LE); } }
bool VerifyCert(u8 *cert, u8 *pubk) { u32 SigSize = 0; u32 SigPadding = 0; GetCertSigSectionSizes(&SigSize,&SigPadding,cert); if(!SigSize || !SigPadding) return 0; u8 *signature = (cert+4); u8 *data = (cert+4+SigSize+SigPadding); u32 datasize = sizeof(Cert_Struct) + GetCertPubkSectionSize(GetCertPubkType(cert)); int result = ctr_sig(data,datasize,signature,pubk,NULL,u8_to_u32(cert,BE),CTR_RSA_VERIFY); if(result == 0) return true; else return false; }
int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx) { ctx->ImportRomfsBinary = true; ctx->romfsSize = ncchset->componentFilePtrs.romfsSize; ctx->romfsBinary = ncchset->componentFilePtrs.romfs; ivfc_hdr *hdr = calloc(1,sizeof(ivfc_hdr)); ReadFile64(hdr,sizeof(ivfc_hdr),0,ctx->romfsBinary); if(memcmp(hdr->magic,"IVFC",4) != 0){ fprintf(stderr,"[ROMFS ERROR] Invalid RomFS Binary.\n"); return INVALID_ROMFS_FILE; } ctx->romfsHeaderSize = align(sizeof(ivfc_hdr),0x10) + (u64)u8_to_u32(hdr->masterHashSize,LE); return 0; }
static inline u32 dispatch_t207(t207 a208, u8 a209) { return u8_to_u32(a209); }
/** * gnutls_utf8_password_normalize: * @password: contain the UTF-8 formatted password * @plen: the length of the provided password * @out: the result in an null-terminated allocated string * @flags: should be zero * * This function will convert the provided UTF-8 password according * to the normalization rules in RFC7613. * * If the flag %GNUTLS_UTF8_IGNORE_ERRS is specified, any UTF-8 encoding * errors will be ignored, and in that case the output will be a copy of the input. * * Returns: %GNUTLS_E_INVALID_UTF8_STRING on invalid UTF-8 data, or 0 on success. * * Since: 3.5.7 **/ int gnutls_utf8_password_normalize(const unsigned char *password, unsigned plen, gnutls_datum_t *out, unsigned flags) { size_t ucs4_size = 0, nrm_size = 0; size_t final_size = 0; uint8_t *final = NULL; uint32_t *ucs4 = NULL; uint32_t *nrm = NULL; uint8_t *nrmu8 = NULL; int ret; if (plen == 0) { out->data = (uint8_t*)gnutls_strdup(""); out->size = 0; if (out->data == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); return 0; } /* check for invalid UTF-8 */ if (u8_check((uint8_t*)password, plen) != NULL) { gnutls_assert(); if (flags & GNUTLS_UTF8_IGNORE_ERRS) { raw_copy: out->data = gnutls_malloc(plen+1); if (out->data == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); out->size = plen; memcpy(out->data, password, plen); out->data[plen] = 0; return 0; } else { return GNUTLS_E_INVALID_UTF8_STRING; } } /* convert to UTF-32 */ ucs4 = u8_to_u32((uint8_t*)password, plen, NULL, &ucs4_size); if (ucs4 == NULL) { gnutls_assert(); ret = GNUTLS_E_PARSING_ERROR; goto fail; } ret = check_for_valid_freeformclass(ucs4, ucs4_size); if (ret < 0) { gnutls_assert(); if (flags & GNUTLS_UTF8_IGNORE_ERRS) { free(ucs4); goto raw_copy; } if (ret == GNUTLS_E_INVALID_UTF8_STRING) ret = GNUTLS_E_INVALID_PASSWORD_STRING; goto fail; } /* normalize to NFC */ nrm = u32_normalize(UNINORM_NFC, ucs4, ucs4_size, NULL, &nrm_size); if (nrm == NULL) { gnutls_assert(); ret = GNUTLS_E_INVALID_PASSWORD_STRING; goto fail; } /* convert back to UTF-8 */ final_size = 0; nrmu8 = u32_to_u8(nrm, nrm_size, NULL, &final_size); if (nrmu8 == NULL) { gnutls_assert(); ret = GNUTLS_E_INVALID_PASSWORD_STRING; goto fail; } /* copy to output with null terminator */ final = gnutls_malloc(final_size+1);
void PrintNCSDData(NCSD_STRUCT *ctx, NCSD_HEADER *header, CARD_INFO_HEADER *card_info, DEV_CARD_INFO_HEADER *dev_card_info) { if(ctx->valid != True){ printf("[!] NCSD Corrupt\n"); return; } printf("[+] NCSD\n"); switch(ctx->sig_valid){ case Good : memdump(stdout,"Signature(Good): ",ctx->signature,0x100); break; case Fail : memdump(stdout,"Signature(Fail): ",ctx->signature,0x100); break; case NotChecked: memdump(stdout,"Signature: ",ctx->signature,0x100); break; } switch(ctx->type){ case retail : printf("Target: Retail/Production\n"); printf("CVer Title ID: %016llx\n",u8_to_u64(card_info->cver_title_id,LE)); printf("CVer Title Ver: v%d\n",u8_to_u16(card_info->cver_title_version,LE)); char *FW_STRING = malloc(10); memset(FW_STRING,0,10); GetMin3DSFW(FW_STRING,card_info); printf("Min 3DS Firm: %s\n",FW_STRING); _free(FW_STRING); break; case dev_internal_SDK : printf("Target: Debug/Development\n"); printf("SDK Type: Nintendo Internal SDK\n"); memdump(stdout,"Title Key: ",dev_card_info->TitleKey,0x10); break; case dev_external_SDK : printf("Target: Debug/Development\n"); printf("SDK Type: Nintendo 3RD Party SDK\n"); memdump(stdout,"Title Key: ",dev_card_info->TitleKey,0x10); break; } if(ctx->rom_size >= GB){ printf("ROM Cart Size: %lld GB",ctx->rom_size/GB); printf(" (%lld Gbit)\n",(ctx->rom_size/GB)*8); } else{ printf("ROM Cart Size: %lld MB",ctx->rom_size/MB); u32 tmp = (ctx->rom_size/MB)*8; if(tmp >= 1024) printf(" (%d Gbit)\n",tmp/1024); else printf(" (%d Mbit)\n",tmp); } if(ctx->used_rom_size >= MB){ printf("ROM Used Size: %lld MB",ctx->used_rom_size/MB); printf(" (0x%llx bytes)\n",ctx->used_rom_size); } else if(ctx->used_rom_size >= KB){ printf("ROM Used Size: %lld KB",ctx->used_rom_size/KB); printf(" (0x%llx bytes)\n",ctx->used_rom_size); } printf("NCSD Title ID: %016llx\n",u8_to_u64(header->title_id,LE)); memdump(stdout,"ExHeader Hash: ",header->exheader_hash,0x20); printf("AddHeader Size: 0x%x\n",u8_to_u32(header->additional_header_size,LE)); printf("Sector 0 Offset: 0x%x\n",u8_to_u32(header->sector_zero_offset,LE)); memdump(stdout,"Flags: ",header->partition_flags,8); printf("\n"); for(int i = 0; i < 8; i++){ if(ctx->partition_data[i].active == True){ printf("Partition %d\n",i); printf(" Title ID: %016llx\n",ctx->partition_data[i].title_id); printf(" Content Type: "); switch(ctx->partition_data[i].content_type){ case _unknown : printf("Unknown\n"); break; case CXI : printf("Application\n"); break; case CFA_Manual : printf("Electronic Manual\n"); break; case CFA_DLPChild : printf("Download Play Child\n"); break; case CFA_Update : printf("Software Update Partition\n"); break; } printf(" FS Type: %x\n",ctx->partition_data[i].fs_type); printf(" Crypto Type: %x\n",ctx->partition_data[i].crypto_type); printf(" Offset: 0x%x\n",ctx->partition_data[i].offset); printf(" Size: 0x%x\n",ctx->partition_data[i].size); printf("\n"); } } }
void LazyText::setText(std::string new_text) { setText(u8_to_u32(new_text)); }
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 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; }
int GetNcchInfo(ncch_info *info, ncch_hdr *hdr) { clrmem(info, sizeof(ncch_info)); info->titleId = u8_to_u64(hdr->titleId,LE); info->programId = u8_to_u64(hdr->programId,LE); u32 block_size = GetNcchBlockSize(hdr); info->formatVersion = u8_to_u16(hdr->formatVersion,LE); if(!IsCfa(hdr)){ info->exhdrOffset = sizeof(ncch_hdr); info->exhdrSize = u8_to_u32(hdr->exhdrSize,LE); info->acexOffset = (info->exhdrOffset + info->exhdrSize); info->acexSize = sizeof(access_descriptor); info->plainRegionOffset = (u64)(u8_to_u32(hdr->plainRegionOffset,LE)*block_size); info->plainRegionSize = (u64)(u8_to_u32(hdr->plainRegionSize,LE)*block_size); } info->logoOffset = (u64)(u8_to_u32(hdr->logoOffset,LE)*block_size); info->logoSize = (u64)(u8_to_u32(hdr->logoSize,LE)*block_size); info->exefsOffset = (u64)(u8_to_u32(hdr->exefsOffset,LE)*block_size); info->exefsSize = (u64)(u8_to_u32(hdr->exefsSize,LE)*block_size); info->exefsHashDataSize = (u64)(u8_to_u32(hdr->exefsHashSize,LE)*block_size); info->romfsOffset = (u64) (u8_to_u32(hdr->romfsOffset,LE)*block_size); info->romfsSize = (u64) (u8_to_u32(hdr->romfsSize,LE)*block_size); info->romfsHashDataSize = (u64)(u8_to_u32(hdr->romfsHashSize,LE)*block_size); return 0; }
u64 GetNcchSize(ncch_hdr* hdr) { return (u64)u8_to_u32(hdr->ncchSize,LE) * (u64)GetNcchBlockSize(hdr); }
int main () { /* Empty string. */ ASSERT (check (NULL, 0, NULL, 0) == 0); /* Simple string. */ { /* "Grüß Gott. Здравствуйте! x=(-b±sqrt(b²-4ac))/(2a) 日本語,中文,한글" */ static const uint8_t input[] = { 'G', 'r', 0xC3, 0xBC, 0xC3, 0x9F, ' ', 'G', 'o', 't', 't', '.', ' ', 0xD0, 0x97, 0xD0, 0xB4, 0xD1, 0x80, 0xD0, 0xB0, 0xD0, 0xB2, 0xD1, 0x81, 0xD1, 0x82, 0xD0, 0xB2, 0xD1, 0x83, 0xD0, 0xB9, 0xD1, 0x82, 0xD0, 0xB5, '!', ' ', 'x', '=', '(', '-', 'b', 0xC2, 0xB1, 's', 'q', 'r', 't', '(', 'b', 0xC2, 0xB2, '-', '4', 'a', 'c', ')', ')', '/', '(', '2', 'a', ')', ' ', ' ', 0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE8, 0xAA, 0x9E, ',', 0xE4, 0xB8, 0xAD, 0xE6, 0x96, 0x87, ',', 0xED, 0x95, 0x9C, 0xEA, 0xB8, 0x80, '\n' }; static const uint32_t expected[] = { 'G', 'r', 0x00FC, 0x00DF, ' ', 'G', 'o', 't', 't', '.', ' ', 0x0417, 0x0434, 0x0440, 0x0430, 0x0432, 0x0441, 0x0442, 0x0432, 0x0443, 0x0439, 0x0442, 0x0435, '!', ' ', 'x', '=', '(', '-', 'b', 0x00B1, 's', 'q', 'r', 't', '(', 'b', 0x00B2, '-', '4', 'a', 'c', ')', ')', '/', '(', '2', 'a', ')', ' ', ' ', 0x65E5, 0x672C, 0x8A9E, ',', 0x4E2D, 0x6587, ',', 0xD55C, 0xAE00, '\n' }; ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0); } /* String with characters outside the BMP. */ { static const uint8_t input[] = { '-', '(', 0xF0, 0x9D, 0x94, 0x9E, 0xC3, 0x97, 0xF0, 0x9D, 0x94, 0x9F, ')', '=', 0xF0, 0x9D, 0x94, 0x9F, 0xC3, 0x97, 0xF0, 0x9D, 0x94, 0x9E }; static const uint32_t expected[] = { '-', '(', 0x1D51E, 0x00D7, 0x1D51F, ')', '=', 0x1D51F, 0x00D7, 0x1D51E }; ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0); } /* Invalid input. */ { static const uint8_t input[] = { 'x', 0xC2, 0xC3, 'y' }; #if 0 /* Currently invalid input is rejected, not accommodated. */ static const uint32_t expected[] = { 'x', 0xFFFD, 0xFFFD, 'y' }; ASSERT (check (input, SIZEOF (input), expected, SIZEOF (expected)) == 0); #else size_t length; uint32_t *result; uint32_t preallocated[10]; /* Test return conventions with resultbuf == NULL. */ result = u8_to_u32 (input, SIZEOF (input), NULL, &length); ASSERT (result == NULL); ASSERT (errno == EILSEQ); /* Test return conventions with resultbuf too small. */ length = 1; result = u8_to_u32 (input, SIZEOF (input), preallocated, &length); ASSERT (result == NULL); ASSERT (errno == EILSEQ); /* Test return conventions with resultbuf large enough. */ length = SIZEOF (preallocated); result = u8_to_u32 (input, SIZEOF (input), preallocated, &length); ASSERT (result == NULL); ASSERT (errno == EILSEQ); #endif } return 0; }
// Pubk pubk_types GetCertPubkType(u8 *cert) { cert_hdr *hdr = GetCertHdr(cert); return (pubk_types)u8_to_u32(hdr->keyType,BE); }
int FinaliseNcch(ncch_settings *set) { u8 *ncch = set->out->buffer; ncch_hdr *hdr = (ncch_hdr*)ncch; u8 *exhdr = (u8*)(ncch + set->cryptoDetails.exhdrOffset); u8 *acexDesc = (u8*)(ncch + set->cryptoDetails.acexOffset); u8 *logo = (u8*)(ncch + set->cryptoDetails.logoOffset); u8 *exefs = (u8*)(ncch + set->cryptoDetails.exefsOffset); u8 *romfs = (u8*)(ncch + set->cryptoDetails.romfsOffset); // Taking Hashes if(set->cryptoDetails.exhdrSize) ShaCalc(exhdr,set->cryptoDetails.exhdrSize,hdr->exhdrHash,CTR_SHA_256); if(set->cryptoDetails.logoSize) ShaCalc(logo,set->cryptoDetails.logoSize,hdr->logoHash,CTR_SHA_256); if(set->cryptoDetails.exefsHashDataSize) ShaCalc(exefs,set->cryptoDetails.exefsHashDataSize,hdr->exefsHash,CTR_SHA_256); if(set->cryptoDetails.romfsHashDataSize) ShaCalc(romfs,set->cryptoDetails.romfsHashDataSize,hdr->romfsHash,CTR_SHA_256); // Signing NCCH int sig_result = Good; if(set->options.IsCfa) sig_result = SignCFA(hdr,set->keys); else sig_result = SignCXI(hdr,set->keys); if(sig_result != Good){ fprintf(stderr,"[NCCH ERROR] Failed to sign %s header\n",set->options.IsCfa ? "CFA" : "CXI"); return sig_result; } // Crypting NCCH\n"); if(IsNcchEncrypted(hdr)){ if(!SetNcchKeys(set->keys, hdr)){ fprintf(stderr,"[NCCH ERROR] Failed to load NCCH AES key\n"); return -1; } if(set->options.verbose){ printf("[NCCH] NCCH AES keys:\n"); memdump(stdout," > key0: ",set->keys->aes.ncchKey0,AES_128_KEY_SIZE); memdump(stdout," > key1: ",set->keys->aes.ncchKey1,AES_128_KEY_SIZE); } // Crypting Exheader/AcexDesc if(set->cryptoDetails.exhdrSize){ CryptNcchRegion(exhdr,set->cryptoDetails.exhdrSize,0x0,set->cryptoDetails.titleId,set->keys->aes.ncchKey0,ncch_exhdr); CryptNcchRegion(acexDesc,set->cryptoDetails.acexSize,set->cryptoDetails.exhdrSize,set->cryptoDetails.titleId,set->keys->aes.ncchKey0,ncch_exhdr); } // Crypting ExeFs Files if(set->cryptoDetails.exefsSize){ exefs_hdr *exefsHdr = (exefs_hdr*)exefs; for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){ u8 *key = NULL; if(strncmp(exefsHdr->fileHdr[i].name,"icon",8) == 0 || strncmp(exefsHdr->fileHdr[i].name,"banner",8) == 0) key = set->keys->aes.ncchKey0; else key = set->keys->aes.ncchKey1; u32 offset = u8_to_u32(exefsHdr->fileHdr[i].offset,LE) + sizeof(exefs_hdr); u32 size = u8_to_u32(exefsHdr->fileHdr[i].size,LE); if(size) CryptNcchRegion((exefs+offset),align(size,set->options.blockSize),offset,set->cryptoDetails.titleId,key,ncch_exefs); } // Crypting ExeFs Header CryptNcchRegion(exefs,sizeof(exefs_hdr),0x0,set->cryptoDetails.titleId,set->keys->aes.ncchKey0,ncch_exefs); } // Crypting RomFs if(set->cryptoDetails.romfsSize) CryptNcchRegion(romfs,set->cryptoDetails.romfsSize,0x0,set->cryptoDetails.titleId,set->keys->aes.ncchKey1,ncch_romfs); } return 0; }