diff --git a/makerom/Makefile b/makerom/Makefile index 36c952e..5293084 100644 --- a/makerom/Makefile +++ b/makerom/Makefile @@ -1,8 +1,8 @@ # Makerom Sources -UTILS_OBJS = utils.o dir.o utf.o keyset.o titleid.o -CIA_OBJS = cia.o cia_read.o certs.o tik.o tmd.o tmd_read.o -NCCH_OBJS = ncch.o exheader.o accessdesc.o exefs.o elf.o romfs.o romfs_import.o romfs_binary.o -NCSD_OBJS = ncsd.o +UTILS_OBJS = utils.o ctr_utils.o dir.o utf.o keyset.o titleid.o +CIA_OBJS = cia.o certs.o tik.o tmd.o +NCCH_OBJS = ncch.o exheader.o accessdesc.o exefs.o elf.o romfs.o romfs_import.o romfs_gen.o +NCSD_OBJS = ncsd.o cardinfo.o SETTINGS_OBJS = user_settings.o rsf_settings.o LIB_API_OBJS = crypto.o yaml_parser.o blz.o @@ -21,7 +21,7 @@ CC = gcc # MAKEROM Build Settings MAKEROM_BUILD_FLAGS = #-DDEBUG VER_MAJOR = 0 -VER_MINOR = 10 +VER_MINOR = 11 OUTPUT = makerom main: build diff --git a/makerom/accessdesc.c b/makerom/accessdesc.c index 8c316c5..f02d9f1 100644 --- a/makerom/accessdesc.c +++ b/makerom/accessdesc.c @@ -1,13 +1,11 @@ #include "lib.h" -#include "ncch.h" -#include "exheader.h" +#include "ncch_build.h" +#include "exheader_build.h" #include "accessdesc.h" -#include "polarssl/base64.h" - -#include "desc_presets.h" -#include "desc_dev_sigdata.h" -#include "desc_prod_sigdata.h" +#include "desc/presets.h" +#include "desc/dev_sigdata.h" +#include "desc/prod_sigdata.h" const int RSF_RSA_DATA_LEN = 344; const int RSF_DESC_DATA_LEN = 684; @@ -19,20 +17,16 @@ int accessdesc_GetSignFromPreset(exheader_settings *exhdrset); void accessdesc_GetPresetData(u8 **desc, u8 **accessDesc, u8 **depList, keys_struct *keys); void accessdesc_GetPresetSigData(u8 **accessDescSig, u8 **cxiPubk, u8 **cxiPvtk, keys_struct *keys); -bool IsValidB64Char(char chr); -u32 b64_strlen(char *str); -void b64_strcpy(char *dst, char *src); - int set_AccessDesc(exheader_settings *exhdrset) { - if(exhdrset->useAccessDescPreset) + if(exhdrset->useAccessDescPreset) // Use AccessDesc Template return accessdesc_GetSignFromPreset(exhdrset); else if(exhdrset->rsf->CommonHeaderKey.Found) // Keydata exists in RSF return accessdesc_GetSignFromRsf(exhdrset); else if(!exhdrset->keys->rsa.requiresPresignedDesc) // Else if The AccessDesc can be signed with key return accessdesc_SignWithKey(exhdrset); else{ // No way the access desc signature can be 'obtained' - fprintf(stderr,"[EXHEADER ERROR] Current keyset cannot sign AccessDesc, please appropriatly setup RSF, or specify a preset with -accessdesc\n"); + fprintf(stderr,"[ACEXDESC ERROR] Current keyset cannot sign AccessDesc, please appropriately set-up RSF, or specify a preset with \"-desc\"\n"); return CANNOT_SIGN_ACCESSDESC; } } @@ -65,7 +59,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset) { /* Yaml Option Sanity Checks */ if(!exhdrset->rsf->CommonHeaderKey.Found){ - fprintf(stderr,"[EXHEADER ERROR] RSF Section \"CommonHeaderKey\" not found\n"); + fprintf(stderr,"[ACEXDESC ERROR] RSF Section \"CommonHeaderKey\" not found\n"); return COMMON_HEADER_KEY_NOT_FOUND; } @@ -74,7 +68,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset) return COMMON_HEADER_KEY_NOT_FOUND; } if(b64_strlen(exhdrset->rsf->CommonHeaderKey.D) != RSF_RSA_DATA_LEN){ - fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/D\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.D)); + fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/D\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.D)); return COMMON_HEADER_KEY_NOT_FOUND; } @@ -83,7 +77,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset) return COMMON_HEADER_KEY_NOT_FOUND; } if(b64_strlen(exhdrset->rsf->CommonHeaderKey.Modulus) != RSF_RSA_DATA_LEN){ - fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Modulus\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.Modulus)); + fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/Modulus\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.Modulus)); return COMMON_HEADER_KEY_NOT_FOUND; } @@ -92,7 +86,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset) return COMMON_HEADER_KEY_NOT_FOUND; } if(b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign) != RSF_RSA_DATA_LEN){ - fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Signature\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign)); + fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/Signature\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign)); return COMMON_HEADER_KEY_NOT_FOUND; } @@ -101,41 +95,30 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset) return COMMON_HEADER_KEY_NOT_FOUND; } if(b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin) != RSF_DESC_DATA_LEN){ - fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Descriptor\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin)); + fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/Descriptor\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin)); return COMMON_HEADER_KEY_NOT_FOUND; } /* Set RSA Keys */ int result = 0; - u32 out; - - out = 0x100; - result = base64_decode(exhdrset->keys->rsa.cxiHdrPub,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.Modulus,strlen(exhdrset->rsf->CommonHeaderKey.Modulus)); - if(out != 0x100) - result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL; - if(result) goto finish; - - out = 0x100; - result = base64_decode(exhdrset->keys->rsa.cxiHdrPvt,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.D,strlen(exhdrset->rsf->CommonHeaderKey.D)); - if(out != 0x100) - result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL; - if(result) goto finish; + // NCCH Header pubk + result = b64_decode(exhdrset->keys->rsa.cxiHdrPub,exhdrset->rsf->CommonHeaderKey.Modulus,0x100); + if(result) return result; + // NCCH Header privk + result = b64_decode(exhdrset->keys->rsa.cxiHdrPvt,exhdrset->rsf->CommonHeaderKey.D,0x100); + if(result) return result; /* Set AccessDesc */ - out = 0x100; - result = base64_decode(exhdrset->acexDesc->signature,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.AccCtlDescSign, strlen( exhdrset->rsf->CommonHeaderKey.AccCtlDescSign)); - if(out != 0x100) - result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL; - if(result) goto finish; + // Signature + result = b64_decode(exhdrset->acexDesc->signature,exhdrset->rsf->CommonHeaderKey.AccCtlDescSign,0x100); + if(result) return result; + // NCCH Header pubk memcpy(exhdrset->acexDesc->ncchRsaPubKey,exhdrset->keys->rsa.cxiHdrPub,0x100); - - out = 0x200; - result = base64_decode((u8*)&exhdrset->acexDesc->arm11SystemLocalCapabilities,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.AccCtlDescBin,strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin)); - if(out != 0x200) - result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL; - if(result) goto finish; -finish: - return result; + // Access Control + result = b64_decode((u8*)&exhdrset->acexDesc->arm11SystemLocalCapabilities,exhdrset->rsf->CommonHeaderKey.AccCtlDescBin,0x200); + if(result) return result; + + return 0; } int accessdesc_GetSignFromPreset(exheader_settings *exhdrset) @@ -153,12 +136,12 @@ int accessdesc_GetSignFromPreset(exheader_settings *exhdrset) // Error Checking if(!desc || !depList){ - fprintf(stderr,"[EXHEADER ERROR] AccessDesc preset is unavailable, please configure RSF file\n"); + fprintf(stderr,"[ACEXDESC ERROR] AccessDesc template is unavailable, please configure RSF file\n"); return CANNOT_SIGN_ACCESSDESC; } if((!cxiPubk || !cxiPvtk || !accessDesc || !accessDescSig) && exhdrset->keys->rsa.requiresPresignedDesc){ - fprintf(stderr,"[EXHEADER ERROR] This AccessDesc preset needs to be signed, the current keyset is incapable of doing so. Please configure RSF file with the appropriate signature data.\n"); + fprintf(stderr,"[ACEXDESC ERROR] This AccessDesc template needs to be signed, the current keyset is incapable of doing so. Please configure RSF file with the appropriate signature data.\n"); return CANNOT_SIGN_ACCESSDESC; } @@ -451,40 +434,4 @@ void accessdesc_GetPresetSigData(u8 **accessDescSig, u8 **cxiPubk, u8 **cxiPvtk, break; } } -} - -bool IsValidB64Char(char chr) -{ - return (isalnum(chr) || chr == '+' || chr == '/' || chr == '='); -} - -u32 b64_strlen(char *str) -{ - u32 count = 0; - u32 i = 0; - while(str[i] != 0x0){ - if(IsValidB64Char(str[i])) { - //printf("Is Valid: %c\n",str[i]); - count++; - } - i++; - } - - return count; -} - -void b64_strcpy(char *dst, char *src) -{ - u32 src_len = strlen(src); - u32 j = 0; - for(u32 i = 0; i < src_len; i++){ - if(IsValidB64Char(src[i])){ - dst[j] = src[i]; - j++; - } - } - dst[j] = 0; - - //memdump(stdout,"src: ",(u8*)src,src_len+1); - //memdump(stdout,"dst: ",(u8*)dst,j+1); } \ No newline at end of file diff --git a/makerom/cardinfo.c b/makerom/cardinfo.c new file mode 100644 index 0000000..f2ac692 --- /dev/null +++ b/makerom/cardinfo.c @@ -0,0 +1,207 @@ +#include "lib.h" +#include "ncch_read.h" +#include "ncsd_build.h" +#include "cardinfo.h" + +void InitCardInfoHdr(cardinfo_hdr **cihdr, devcardinfo_hdr **dcihdr, cci_settings *set); +int SetWriteableAddress(cardinfo_hdr *hdr, cci_settings *set); +int SetCardInfoBitmask(cardinfo_hdr *hdr, cci_settings *set); +int SetCardInfoNotes(cardinfo_hdr *hdr, cci_settings *set); +void ImportNcch0Data(cardinfo_hdr *hdr, cci_settings *set); +void SetInitialData(cardinfo_hdr *hdr, cci_settings *set); +void SetDevCardInfo(devcardinfo_hdr *hdr, cci_settings *set); + + +int GenCardInfoHdr(cci_settings *set) +{ + cardinfo_hdr *cihdr; + devcardinfo_hdr *dcihdr; + + InitCardInfoHdr(&cihdr,&dcihdr,set); + + if(SetWriteableAddress(cihdr,set)) + return GEN_HDR_FAIL; + if(SetCardInfoBitmask(cihdr,set)) + return GEN_HDR_FAIL; + if(SetCardInfoNotes(cihdr,set)) + return GEN_HDR_FAIL; + ImportNcch0Data(cihdr,set); + SetInitialData(cihdr,set); + + if(dcihdr) + SetDevCardInfo(dcihdr,set); + + return 0; +} + +void InitCardInfoHdr(cardinfo_hdr **cihdr, devcardinfo_hdr **dcihdr, cci_settings *set) +{ + set->headers.cardinfohdr.size = sizeof(cardinfo_hdr); + if(set->options.useExternalSdkCardInfo) + set->headers.cardinfohdr.size += sizeof(devcardinfo_hdr); + + set->headers.cardinfohdr.buffer = calloc(1,set->headers.cardinfohdr.size); + + *cihdr = (cardinfo_hdr*)set->headers.cardinfohdr.buffer; + + if(set->headers.cardinfohdr.size > sizeof(cardinfo_hdr)) + *dcihdr = (devcardinfo_hdr*)(set->headers.cardinfohdr.buffer+sizeof(cardinfo_hdr)); + else + *dcihdr = NULL; + + return; +} + +u64 GetCciUnusedSize(u64 mediaSize, u8 cardType) +{ + if(cardType == mediatype_CARD1){ + switch(mediaSize){ + case (u64)MB*128: return (u64)2621440; + case (u64)MB*256: return (u64)5242880; + case (u64)MB*512: return (u64)10485760; + case (u64)GB*1: return (u64)73924608; + case (u64)GB*2: return (u64)147324928; + case (u64)GB*4: return (u64)294649856; + case (u64)GB*8: return (u64)587202560; + default: return 0; + } + } + else if(cardType == mediatype_CARD2){ + switch(mediaSize){ + case (u64)MB*512: return (u64)37224448; + case (u64)GB*1: return (u64)73924608; + case (u64)GB*2: return (u64)147324928; + case (u64)GB*4: return (u64)294649856; + case (u64)GB*8: return (u64)587202560; + default: return 0; + } + } + return 0; +} + +int SetWriteableAddress(cardinfo_hdr *hdr, cci_settings *set) +{ + if(set->romInfo.mediaType != mediatype_CARD2){ // Can only be set for Card2 Media + u32_to_u8(hdr->writableAddress,(u32)-1,LE); + return 0; + } + + char *str = set->rsf->CardInfo.WritableAddress; + set->romInfo.card2SaveOffset = -1; + + if(str){ + if(strncmp(str,"0x",2) != 0){ + fprintf(stderr,"[CCI ERROR] WritableAddress requires a Hexadecimal value\n"); + return INVALID_RSF_OPT; + } + set->romInfo.card2SaveOffset = strtoull(str,NULL,16); + } + else{ + if ((set->romInfo.mediaSize / 2) < set->romInfo.saveSize || set->romInfo.saveSize > (u64)(2047*MB)){ + u64 saveDataSize = set->romInfo.saveSize / KB; + fprintf(stderr,"[CCI ERROR] Too large SavedataSize %"PRIu64"K\n",saveDataSize); + return SAVE_DATA_TOO_LARGE; + } + if(set->options.closeAlignWR) + set->romInfo.card2SaveOffset = align(set->romInfo.usedSize, set->romInfo.blockSize); // invalid for "real" chips + else{ + u64 unusedSize = GetCciUnusedSize(set->romInfo.mediaSize,set->romInfo.mediaType); // Some value related to the physical implementation of gamecards + if(unusedSize > 0) + set->romInfo.card2SaveOffset = set->romInfo.mediaSize - unusedSize - set->romInfo.saveSize; // Nintendo's method for calculating writable region offset + else{ + fprintf(stderr,"[CCI WARNING] Nintendo does not support CARD2 for the current MediaSize, aligning save offset after last NCCH\n"); + set->romInfo.card2SaveOffset = align(set->romInfo.usedSize, set->romInfo.blockSize); // invalid for "real" chips + } + } + } + + u32_to_u8(hdr->writableAddress,(u32)(set->romInfo.card2SaveOffset/set->romInfo.blockSize),LE); + + return 0; +} + +int SetCardInfoBitmask(cardinfo_hdr *hdr, cci_settings *set) +{ + u32 bitmask = 0; + + char *str = set->rsf->CardInfo.CardType; + if(!str) + bitmask |= 0; + else{ + if(strcasecmp(str,"s1") == 0) + bitmask |= 0; + else if(strcasecmp(str,"s2") == 0) + bitmask |= 0x20; + else { + fprintf(stderr,"[CCI ERROR] Invalid CardType: %s\n",str); + return INVALID_RSF_OPT; + } + } + + str = set->rsf->CardInfo.CryptoType; + if(!str) + bitmask |= 0;//(3*0x40); + else{ + int val = strtol(str,NULL,10); + if(val < 0 || val > 3) { + fprintf(stderr,"[CCI ERROR] Invalid CryptoType: %s\n",str); + return INVALID_RSF_OPT; + } + if(val != 3) + fprintf(stderr,"[CCI WARNING] Card crypto type = '%d'\n",val); + bitmask |= val * 0x40; + } + + u32_to_u8(hdr->cardInfoBitmask,bitmask,BE); + + return 0; +} + +int SetCardInfoNotes(cardinfo_hdr *hdr, cci_settings *set) +{ + u64_to_u8(hdr->notes.mediaSizeUsed,set->romInfo.usedSize,LE); + u32_to_u8(hdr->notes.unknown,0,LE); + + if(set->options.tmdHdr){ + u64_to_u8(hdr->notes.cverTitleId,GetTmdTitleId(set->options.tmdHdr),LE); + u16_to_u8(hdr->notes.cverTitleId,GetTmdVersion(set->options.tmdHdr),LE); + } + + return 0; +} + +void ImportNcch0Data(cardinfo_hdr *hdr, cci_settings *set) +{ + u8 *ncch; + ncch_hdr *ncchHdr; + + ncch = set->content.data + set->content.dOffset[0]; + ncchHdr = (ncch_hdr*)ncch; + + memcpy(hdr->ncch0TitleId,ncchHdr->titleId,8); + memcpy(hdr->ncch0Hdr,GetNcchHdrData(ncchHdr),GetNcchHdrDataLen(ncchHdr)); + + return; +} + +void SetInitialData(cardinfo_hdr *hdr, cci_settings *set) +{ + clrmem(hdr->initialData,0x30); + if(set->options.useExternalSdkCardInfo) + memcpy(hdr->initialData,(u8*)stock_initial_data,0x30); + else + rndset(hdr->initialData,0x2c); + + return; +} + +void SetDevCardInfo(devcardinfo_hdr *hdr, cci_settings *set) +{ + clrmem(hdr,sizeof(devcardinfo_hdr)); + if(set->options.useExternalSdkCardInfo) + memcpy(hdr->titleKey,(u8*)stock_title_key,0x10); + else + rndset(hdr->titleKey,0x10); + + return; +} \ No newline at end of file diff --git a/makerom/cardinfo.h b/makerom/cardinfo.h new file mode 100644 index 0000000..271edac --- /dev/null +++ b/makerom/cardinfo.h @@ -0,0 +1,53 @@ +#pragma once + +typedef struct +{ + u8 reserved0[0xf8]; + u8 mediaSizeUsed[8]; + u8 reserved1[0x8]; + u8 unknown[0x4]; + u8 reserved2[0xc]; + u8 cverTitleId[8]; + u8 cverTitleVersion[2]; + u8 reserved3[0xcd6]; +} cardinfo_notes; // reserved[0xDF8]; + +typedef struct +{ + u8 writableAddress[4]; + u8 cardInfoBitmask[4]; + cardinfo_notes notes; + u8 ncch0TitleId[8]; + u8 reserved0[8]; + u8 initialData[0x30]; + u8 reserved1[0xc0]; + u8 ncch0Hdr[0x100]; +} cardinfo_hdr; + +typedef struct +{ + u8 cardDeviceReserved1[0x200]; + u8 titleKey[0x10]; + u8 cardDeviceReserved2[0xf0]; +} devcardinfo_hdr; + +static const u8 stock_initial_data[0x30] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xAD, 0x88, + 0xAC, 0x41, 0xA2, 0xB1, 0x5E, 0x8F, + 0x66, 0x9C, 0x97, 0xE5, 0xE1, 0x5E, + 0xA3, 0xEB, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 stock_title_key[0x10] = +{ + 0x6E, 0xC7, 0x5F, 0xB2, 0xE2, 0xB4, + 0x87, 0x46, 0x1E, 0xDD, 0xCB, 0xB8, + 0x97, 0x11, 0x92, 0xBA +}; + +int GenCardInfoHdr(cci_settings *set); \ No newline at end of file diff --git a/makerom/cia.c b/makerom/cia.c index e820a9d..b9ab061 100644 --- a/makerom/cia.c +++ b/makerom/cia.c @@ -1,41 +1,44 @@ #include "lib.h" -#include "ncch.h" -#include "exheader.h" -#include "exefs.h" -#include "certs.h" -#include "cia.h" -#include "tik.h" -#include "tmd.h" -#include "titleid.h" + #include "srl.h" -#include "ncsd.h" +#include "ncsd_read.h" +#include "ncch_read.h" +#include "exheader_read.h" +#include "exefs_read.h" + +#include "cia_build.h" +#include "cia_read.h" +#include "tik_build.h" +#include "tmd_build.h" +#include "titleid.h" +#include "certs.h" + +const int CIA_ALIGN_SIZE = 0x40; +const int CIA_CONTENT_ALIGN = 0x10; // Private Prototypes -/* cia_settings tools */ -void init_CIASettings(cia_settings *set); -void free_CIASettings(cia_settings *set); -int get_CIASettings(cia_settings *ciaset, user_settings *usrset); +void InitCiaSettings(cia_settings *set); +void FreeCiaSettings(cia_settings *set); +int GetCiaSettings(cia_settings *ciaset, user_settings *usrset); int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset); int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset); -int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key); -int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key); +int GetTmdDataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *key); +int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *key); int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset); int ImportNcchContent(cia_settings *ciaset); int GetSettingsFromSrl(cia_settings *ciaset); int GetSettingsFromCci(cia_settings *ciaset); -u16 SetupVersion(u16 Major, u16 Minor, u16 Micro); +u16 SetupVersion(u16 major, u16 minor, u16 micro); void GetContentHashes(cia_settings *ciaset); void EncryptContent(cia_settings *ciaset); -int BuildCIA_CertChain(cia_settings *ciaset); -int BuildCIA_Header(cia_settings *ciaset); +int BuildCiaCertChain(cia_settings *ciaset); +int BuildCiaHdr(cia_settings *ciaset); -int WriteCIAtoFile(cia_settings *ciaset); - -int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, u8 mode); +int WriteCiaToFile(cia_settings *ciaset); int build_CIA(user_settings *usrset) @@ -50,8 +53,8 @@ int build_CIA(user_settings *usrset) } // Get Settings - init_CIASettings(ciaset); - result = get_CIASettings(ciaset,usrset); + InitCiaSettings(ciaset); + result = GetCiaSettings(ciaset,usrset); if(result) goto finish; // Create Output File @@ -65,7 +68,7 @@ int build_CIA(user_settings *usrset) // Create CIA Sections /* Certificate Chain */ - result = BuildCIA_CertChain(ciaset); + result = BuildCiaCertChain(ciaset); if(result) goto finish; /* Ticket */ @@ -77,28 +80,28 @@ int build_CIA(user_settings *usrset) if(result) goto finish; /* CIA Header */ - result = BuildCIA_Header(ciaset); + result = BuildCiaHdr(ciaset); if(result) goto finish; /* Write To File */ - result = WriteCIAtoFile(ciaset); + result = WriteCiaToFile(ciaset); if(result) goto finish; finish: if(result != FAILED_TO_CREATE_OUTFILE && ciaset->out) fclose(ciaset->out); - free_CIASettings(ciaset); + FreeCiaSettings(ciaset); return result; } -void init_CIASettings(cia_settings *set) +void InitCiaSettings(cia_settings *set) { memset(set,0,sizeof(cia_settings)); } -void free_CIASettings(cia_settings *set) +void FreeCiaSettings(cia_settings *set) { if(set->content.filePtrs){ for(u32 i = 1; i < set->content.count; i++){ @@ -117,7 +120,7 @@ void free_CIASettings(cia_settings *set) free(set); } -int get_CIASettings(cia_settings *ciaset, user_settings *usrset) +int GetCiaSettings(cia_settings *ciaset, user_settings *usrset) { int result = 0; @@ -125,26 +128,21 @@ int get_CIASettings(cia_settings *ciaset, user_settings *usrset) result = GetSettingsFromUsrset(ciaset,usrset); if(usrset->common.workingFileType == infile_ncch){ - result = GetSettingsFromNcch0(ciaset,0); - if(result) + if((result = GetSettingsFromNcch0(ciaset,0)) != 0) return result; - result = GetContentFilePtrs(ciaset,usrset); - if(result) + if((result = GetContentFilePtrs(ciaset,usrset)) != 0) return result; - result = ImportNcchContent(ciaset); - if(result) + if((result = ImportNcchContent(ciaset)) != 0) return result; } else if(usrset->common.workingFileType == infile_srl){ - result = GetSettingsFromSrl(ciaset); - if(result) + if((result = GetSettingsFromSrl(ciaset)) != 0) return result; } else if(usrset->common.workingFileType == infile_ncsd){ - result = GetSettingsFromCci(ciaset); - if(result) + if((result = GetSettingsFromCci(ciaset)) != 0) return result; } @@ -165,7 +163,9 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset) ciaset->ciaSections.content.size = usrset->common.workingFile.size; usrset->common.workingFile.buffer = NULL; ciaset->ciaSections.content.size = 0; - + ciaset->content.includeUpdateNcch = usrset->cia.includeUpdateNcch; + ciaset->verbose = usrset->common.verbose; + u32_to_u8(ciaset->tmd.titleType,TYPE_CTR,BE); ciaset->content.encryptCia = usrset->common.rsfSet.Option.EnableCrypt; ciaset->content.IsDlc = usrset->cia.DlcContent; @@ -183,16 +183,19 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset) // Ticket Data rndset(ciaset->tik.ticketId,8); - clrmem(ciaset->tik.deviceId,4); - clrmem(ciaset->tik.eshopAccId,4); + u32_to_u8(ciaset->tik.deviceId,usrset->cia.deviceId,BE); + u32_to_u8(ciaset->tik.eshopAccId,usrset->cia.eshopAccId,BE); ciaset->tik.licenceType = 0; ciaset->tik.audit = 0; if(usrset->cia.randomTitleKey) - rndset(ciaset->common.titleKey,16); + rndset(ciaset->common.titleKey,AES_128_KEY_SIZE); else - clrmem(ciaset->common.titleKey,16); + clrmem(ciaset->common.titleKey,AES_128_KEY_SIZE); + if(ciaset->verbose) + memdump(stdout,"[CIA] CIA title key: ",ciaset->common.titleKey,AES_128_KEY_SIZE); + ciaset->tik.formatVersion = 1; int result = GenCertChildIssuer(ciaset->tik.issuer,ciaset->keys->certs.xsCert); @@ -217,33 +220,29 @@ int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset) u8 *ncch0 = (u8*)(ciaset->ciaSections.content.buffer+ncch0_offset); - if(!IsNCCH(NULL,ncch0)){ + if(!IsNcch(NULL,ncch0)){ fprintf(stderr,"[CIA ERROR] Content0 is not NCCH\n"); return CIA_INVALID_NCCH0; } /* Get Ncch0 Header */ - ncch_hdr *hdr = NULL; - hdr = GetNCCH_CommonHDR(hdr,NULL,ncch0); - if(IsCfa(hdr)){ - ciaset->content.IsCfa = true; - } + ncch_hdr *hdr = (ncch_hdr*)ncch0; + ciaset->content.IsCfa = IsCfa(hdr); ciaset->content.offset[0] = 0; - ciaset->content.size[0] = align(GetNCCH_MediaSize(hdr)*GetNCCH_MediaUnitSize(hdr),0x10); + ciaset->content.size[0] = align(GetNcchSize(hdr),0x10); ciaset->content.totalSize = ciaset->content.size[0]; /* Get Ncch0 Import Context */ - ncch_struct *ncch_ctx = malloc(sizeof(ncch_struct)); - if(!ncch_ctx){ + ncch_info *info = calloc(1,sizeof(ncch_info)); + if(!info){ fprintf(stderr,"[CIA ERROR] Not enough memory\n"); return MEM_ERROR; } - memset(ncch_ctx,0x0,sizeof(ncch_struct)); - GetNCCHStruct(ncch_ctx,hdr); + GetNcchInfo(info,hdr); /* Verify Ncch0 (Sig&Hash Checks) */ - int result = VerifyNCCH(ncch0,ciaset->keys,false,true); + int result = VerifyNcch(ncch0,ciaset->keys,false,true); if(result == UNABLE_TO_LOAD_NCCH_KEY){ ciaset->content.keyNotFound = true; if(!ciaset->content.IsCfa){ @@ -261,31 +260,35 @@ int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset) /* Getting ncch key */ - ncch_key_type keyType = GetNCCHKeyType(hdr); u8 *ncchkey = NULL; - if(!ciaset->content.keyNotFound){ - SetNcchUnfixedKeys(ciaset->keys,ncch0); - ncchkey = GetNCCHKey0(keyType,ciaset->keys); + if(!ciaset->content.keyNotFound || IsNcchEncrypted(hdr)){ + SetNcchKeys(ciaset->keys,hdr); + ncchkey = ciaset->keys->aes.ncchKey0; + if(ciaset->verbose){ + printf("[CIA] NCCH AES keys:\n"); + memdump(stdout," > key0: ",ciaset->keys->aes.ncchKey0,AES_128_KEY_SIZE); + memdump(stdout," > key1: ",ciaset->keys->aes.ncchKey1,AES_128_KEY_SIZE); + } } /* Get TMD Data from ncch */ - result = GetCIADataFromNcch(ciaset,ncch0,ncch_ctx,ncchkey); // Data For TMD + result = GetTmdDataFromNcch(ciaset,ncch0,info,ncchkey); // Data For TMD if(result) goto finish; /* Get META Region from ncch */ - result = GetMetaRegion(ciaset,ncch0,ncch_ctx,ncchkey); // Meta Region + result = GetMetaRegion(ciaset,ncch0,info,ncchkey); // Meta Region /* Finish */ finish: /* Return */ - free(ncch_ctx); + free(info); return result; } -int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key) +int GetTmdDataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *key) { extended_hdr *exhdr = malloc(sizeof(extended_hdr)); memcpy(exhdr,ncch+ncch_ctx->exhdrOffset,sizeof(extended_hdr)); if(key != NULL) - CryptNCCHSection((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx,key,ncch_exhdr); + CryptNcchRegion((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx,key,ncch_exhdr); u16 Category = u8_to_u16((ciaset->common.titleId+2),BE); if(IsPatch(Category)||ciaset->content.IsCfa||ciaset->content.keyNotFound) @@ -318,28 +321,26 @@ int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 ciaset->common.titleVersion[VER_MAJOR] = GetRemasterVersion_frm_exhdr(exhdr); } - u16 version = SetupVersion(ciaset->common.titleVersion[VER_MAJOR],ciaset->common.titleVersion[VER_MINOR],ciaset->common.titleVersion[VER_MICRO]); - ciaset->tik.version = version; - ciaset->tmd.version = version; + ciaset->tmd.version = ciaset->tik.version = SetupVersion(ciaset->common.titleVersion[VER_MAJOR],ciaset->common.titleVersion[VER_MINOR],ciaset->common.titleVersion[VER_MICRO]); free(exhdr); return 0; } -int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key) +int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_info *info, u8 *key) { if(ciaset->content.IsCfa || ciaset->content.keyNotFound) return 0; extended_hdr *exhdr = malloc(sizeof(extended_hdr)); - memcpy(exhdr,ncch+ncch_ctx->exhdrOffset,sizeof(extended_hdr)); + memcpy(exhdr,ncch+info->exhdrOffset,sizeof(extended_hdr)); if(key != NULL) - CryptNCCHSection((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx,key,ncch_exhdr); + CryptNcchRegion((u8*)exhdr,sizeof(extended_hdr),0,info,key,ncch_exhdr); exefs_hdr *exefsHdr = malloc(sizeof(exefs_hdr)); - memcpy(exefsHdr,ncch+ncch_ctx->exefsOffset,sizeof(exefs_hdr)); + memcpy(exefsHdr,ncch+info->exefsOffset,sizeof(exefs_hdr)); if(key != NULL) - CryptNCCHSection((u8*)exefsHdr,sizeof(exefs_hdr),0,ncch_ctx,key,ncch_exefs); + CryptNcchRegion((u8*)exefsHdr,sizeof(exefs_hdr),0,info,key,ncch_exefs); u32 icon_size = 0; u32 icon_offset = 0; @@ -349,7 +350,7 @@ int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key icon_offset = u8_to_u32(exefsHdr->fileHdr[i].offset,LE) + sizeof(exefs_hdr); } } - + ciaset->ciaSections.meta.size = sizeof(cia_metadata) + icon_size; ciaset->ciaSections.meta.buffer = malloc(ciaset->ciaSections.meta.size); if(!ciaset->ciaSections.meta.buffer){ @@ -362,9 +363,9 @@ int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key GetCoreVersion_frm_exhdr(hdr->coreVersion,exhdr); if(icon_size > 0){ u8 *IconDestPos = (ciaset->ciaSections.meta.buffer + sizeof(cia_metadata)); - memcpy(IconDestPos,ncch+ncch_ctx->exefsOffset+icon_offset,icon_size); + memcpy(IconDestPos,ncch+info->exefsOffset+icon_offset,icon_size); if(key != NULL) - CryptNCCHSection(IconDestPos,icon_size,icon_offset,ncch_ctx,key,ncch_exefs); + CryptNcchRegion(IconDestPos,icon_size,icon_offset,info,key,ncch_exefs); //memdump(stdout,"Icon: ",IconDestPos,0x10); } @@ -389,7 +390,7 @@ int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset) fprintf(stderr,"[CIA ERROR] Failed to open \"%s\"\n",usrset->common.contentPath[i]); return FAILED_TO_OPEN_FILE; } - ciaset->content.fileSize[j] = GetFileSize_u64(usrset->common.contentPath[i]); + ciaset->content.fileSize[j] = GetFileSize64(usrset->common.contentPath[i]); ciaset->content.filePtrs[j] = fopen(usrset->common.contentPath[i],"rb"); if(usrset->cia.contentId[i] > MAX_U32) @@ -400,10 +401,10 @@ int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset) ciaset->content.index[j] = (u16)i; // Get Data from ncch HDR - GetNCCH_CommonHDR(hdr,ciaset->content.filePtrs[j],NULL); + ReadNcchHdr(hdr,ciaset->content.filePtrs[j]); // Get Size - u64 calcSize = (u64)GetNCCH_MediaSize(hdr) * (u64)GetNCCH_MediaUnitSize(hdr); + u64 calcSize = GetNcchSize(hdr); if(calcSize != ciaset->content.fileSize[j]){ fprintf(stderr,"[CIA ERROR] \"%s\" is corrupt\n",usrset->common.contentPath[i]); return FAILED_TO_OPEN_FILE; @@ -447,7 +448,7 @@ int ImportNcchContent(cia_settings *ciaset) // Import u8 *ncchpos = (u8*)(ciaset->ciaSections.content.buffer+ciaset->content.offset[i]); - ReadFile_64(ncchpos, ciaset->content.fileSize[i], 0, ciaset->content.filePtrs[i]); + ReadFile64(ncchpos, ciaset->content.fileSize[i], 0, ciaset->content.filePtrs[i]); if(ModifyNcchIds(ncchpos, NULL, ncch0hdr->programId, ciaset->keys) != 0) return -1; @@ -528,6 +529,11 @@ int GetSettingsFromCci(cia_settings *ciaset) cciContentOffsets[0] = ncch0_offset; for(int i = 1; i < 8; i++){ if(GetPartitionSize(ciaset->ciaSections.content.buffer,i)){ + ncch_hdr *ncchHdr = (ncch_hdr*)GetPartition(ciaset->ciaSections.content.buffer, i); + + if(IsUpdateCfa(ncchHdr) && !ciaset->content.includeUpdateNcch) + continue; + cciContentOffsets[j] = GetPartitionOffset(ciaset->ciaSections.content.buffer,i); // Get Size @@ -557,9 +563,9 @@ int GetSettingsFromCci(cia_settings *ciaset) return 0; } -u16 SetupVersion(u16 Major, u16 Minor, u16 Micro) +u16 SetupVersion(u16 major, u16 minor, u16 micro) { - return (((Major << 10) & 0xFC00) | ((Minor << 4) & 0x3F0) | (Micro & 0xf)); + return (((major << 10) & 0xFC00) | ((minor << 4) & 0x3F0) | (micro & 0xf)); } void GetContentHashes(cia_settings *ciaset) @@ -577,7 +583,7 @@ void EncryptContent(cia_settings *ciaset) } } -int BuildCIA_CertChain(cia_settings *ciaset) +int BuildCiaCertChain(cia_settings *ciaset) { ciaset->ciaSections.certChain.size = GetCertSize(ciaset->keys->certs.caCert) + GetCertSize(ciaset->keys->certs.xsCert) + GetCertSize(ciaset->keys->certs.cpCert); ciaset->ciaSections.certChain.buffer = malloc(ciaset->ciaSections.certChain.size); @@ -591,7 +597,7 @@ int BuildCIA_CertChain(cia_settings *ciaset) return 0; } -int BuildCIA_Header(cia_settings *ciaset) +int BuildCiaHdr(cia_settings *ciaset) { // Allocating memory for header ciaset->ciaSections.ciaHdr.size = sizeof(cia_hdr); @@ -644,7 +650,7 @@ int BuildCIA_Header(cia_settings *ciaset) return 0; } -int WriteCIAtoFile(cia_settings *ciaset) +int WriteCiaToFile(cia_settings *ciaset) { WriteBuffer(ciaset->ciaSections.ciaHdr.buffer,ciaset->ciaSections.ciaHdr.size,0,ciaset->out); WriteBuffer(ciaset->ciaSections.certChain.buffer,ciaset->ciaSections.certChain.size,ciaset->ciaSections.certChainOffset,ciaset->out); @@ -656,7 +662,7 @@ int WriteCIAtoFile(cia_settings *ciaset) } -int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, u8 mode) +int CryptContent(u8 *enc, u8 *dec, u64 size, u8 *title_key, u16 index, u8 mode) { //generating IV u8 iv[16]; @@ -667,7 +673,110 @@ int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, ctr_aes_context ctx; memset(&ctx,0x0,sizeof(ctr_aes_context)); ctr_init_aes_cbc(&ctx,title_key,iv,mode); - if(mode == ENC) ctr_aes_cbc(&ctx,DecBuffer,EncBuffer,size,ENC); - else ctr_aes_cbc(&ctx,EncBuffer,DecBuffer,size,DEC); + if(mode == ENC) ctr_aes_cbc(&ctx,dec,enc,size,ENC); + else ctr_aes_cbc(&ctx,enc,dec,size,DEC); return 0; +} + +bool IsCia(u8 *cia) +{ + if(!cia) + return false; + + cia_hdr *hdr = (cia_hdr*)cia; + + if(u8_to_u32(hdr->hdrSize,LE) != sizeof(cia_hdr) || u8_to_u16(hdr->type,LE) != 0 || u8_to_u16(hdr->version,LE) != 0) + return false; + + if(!GetCiaCertSize(hdr) || !GetCiaTikSize(hdr) || !GetCiaTmdSize(hdr) || !GetCiaContentSize(hdr)) + return false; + + return true; +} + +u64 GetCiaCertOffset(cia_hdr *hdr) +{ + u64 hdrSize = u8_to_u32(hdr->hdrSize,LE); + return align(hdrSize,CIA_ALIGN_SIZE); +} + +u64 GetCiaCertSize(cia_hdr *hdr) +{ + return u8_to_u32(hdr->certChainSize,LE); +} + +u64 GetCiaTikOffset(cia_hdr *hdr) +{ + u64 certOffset = GetCiaCertOffset(hdr); + u64 certSize = GetCiaCertSize(hdr); + return align(certOffset + certSize,CIA_ALIGN_SIZE); +} + +u64 GetCiaTikSize(cia_hdr *hdr) +{ + return u8_to_u32(hdr->tikSize,LE); +} + +u64 GetCiaTmdOffset(cia_hdr *hdr) +{ + u64 tikOffset = GetCiaTikOffset(hdr); + u64 tikSize = GetCiaTikSize(hdr); + return align(tikOffset + tikSize,CIA_ALIGN_SIZE); +} + +u64 GetCiaTmdSize(cia_hdr *hdr) +{ + return u8_to_u32(hdr->tmdSize,LE); +} + +u64 GetCiaContentOffset(cia_hdr *hdr) +{ + u64 tmdOffset = GetCiaTmdOffset(hdr); + u64 tmdSize = GetCiaTmdSize(hdr); + return align(tmdOffset + tmdSize,CIA_ALIGN_SIZE); +} + +u64 GetCiaContentSize(cia_hdr *hdr) +{ + return u8_to_u64(hdr->contentSize,LE); +} + +u64 GetCiaMetaOffset(cia_hdr *hdr) +{ + u64 contentOffset = GetCiaContentOffset(hdr); + u64 contentSize = GetCiaContentSize(hdr); + return align(contentOffset + contentSize,CIA_ALIGN_SIZE); +} + +u64 GetCiaMetaSize(cia_hdr *hdr) +{ + return u8_to_u32(hdr->metaSize,LE); +} + +u8* GetCiaCert(u8 *cia) +{ + return cia + GetCiaCertOffset((cia_hdr*)cia); +} + +u8* GetCiaTik(u8 *cia) +{ + return cia + GetCiaTikOffset((cia_hdr*)cia); +} + +u8* GetCiaTmd(u8 *cia) +{ + return cia + GetCiaTmdOffset((cia_hdr*)cia); +} + +u8* GetCiaContent(u8 *cia) +{ + return cia + GetCiaContentOffset((cia_hdr*)cia); +} + +u8* GetCiaMeta(u8 *cia) +{ + if(GetCiaMetaSize((cia_hdr*)cia)) + return cia + GetCiaMetaOffset((cia_hdr*)cia); + else + return NULL; } \ No newline at end of file diff --git a/makerom/cia.h b/makerom/cia.h index b810049..b7dc6c2 100644 --- a/makerom/cia.h +++ b/makerom/cia.h @@ -1,17 +1,5 @@ #pragma once -static const int CIA_ALIGN_SIZE = 0x40; -static const int CIA_CONTENT_ALIGN = 0x10; - -// Enums -typedef enum -{ - CIA_NO_NCCH0 = -1, - CIA_INVALID_NCCH0 = -2, - CIA_CONFILCTING_CONTENT_IDS = -3, - CIA_BAD_VERSION = -4, -} cia_errors; - // Structs typedef struct { @@ -34,107 +22,5 @@ typedef struct u8 padding1[0xfc]; } cia_metadata; -typedef struct -{ - u8 *inFile; - u64 inFileSize; +int CryptContent(u8 *enc, u8 *dec, u64 size, u8 *title_key, u16 index, u8 mode); - FILE *out; - - rsf_settings *rsf; - keys_struct *keys; - - struct{ - u8 titleId[8]; - u16 titleVersion[4]; - u8 titleKey[16]; - } common; - - - struct{ - u8 caCrlVersion; - u8 signerCrlVersion; - } cert; - - struct{ - u8 issuer[0x40]; - u8 formatVersion; - - u16 version; - - u8 ticketId[8]; - u8 deviceId[4]; - u8 licenceType; - u8 audit; - u8 eshopAccId[4]; - } tik; - - struct{ - u8 issuer[0x40]; - u8 formatVersion; - - u16 version; - - u8 titleType[4]; - u8 savedataSize[4]; - u8 privSavedataSize[4]; - u8 twlFlag; - } tmd; - - struct{ - bool IsCfa; - bool IsDlc; - bool encryptCia; - - bool keyNotFound; - - FILE **filePtrs; - u64 fileSize[CIA_MAX_CONTENT]; - - /* Misc Records */ - u16 count; - u64 offset[CIA_MAX_CONTENT]; - u64 totalSize; - - /* Content Chunk Records */ - u64 size[CIA_MAX_CONTENT]; - u16 index[CIA_MAX_CONTENT]; - u16 flags[CIA_MAX_CONTENT]; - u32 id[CIA_MAX_CONTENT]; - u8 hash[CIA_MAX_CONTENT][0x20]; - } content; - - struct{ - buffer_struct ciaHdr; - - u32 certChainOffset; - buffer_struct certChain; - - u32 tikOffset; - buffer_struct tik; - - u32 tmdOffset; - buffer_struct tmd; - - u32 metaOffset; - buffer_struct meta; - - u64 contentOffset; - buffer_struct content; - } ciaSections; -} cia_settings; - -// Public Prototypes -int build_CIA(user_settings *usrset); - -// Cia Read Functions -u64 GetCiaCertOffset(cia_hdr *hdr); -u64 GetCiaCertSize(cia_hdr *hdr); -u64 GetTikOffset(cia_hdr *hdr); -u64 GetTikSize(cia_hdr *hdr); -u64 GetTmdOffset(cia_hdr *hdr); -u64 GetTmdSize(cia_hdr *hdr); -u64 GetContentOffset(cia_hdr *hdr); -u64 GetContentSize(cia_hdr *hdr); -u64 GetMetaOffset(cia_hdr *hdr); -u64 GetMetaSize(cia_hdr *hdr); \ No newline at end of file diff --git a/makerom/cia_build.h b/makerom/cia_build.h new file mode 100644 index 0000000..a33717d --- /dev/null +++ b/makerom/cia_build.h @@ -0,0 +1,107 @@ +#pragma once +#include "cia.h" + +// Enums +typedef enum +{ + CIA_NO_NCCH0 = -1, + CIA_INVALID_NCCH0 = -2, + CIA_CONFILCTING_CONTENT_IDS = -3, + CIA_BAD_VERSION = -4, +} cia_errors; + +typedef struct +{ + u8 *inFile; + u64 inFileSize; + + FILE *out; + + rsf_settings *rsf; + keys_struct *keys; + + bool verbose; + + struct{ + u8 titleId[8]; + u16 titleVersion[4]; + u8 titleKey[16]; + } common; + + + struct{ + u8 caCrlVersion; + u8 signerCrlVersion; + } cert; + + struct{ + u8 issuer[0x40]; + u8 formatVersion; + + u16 version; + + u8 ticketId[8]; + u8 deviceId[4]; + u8 licenceType; + u8 audit; + u8 eshopAccId[4]; + } tik; + + struct{ + u8 issuer[0x40]; + u8 formatVersion; + + u16 version; + + u8 titleType[4]; + u8 savedataSize[4]; + u8 privSavedataSize[4]; + u8 twlFlag; + } tmd; + + struct{ + bool IsCfa; + bool IsDlc; + bool encryptCia; + bool includeUpdateNcch; // for cci -> cia conversions + + bool keyNotFound; + + FILE **filePtrs; + u64 fileSize[CIA_MAX_CONTENT]; + + /* Misc Records */ + u16 count; + u64 offset[CIA_MAX_CONTENT]; + u64 totalSize; + + /* Content Chunk Records */ + u64 size[CIA_MAX_CONTENT]; + u16 index[CIA_MAX_CONTENT]; + u16 flags[CIA_MAX_CONTENT]; + u32 id[CIA_MAX_CONTENT]; + u8 hash[CIA_MAX_CONTENT][0x20]; + } content; + + struct{ + buffer_struct ciaHdr; + + u32 certChainOffset; + buffer_struct certChain; + + u32 tikOffset; + buffer_struct tik; + + u32 tmdOffset; + buffer_struct tmd; + + u32 metaOffset; + buffer_struct meta; + + u64 contentOffset; + buffer_struct content; + } ciaSections; +} cia_settings; + +// Public Prototypes +int build_CIA(user_settings *usrset); \ No newline at end of file diff --git a/makerom/cia_read.c b/makerom/cia_read.c deleted file mode 100644 index dbf27aa..0000000 --- a/makerom/cia_read.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "lib.h" -#include "cia.h" - -u64 GetCiaCertOffset(cia_hdr *hdr) -{ - u64 hdrSize = u8_to_u32(hdr->hdrSize,LE); - return align(hdrSize,CIA_ALIGN_SIZE); -} - -u64 GetCiaCertSize(cia_hdr *hdr) -{ - return u8_to_u32(hdr->certChainSize,LE); -} - -u64 GetTikOffset(cia_hdr *hdr) -{ - u64 certOffset = GetCiaCertOffset(hdr); - u64 certSize = GetCiaCertSize(hdr); - return align(certOffset + certSize,CIA_ALIGN_SIZE); -} - -u64 GetTikSize(cia_hdr *hdr) -{ - return u8_to_u32(hdr->tikSize,LE); -} - -u64 GetTmdOffset(cia_hdr *hdr) -{ - u64 tikOffset = GetTikOffset(hdr); - u64 tikSize = GetTikSize(hdr); - return align(tikOffset + tikSize,CIA_ALIGN_SIZE); -} - -u64 GetTmdSize(cia_hdr *hdr) -{ - return u8_to_u32(hdr->tmdSize,LE); -} - -u64 GetContentOffset(cia_hdr *hdr) -{ - u64 tmdOffset = GetTmdOffset(hdr); - u64 tmdSize = GetTmdSize(hdr); - return align(tmdOffset + tmdSize,CIA_ALIGN_SIZE); -} - -u64 GetContentSize(cia_hdr *hdr) -{ - return u8_to_u64(hdr->contentSize,LE); -} - -u64 GetMetaOffset(cia_hdr *hdr) -{ - u64 contentOffset = GetContentOffset(hdr); - u64 contentSize = GetContentSize(hdr); - return align(contentOffset + contentSize,CIA_ALIGN_SIZE); -} - -u64 GetMetaSize(cia_hdr *hdr) -{ - return u8_to_u32(hdr->metaSize,LE); -} \ No newline at end of file diff --git a/makerom/cia_read.h b/makerom/cia_read.h new file mode 100644 index 0000000..c75090a --- /dev/null +++ b/makerom/cia_read.h @@ -0,0 +1,21 @@ +#pragma once +#include "cia.h" + +// Cia Read Functions +bool IsCia(u8 *cia); +u64 GetCiaCertOffset(cia_hdr *hdr); +u64 GetCiaCertSize(cia_hdr *hdr); +u64 GetCiaTikOffset(cia_hdr *hdr); +u64 GetCiaTikSize(cia_hdr *hdr); +u64 GetCiaTmdOffset(cia_hdr *hdr); +u64 GetCiaTmdSize(cia_hdr *hdr); +u64 GetCiaContentOffset(cia_hdr *hdr); +u64 GetCiaContentSize(cia_hdr *hdr); +u64 GetCiaMetaOffset(cia_hdr *hdr); +u64 GetCiaMetaSize(cia_hdr *hdr); + +u8* GetCiaCert(u8 *cia); +u8* GetCiaTik(u8 *cia); +u8* GetCiaTmd(u8 *cia); +u8* GetCiaContent(u8 *cia); +u8* GetCiaMeta(u8 *cia); diff --git a/makerom/crypto.c b/makerom/crypto.c index fc482e0..bbc977e 100644 --- a/makerom/crypto.c +++ b/makerom/crypto.c @@ -1,6 +1,13 @@ #include "lib.h" #include "crypto.h" +bool VerifySha256(void *data, u64 size, u8 hash[32]) +{ + u8 calchash[32]; + ctr_sha(data, size, calchash, CTR_SHA_256); + return memcmp(hash,calchash,32) == 0; +} + void ctr_sha(void *data, u64 size, u8 *hash, int mode) { switch(mode){ @@ -9,21 +16,6 @@ void ctr_sha(void *data, u64 size, u8 *hash, int mode) } } -u8* AesKeyScrambler(u8 *Key, u8 *KeyX, u8 *KeyY) -{ - // Process KeyX/KeyY to get raw normal key - for(int i = 0; i < 16; i++) - Key[i] = KeyX[i] ^ ((KeyY[i] >> 2) | ((KeyY[i < 15 ? i+1 : 0] & 3) << 6)); - - const u8 SCRAMBLE_SECRET[16] = {0x51, 0xD7, 0x5D, 0xBE, 0xFD, 0x07, 0x57, 0x6A, 0x1C, 0xFC, 0x2A, 0xF0, 0x94, 0x4B, 0xD5, 0x6C}; - - // Apply Secret to get final normal key - for(int i = 0; i < 16; i++) - Key[i] = Key[i] ^ SCRAMBLE_SECRET[i]; - - return Key; -} - void ctr_add_counter(ctr_aes_context* ctx, u32 carry) { u32 counter[4]; diff --git a/makerom/crypto.h b/makerom/crypto.h index 19b5163..3d5aaee 100644 --- a/makerom/crypto.h +++ b/makerom/crypto.h @@ -71,9 +71,9 @@ typedef struct extern "C" { #endif // SHA +bool VerifySha256(void *data, u64 size, u8 hash[32]); void ctr_sha(void *data, u64 size, u8 *hash, int mode); // AES -u8* AesKeyScrambler(u8 *Key, u8 *KeyX, u8 *KeyY); void ctr_add_counter(ctr_aes_context* ctx, u32 carry); void ctr_init_counter(ctr_aes_context* ctx, u8 key[16],u8 ctr[16]); void ctr_crypt_counter_block(ctr_aes_context* ctx, u8 input[16], u8 output[16]); diff --git a/makerom/ctr_utils.c b/makerom/ctr_utils.c new file mode 100644 index 0000000..d8e9610 --- /dev/null +++ b/makerom/ctr_utils.c @@ -0,0 +1,14 @@ +#include "lib.h" + +u32 GetCtrBlockSize(u8 flag) +{ + return 1 << (flag + 9); +} + +u8 GetCtrBlockSizeFlag(u32 size) +{ + u8 ret = 0; + for(u32 tmp = size; tmp > 0x200; tmp = tmp >> 1) + ret++; + return ret; +} \ No newline at end of file diff --git a/makerom/ctr_utils.h b/makerom/ctr_utils.h new file mode 100644 index 0000000..3c92de4 --- /dev/null +++ b/makerom/ctr_utils.h @@ -0,0 +1,4 @@ +#pragma once + +u32 GetCtrBlockSize(u8 flag); +u8 GetCtrBlockSizeFlag(u32 size); \ No newline at end of file diff --git a/makerom/desc_dev_sigdata.h b/makerom/desc/dev_sigdata.h similarity index 100% rename from makerom/desc_dev_sigdata.h rename to makerom/desc/dev_sigdata.h diff --git a/makerom/desc_presets.h b/makerom/desc/presets.h similarity index 100% rename from makerom/desc_presets.h rename to makerom/desc/presets.h diff --git a/makerom/desc_prod_sigdata.h b/makerom/desc/prod_sigdata.h similarity index 100% rename from makerom/desc_prod_sigdata.h rename to makerom/desc/prod_sigdata.h diff --git a/makerom/dir.c b/makerom/dir.c index bcd57b2..b0fb1e7 100644 --- a/makerom/dir.c +++ b/makerom/dir.c @@ -118,10 +118,10 @@ fs_entry* fs_GetEntry(fs_DIR *dp) { entry->IsDir = false; #ifdef _WIN32 - entry->size = wGetFileSize_u64(entry->fs_name); + entry->size = wGetFileSize64(entry->fs_name); entry->fp = _wfopen(entry->fs_name,L"rb"); #else - entry->size = GetFileSize_u64(entry->fs_name); + entry->size = GetFileSize64(entry->fs_name); entry->fp = fopen(entry->fs_name,"rb"); #endif } diff --git a/makerom/elf.c b/makerom/elf.c index 2ef515c..3f5a91c 100644 --- a/makerom/elf.c +++ b/makerom/elf.c @@ -1,125 +1,111 @@ #include "lib.h" -#include "ncch.h" +#include "ncch_build.h" #include "elf_hdr.h" #include "elf.h" #include "blz.h" -int ImportPlainRegionFromFile(ncch_settings *ncchset); -int ImportExeFsCodeBinaryFromFile(ncch_settings *ncchset); +int ImportPlainRegionFromFile(ncch_settings *set); +int ImportExeFsCodeBinaryFromFile(ncch_settings *set); -u32 GetPageSize(ncch_settings *ncchset); -u32 SizeToPage(u32 memorySize, ElfContext *elf); +u32 GetPageSize(ncch_settings *set); +u32 SizeToPage(u32 memorySize, elf_context *elf); -int GetBSS_SizeFromElf(ElfContext *elf, u8 *ElfFile, ncch_settings *ncchset); -int ImportPlainRegionFromElf(ElfContext *elf, u8 *ElfFile, ncch_settings *ncchset); -int CreateExeFsCode(ElfContext *elf, u8 *ElfFile, ncch_settings *ncchset); -int CreateCodeSegmentFromElf(CodeSegment *out, ElfContext *elf, u8 *ElfFile, char **Names, u32 NameNum); -ElfSegment** GetContinuousSegments(u16 *ContinuousSegmentNum, ElfContext *elf, char **Names, u32 NameNum); -ElfSegment** GetSegments(u16 *SegmentNum, ElfContext *elf, char **Names, u32 NameNum); +int GetBSSFromElf(elf_context *elf, u8 *elfFile, ncch_settings *set); +int ImportPlainRegionFromElf(elf_context *elf, u8 *elfFile, ncch_settings *set); +int CreateExeFsCode(elf_context *elf, u8 *elfFile, ncch_settings *set); +int CreateCodeSegmentFromElf(code_segment *out, elf_context *elf, u8 *elfFile, char **names, u32 nameNum); +elf_segment** GetContinuousSegments(u16 *ContinuousSegmentNum, elf_context *elf, char **names, u32 nameNum); +elf_segment** GetSegments(u16 *SegmentNum, elf_context *elf, char **names, u32 nameNum); // ELF Functions -int GetElfContext(ElfContext *elf, u8 *ElfFile); -int GetElfSectionEntries(ElfContext *elf, u8 *ElfFile); -int GetElfProgramEntries(ElfContext *elf, u8 *ElfFile); -#ifdef DEBUG -void PrintElfContext(ElfContext *elf, u8 *ElfFile); -#endif -int ReadElfHdr(ElfContext *elf, u8 *ElfFile); +int GetElfContext(elf_context *elf, u8 *elfFile); +int GetElfSectionEntries(elf_context *elf, u8 *elfFile); +int GetElfProgramEntries(elf_context *elf, u8 *elfFile); +void PrintElfContext(elf_context *elf, u8 *elfFile); +int ReadElfHdr(elf_context *elf, u8 *elfFile); -int CreateElfSegments(ElfContext *elf, u8 *ElfFile); -bool IsIgnoreSection(ElfSectionEntry info); +int CreateElfSegments(elf_context *elf, u8 *elfFile); +bool IsIgnoreSection(elf_section_entry info); /* ELF Section Entry Functions */ -u8* GetELFSectionHeader(u16 Index, ElfContext *elf, u8 *ElfFile); -u8* GetELFSectionEntry(u16 Index, ElfContext *elf, u8 *ElfFile); -char* GetELFSectionEntryName(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFSectionEntryType(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFSectionEntryFlags(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFSectionEntryAddress(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFSectionEntryFileOffset(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFSectionEntrySize(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFSectionEntryAlignment(u16 Index, ElfContext *elf, u8 *ElfFile); +u8* GetELFSectionHeader(u16 index, elf_context *elf, u8 *elfFile); +u8* GetELFSectionEntry(u16 index, elf_context *elf, u8 *elfFile); +char* GetELFSectionEntryName(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFSectionEntryType(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFSectionEntryFlags(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFSectionEntryAddress(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFSectionEntryFileOffset(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFSectionEntrySize(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFSectionEntryAlignment(u16 index, elf_context *elf, u8 *elfFile); -u16 GetElfSectionIndexFromName(char *Name, ElfContext *elf, u8 *ElfFile); +u16 GetElfSectionIndexFromName(char *name, elf_context *elf, u8 *elfFile); -bool IsBss(ElfSectionEntry *Section); -bool IsData(ElfSectionEntry *Section); -bool IsRO(ElfSectionEntry *Section); -bool IsText(ElfSectionEntry *Section); +bool IsBss(elf_section_entry *section); +bool IsData(elf_section_entry *section); +bool IsRoData(elf_section_entry *section); +bool IsText(elf_section_entry *section); /* ELF Program Entry Functions */ -u8* GetELFProgramHeader(u16 Index, ElfContext *elf, u8 *ElfFile); -u8* GetELFProgramEntry(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFProgramEntryType(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFProgramEntryFlags(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFProgramEntryFileSize(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFProgramEntryFileOffset(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFProgramEntryMemorySize(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFProgramEntryVAddress(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFProgramEntryPAddress(u16 Index, ElfContext *elf, u8 *ElfFile); -u64 GetELFProgramEntryAlignment(u16 Index, ElfContext *elf, u8 *ElfFile); +u8* GetELFProgramHeader(u16 index, elf_context *elf, u8 *elfFile); +u8* GetELFProgramEntry(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFProgramEntryType(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFProgramEntryFlags(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFProgramEntryFileSize(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFProgramEntryFileOffset(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFProgramEntryMemorySize(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFProgramEntryVAddress(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFProgramEntryPAddress(u16 index, elf_context *elf, u8 *elfFile); +u64 GetELFProgramEntryAlignment(u16 index, elf_context *elf, u8 *elfFile); -int BuildExeFsCode(ncch_settings *ncchset) +int BuildExeFsCode(ncch_settings *set) { int result = 0; - if(ncchset->options.IsCfa) + if(set->options.IsCfa) return result; - if(ncchset->componentFilePtrs.plainregion){ // Import PlainRegion from file - result = ImportPlainRegionFromFile(ncchset); + if(set->componentFilePtrs.plainregion){ // Import PlainRegion from file + result = ImportPlainRegionFromFile(set); if(result) return result; } - if(!ncchset->options.IsBuildingCodeSection){ // Import ExeFs Code from file and return - result = ImportExeFsCodeBinaryFromFile(ncchset); + if(!set->options.IsBuildingCodeSection){ // Import ExeFs Code from file and return + result = ImportExeFsCodeBinaryFromFile(set); return result; } -#ifdef DEBUG - printf("[DEBUG] Import ELF\n"); -#endif /* Import ELF */ - u8 *ElfFile = malloc(ncchset->componentFilePtrs.elfSize); - if(!ElfFile) { + u8 *elfFile = malloc(set->componentFilePtrs.elfSize); + if(!elfFile) { fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR; } - ReadFile_64(ElfFile,ncchset->componentFilePtrs.elfSize,0,ncchset->componentFilePtrs.elf); + ReadFile64(elfFile,set->componentFilePtrs.elfSize,0,set->componentFilePtrs.elf); -#ifdef DEBUG - printf("[DEBUG] Create ELF Context\n"); -#endif /* Create ELF Context */ - ElfContext *elf = calloc(1,sizeof(ElfContext)); + elf_context *elf = calloc(1,sizeof(elf_context)); if(!elf) { fprintf(stderr,"[ELF ERROR] Not enough memory\n"); - free(ElfFile); + free(elfFile); return MEM_ERROR; } - result = GetElfContext(elf,ElfFile); + result = GetElfContext(elf,elfFile); if(result) goto finish; /* Setting Page Size */ - elf->pageSize = GetPageSize(ncchset); + elf->pageSize = GetPageSize(set); - if(!ncchset->componentFilePtrs.plainregion){ - result = ImportPlainRegionFromElf(elf,ElfFile,ncchset); + if(!set->componentFilePtrs.plainregion){ + result = ImportPlainRegionFromElf(elf,elfFile,set); if(result) goto finish; } -#ifdef DEBUG - PrintElfContext(elf,ElfFile); -#endif + if(set->options.verbose) + PrintElfContext(elf,elfFile); -#ifdef DEBUG - printf("[DEBUG] Create ExeFs Code\n"); -#endif - result = CreateExeFsCode(elf,ElfFile,ncchset); + result = CreateExeFsCode(elf,elfFile,set); if(result) goto finish; -#ifdef DEBUG - printf("[DEBUG] Get BSS Size\n"); -#endif - result = GetBSS_SizeFromElf(elf,ElfFile,ncchset); + + result = GetBSSFromElf(elf,elfFile,set); if(result) goto finish; finish: @@ -131,19 +117,9 @@ finish: else if(result == NOT_FIND_CODE_SECTIONS) fprintf(stderr,"[ELF ERROR] Failed to retrieve code sections from ELF\n"); else fprintf(stderr,"[ELF ERROR] Failed to process ELF file (%d)\n",result); } -#ifdef DEBUG - printf("[DEBUG] Free Segment Header/Sections\n"); -#endif - for(int i = 0; i < elf->activeSegments; i++){ -#ifdef DEBUG - printf("[DEBUG] %d\n",i); -#endif + for(int i = 0; i < elf->activeSegments; i++) free(elf->segments[i].sections); - } -#ifdef DEBUG - printf("[DEBUG] Free others\n"); -#endif - free(ElfFile); + free(elfFile); free(elf->sections); free(elf->programHeaders); free(elf->segments); @@ -151,168 +127,168 @@ finish: return result; } -int ImportPlainRegionFromFile(ncch_settings *ncchset) +int ImportPlainRegionFromFile(ncch_settings *set) { - ncchset->sections.plainRegion.size = align(ncchset->componentFilePtrs.plainregionSize,ncchset->options.mediaSize); - ncchset->sections.plainRegion.buffer = malloc(ncchset->sections.plainRegion.size); - if(!ncchset->sections.plainRegion.buffer) {fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR;} - ReadFile_64(ncchset->sections.plainRegion.buffer,ncchset->componentFilePtrs.plainregionSize,0,ncchset->componentFilePtrs.plainregion); + set->sections.plainRegion.size = align(set->componentFilePtrs.plainregionSize,set->options.blockSize); + set->sections.plainRegion.buffer = malloc(set->sections.plainRegion.size); + if(!set->sections.plainRegion.buffer) {fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR;} + ReadFile64(set->sections.plainRegion.buffer,set->componentFilePtrs.plainregionSize,0,set->componentFilePtrs.plainregion); return 0; } -int ImportExeFsCodeBinaryFromFile(ncch_settings *ncchset) +int ImportExeFsCodeBinaryFromFile(ncch_settings *set) { - u32 size = ncchset->componentFilePtrs.codeSize; + u32 size = set->componentFilePtrs.codeSize; u8 *buffer = malloc(size); if(!buffer) {fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR;} - ReadFile_64(buffer,size,0,ncchset->componentFilePtrs.code); + ReadFile64(buffer,size,0,set->componentFilePtrs.code); - ncchset->exefsSections.code.size = ncchset->componentFilePtrs.codeSize; - ncchset->exefsSections.code.buffer = malloc(ncchset->exefsSections.code.size); - if(!ncchset->exefsSections.code.buffer) {fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR;} - ReadFile_64(ncchset->exefsSections.code.buffer,ncchset->exefsSections.code.size,0,ncchset->componentFilePtrs.code); - if(ncchset->options.CompressCode){ + set->exefsSections.code.size = set->componentFilePtrs.codeSize; + set->exefsSections.code.buffer = malloc(set->exefsSections.code.size); + if(!set->exefsSections.code.buffer) {fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR;} + ReadFile64(set->exefsSections.code.buffer,set->exefsSections.code.size,0,set->componentFilePtrs.code); + if(set->options.CompressCode){ u32 new_len; - ncchset->exefsSections.code.buffer = BLZ_Code(buffer,size,&new_len,BLZ_NORMAL); - ncchset->exefsSections.code.size = new_len; + set->exefsSections.code.buffer = BLZ_Code(buffer,size,&new_len,BLZ_NORMAL); + set->exefsSections.code.size = new_len; free(buffer); } else{ - ncchset->exefsSections.code.size = size; - ncchset->exefsSections.code.buffer = buffer; + set->exefsSections.code.size = size; + set->exefsSections.code.buffer = buffer; } return 0; } -u32 GetPageSize(ncch_settings *ncchset) +u32 GetPageSize(ncch_settings *set) { - if(ncchset->rsfSet->Option.PageSize) - return strtoul(ncchset->rsfSet->Option.PageSize,NULL,10); + if(set->rsfSet->Option.PageSize) + return strtoul(set->rsfSet->Option.PageSize,NULL,10); return 0x1000; } -u32 SizeToPage(u32 memorySize, ElfContext *elf) +u32 SizeToPage(u32 memorySize, elf_context *elf) { return align(memorySize,elf->pageSize)/elf->pageSize; } -int GetBSS_SizeFromElf(ElfContext *elf, u8 *ElfFile, ncch_settings *ncchset) +int GetBSSFromElf(elf_context *elf, u8 *elfFile, ncch_settings *set) { for(int i = 0; i < elf->sectionTableEntryCount; i++){ if(IsBss(&elf->sections[i])) { - ncchset->codeDetails.bssSize = elf->sections[i].size; + set->codeDetails.bssSize = elf->sections[i].size; return 0; } } return NOT_FIND_BSS_SIZE; } -int ImportPlainRegionFromElf(ElfContext *elf, u8 *ElfFile, ncch_settings *ncchset) // Doesn't work same as N makerom +int ImportPlainRegionFromElf(elf_context *elf, u8 *elfFile, ncch_settings *set) // Doesn't work same as N makerom { - if(!ncchset->rsfSet->PlainRegionNum) return 0; - u16 *Index = calloc(ncchset->rsfSet->PlainRegionNum,sizeof(u16)); + if(!set->rsfSet->PlainRegionNum) return 0; + u16 *index = calloc(set->rsfSet->PlainRegionNum,sizeof(u16)); - /* Getting Index Values for each section */ - for(int i = 0; i < ncchset->rsfSet->PlainRegionNum; i++){ - Index[i] = GetElfSectionIndexFromName(ncchset->rsfSet->PlainRegion[i],elf,ElfFile); + /* Getting index Values for each section */ + for(int i = 0; i < set->rsfSet->PlainRegionNum; i++){ + index[i] = GetElfSectionIndexFromName(set->rsfSet->PlainRegion[i],elf,elfFile); } // Eliminating Duplicated Sections - for(int i = ncchset->rsfSet->PlainRegionNum - 1; i >= 0; i--){ + for(int i = set->rsfSet->PlainRegionNum - 1; i >= 0; i--){ for(int j = i-1; j >= 0; j--){ - if(Index[i] == Index[j]) Index[i] = 0; + if(index[i] == index[j]) index[i] = 0; } } /* Calculating Total Size of Data */ - u64 TotalSize = 0; - for(int i = 0; i < ncchset->rsfSet->PlainRegionNum; i++){ - TotalSize += elf->sections[Index[i]].size; + u64 totalSize = 0; + for(int i = 0; i < set->rsfSet->PlainRegionNum; i++){ + totalSize += elf->sections[index[i]].size; } /* Creating Output Buffer */ - ncchset->sections.plainRegion.size = align(TotalSize,ncchset->options.mediaSize); - ncchset->sections.plainRegion.buffer = malloc(ncchset->sections.plainRegion.size); - if(!ncchset->sections.plainRegion.buffer) {fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR;} - memset(ncchset->sections.plainRegion.buffer,0,ncchset->sections.plainRegion.size); + set->sections.plainRegion.size = align(totalSize,set->options.blockSize); + set->sections.plainRegion.buffer = malloc(set->sections.plainRegion.size); + if(!set->sections.plainRegion.buffer) {fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR;} + memset(set->sections.plainRegion.buffer,0,set->sections.plainRegion.size); /* Storing Sections */ u64 pos = 0; - for(int i = 0; i < ncchset->rsfSet->PlainRegionNum; i++){ - memcpy((ncchset->sections.plainRegion.buffer+pos),elf->sections[Index[i]].ptr,elf->sections[Index[i]].size); - pos += elf->sections[Index[i]].size; + for(int i = 0; i < set->rsfSet->PlainRegionNum; i++){ + memcpy((set->sections.plainRegion.buffer+pos),elf->sections[index[i]].ptr,elf->sections[index[i]].size); + pos += elf->sections[index[i]].size; } return 0; } -int CreateExeFsCode(ElfContext *elf, u8 *ElfFile, ncch_settings *ncchset) +int CreateExeFsCode(elf_context *elf, u8 *elfFile, ncch_settings *set) { /* Getting Code Segments */ - CodeSegment Text; - memset(&Text,0,sizeof(CodeSegment)); - CodeSegment RO; - memset(&RO,0,sizeof(CodeSegment)); - CodeSegment Data; - memset(&Data,0,sizeof(CodeSegment)); + code_segment text; + memset(&text,0,sizeof(code_segment)); + code_segment rodata; + memset(&rodata,0,sizeof(code_segment)); + code_segment rwdata; + memset(&rwdata,0,sizeof(code_segment)); - int result = CreateCodeSegmentFromElf(&Text,elf,ElfFile,ncchset->rsfSet->ExeFs.Text,ncchset->rsfSet->ExeFs.TextNum); + int result = CreateCodeSegmentFromElf(&text,elf,elfFile,set->rsfSet->ExeFs.Text,set->rsfSet->ExeFs.TextNum); if(result) return result; - result = CreateCodeSegmentFromElf(&RO,elf,ElfFile,ncchset->rsfSet->ExeFs.ReadOnly,ncchset->rsfSet->ExeFs.ReadOnlyNum); + result = CreateCodeSegmentFromElf(&rodata,elf,elfFile,set->rsfSet->ExeFs.ReadOnly,set->rsfSet->ExeFs.ReadOnlyNum); if(result) return result; - result = CreateCodeSegmentFromElf(&Data,elf,ElfFile,ncchset->rsfSet->ExeFs.ReadWrite,ncchset->rsfSet->ExeFs.ReadWriteNum); + result = CreateCodeSegmentFromElf(&rwdata,elf,elfFile,set->rsfSet->ExeFs.ReadWrite,set->rsfSet->ExeFs.ReadWriteNum); if(result) return result; /* Allocating Buffer for ExeFs Code */ - u32 size = (Text.maxPageNum + RO.maxPageNum + Data.maxPageNum)*elf->pageSize; + u32 size = (text.maxPageNum + rodata.maxPageNum + rwdata.maxPageNum)*elf->pageSize; u8 *code = malloc(size); /* Writing Code into Buffer */ - u8 *TextPos = (code + 0); - u8 *ROPos = (code + Text.maxPageNum*elf->pageSize); - u8 *DataPos = (code + (Text.maxPageNum + RO.maxPageNum)*elf->pageSize); - if(Text.size) memcpy(TextPos,Text.data,Text.size); - if(RO.size) memcpy(ROPos,RO.data,RO.size); - if(Data.size) memcpy(DataPos,Data.data,Data.size); + u8 *textPos = (code + 0); + u8 *rodataPos = (code + text.maxPageNum*elf->pageSize); + u8 *rwdataPos = (code + (text.maxPageNum + rodata.maxPageNum)*elf->pageSize); + if(text.size) memcpy(textPos,text.data,text.size); + if(rodata.size) memcpy(rodataPos,rodata.data,rodata.size); + if(rwdata.size) memcpy(rwdataPos,rwdata.data,rwdata.size); /* Compressing If needed */ - if(ncchset->options.CompressCode){ + if(set->options.CompressCode){ u32 new_len; - ncchset->exefsSections.code.buffer = BLZ_Code(code,size,&new_len,BLZ_NORMAL); - ncchset->exefsSections.code.size = new_len; + set->exefsSections.code.buffer = BLZ_Code(code,size,&new_len,BLZ_NORMAL); + set->exefsSections.code.size = new_len; free(code); } else{ - ncchset->exefsSections.code.size = size; - ncchset->exefsSections.code.buffer = code; + set->exefsSections.code.size = size; + set->exefsSections.code.buffer = code; } - /* Setting CodeSegment Data and freeing original buffers */ - ncchset->codeDetails.textAddress = Text.address; - ncchset->codeDetails.textMaxPages = Text.maxPageNum; - ncchset->codeDetails.textSize = Text.size; - if(Text.size) free(Text.data); + /* Setting code_segment rwdata and freeing original buffers */ + set->codeDetails.textAddress = text.address; + set->codeDetails.textMaxPages = text.maxPageNum; + set->codeDetails.textSize = text.size; + if(text.size) free(text.data); - ncchset->codeDetails.roAddress = RO.address; - ncchset->codeDetails.roMaxPages = RO.maxPageNum; - ncchset->codeDetails.roSize = RO.size; - if(RO.size) free(RO.data); + set->codeDetails.roAddress = rodata.address; + set->codeDetails.roMaxPages = rodata.maxPageNum; + set->codeDetails.roSize = rodata.size; + if(rodata.size) free(rodata.data); - ncchset->codeDetails.rwAddress = Data.address; - ncchset->codeDetails.rwMaxPages = Data.maxPageNum; - ncchset->codeDetails.rwSize = Data.size; - if(Data.size) free(Data.data); + set->codeDetails.rwAddress = rwdata.address; + set->codeDetails.rwMaxPages = rwdata.maxPageNum; + set->codeDetails.rwSize = rwdata.size; + if(rwdata.size) free(rwdata.data); /* Return */ return 0; } -int CreateCodeSegmentFromElf(CodeSegment *out, ElfContext *elf, u8 *ElfFile, char **Names, u32 NameNum) +int CreateCodeSegmentFromElf(code_segment *out, elf_context *elf, u8 *elfFile, char **names, u32 nameNum) { u16 ContinuousSegmentNum = 0; - memset(out,0,sizeof(CodeSegment)); - ElfSegment **ContinuousSegments = GetContinuousSegments(&ContinuousSegmentNum,elf,Names,NameNum); + memset(out,0,sizeof(code_segment)); + elf_segment **ContinuousSegments = GetContinuousSegments(&ContinuousSegmentNum,elf,names,nameNum); if (ContinuousSegments == NULL){ if(!ContinuousSegmentNum){// Nothing Was Found //printf("Nothing was found\n"); @@ -366,17 +342,17 @@ int CreateCodeSegmentFromElf(CodeSegment *out, ElfContext *elf, u8 *ElfFile, cha */ //u32 size = 0; for (int j = 0; j < ContinuousSegments[i]->sectionNum; j++){ - ElfSectionEntry *Section = &ContinuousSegments[i]->sections[j]; - if (!IsBss(Section)){ - u8 *pos = (out->data + (Section->address - ContinuousSegments[i]->vAddr)); - memcpy(pos,Section->ptr,Section->size); - //size += Section->size; + elf_section_entry *section = &ContinuousSegments[i]->sections[j]; + if (!IsBss(section)){ + u8 *pos = (out->data + (section->address - ContinuousSegments[i]->vAddr)); + memcpy(pos,section->ptr,section->size); + //size += section->size; } //else if (j == (ContinuousSegments[i]->sectionNum-1)) - //memorySize -= Section->size; + //memorySize -= section->size; //'else - //size += Section->size; + //size += section->size; } } @@ -385,10 +361,10 @@ int CreateCodeSegmentFromElf(CodeSegment *out, ElfContext *elf, u8 *ElfFile, cha } -ElfSegment** GetContinuousSegments(u16 *ContinuousSegmentNum, ElfContext *elf, char **Names, u32 NameNum) +elf_segment** GetContinuousSegments(u16 *ContinuousSegmentNum, elf_context *elf, char **names, u32 nameNum) { u16 SegmentNum = 0; - ElfSegment **Segments = GetSegments(&SegmentNum, elf, Names, NameNum); + elf_segment **Segments = GetSegments(&SegmentNum, elf, names, nameNum); if (Segments == NULL || SegmentNum == 0){ // No Segments for the names were found //printf("Not Found Segment\n"); return NULL; @@ -413,18 +389,18 @@ ElfSegment** GetContinuousSegments(u16 *ContinuousSegmentNum, ElfContext *elf, c } -ElfSegment** GetSegments(u16 *SegmentNum, ElfContext *elf, char **Names, u32 NameNum) +elf_segment** GetSegments(u16 *SegmentNum, elf_context *elf, char **names, u32 nameNum) { - if (Names == NULL) + if (names == NULL) { return NULL; } - ElfSegment **Segments = calloc(NameNum,sizeof(ElfSegment*)); - *SegmentNum = 0; // There can be a max of NameNum Segments, however, they might not all exist - for (int i = 0; i < NameNum; i++){ + elf_segment **Segments = calloc(nameNum,sizeof(elf_segment*)); + *SegmentNum = 0; // There can be a max of nameNum Segments, however, they might not all exist + for (int i = 0; i < nameNum; i++){ for(int j = 0; j < elf->activeSegments; j++){ - if(strcmp(Names[i],elf->segments[j].name) == 0){ // If there is a match, store Segment data pointer & increment index + if(strcmp(names[i],elf->segments[j].name) == 0){ // If there is a match, store Segment data pointer & increment index Segments[*SegmentNum] = &elf->segments[j]; *SegmentNum = *SegmentNum + 1; } @@ -435,95 +411,93 @@ ElfSegment** GetSegments(u16 *SegmentNum, ElfContext *elf, char **Names, u32 Nam // ELF Functions -int GetElfContext(ElfContext *elf, u8 *ElfFile) +int GetElfContext(elf_context *elf, u8 *elfFile) { - if(u8_to_u32(ElfFile,BE) != ELF_MAGIC) return NOT_ELF_FILE; + if(u8_to_u32(elfFile,BE) != ELF_MAGIC) return NOT_ELF_FILE; - elf->Is64bit = (ElfFile[4] == elf_64_bit); - elf->IsLittleEndian = (ElfFile[5] == elf_little_endian); + elf->Is64bit = (elfFile[4] == elf_64_bit); + elf->IsLittleEndian = (elfFile[5] == elf_little_endian); - int result = ReadElfHdr(elf,ElfFile); + int result = ReadElfHdr(elf,elfFile); if(result) return result; - result = GetElfSectionEntries(elf,ElfFile); + result = GetElfSectionEntries(elf,elfFile); if(result) return result; - result = GetElfProgramEntries(elf,ElfFile); + result = GetElfProgramEntries(elf,elfFile); if(result) return result; - result = CreateElfSegments(elf,ElfFile); + result = CreateElfSegments(elf,elfFile); if(result) return result; return 0; } -int GetElfSectionEntries(ElfContext *elf, u8 *ElfFile) +int GetElfSectionEntries(elf_context *elf, u8 *elfFile) { - elf->sections = calloc(elf->sectionTableEntryCount,sizeof(ElfSectionEntry)); + elf->sections = calloc(elf->sectionTableEntryCount,sizeof(elf_section_entry)); if(!elf->sections) { fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR; } for(int i = 0; i < elf->sectionTableEntryCount; i++){ - elf->sections[i].name = GetELFSectionEntryName(i,elf,ElfFile); - elf->sections[i].type = GetELFSectionEntryType(i,elf,ElfFile); - elf->sections[i].flags = GetELFSectionEntryFlags(i,elf,ElfFile); - elf->sections[i].ptr = GetELFSectionEntry(i,elf,ElfFile); - elf->sections[i].offsetInFile = GetELFSectionEntryFileOffset(i,elf,ElfFile); - elf->sections[i].size = GetELFSectionEntrySize(i,elf,ElfFile); - elf->sections[i].address = GetELFSectionEntryAddress(i,elf,ElfFile); - elf->sections[i].alignment = GetELFSectionEntryAlignment(i,elf,ElfFile); + elf->sections[i].name = GetELFSectionEntryName(i,elf,elfFile); + elf->sections[i].type = GetELFSectionEntryType(i,elf,elfFile); + elf->sections[i].flags = GetELFSectionEntryFlags(i,elf,elfFile); + elf->sections[i].ptr = GetELFSectionEntry(i,elf,elfFile); + elf->sections[i].offsetInFile = GetELFSectionEntryFileOffset(i,elf,elfFile); + elf->sections[i].size = GetELFSectionEntrySize(i,elf,elfFile); + elf->sections[i].address = GetELFSectionEntryAddress(i,elf,elfFile); + elf->sections[i].alignment = GetELFSectionEntryAlignment(i,elf,elfFile); } return 0; } -int GetElfProgramEntries(ElfContext *elf, u8 *ElfFile) +int GetElfProgramEntries(elf_context *elf, u8 *elfFile) { - elf->programHeaders = calloc(elf->programTableEntryCount,sizeof(ElfProgramEntry)); + elf->programHeaders = calloc(elf->programTableEntryCount,sizeof(elf_program_entry)); if(!elf->programHeaders) { fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR; } for(int i = 0; i < elf->programTableEntryCount; i++){ - elf->programHeaders[i].type = GetELFProgramEntryType(i,elf,ElfFile); - elf->programHeaders[i].flags = GetELFProgramEntryFlags(i,elf,ElfFile); - elf->programHeaders[i].ptr = GetELFProgramEntry(i,elf,ElfFile); - elf->programHeaders[i].offsetInFile = GetELFProgramEntryFileOffset(i,elf,ElfFile); - elf->programHeaders[i].sizeInFile = GetELFProgramEntryFileSize(i,elf,ElfFile); - elf->programHeaders[i].physicalAddress = GetELFProgramEntryPAddress(i,elf,ElfFile); - elf->programHeaders[i].virtualAddress = GetELFProgramEntryVAddress(i,elf,ElfFile); - elf->programHeaders[i].sizeInMemory = GetELFProgramEntryMemorySize(i,elf,ElfFile); - elf->programHeaders[i].alignment = GetELFProgramEntryAlignment(i,elf,ElfFile); + elf->programHeaders[i].type = GetELFProgramEntryType(i,elf,elfFile); + elf->programHeaders[i].flags = GetELFProgramEntryFlags(i,elf,elfFile); + elf->programHeaders[i].ptr = GetELFProgramEntry(i,elf,elfFile); + elf->programHeaders[i].offsetInFile = GetELFProgramEntryFileOffset(i,elf,elfFile); + elf->programHeaders[i].sizeInFile = GetELFProgramEntryFileSize(i,elf,elfFile); + elf->programHeaders[i].physicalAddress = GetELFProgramEntryPAddress(i,elf,elfFile); + elf->programHeaders[i].virtualAddress = GetELFProgramEntryVAddress(i,elf,elfFile); + elf->programHeaders[i].sizeInMemory = GetELFProgramEntryMemorySize(i,elf,elfFile); + elf->programHeaders[i].alignment = GetELFProgramEntryAlignment(i,elf,elfFile); } return 0; } -#ifdef DEBUG -void PrintElfContext(ElfContext *elf, u8 *ElfFile) +void PrintElfContext(elf_context *elf, u8 *elfFile) { - printf("[+] Basic Details\n"); + printf("[ELF] Basic Details\n"); printf(" Class: %s\n",elf->Is64bit ? "64-bit" : "32-bit"); printf(" Data: %s\n",elf->IsLittleEndian ? "Little Endian" : "Big Endian"); - printf("\n[+] Program Table Data\n"); - printf(" Offset: 0x%lx\n",elf->programTableOffset); + printf("[ELF] Program Table Data\n"); + printf(" Offset: 0x%"PRIX64"\n",elf->programTableOffset); printf(" Size: 0x%x\n",elf->programTableEntrySize); printf(" Count: 0x%x\n",elf->programTableEntryCount); - printf("\n[+] Section Table Data\n"); - printf(" Offset: 0x%lx\n",elf->sectionTableOffset); + printf("[ELF] Section Table Data\n"); + printf(" Offset: 0x%"PRIX64"\n",elf->sectionTableOffset); printf(" Size: 0x%x\n",elf->sectionTableEntrySize); printf(" Count: 0x%x\n",elf->sectionTableEntryCount); - printf(" Lable Index: 0x%x\n",elf->sectionHeaderNameEntryIndex); + printf(" Label index: 0x%x\n",elf->sectionHeaderNameEntryIndex); for(int i = 0; i < elf->activeSegments; i++){ printf(" Segment [%d][%s]\n",i,elf->segments[i].name); - printf(" > Size : 0x%x\n",elf->segments[i].header->sizeInFile); - printf(" > Address : 0x%x\n",elf->segments[i].vAddr); + printf(" > Size : 0x%"PRIX64"\n",elf->segments[i].header->sizeInFile); + printf(" > Address : 0x%"PRIX64"\n",elf->segments[i].vAddr); printf(" > Sections : %d\n",elf->segments[i].sectionNum); - for(int j = 0; j < elf->segments[i].sectionNum; j++){ + for(int j = 0; j < elf->segments[i].sectionNum; j++) printf(" > Section [%d][%s]\n",j,elf->segments[i].sections[j].name); - } /* char outpath[100]; @@ -538,12 +512,11 @@ void PrintElfContext(ElfContext *elf, u8 *ElfFile) } } -#endif -int ReadElfHdr(ElfContext *elf, u8 *ElfFile) +int ReadElfHdr(elf_context *elf, u8 *elfFile) { if(elf->Is64bit){ - elf_64_hdr *hdr = (elf_64_hdr*)ElfFile; + elf_64_hdr *hdr = (elf_64_hdr*)elfFile; u16 Architecture = u8_to_u16(hdr->targetArchitecture,elf->IsLittleEndian); u16 Type = u8_to_u16(hdr->type,elf->IsLittleEndian); @@ -561,7 +534,7 @@ int ReadElfHdr(ElfContext *elf, u8 *ElfFile) elf->sectionHeaderNameEntryIndex = u8_to_u16(hdr->sectionHeaderNameEntryIndex,elf->IsLittleEndian); } else{ - elf_32_hdr *hdr = (elf_32_hdr*)ElfFile; + elf_32_hdr *hdr = (elf_32_hdr*)elfFile; u16 Architecture = u8_to_u16(hdr->targetArchitecture,elf->IsLittleEndian); u16 Type = u8_to_u16(hdr->type,elf->IsLittleEndian); @@ -583,129 +556,129 @@ int ReadElfHdr(ElfContext *elf, u8 *ElfFile) /* Section Hdr Functions */ -u8* GetELFSectionHeader(u16 Index, ElfContext *elf, u8 *ElfFile) +u8* GetELFSectionHeader(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->sectionTableEntryCount) return NULL; + if(index >= elf->sectionTableEntryCount) return NULL; - return (ElfFile + elf->sectionTableOffset + elf->sectionTableEntrySize*Index); + return (elfFile + elf->sectionTableOffset + elf->sectionTableEntrySize*index); } -u8* GetELFSectionEntry(u16 Index, ElfContext *elf, u8 *ElfFile) +u8* GetELFSectionEntry(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->sectionTableEntryCount) return NULL; + if(index >= elf->sectionTableEntryCount) return NULL; - return (u8*) (ElfFile + GetELFSectionEntryFileOffset(Index,elf,ElfFile)); + return (u8*) (elfFile + GetELFSectionEntryFileOffset(index,elf,elfFile)); } -char* GetELFSectionEntryName(u16 Index, ElfContext *elf, u8 *ElfFile) +char* GetELFSectionEntryName(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->sectionTableEntryCount) return 0; + if(index >= elf->sectionTableEntryCount) return 0; u64 NameIndex = 0; if(elf->Is64bit){ - elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(index,elf,elfFile); NameIndex = u8_to_u64(shdr->sh_name,elf->IsLittleEndian); } else{ - elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(index,elf,elfFile); NameIndex = u8_to_u32(shdr->sh_name,elf->IsLittleEndian); } - u8 *NameTable = GetELFSectionEntry(elf->sectionHeaderNameEntryIndex,elf,ElfFile); + u8 *NameTable = GetELFSectionEntry(elf->sectionHeaderNameEntryIndex,elf,elfFile); return (char*)(NameTable+NameIndex); } -u64 GetELFSectionEntryType(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFSectionEntryType(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->sectionTableEntryCount) return 0; + if(index >= elf->sectionTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u64(shdr->sh_type,elf->IsLittleEndian); } else{ - elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u32(shdr->sh_type,elf->IsLittleEndian); } return 0; } -u64 GetELFSectionEntryFlags(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFSectionEntryFlags(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->sectionTableEntryCount) return 0; + if(index >= elf->sectionTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u64(shdr->sh_flags,elf->IsLittleEndian); } else{ - elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u32(shdr->sh_flags,elf->IsLittleEndian); } return 0; } -u64 GetELFSectionEntryAddress(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFSectionEntryAddress(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->sectionTableEntryCount) return 0; + if(index >= elf->sectionTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u64(shdr->sh_addr,elf->IsLittleEndian); } else{ - elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u32(shdr->sh_addr,elf->IsLittleEndian); } return 0; } -u64 GetELFSectionEntryFileOffset(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFSectionEntryFileOffset(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->sectionTableEntryCount) return 0; + if(index >= elf->sectionTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u64(shdr->sh_offset,elf->IsLittleEndian); } else{ - elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u32(shdr->sh_offset,elf->IsLittleEndian); } return 0; } -u64 GetELFSectionEntrySize(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFSectionEntrySize(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->sectionTableEntryCount) return 0; + if(index >= elf->sectionTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u64(shdr->sh_size,elf->IsLittleEndian); } else{ - elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u32(shdr->sh_size,elf->IsLittleEndian); } return 0; } -u64 GetELFSectionEntryAlignment(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFSectionEntryAlignment(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->sectionTableEntryCount) return 0; + if(index >= elf->sectionTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_64_shdr *shdr = (elf_64_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u64(shdr->sh_addralign,elf->IsLittleEndian); } else{ - elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(Index,elf,ElfFile); + elf_32_shdr *shdr = (elf_32_shdr*)GetELFSectionHeader(index,elf,elfFile); return u8_to_u32(shdr->sh_addralign,elf->IsLittleEndian); } @@ -713,166 +686,166 @@ u64 GetELFSectionEntryAlignment(u16 Index, ElfContext *elf, u8 *ElfFile) } -u16 GetElfSectionIndexFromName(char *Name, ElfContext *elf, u8 *ElfFile) +u16 GetElfSectionIndexFromName(char *name, elf_context *elf, u8 *elfFile) { for(int i = 0; i < elf->sectionTableEntryCount; i++){ - if(strcmp(Name,elf->sections[i].name) == 0) return i; + if(strcmp(name,elf->sections[i].name) == 0) return i; } return 0; // Assuming 0 is always empty } -bool IsBss(ElfSectionEntry *Section) +bool IsBss(elf_section_entry *section) { - if(Section->type == 8 && Section->flags == 3) + if(section->type == 8 && section->flags == 3) return true; return false; } -bool IsData(ElfSectionEntry *Section) +bool IsData(elf_section_entry *section) { - if(Section->type == 1 && Section->flags == 3) + if(section->type == 1 && section->flags == 3) return true; return false; } -bool IsRO(ElfSectionEntry *Section) +bool IsRoData(elf_section_entry *section) { - if(Section->type == 1 && Section->flags == 2) + if(section->type == 1 && section->flags == 2) return true; return false; } -bool IsText(ElfSectionEntry *Section) +bool IsText(elf_section_entry *section) { - if(Section->type == 1 && Section->flags == 6) + if(section->type == 1 && section->flags == 6) return true; return false; } /* ProgramHeader Functions */ -u8* GetELFProgramHeader(u16 Index, ElfContext *elf, u8 *ElfFile) +u8* GetELFProgramHeader(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->programTableEntryCount) return NULL; + if(index >= elf->programTableEntryCount) return NULL; - return (ElfFile + elf->programTableOffset + elf->programTableEntrySize*Index); + return (elfFile + elf->programTableOffset + elf->programTableEntrySize*index); } -u8* GetELFProgramEntry(u16 Index, ElfContext *elf, u8 *ElfFile) +u8* GetELFProgramEntry(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->programTableEntryCount) return NULL; + if(index >= elf->programTableEntryCount) return NULL; - return (u8*) (ElfFile + GetELFProgramEntryFileOffset(Index,elf,ElfFile)); + return (u8*) (elfFile + GetELFProgramEntryFileOffset(index,elf,elfFile)); return NULL; } -u64 GetELFProgramEntryType(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFProgramEntryType(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->programTableEntryCount) return 0; + if(index >= elf->programTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u64(phdr->p_type,elf->IsLittleEndian); } else{ - elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u32(phdr->p_type,elf->IsLittleEndian); } return 0; } -u64 GetELFProgramEntryFlags(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFProgramEntryFlags(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->programTableEntryCount) return 0; + if(index >= elf->programTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u64(phdr->p_flags,elf->IsLittleEndian); } else{ - elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u32(phdr->p_flags,elf->IsLittleEndian); } return 0; } -u64 GetELFProgramEntryFileSize(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFProgramEntryFileSize(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->programTableEntryCount) return 0; + if(index >= elf->programTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u64(phdr->p_filesz,elf->IsLittleEndian); } else{ - elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u32(phdr->p_filesz,elf->IsLittleEndian); } return 0; } -u64 GetELFProgramEntryFileOffset(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFProgramEntryFileOffset(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->programTableEntryCount) return 0; + if(index >= elf->programTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u64(phdr->p_offset,elf->IsLittleEndian); } else{ - elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u32(phdr->p_offset,elf->IsLittleEndian); } return 0; } -u64 GetELFProgramEntryMemorySize(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFProgramEntryMemorySize(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->programTableEntryCount) return 0; + if(index >= elf->programTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u64(phdr->p_memsz,elf->IsLittleEndian); } else{ - elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u32(phdr->p_memsz,elf->IsLittleEndian); } return 0; } -u64 GetELFProgramEntryVAddress(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFProgramEntryVAddress(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->programTableEntryCount) return 0; + if(index >= elf->programTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u64(phdr->p_vaddr,elf->IsLittleEndian); } else{ - elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u32(phdr->p_vaddr,elf->IsLittleEndian); } return 0; } -u64 GetELFProgramEntryPAddress(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFProgramEntryPAddress(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->programTableEntryCount) return 0; + if(index >= elf->programTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u64(phdr->p_paddr,elf->IsLittleEndian); } else{ - elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u32(phdr->p_paddr,elf->IsLittleEndian); } @@ -880,16 +853,16 @@ u64 GetELFProgramEntryPAddress(u16 Index, ElfContext *elf, u8 *ElfFile) } -u64 GetELFProgramEntryAlignment(u16 Index, ElfContext *elf, u8 *ElfFile) +u64 GetELFProgramEntryAlignment(u16 index, elf_context *elf, u8 *elfFile) { - if(Index >= elf->programTableEntryCount) return 0; + if(index >= elf->programTableEntryCount) return 0; if(elf->Is64bit){ - elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_64_phdr *phdr = (elf_64_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u64(phdr->p_align,elf->IsLittleEndian); } else{ - elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(Index,elf,ElfFile); + elf_32_phdr *phdr = (elf_32_phdr*)GetELFProgramHeader(index,elf,elfFile); return u8_to_u32(phdr->p_align,elf->IsLittleEndian); } @@ -897,16 +870,16 @@ u64 GetELFProgramEntryAlignment(u16 Index, ElfContext *elf, u8 *ElfFile) } -int CreateElfSegments(ElfContext *elf, u8 *ElfFile) +int CreateElfSegments(elf_context *elf, u8 *elfFile) { int num = 0; // Interate through Each Program Header elf->activeSegments = 0; - elf->segments = calloc(elf->programTableEntryCount,sizeof(ElfSegment)); - ElfSegment *segment = malloc(sizeof(ElfSegment)); // Temporary Buffer + elf->segments = calloc(elf->programTableEntryCount,sizeof(elf_segment)); + elf_segment *segment = malloc(sizeof(elf_segment)); // Temporary Buffer for (int i = 0; i < elf->programTableEntryCount; i++){ if (elf->programHeaders[i].sizeInMemory != 0 && elf->programHeaders[i].type == 1){ - memset(segment,0,sizeof(ElfSegment)); + memset(segment,0,sizeof(elf_segment)); bool foundFirstSection = false; u32 size = 0; @@ -917,7 +890,7 @@ int CreateElfSegments(ElfContext *elf, u8 *ElfFile) u16 SectionInfoCapacity = 10; segment->sectionNum = 0; - segment->sections = calloc(SectionInfoCapacity,sizeof(ElfSectionEntry)); + segment->sections = calloc(SectionInfoCapacity,sizeof(elf_section_entry)); // Itterate Through Section Headers for (int j = num; j < elf->sectionTableEntryCount; j++){ @@ -936,15 +909,15 @@ int CreateElfSegments(ElfContext *elf, u8 *ElfFile) } if(segment->sectionNum < SectionInfoCapacity) - memcpy(&segment->sections[segment->sectionNum],&elf->sections[j],sizeof(ElfSectionEntry)); + memcpy(&segment->sections[segment->sectionNum],&elf->sections[j],sizeof(elf_section_entry)); else{ SectionInfoCapacity = SectionInfoCapacity*2; - ElfSectionEntry *tmp = calloc(SectionInfoCapacity,sizeof(ElfSectionEntry)); + elf_section_entry *tmp = calloc(SectionInfoCapacity,sizeof(elf_section_entry)); for(int k = 0; k < segment->sectionNum; k++) - memcpy(&tmp[k],&segment->sections[k],sizeof(ElfSectionEntry)); + memcpy(&tmp[k],&segment->sections[k],sizeof(elf_section_entry)); free(segment->sections); segment->sections = tmp; - memcpy(&segment->sections[segment->sectionNum],&elf->sections[j],sizeof(ElfSectionEntry)); + memcpy(&segment->sections[segment->sectionNum],&elf->sections[j],sizeof(elf_section_entry)); } segment->sectionNum++; @@ -955,7 +928,7 @@ int CreateElfSegments(ElfContext *elf, u8 *ElfFile) size += padding + elf->sections[j].size; } - //printf("Section Name: %s",elf->sections[j].name); + //printf("Section name: %s",elf->sections[j].name); //printf(" 0x%lx",elf->sections[j].size); //printf(" (Total Size: 0x%x)\n",size); @@ -969,7 +942,7 @@ int CreateElfSegments(ElfContext *elf, u8 *ElfFile) } if(segment->sectionNum){ segment->header = &elf->programHeaders[i]; - memcpy(&elf->segments[elf->activeSegments],segment,sizeof(ElfSegment)); + memcpy(&elf->segments[elf->activeSegments],segment,sizeof(elf_segment)); elf->activeSegments++; } else{ @@ -985,7 +958,7 @@ int CreateElfSegments(ElfContext *elf, u8 *ElfFile) return 0; } -bool IsIgnoreSection(ElfSectionEntry info) +bool IsIgnoreSection(elf_section_entry info) { if (info.address) return false; diff --git a/makerom/elf.h b/makerom/elf.h index 431a3ed..d3a2464 100644 --- a/makerom/elf.h +++ b/makerom/elf.h @@ -23,7 +23,7 @@ typedef struct u64 size; u64 address; u64 alignment; -} ElfSectionEntry; +} elf_section_entry; typedef struct { @@ -36,18 +36,17 @@ typedef struct u64 physicalAddress; u64 sizeInMemory; u64 alignment; - -} ElfProgramEntry; +} elf_program_entry; typedef struct { char *name; u64 vAddr; - ElfProgramEntry *header; + elf_program_entry *header; u32 sectionNum; - ElfSectionEntry *sections; -} ElfSegment; + elf_section_entry *sections; +} elf_segment; typedef struct { @@ -55,7 +54,7 @@ typedef struct u32 size; u32 maxPageNum; u8 *data; -} CodeSegment; +} code_segment; typedef struct { @@ -73,12 +72,12 @@ typedef struct u16 sectionHeaderNameEntryIndex; - ElfSectionEntry *sections; - ElfProgramEntry *programHeaders; + elf_section_entry *sections; + elf_program_entry *programHeaders; u16 activeSegments; - ElfSegment *segments; + elf_segment *segments; -} ElfContext; +} elf_context; int BuildExeFsCode(ncch_settings *ncchset); \ No newline at end of file diff --git a/makerom/exefs.c b/makerom/exefs.c index c1e5328..1d3f230 100644 --- a/makerom/exefs.c +++ b/makerom/exefs.c @@ -1,6 +1,6 @@ #include "lib.h" -#include "ncch.h" -#include "exefs.h" +#include "ncch_build.h" +#include "exefs_build.h" // Private Prototypes u32 PredictExeFS_Size(exefs_buildctx *ctx); @@ -18,7 +18,7 @@ int BuildExeFs(ncch_settings *ncchset) fprintf(stderr,"[EXEFS ERROR] Not enough memory\n"); return MEM_ERROR; } - ctx->mediaUnit = ncchset->options.mediaSize; + ctx->blockSize = ncchset->options.blockSize; /* Importing ExeFs */ if(ncchset->exefsSections.code.size) @@ -56,10 +56,9 @@ int BuildExeFs(ncch_settings *ncchset) u32 PredictExeFS_Size(exefs_buildctx *ctx) { - u32 exefs_size = 0x200; // Size of header - for(int i = 0; i < ctx->fileCount; i++){ - exefs_size += align(ctx->fileSize[i],ctx->mediaUnit); - } + u32 exefs_size = sizeof(exefs_hdr); // Size of header + for(int i = 0; i < ctx->fileCount; i++) + exefs_size += align(ctx->fileSize[i],ctx->blockSize); //exefs_size = align(ctx->exefs_size,ctx->mediaUnit); return exefs_size; } @@ -70,7 +69,7 @@ int GenerateExeFS_Header(exefs_buildctx *ctx, u8 *outbuff) if(i == 0) ctx->fileOffset[i] = 0; else - ctx->fileOffset[i] = align((ctx->fileOffset[i-1]+ctx->fileSize[i-1]),ctx->mediaUnit); + ctx->fileOffset[i] = align((ctx->fileOffset[i-1]+ctx->fileSize[i-1]),ctx->blockSize); memcpy(ctx->fileHdr[i].name,ctx->fileName[i],8); u32_to_u8(ctx->fileHdr[i].offset,ctx->fileOffset[i],LE); diff --git a/makerom/exefs.h b/makerom/exefs.h index 52afe84..f6e6c13 100644 --- a/makerom/exefs.h +++ b/makerom/exefs.h @@ -2,14 +2,6 @@ #define MAX_EXEFS_SECTIONS 10 // DO NOT CHANGE -typedef enum -{ - PTR_ERROR = -10, - EXEFS_MAX_REACHED = -11, - EXEFS_SECTION_NAME_ERROR = -12, - -} exefs_errors; - typedef struct { char name[8]; @@ -23,29 +15,3 @@ typedef struct u8 reserved[0x20]; u8 fileHashes[MAX_EXEFS_SECTIONS][0x20]; } exefs_hdr; - -typedef struct -{ - //Input - int fileCount; - u8 *file[MAX_EXEFS_SECTIONS]; - u32 fileSize[MAX_EXEFS_SECTIONS]; - u32 fileOffset[MAX_EXEFS_SECTIONS]; - char fileName[MAX_EXEFS_SECTIONS][8]; - u32 mediaUnit; - - //Working Data - exefs_filehdr fileHdr[MAX_EXEFS_SECTIONS]; - u8 fileHashes[MAX_EXEFS_SECTIONS][0x20]; - -} exefs_buildctx; - -/* ExeFs Build Functions */ -int BuildExeFs(ncch_settings *ncchset); - -/* ExeFs Read Functions */ -bool DoesExeFsSectionExist(char *section, u8 *ExeFs); -u8* GetExeFsSection(char *section, u8 *ExeFs); -u8* GetExeFsSectionHash(char *section, u8 *ExeFs); -u32 GetExeFsSectionSize(char *section, u8 *ExeFs); -u32 GetExeFsSectionOffset(char *section, u8 *ExeFs); diff --git a/makerom/exefs_build.h b/makerom/exefs_build.h new file mode 100644 index 0000000..93f45a4 --- /dev/null +++ b/makerom/exefs_build.h @@ -0,0 +1,28 @@ +#pragma once +#include "exefs.h" + +typedef enum +{ + PTR_ERROR = -10, + EXEFS_MAX_REACHED = -11, + EXEFS_SECTION_NAME_ERROR = -12, +} exefs_errors; + +typedef struct +{ + //Input + int fileCount; + u8 *file[MAX_EXEFS_SECTIONS]; + u32 fileSize[MAX_EXEFS_SECTIONS]; + u32 fileOffset[MAX_EXEFS_SECTIONS]; + char fileName[MAX_EXEFS_SECTIONS][8]; + u32 blockSize; + + //Working Data + exefs_filehdr fileHdr[MAX_EXEFS_SECTIONS]; + u8 fileHashes[MAX_EXEFS_SECTIONS][0x20]; + +} exefs_buildctx; + +/* ExeFs Build Functions */ +int BuildExeFs(ncch_settings *ncchset); \ No newline at end of file diff --git a/makerom/exefs_read.h b/makerom/exefs_read.h new file mode 100644 index 0000000..990729b --- /dev/null +++ b/makerom/exefs_read.h @@ -0,0 +1,9 @@ +#pragma once +#include "exefs.h" + +/* ExeFs Read Functions */ +bool DoesExeFsSectionExist(char *section, u8 *ExeFs); +u8* GetExeFsSection(char *section, u8 *ExeFs); +u8* GetExeFsSectionHash(char *section, u8 *ExeFs); +u32 GetExeFsSectionSize(char *section, u8 *ExeFs); +u32 GetExeFsSectionOffset(char *section, u8 *ExeFs); \ No newline at end of file diff --git a/makerom/exheader.c b/makerom/exheader.c index 0270b35..9c99f25 100644 --- a/makerom/exheader.c +++ b/makerom/exheader.c @@ -1,6 +1,6 @@ #include "lib.h" -#include "ncch.h" -#include "exheader.h" +#include "ncch_build.h" +#include "exheader_build.h" #include "accessdesc.h" #include "titleid.h" @@ -124,13 +124,13 @@ int get_ExHeaderSettingsFromNcchset(exheader_settings *exhdrset, ncch_settings * /* Import ExHeader Code Section template */ if(ncchset->componentFilePtrs.exhdrSize){ - u32 import_size = 0x30; //min_u64(0x30,ncchset->componentFilePtrs.exhdrSize); + u32 import_size = 0x30; //min64(0x30,ncchset->componentFilePtrs.exhdrSize); u32 import_offset = 0x10; if((import_size+import_offset) > ncchset->componentFilePtrs.exhdrSize){ fprintf(stderr,"[EXHEADER ERROR] Exheader Template is too small\n"); return FAILED_TO_IMPORT_FILE; } - ReadFile_64((ncchset->sections.exhdr.buffer+import_offset),import_size,import_offset,ncchset->componentFilePtrs.exhdr); + ReadFile64((ncchset->sections.exhdr.buffer+import_offset),import_size,import_offset,ncchset->componentFilePtrs.exhdr); } /* Create ExHeader Struct for output */ diff --git a/makerom/exheader.h b/makerom/exheader.h index 82e778f..d2d216f 100644 --- a/makerom/exheader.h +++ b/makerom/exheader.h @@ -1,12 +1,5 @@ #pragma once -typedef enum -{ - COMMON_HEADER_KEY_NOT_FOUND = -10, - EXHDR_BAD_YAML_OPT = -11, - CANNOT_SIGN_ACCESSDESC = -12 -} exheader_errors; - typedef enum { infoflag_COMPRESS_EXEFS_0 = 1, @@ -197,37 +190,11 @@ typedef struct exhdr_ARM9AccessControlInfo arm9AccessControlInfo; } access_descriptor; -typedef struct -{ - keys_struct *keys; - rsf_settings *rsf; - bool useAccessDescPreset; - - /* Output */ - extended_hdr *exHdr; // is the exheader output buffer ptr(in ncchset) cast as exheader struct ptr; - access_descriptor *acexDesc; -} exheader_settings; - - /* ExHeader Signature Functions */ int SignAccessDesc(access_descriptor *acexDesc, keys_struct *keys); int CheckAccessDescSignature(access_descriptor *acexDesc, keys_struct *keys); -/* ExHeader Build Functions */ -int BuildExHeader(ncch_settings *ncchset); - -/* ExHeader Binary Print Functions */ -void exhdr_Print_ServiceAccessControl(extended_hdr *hdr); - -/* ExHeader Binary Read Functions */ -u8* GetAcexRsaSig(access_descriptor *acexDesc); -u8* GetAcexNcchPubKey(access_descriptor *acexDesc); -u16 GetRemasterVersion_frm_exhdr(extended_hdr *hdr); -u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr); -int GetDependencyList_frm_exhdr(u8 *Dest,extended_hdr *hdr); -void GetCoreVersion_frm_exhdr(u8 *Dest, extended_hdr *hdr); - -/* ExHeader Settings Read from Yaml */ +/* ExHeader Settings Read from Rsf */ int GetSaveDataSizeFromString(u64 *out, char *string, char *moduleName); int GetRemasterVersion_rsf(u16 *RemasterVersion, user_settings *usrset); diff --git a/makerom/exheader_build.h b/makerom/exheader_build.h new file mode 100644 index 0000000..f7fd894 --- /dev/null +++ b/makerom/exheader_build.h @@ -0,0 +1,23 @@ +#pragma once +#include "exheader.h" + +typedef enum +{ + COMMON_HEADER_KEY_NOT_FOUND = -10, + EXHDR_BAD_YAML_OPT = -11, + CANNOT_SIGN_ACCESSDESC = -12 +} exheader_errors; + +typedef struct +{ + keys_struct *keys; + rsf_settings *rsf; + bool useAccessDescPreset; + + /* Output, these ptrs where created originally in ncchset */ + extended_hdr *exHdr; + access_descriptor *acexDesc; +} exheader_settings; + +/* ExHeader Build Functions */ +int BuildExHeader(ncch_settings *ncchset); \ No newline at end of file diff --git a/makerom/exheader_read.h b/makerom/exheader_read.h new file mode 100644 index 0000000..9c09ca9 --- /dev/null +++ b/makerom/exheader_read.h @@ -0,0 +1,13 @@ +#pragma once +#include "exheader.h" + +/* ExHeader Binary Print Functions */ +void exhdr_Print_ServiceAccessControl(extended_hdr *hdr); + +/* ExHeader Binary Read Functions */ +u8* GetAcexRsaSig(access_descriptor *acexDesc); +u8* GetAcexNcchPubKey(access_descriptor *acexDesc); +u16 GetRemasterVersion_frm_exhdr(extended_hdr *hdr); +u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr); +int GetDependencyList_frm_exhdr(u8 *Dest,extended_hdr *hdr); +void GetCoreVersion_frm_exhdr(u8 *Dest, extended_hdr *hdr); diff --git a/makerom/keyset.c b/makerom/keyset.c index b44ecb6..a39ce54 100644 --- a/makerom/keyset.c +++ b/makerom/keyset.c @@ -1,14 +1,16 @@ #include "lib.h" // KeyData -#include "tpki.h" // Test PKI -#include "ppki.h" // Production PKI -#include "dpki.h" // Development PKI +#include "pki/test.h" // Test PKI +#include "pki/prod.h" // Production PKI +#include "pki/dev.h" // Development PKI // Private Prototypes int SetRsaKeySet(u8 **PrivDest, u8 *PrivSource, u8 **PubDest, u8 *PubSource); int SetunFixedKey(keys_struct *keys, u8 *unFixedKey); -void InitcommonKeySlots(keys_struct *keys); +void InitCommonKeySlots(keys_struct *keys); +void InitNcchKeyXSlots(keys_struct *keys); +int SetNcchKeyX(keys_struct *keys, u8 *keyX, u8 index); FILE* keyset_OpenFile(char *dir, char *name, bool FileRequired); void keysetOpenError(char *file); @@ -33,11 +35,12 @@ void DumpKeyset(keys_struct *keys); void InitKeys(keys_struct *keys) { memset(keys,0,sizeof(keys_struct)); - InitcommonKeySlots(keys); + InitCommonKeySlots(keys); + InitNcchKeyXSlots(keys); keys->rsa.cxiHdrPub = malloc(RSA_2048_KEY_SIZE); keys->rsa.cxiHdrPvt = malloc(RSA_2048_KEY_SIZE); - keys->aes.unFixedKey0 = malloc(16); - keys->aes.unFixedKey1 = malloc(16); + keys->aes.ncchKey0 = malloc(AES_128_KEY_SIZE); + keys->aes.ncchKey1 = malloc(AES_128_KEY_SIZE); } void PrintBadKeySize(char *path, u32 size) @@ -45,6 +48,21 @@ void PrintBadKeySize(char *path, u32 size) fprintf(stderr,"[KEYSET ERROR] %s has invalid size (0x%x)\n",path,size); } +u8* AesKeyScrambler(u8 *key, u8 *keyX, u8 *keyY) +{ + // Process keyX/keyY to get raw normal key + for(int i = 0; i < 16; i++) + key[i] = keyX[i] ^ ((keyY[i] >> 2) | ((keyY[i < 15 ? i+1 : 0] & 3) << 6)); // keyX[i] ^ + + const u8 SCRAMBLE_SECRET[16] = {0x51, 0xD7, 0x5D, 0xBE, 0xFD, 0x07, 0x57, 0x6A, 0x1C, 0xFC, 0x2A, 0xF0, 0x94, 0x4B, 0xD5, 0x6C}; + + // Apply Secret to get final normal key + for(int i = 0; i < 16; i++) + key[i] = key[i] ^ SCRAMBLE_SECRET[i]; + + return key; +} + int SetKeys(keys_struct *keys) { int result = 0; @@ -90,9 +108,9 @@ int LoadKeysFromResources(keys_struct *keys) keys->keysetLoaded = true; /* AES Keys */ // CIA - for(int i = 0; i < 2; i++){ + for(int i = 0; i < 2; i++) SetCommonKey(keys,(u8*)ctr_common_etd_key_dpki[i],i); - } + if(keys->aes.currentCommonKey > 0xff) SetCurrentCommonKey(keys,0); @@ -100,10 +118,9 @@ int LoadKeysFromResources(keys_struct *keys) SetNormalKey(keys,(u8*)dev_fixed_ncch_key[0]); SetSystemFixedKey(keys,(u8*)dev_fixed_ncch_key[1]); - /* - keys->aes.ncchKeyX0 = (u8*)dev_unfixed_ncch_keyX[0]; - keys->aes.ncchKeyX1 = (u8*)dev_unfixed_ncch_keyX[1]; - */ + for(int i = 0; i < 2; i++) + SetNcchKeyX(keys,(u8*)dev_unfixed_ncch_keyX[i],i); + /* RSA Keys */ // CIA @@ -123,18 +140,19 @@ int LoadKeysFromResources(keys_struct *keys) keys->keysetLoaded = true; /* AES Keys */ // CIA - for(int i = 0; i < 6; i++){ - keys->aes.commonKey[i] = malloc(16); - AesKeyScrambler(keys->aes.commonKey[i],(u8*)ctr_common_etd_keyX_ppki,(u8*)ctr_common_etd_keyY_ppki[i]); - } - SetCurrentCommonKey(keys,1); + //for(int i = 0; i < 6; i++){ + // keys->aes.commonKey[i] = malloc(16); + // AesKeyScrambler(keys->aes.commonKey[i],(u8*)ctr_common_etd_keyX_ppki,(u8*)ctr_common_etd_keyY_ppki[i]); + //} + if(keys->aes.currentCommonKey > 0xff) + SetCurrentCommonKey(keys,0); // NCCH keys->aes.normalKey = NULL; keys->aes.systemFixedKey = NULL; /* - keys->aes.ncchKeyX0 = (u8*)prod_unfixed_ncch_keyX[0]; - keys->aes.ncchKeyX1 = (u8*)prod_unfixed_ncch_keyX[1]; + for(int i = 0; i < 2; i++) + SetNcchKeyX(keys,(u8*)prod_unfixed_ncch_keyX[i],i); */ /* RSA Keys */ @@ -264,15 +282,19 @@ void FreeKeys(keys_struct *keys) { // AES if(keys->aes.commonKey){ - for(int i = 0; i < 256; i++){ + for(int i = 0; i <= MAX_CMN_KEY; i++) free(keys->aes.commonKey[i]); - } } free(keys->aes.commonKey); free(keys->aes.normalKey); free(keys->aes.systemFixedKey); - free(keys->aes.unFixedKey0); - free(keys->aes.unFixedKey1); + if(keys->aes.ncchKeyX){ + for(int i = 0; i <= MAX_NCCH_KEYX; i++) + free(keys->aes.ncchKeyX[i]); + } + free(keys->aes.ncchKeyX); + free(keys->aes.ncchKey0); + free(keys->aes.ncchKey1); // RSA free(keys->rsa.xsPvt); @@ -309,18 +331,28 @@ int SetRsaKeySet(u8 **PrivDest, u8 *PrivSource, u8 **PubDest, u8 *PubSource) return 0; } -int SetCommonKey(keys_struct *keys, u8 *commonKey, u8 Index) +int SetCommonKey(keys_struct *keys, u8 *commonKey, u8 index) { if(!keys) return -1; - return CopyData(&keys->aes.commonKey[Index],commonKey,16); + return CopyData(&keys->aes.commonKey[index],commonKey,AES_128_KEY_SIZE); } -void InitcommonKeySlots(keys_struct *keys) +void InitCommonKeySlots(keys_struct *keys) { - if(!keys->aes.commonKey){ - keys->aes.commonKey = malloc(sizeof(u8*)*256); - memset(keys->aes.commonKey,0,sizeof(u8*)*256); - } + if(!keys->aes.commonKey) + keys->aes.commonKey = calloc(MAX_CMN_KEY+1,sizeof(u8*)); +} + +int SetNcchKeyX(keys_struct *keys, u8 *keyX, u8 index) +{ + if(!keys) return -1; + return CopyData(&keys->aes.ncchKeyX[index],keyX,AES_128_KEY_SIZE); +} + +void InitNcchKeyXSlots(keys_struct *keys) +{ + if(!keys->aes.ncchKeyX) + keys->aes.ncchKeyX = calloc(MAX_NCCH_KEYX+1,sizeof(u8*)); } int SetCurrentCommonKey(keys_struct *keys, u8 Index) @@ -342,22 +374,6 @@ int SetSystemFixedKey(keys_struct *keys, u8 *systemFixedKey) return CopyData(&keys->aes.systemFixedKey,systemFixedKey,16); } -int SetNcchUnfixedKeys(keys_struct *keys, u8 *ncchSig) -{ - if(!keys) return -1; - - //memdump(stdout,"keyY: ",ncchSig,16); - //memdump(stdout,"keyX0: ",keys->aes.ncchKeyX0,16); - //memdump(stdout,"keyX1: ",keys->aes.ncchKeyX1,16); - - if(keys->aes.ncchKeyX0) - AesKeyScrambler(keys->aes.unFixedKey0,keys->aes.ncchKeyX0,ncchSig); - if(keys->aes.ncchKeyX1) - AesKeyScrambler(keys->aes.unFixedKey1,keys->aes.ncchKeyX1,ncchSig); - - return 0; -} - int SetTIK_RsaKey(keys_struct *keys, u8 *PrivateExp, u8 *PublicMod) { if(!keys) return -1; diff --git a/makerom/keyset.h b/makerom/keyset.h index 81741a3..9d6c0c6 100644 --- a/makerom/keyset.h +++ b/makerom/keyset.h @@ -1,5 +1,12 @@ #pragma once +typedef enum +{ + AES_128_KEY_SIZE = 16, + MAX_CMN_KEY = MAX_U8, + MAX_NCCH_KEYX = MAX_U8 +} keydata_limits; + typedef enum { KEYSET_ERROR = -10, @@ -54,11 +61,10 @@ typedef struct // NCCH Keys u8 *normalKey; u8 *systemFixedKey; - - u8 *ncchKeyX0; - u8 *ncchKeyX1; - u8 *unFixedKey0; - u8 *unFixedKey1; + u8 **ncchKeyX; + + u8 *ncchKey0; + u8 *ncchKey1; } aes; struct @@ -101,5 +107,4 @@ int SetCurrentCommonKey(keys_struct *keys, u8 Index); int SetNormalKey(keys_struct *keys, u8 *systemFixedKey); int SetSystemFixedKey(keys_struct *keys, u8 *systemFixedKey); - -int SetNcchUnfixedKeys(keys_struct *keys, u8 *ncchSig); \ No newline at end of file +u8* AesKeyScrambler(u8 *key, u8 *keyX, u8 *keyY); diff --git a/makerom/lib.h b/makerom/lib.h index e0ef089..a35a146 100644 --- a/makerom/lib.h +++ b/makerom/lib.h @@ -27,6 +27,7 @@ #include "types.h" #include "utils.h" +#include "ctr_utils.h" #include "crypto.h" #include "keyset.h" diff --git a/makerom/makerom.c b/makerom/makerom.c index fe72bb8..3d891ce 100644 --- a/makerom/makerom.c +++ b/makerom/makerom.c @@ -1,73 +1,66 @@ #include "lib.h" -#include "ncch.h" -#include "ncsd.h" -#include "cia.h" +#include "ncch_build.h" +#include "ncsd_build.h" +#include "cia_build.h" int main(int argc, char *argv[]) { // Setting up user settings - user_settings *usrset = calloc(1,sizeof(user_settings)); - if(usrset == NULL) { + user_settings *set = calloc(1,sizeof(user_settings)); + if(set == NULL) { fprintf(stderr,"[!] Not enough memory\n"); return -1; } - init_UserSettings(usrset); + init_UserSettings(set); initRand(); int result; - -#ifdef DEBUG - printf("[DEBUG] Parseing Args\n"); -#endif // Parsing command args - result = ParseArgs(argc,argv,usrset); - if(result < 0) goto finish; + if((result = ParseArgs(argc,argv,set)) < 0) + goto finish; -#ifdef DEBUG - printf("[DEBUG] Importing Yaml Settings\n"); -#endif // Import RSF Settings if present - result = GetYamlSettings(usrset); - if(result < 0) goto finish; + if((result = GetRsfSettings(set)) < 0) + goto finish; // Setup Content 0 - if(!usrset->ncch.buildNcch0){ // Import Content - if(usrset->common.workingFileType == infile_ncch){ - if(!AssertFile(usrset->common.contentPath[0])){ - fprintf(stderr,"[MAKEROM ERROR] Failed to open Content 0: %s\n",usrset->common.contentPath[0]); + if(!set->ncch.buildNcch0){ // Import Content + if(set->common.workingFileType == infile_ncch){ + if(!AssertFile(set->common.contentPath[0])){ + fprintf(stderr,"[MAKEROM ERROR] Failed to open Content 0: %s\n",set->common.contentPath[0]); goto finish; } - u64 fileSize = GetFileSize_u64(usrset->common.contentPath[0]); + u64 fileSize = GetFileSize64(set->common.contentPath[0]); u64 calcSize = 0; - FILE *ncch0 = fopen(usrset->common.contentPath[0],"rb"); + FILE *ncch0 = fopen(set->common.contentPath[0],"rb"); ncch_hdr hdr; - GetNCCH_CommonHDR(&hdr,ncch0,NULL); - calcSize = GetNCCH_MediaSize(&hdr) * GetNCCH_MediaUnitSize(&hdr); + ReadNcchHdr(&hdr,ncch0); + calcSize = GetNcchSize(&hdr); if(calcSize != fileSize){ fprintf(stderr,"[MAKEROM ERROR] Content 0 is corrupt\n"); fclose(ncch0); goto finish; } - usrset->common.workingFile.size = fileSize; - usrset->common.workingFile.buffer = malloc(fileSize); - ReadFile_64(usrset->common.workingFile.buffer, usrset->common.workingFile.size,0,ncch0); + set->common.workingFile.size = fileSize; + set->common.workingFile.buffer = malloc(fileSize); + ReadFile64(set->common.workingFile.buffer, set->common.workingFile.size,0,ncch0); fclose(ncch0); } - else if(usrset->common.workingFileType == infile_srl || usrset->common.workingFileType == infile_ncsd){ - if(!AssertFile(usrset->common.workingFilePath)) { - fprintf(stderr,"[MAKEROM ERROR] Failed to open %s: %s\n",usrset->common.workingFileType == infile_srl? "SRL":"CCI",usrset->common.workingFilePath); + else{ + if(!AssertFile(set->common.workingFilePath)) { + fprintf(stderr,"[MAKEROM ERROR] Failed to open: %s\n",set->common.workingFilePath); goto finish; } - u64 size = GetFileSize_u64(usrset->common.workingFilePath); - usrset->common.workingFile.size = align(size,0x10); - usrset->common.workingFile.buffer = malloc(usrset->common.workingFile.size); - FILE *fp = fopen(usrset->common.workingFilePath,"rb"); - ReadFile_64(usrset->common.workingFile.buffer,size,0,fp); + u64 size = GetFileSize64(set->common.workingFilePath); + set->common.workingFile.size = align(size,0x10); + set->common.workingFile.buffer = malloc(set->common.workingFile.size); + FILE *fp = fopen(set->common.workingFilePath,"rb"); + ReadFile64(set->common.workingFile.buffer,size,0,fp); fclose(fp); } } @@ -75,48 +68,48 @@ int main(int argc, char *argv[]) #ifdef DEBUG printf("[DEBUG] Build NCCH0\n"); #endif - result = build_NCCH(usrset); + result = build_NCCH(set); if(result < 0) { - //fprintf(stderr,"[ERROR] %s generation failed\n",usrset->build_ncch_type == CXI? "CXI" : "CFA"); + //fprintf(stderr,"[ERROR] %s generation failed\n",set->build_ncch_type == CXI? "CXI" : "CFA"); fprintf(stderr,"[RESULT] Failed to build outfile\n"); goto finish; } } // Make CCI - if(usrset->common.outFormat == CCI){ + if(set->common.outFormat == CCI){ #ifdef DEBUG printf("[DEBUG] Building CCI\n"); #endif - result = build_CCI(usrset); + result = build_CCI(set); if(result < 0) { fprintf(stderr,"[RESULT] Failed to build CCI\n"); goto finish; } } // Make CIA - else if(usrset->common.outFormat == CIA){ + else if(set->common.outFormat == CIA){ #ifdef DEBUG printf("[DEBUG] Building CIA\n"); #endif - result = build_CIA(usrset); + result = build_CIA(set); if(result < 0) { fprintf(stderr,"[RESULT] Failed to build CIA\n"); goto finish; } } // No Container Raw CXI/CFA - else if(usrset->common.outFormat == CXI || usrset->common.outFormat == CFA){ + else if(set->common.outFormat == CXI || set->common.outFormat == CFA){ #ifdef DEBUG printf("[DEBUG] Outputting NCCH, because No Container\n"); #endif - FILE *ncch_out = fopen(usrset->common.outFileName,"wb"); + FILE *ncch_out = fopen(set->common.outFileName,"wb"); if(!ncch_out) { - fprintf(stderr,"[MAKEROM ERROR] Failed to create '%s'\n",usrset->common.outFileName); - fprintf(stderr,"[RESULT] Failed to build '%s'\n",usrset->common.outFormat == CXI? "CXI" : "CFA"); + fprintf(stderr,"[MAKEROM ERROR] Failed to create '%s'\n",set->common.outFileName); + fprintf(stderr,"[RESULT] Failed to build '%s'\n",set->common.outFormat == CXI? "CXI" : "CFA"); result = FAILED_TO_CREATE_OUTFILE; goto finish; } - WriteBuffer(usrset->common.workingFile.buffer,usrset->common.workingFile.size,0,ncch_out); + WriteBuffer(set->common.workingFile.buffer,set->common.workingFile.size,0,ncch_out); fclose(ncch_out); } @@ -124,7 +117,7 @@ finish: #ifdef DEBUG printf("[DEBUG] Free Context\n"); #endif - free_UserSettings(usrset); + free_UserSettings(set); #ifdef DEBUG printf("[DEBUG] Finished returning (result=%d)\n",result); #endif diff --git a/makerom/ncch.c b/makerom/ncch.c index cc53630..e81ede8 100644 --- a/makerom/ncch.c +++ b/makerom/ncch.c @@ -1,26 +1,28 @@ #include "lib.h" #include "dir.h" -#include "ncch.h" -#include "exheader.h" +#include "ncch_build.h" +#include "exheader_build.h" +#include "exheader_read.h" #include "elf.h" -#include "exefs.h" +#include "exefs_build.h" +#include "exefs_read.h" #include "romfs.h" #include "titleid.h" -#include "logo_data.h" // Contains Logos +#include "ncch_logo.h" // Contains Logos -const u32 MEDIA_UNIT = 0x200; +const u32 NCCH_BLOCK_SIZE = 0x200; // Private Prototypes -int SignCFA(u8 *Signature, u8 *CFA_HDR, keys_struct *keys); -int CheckCFASignature(u8 *Signature, u8 *CFA_HDR, keys_struct *keys); -int SignCXI(u8 *Signature, u8 *CXI_HDR, keys_struct *keys); -int CheckCXISignature(u8 *Signature, u8 *CXI_HDR, u8 *PubK); +int SignCFA(ncch_hdr *hdr, keys_struct *keys); +int CheckCFASignature(ncch_hdr *hdr, keys_struct *keys); +int SignCXI(ncch_hdr *hdr, keys_struct *keys); +int CheckCXISignature(ncch_hdr *hdr, u8 *pubk); -void init_NCCHSettings(ncch_settings *set); -void free_NCCHSettings(ncch_settings *set); -int get_NCCHSettings(ncch_settings *ncchset, user_settings *usrset); -int SetBasicOptions(ncch_settings *ncchset, user_settings *usrset); +void InitNcchSettings(ncch_settings *set); +void FreeNcchSettings(ncch_settings *set); +int GetNcchSettings(ncch_settings *ncchset, user_settings *usrset); +int GetBasicOptions(ncch_settings *ncchset, user_settings *usrset); int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset); int ImportNonCodeExeFsSections(ncch_settings *ncchset); int ImportLogo(ncch_settings *ncchset); @@ -31,29 +33,29 @@ int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr); bool IsValidProductCode(char *ProductCode, bool FreeProductCode); int BuildCommonHeader(ncch_settings *ncchset); -int EncryptNCCHSections(ncch_settings *ncchset); +int EnCryptNcchRegions(ncch_settings *ncchset); int WriteNCCHSectionsToBuffer(ncch_settings *ncchset); // Code -int SignCFA(u8 *Signature, u8 *CFA_HDR, keys_struct *keys) +int SignCFA(ncch_hdr *hdr, keys_struct *keys) { - return ctr_sig(CFA_HDR,sizeof(ncch_hdr),Signature,keys->rsa.cciCfaPub,keys->rsa.cciCfaPvt,RSA_2048_SHA256,CTR_RSA_SIGN); + return ctr_sig(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),keys->rsa.cciCfaPub,keys->rsa.cciCfaPvt,RSA_2048_SHA256,CTR_RSA_SIGN); } -int CheckCFASignature(u8 *Signature, u8 *CFA_HDR, keys_struct *keys) +int CheckCFASignature(ncch_hdr *hdr, keys_struct *keys) { - return ctr_sig(CFA_HDR,sizeof(ncch_hdr),Signature,keys->rsa.cciCfaPub,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY); + return ctr_sig(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),keys->rsa.cciCfaPub,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY); } -int SignCXI(u8 *Signature, u8 *CXI_HDR, keys_struct *keys) +int SignCXI(ncch_hdr *hdr, keys_struct *keys) { - return ctr_sig(CXI_HDR,sizeof(ncch_hdr),Signature,keys->rsa.cxiHdrPub,keys->rsa.cxiHdrPvt,RSA_2048_SHA256,CTR_RSA_SIGN); + return ctr_sig(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),keys->rsa.cxiHdrPub,keys->rsa.cxiHdrPvt,RSA_2048_SHA256,CTR_RSA_SIGN); } -int CheckCXISignature(u8 *Signature, u8 *CXI_HDR, u8 *PubK) +int CheckCXISignature(ncch_hdr *hdr, u8 *pubk) { - int result = ctr_sig(CXI_HDR,sizeof(ncch_hdr),Signature,PubK,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY); + int result = ctr_sig(GetNcchHdrData(hdr),GetNcchHdrDataLen(hdr),GetNcchHdrSig(hdr),pubk,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY); return result; } @@ -63,21 +65,26 @@ int build_NCCH(user_settings *usrset) { int result; - // Init Settings\n"); + // Init Settings ncch_settings *ncchset = calloc(1,sizeof(ncch_settings)); if(!ncchset) { fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); return MEM_ERROR; } - init_NCCHSettings(ncchset); + InitNcchSettings(ncchset); - // Get Settings\n"); - result = get_NCCHSettings(ncchset,usrset); + // Get Settings + result = GetNcchSettings(ncchset,usrset); if(result) goto finish; + // Import Data + result = ImportNonCodeExeFsSections(ncchset); + if(result) return result; + result = ImportLogo(ncchset); + if(result) return result; - if(!ncchset->options.IsCfa){ // CXI Specfic Sections + if(!ncchset->options.IsCfa){ // CXI Specific Sections // Build ExeFs Code Section\n"); result = BuildExeFsCode(ncchset); if(result) goto finish; @@ -94,18 +101,18 @@ int build_NCCH(user_settings *usrset) // Prepare for RomFs\n"); - romfs_buildctx romfs_ctx; - memset(&romfs_ctx,0,sizeof(romfs_buildctx)); - result = SetupRomFs(ncchset,&romfs_ctx); + romfs_buildctx romfs; + memset(&romfs,0,sizeof(romfs_buildctx)); + result = SetupRomFs(ncchset,&romfs); if(result) goto finish; // Setup NCCH including final memory allocation\n"); - result = SetupNcch(ncchset,&romfs_ctx); + result = SetupNcch(ncchset,&romfs); if(result) goto finish; // Build RomFs\n"); - result = BuildRomFs(&romfs_ctx); + result = BuildRomFs(&romfs); if(result) goto finish; // Finalise NCCH (Hashes/Signatures and crypto)\n"); @@ -115,16 +122,16 @@ int build_NCCH(user_settings *usrset) finish: if(result) fprintf(stderr,"[NCCH ERROR] NCCH Build Process Failed\n"); - free_NCCHSettings(ncchset); + FreeNcchSettings(ncchset); return result; } -void init_NCCHSettings(ncch_settings *set) +void InitNcchSettings(ncch_settings *set) { memset(set,0,sizeof(ncch_settings)); } -void free_NCCHSettings(ncch_settings *set) +void FreeNcchSettings(ncch_settings *set) { if(set->componentFilePtrs.elf) fclose(set->componentFilePtrs.elf); if(set->componentFilePtrs.banner) fclose(set->componentFilePtrs.banner); @@ -149,7 +156,7 @@ void free_NCCHSettings(ncch_settings *set) free(set); } -int get_NCCHSettings(ncch_settings *ncchset, user_settings *usrset) +int GetNcchSettings(ncch_settings *ncchset, user_settings *usrset) { int result = 0; ncchset->out = &usrset->common.workingFile; @@ -157,33 +164,32 @@ int get_NCCHSettings(ncch_settings *ncchset, user_settings *usrset) ncchset->rsfSet = &usrset->common.rsfSet; ncchset->keys = &usrset->common.keys; - result = SetBasicOptions(ncchset,usrset); + result = GetBasicOptions(ncchset,usrset); if(result) return result; result = CreateInputFilePtrs(ncchset,usrset); if(result) return result; - result = ImportNonCodeExeFsSections(ncchset); - if(result) return result; - result = ImportLogo(ncchset); - if(result) return result; return 0; } -int SetBasicOptions(ncch_settings *ncchset, user_settings *usrset) +int GetBasicOptions(ncch_settings *ncchset, user_settings *usrset) { int result = 0; /* Options */ - ncchset->options.mediaSize = MEDIA_UNIT; + ncchset->options.blockSize = NCCH_BLOCK_SIZE; + ncchset->options.verbose = usrset->common.verbose; ncchset->options.IncludeExeFsLogo = usrset->ncch.includeExefsLogo; - ncchset->options.CompressCode = usrset->common.rsfSet.Option.EnableCompress; - ncchset->options.UseOnSD = usrset->common.rsfSet.Option.UseOnSD; - ncchset->options.Encrypt = usrset->common.rsfSet.Option.EnableCrypt; - ncchset->options.FreeProductCode = usrset->common.rsfSet.Option.FreeProductCode; + ncchset->options.CompressCode = ncchset->rsfSet->Option.EnableCompress; + ncchset->options.UseOnSD = ncchset->rsfSet->Option.UseOnSD; + ncchset->options.Encrypt = ncchset->rsfSet->Option.EnableCrypt; + ncchset->options.FreeProductCode = ncchset->rsfSet->Option.FreeProductCode; ncchset->options.IsCfa = (usrset->ncch.ncchType == CFA); ncchset->options.IsBuildingCodeSection = (usrset->ncch.elfPath != NULL); ncchset->options.UseRomFS = ((ncchset->rsfSet->Rom.HostRoot && strlen(ncchset->rsfSet->Rom.HostRoot) > 0) || usrset->ncch.romfsPath); + ncchset->options.useSecCrypto = usrset->ncch.useSecCrypto; + ncchset->options.keyXID = usrset->ncch.keyXID; if(ncchset->options.IsCfa && !ncchset->options.UseRomFS){ fprintf(stderr,"[NCCH ERROR] \"Rom/HostRoot\" must be set\n"); @@ -196,7 +202,7 @@ int SetBasicOptions(ncch_settings *ncchset, user_settings *usrset) int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset) { if(usrset->ncch.romfsPath){ - ncchset->componentFilePtrs.romfsSize = GetFileSize_u64(usrset->ncch.romfsPath); + ncchset->componentFilePtrs.romfsSize = GetFileSize64(usrset->ncch.romfsPath); ncchset->componentFilePtrs.romfs = fopen(usrset->ncch.romfsPath,"rb"); if(!ncchset->componentFilePtrs.romfs){ fprintf(stderr,"[NCCH ERROR] Failed to open RomFs file '%s'\n",usrset->ncch.romfsPath); @@ -204,7 +210,7 @@ int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset) } } if(usrset->ncch.elfPath){ - ncchset->componentFilePtrs.elfSize = GetFileSize_u64(usrset->ncch.elfPath); + ncchset->componentFilePtrs.elfSize = GetFileSize64(usrset->ncch.elfPath); ncchset->componentFilePtrs.elf = fopen(usrset->ncch.elfPath,"rb"); if(!ncchset->componentFilePtrs.elf){ fprintf(stderr,"[NCCH ERROR] Failed to open elf file '%s'\n",usrset->ncch.elfPath); @@ -212,7 +218,7 @@ int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset) } } if(usrset->ncch.bannerPath){ - ncchset->componentFilePtrs.bannerSize = GetFileSize_u64(usrset->ncch.bannerPath); + ncchset->componentFilePtrs.bannerSize = GetFileSize64(usrset->ncch.bannerPath); ncchset->componentFilePtrs.banner = fopen(usrset->ncch.bannerPath,"rb"); if(!ncchset->componentFilePtrs.banner){ fprintf(stderr,"[NCCH ERROR] Failed to open banner file '%s'\n",usrset->ncch.bannerPath); @@ -220,7 +226,7 @@ int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset) } } if(usrset->ncch.iconPath){ - ncchset->componentFilePtrs.iconSize = GetFileSize_u64(usrset->ncch.iconPath); + ncchset->componentFilePtrs.iconSize = GetFileSize64(usrset->ncch.iconPath); ncchset->componentFilePtrs.icon = fopen(usrset->ncch.iconPath,"rb"); if(!ncchset->componentFilePtrs.icon){ fprintf(stderr,"[NCCH ERROR] Failed to open icon file '%s'\n",usrset->ncch.iconPath); @@ -228,7 +234,7 @@ int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset) } } if(usrset->ncch.logoPath){ - ncchset->componentFilePtrs.logoSize = GetFileSize_u64(usrset->ncch.logoPath); + ncchset->componentFilePtrs.logoSize = GetFileSize64(usrset->ncch.logoPath); ncchset->componentFilePtrs.logo = fopen(usrset->ncch.logoPath,"rb"); if(!ncchset->componentFilePtrs.logo){ fprintf(stderr,"[NCCH ERROR] Failed to open logo file '%s'\n",usrset->ncch.logoPath); @@ -237,7 +243,7 @@ int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset) } if(usrset->ncch.codePath){ - ncchset->componentFilePtrs.codeSize = GetFileSize_u64(usrset->ncch.codePath); + ncchset->componentFilePtrs.codeSize = GetFileSize64(usrset->ncch.codePath); ncchset->componentFilePtrs.code = fopen(usrset->ncch.codePath,"rb"); if(!ncchset->componentFilePtrs.code){ fprintf(stderr,"[NCCH ERROR] Failed to open ExeFs Code file '%s'\n",usrset->ncch.codePath); @@ -245,7 +251,7 @@ int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset) } } if(usrset->ncch.exheaderPath){ - ncchset->componentFilePtrs.exhdrSize = GetFileSize_u64(usrset->ncch.exheaderPath); + ncchset->componentFilePtrs.exhdrSize = GetFileSize64(usrset->ncch.exheaderPath); ncchset->componentFilePtrs.exhdr = fopen(usrset->ncch.exheaderPath,"rb"); if(!ncchset->componentFilePtrs.exhdr){ fprintf(stderr,"[NCCH ERROR] Failed to open ExHeader file '%s'\n",usrset->ncch.exheaderPath); @@ -253,7 +259,7 @@ int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset) } } if(usrset->ncch.plainRegionPath){ - ncchset->componentFilePtrs.plainregionSize = GetFileSize_u64(usrset->ncch.plainRegionPath); + ncchset->componentFilePtrs.plainregionSize = GetFileSize64(usrset->ncch.plainRegionPath); ncchset->componentFilePtrs.plainregion = fopen(usrset->ncch.plainRegionPath,"rb"); if(!ncchset->componentFilePtrs.plainregion){ fprintf(stderr,"[NCCH ERROR] Failed to open PlainRegion file '%s'\n",usrset->ncch.plainRegionPath); @@ -263,88 +269,88 @@ int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset) return 0; } -int ImportNonCodeExeFsSections(ncch_settings *ncchset) +int ImportNonCodeExeFsSections(ncch_settings *set) { - if(ncchset->componentFilePtrs.banner){ - ncchset->exefsSections.banner.size = ncchset->componentFilePtrs.bannerSize; - ncchset->exefsSections.banner.buffer = malloc(ncchset->exefsSections.banner.size); - if(!ncchset->exefsSections.banner.buffer) { + if(set->componentFilePtrs.banner){ + set->exefsSections.banner.size = set->componentFilePtrs.bannerSize; + set->exefsSections.banner.buffer = malloc(set->exefsSections.banner.size); + if(!set->exefsSections.banner.buffer) { fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); return MEM_ERROR; } - ReadFile_64(ncchset->exefsSections.banner.buffer,ncchset->exefsSections.banner.size,0,ncchset->componentFilePtrs.banner); + ReadFile64(set->exefsSections.banner.buffer,set->exefsSections.banner.size,0,set->componentFilePtrs.banner); } - if(ncchset->componentFilePtrs.icon){ - ncchset->exefsSections.icon.size = ncchset->componentFilePtrs.iconSize; - ncchset->exefsSections.icon.buffer = malloc(ncchset->exefsSections.icon.size); - if(!ncchset->exefsSections.icon.buffer) { + if(set->componentFilePtrs.icon){ + set->exefsSections.icon.size = set->componentFilePtrs.iconSize; + set->exefsSections.icon.buffer = malloc(set->exefsSections.icon.size); + if(!set->exefsSections.icon.buffer) { fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); return MEM_ERROR; } - ReadFile_64(ncchset->exefsSections.icon.buffer,ncchset->exefsSections.icon.size,0,ncchset->componentFilePtrs.icon); + ReadFile64(set->exefsSections.icon.buffer,set->exefsSections.icon.size,0,set->componentFilePtrs.icon); } return 0; } -int ImportLogo(ncch_settings *ncchset) +int ImportLogo(ncch_settings *set) { - if(ncchset->componentFilePtrs.logo){ - ncchset->sections.logo.size = align(ncchset->componentFilePtrs.logoSize,ncchset->options.mediaSize); - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) { + if(set->componentFilePtrs.logo){ + set->sections.logo.size = align(set->componentFilePtrs.logoSize,set->options.blockSize); + set->sections.logo.buffer = malloc(set->sections.logo.size); + if(!set->sections.logo.buffer) { fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); return MEM_ERROR; } - memset(ncchset->sections.logo.buffer,0,ncchset->sections.logo.size); - ReadFile_64(ncchset->sections.logo.buffer,ncchset->componentFilePtrs.logoSize,0,ncchset->componentFilePtrs.logo); + memset(set->sections.logo.buffer,0,set->sections.logo.size); + ReadFile64(set->sections.logo.buffer,set->componentFilePtrs.logoSize,0,set->componentFilePtrs.logo); } - else if(ncchset->rsfSet->BasicInfo.Logo){ - if(strcasecmp(ncchset->rsfSet->BasicInfo.Logo,"nintendo") == 0){ - ncchset->sections.logo.size = 0x2000; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) { + else if(set->rsfSet->BasicInfo.Logo){ + if(strcasecmp(set->rsfSet->BasicInfo.Logo,"nintendo") == 0){ + set->sections.logo.size = 0x2000; + set->sections.logo.buffer = malloc(set->sections.logo.size); + if(!set->sections.logo.buffer) { fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); return MEM_ERROR; } - memcpy(ncchset->sections.logo.buffer,Nintendo_LZ,0x2000); + memcpy(set->sections.logo.buffer,Nintendo_LZ,0x2000); } - else if(strcasecmp(ncchset->rsfSet->BasicInfo.Logo,"licensed") == 0){ - ncchset->sections.logo.size = 0x2000; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) { + else if(strcasecmp(set->rsfSet->BasicInfo.Logo,"licensed") == 0){ + set->sections.logo.size = 0x2000; + set->sections.logo.buffer = malloc(set->sections.logo.size); + if(!set->sections.logo.buffer) { fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); return MEM_ERROR; } - memcpy(ncchset->sections.logo.buffer,Nintendo_LicensedBy_LZ,0x2000); + memcpy(set->sections.logo.buffer,Nintendo_LicensedBy_LZ,0x2000); } - else if(strcasecmp(ncchset->rsfSet->BasicInfo.Logo,"distributed") == 0){ - ncchset->sections.logo.size = 0x2000; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) { + else if(strcasecmp(set->rsfSet->BasicInfo.Logo,"distributed") == 0){ + set->sections.logo.size = 0x2000; + set->sections.logo.buffer = malloc(set->sections.logo.size); + if(!set->sections.logo.buffer) { fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); return MEM_ERROR; } - memcpy(ncchset->sections.logo.buffer,Nintendo_DistributedBy_LZ,0x2000); + memcpy(set->sections.logo.buffer,Nintendo_DistributedBy_LZ,0x2000); } - else if(strcasecmp(ncchset->rsfSet->BasicInfo.Logo,"ique") == 0){ - ncchset->sections.logo.size = 0x2000; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) { + else if(strcasecmp(set->rsfSet->BasicInfo.Logo,"ique") == 0){ + set->sections.logo.size = 0x2000; + set->sections.logo.buffer = malloc(set->sections.logo.size); + if(!set->sections.logo.buffer) { fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); return MEM_ERROR; } - memcpy(ncchset->sections.logo.buffer,iQue_with_ISBN_LZ,0x2000); + memcpy(set->sections.logo.buffer,iQue_with_ISBN_LZ,0x2000); } - else if(strcasecmp(ncchset->rsfSet->BasicInfo.Logo,"iqueforsystem") == 0){ - ncchset->sections.logo.size = 0x2000; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) { + else if(strcasecmp(set->rsfSet->BasicInfo.Logo,"iqueforsystem") == 0){ + set->sections.logo.size = 0x2000; + set->sections.logo.buffer = malloc(set->sections.logo.size); + if(!set->sections.logo.buffer) { fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); return MEM_ERROR; } - memcpy(ncchset->sections.logo.buffer,iQue_without_ISBN_LZ,0x2000); + memcpy(set->sections.logo.buffer,iQue_without_ISBN_LZ,0x2000); } - else if(strcasecmp(ncchset->rsfSet->BasicInfo.Logo,"none") != 0){ + else if(strcasecmp(set->rsfSet->BasicInfo.Logo,"none") != 0){ fprintf(stderr,"[NCCH ERROR] Invalid logo name\n"); return NCCH_BAD_YAML_SET; } @@ -352,61 +358,61 @@ int ImportLogo(ncch_settings *ncchset) return 0; } -int SetupNcch(ncch_settings *ncchset, romfs_buildctx *romfs) +int SetupNcch(ncch_settings *set, romfs_buildctx *romfs) { u64 ncchSize = 0; u64 exhdrSize,acexSize,logoSize,plnRgnSize,exefsSize,romfsSize; u64 exhdrOffset,acexOffset,logoOffset,plnRgnOffset,exefsOffset,romfsOffset; u32 exefsHashSize,romfsHashSize; - ncchSize += 0x200; // Sig+Hdr - + ncchSize += sizeof(ncch_hdr); // Sig+Hdr + // Sizes for NCCH hdr - if(ncchset->sections.exhdr.size){ - exhdrSize = ncchset->sections.exhdr.size; + if(set->sections.exhdr.size){ + exhdrSize = set->sections.exhdr.size; exhdrOffset = ncchSize; ncchSize += exhdrSize; } else exhdrSize = 0; - if(ncchset->sections.acexDesc.size){ - acexSize = ncchset->sections.acexDesc.size; + if(set->sections.acexDesc.size){ + acexSize = set->sections.acexDesc.size; acexOffset = ncchSize; ncchSize += acexSize; } else acexSize = 0; - if(ncchset->sections.logo.size){ - logoSize = ncchset->sections.logo.size; - logoOffset = align(ncchSize,ncchset->options.mediaSize); + if(set->sections.logo.size){ + logoSize = set->sections.logo.size; + logoOffset = align(ncchSize,set->options.blockSize); ncchSize = logoOffset + logoSize; } else logoSize = 0; - if(ncchset->sections.plainRegion.size){ - plnRgnSize = align(ncchset->sections.plainRegion.size,ncchset->options.mediaSize); - plnRgnOffset = align(ncchSize,ncchset->options.mediaSize); + if(set->sections.plainRegion.size){ + plnRgnSize = align(set->sections.plainRegion.size,set->options.blockSize); + plnRgnOffset = align(ncchSize,set->options.blockSize); ncchSize = plnRgnOffset + plnRgnSize; } else plnRgnSize = 0; - if(ncchset->sections.exeFs.size){ - exefsHashSize = align(sizeof(exefs_hdr),ncchset->options.mediaSize); - exefsSize = align(ncchset->sections.exeFs.size,ncchset->options.mediaSize); - exefsOffset = align(ncchSize,ncchset->options.mediaSize); + if(set->sections.exeFs.size){ + exefsHashSize = align(sizeof(exefs_hdr),set->options.blockSize); + exefsSize = align(set->sections.exeFs.size,set->options.blockSize); + exefsOffset = align(ncchSize,set->options.blockSize); ncchSize = exefsOffset + exefsSize; } else exefsSize = 0; if(romfs->romfsSize){ - romfsHashSize = align(romfs->romfsHeaderSize,ncchset->options.mediaSize); - romfsSize = align(romfs->romfsSize,ncchset->options.mediaSize); - //romfsOffset = align(ncchSize,0x200); // Old makerom method, SDK 2.x and prior + romfsHashSize = align(romfs->romfsHeaderSize,set->options.blockSize); + romfsSize = align(romfs->romfsSize,set->options.blockSize); + //romfsOffset = align(ncchSize,set->options.blockSize); // Old makerom method, SDK 2.x and prior romfsOffset = align(ncchSize,0x1000); ncchSize = romfsOffset + romfsSize; } @@ -416,7 +422,8 @@ int SetupNcch(ncch_settings *ncchset, romfs_buildctx *romfs) // Aligning Total NCCH Size - ncchSize = align(ncchSize,ncchset->options.mediaSize); + ncchSize = align(ncchSize,set->options.blockSize); + u8 *ncch = calloc(1,ncchSize); if(!ncch){ fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); @@ -424,240 +431,231 @@ int SetupNcch(ncch_settings *ncchset, romfs_buildctx *romfs) } // Setting up hdr\n"); - ncch_hdr *hdr = (ncch_hdr*)(ncch+0x100); - int ret = SetCommonHeaderBasicData(ncchset,hdr); + ncch_hdr *hdr = (ncch_hdr*)ncch; + int ret = SetCommonHeaderBasicData(set,hdr); if(ret != 0){ free(ncch); return ret; } - u32_to_u8(hdr->ncchSize,ncchSize/ncchset->options.mediaSize,LE); + u32_to_u8(hdr->ncchSize,ncchSize/set->options.blockSize,LE); - // Copy already built sections to ncch\n"); + // Copy already built sections to ncch if(exhdrSize){ - memcpy((u8*)(ncch+exhdrOffset),ncchset->sections.exhdr.buffer,ncchset->sections.exhdr.size); - free(ncchset->sections.exhdr.buffer); - ncchset->sections.exhdr.buffer = NULL; + memcpy((u8*)(ncch+exhdrOffset),set->sections.exhdr.buffer,set->sections.exhdr.size); + free(set->sections.exhdr.buffer); + set->sections.exhdr.buffer = NULL; u32_to_u8(hdr->exhdrSize,exhdrSize,LE); } if(acexSize){ - memcpy((u8*)(ncch+acexOffset),ncchset->sections.acexDesc.buffer,ncchset->sections.acexDesc.size); - free(ncchset->sections.acexDesc.buffer); - ncchset->sections.acexDesc.buffer = NULL; + memcpy((u8*)(ncch+acexOffset),set->sections.acexDesc.buffer,set->sections.acexDesc.size); + free(set->sections.acexDesc.buffer); + set->sections.acexDesc.buffer = NULL; } if(logoSize){ - memcpy((u8*)(ncch+logoOffset),ncchset->sections.logo.buffer,ncchset->sections.logo.size); - free(ncchset->sections.logo.buffer); - ncchset->sections.logo.buffer = NULL; - u32_to_u8(hdr->logoOffset,logoOffset/ncchset->options.mediaSize,LE); - u32_to_u8(hdr->logoSize,logoSize/ncchset->options.mediaSize,LE); + memcpy((u8*)(ncch+logoOffset),set->sections.logo.buffer,set->sections.logo.size); + free(set->sections.logo.buffer); + set->sections.logo.buffer = NULL; + u32_to_u8(hdr->logoOffset,logoOffset/set->options.blockSize,LE); + u32_to_u8(hdr->logoSize,logoSize/set->options.blockSize,LE); } if(plnRgnSize){ - memcpy((u8*)(ncch+plnRgnOffset),ncchset->sections.plainRegion.buffer,ncchset->sections.plainRegion.size); - free(ncchset->sections.plainRegion.buffer); - ncchset->sections.plainRegion.buffer = NULL; - u32_to_u8(hdr->plainRegionOffset,plnRgnOffset/ncchset->options.mediaSize,LE); - u32_to_u8(hdr->plainRegionSize,plnRgnSize/ncchset->options.mediaSize,LE); + memcpy((u8*)(ncch+plnRgnOffset),set->sections.plainRegion.buffer,set->sections.plainRegion.size); + free(set->sections.plainRegion.buffer); + set->sections.plainRegion.buffer = NULL; + u32_to_u8(hdr->plainRegionOffset,plnRgnOffset/set->options.blockSize,LE); + u32_to_u8(hdr->plainRegionSize,plnRgnSize/set->options.blockSize,LE); } if(exefsSize){ - memcpy((u8*)(ncch+exefsOffset),ncchset->sections.exeFs.buffer,ncchset->sections.exeFs.size); - free(ncchset->sections.exeFs.buffer); + memcpy((u8*)(ncch+exefsOffset),set->sections.exeFs.buffer,set->sections.exeFs.size); + free(set->sections.exeFs.buffer); - ncchset->sections.exeFs.buffer = NULL; + set->sections.exeFs.buffer = NULL; - u32_to_u8(hdr->exefsOffset,exefsOffset/ncchset->options.mediaSize,LE); + u32_to_u8(hdr->exefsOffset,exefsOffset/set->options.blockSize,LE); - u32_to_u8(hdr->exefsSize,exefsSize/ncchset->options.mediaSize,LE); + u32_to_u8(hdr->exefsSize,exefsSize/set->options.blockSize,LE); - u32_to_u8(hdr->exefsHashSize,exefsHashSize/ncchset->options.mediaSize,LE); + u32_to_u8(hdr->exefsHashSize,exefsHashSize/set->options.blockSize,LE); } // Point Romfs CTX to output buffer, if exists\n"); if(romfsSize){ romfs->output = ncch + romfsOffset; - u32_to_u8(hdr->romfsOffset,romfsOffset/ncchset->options.mediaSize,LE); - u32_to_u8(hdr->romfsSize,romfsSize/ncchset->options.mediaSize,LE); - u32_to_u8(hdr->romfsHashSize,romfsHashSize/ncchset->options.mediaSize,LE); + u32_to_u8(hdr->romfsOffset,romfsOffset/set->options.blockSize,LE); + u32_to_u8(hdr->romfsSize,romfsSize/set->options.blockSize,LE); + u32_to_u8(hdr->romfsHashSize,romfsHashSize/set->options.blockSize,LE); } - ncchset->out->buffer = ncch; - ncchset->out->size = ncchSize; + set->out->buffer = ncch; + set->out->size = ncchSize; - GetNCCHStruct(&ncchset->cryptoDetails,hdr); + GetNcchInfo(&set->cryptoDetails,hdr); return 0; } -int FinaliseNcch(ncch_settings *ncchset) +int FinaliseNcch(ncch_settings *set) { - u8 *ncch = ncchset->out->buffer; + u8 *ncch = set->out->buffer; - ncch_hdr *hdr = (ncch_hdr*)(ncch + 0x100); - u8 *exhdr = (u8*)(ncch + ncchset->cryptoDetails.exhdrOffset); - u8 *acexDesc = (u8*)(ncch + ncchset->cryptoDetails.acexOffset); - u8 *logo = (u8*)(ncch + ncchset->cryptoDetails.logoOffset); - u8 *exefs = (u8*)(ncch + ncchset->cryptoDetails.exefsOffset); - u8 *romfs = (u8*)(ncch + ncchset->cryptoDetails.romfsOffset); + 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\n"); - if(ncchset->cryptoDetails.exhdrSize) - ctr_sha(exhdr,ncchset->cryptoDetails.exhdrSize,hdr->exhdrHash,CTR_SHA_256); - if(ncchset->cryptoDetails.logoSize) - ctr_sha(logo,ncchset->cryptoDetails.logoSize,hdr->logoHash,CTR_SHA_256); - if(ncchset->cryptoDetails.exefsHashDataSize) - ctr_sha(exefs,ncchset->cryptoDetails.exefsHashDataSize,hdr->exefsHash,CTR_SHA_256); - if(ncchset->cryptoDetails.romfsHashDataSize) - ctr_sha(romfs,ncchset->cryptoDetails.romfsHashDataSize,hdr->romfsHash,CTR_SHA_256); + // Taking Hashes + if(set->cryptoDetails.exhdrSize) + ctr_sha(exhdr,set->cryptoDetails.exhdrSize,hdr->exhdrHash,CTR_SHA_256); + if(set->cryptoDetails.logoSize) + ctr_sha(logo,set->cryptoDetails.logoSize,hdr->logoHash,CTR_SHA_256); + if(set->cryptoDetails.exefsHashDataSize) + ctr_sha(exefs,set->cryptoDetails.exefsHashDataSize,hdr->exefsHash,CTR_SHA_256); + if(set->cryptoDetails.romfsHashDataSize) + ctr_sha(romfs,set->cryptoDetails.romfsHashDataSize,hdr->romfsHash,CTR_SHA_256); - // Signing NCCH\n"); + // Signing NCCH int sig_result = Good; - if(ncchset->options.IsCfa) sig_result = SignCFA(ncch,(u8*)hdr,ncchset->keys); - else sig_result = SignCXI(ncch,(u8*)hdr,ncchset->keys); + 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",ncchset->options.IsCfa ? "CFA" : "CXI"); + fprintf(stderr,"[NCCH ERROR] Failed to sign %s header\n",set->options.IsCfa ? "CFA" : "CXI"); return sig_result; } - //memdump(stdout,"ncch: ",ncch,0x200); // Crypting NCCH\n"); - ncch_key_type keyType = GetNCCHKeyType(hdr); - if(keyType != NoKey){ - SetNcchUnfixedKeys(ncchset->keys, ncch); - - // Getting AES Keys - u8 *key0 = GetNCCHKey0(keyType, ncchset->keys); - u8 *key1 = GetNCCHKey1(keyType, ncchset->keys); - - if(key0 == NULL || key1 == NULL){ - fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n"); - free(ncch); + if(IsNcchEncrypted(hdr)){ + if(!SetNcchKeys(set->keys, hdr)){ + fprintf(stderr,"[NCCH ERROR] Failed to load NCCH AES key\n"); return -1; } - /* - memdump(stdout,"key0: ",key0,16); - memdump(stdout,"key1: ",key1,16); - */ + 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(ncchset->cryptoDetails.exhdrSize){ - CryptNCCHSection(exhdr,ncchset->cryptoDetails.exhdrSize,0x0,&ncchset->cryptoDetails,key0,ncch_exhdr); - CryptNCCHSection(acexDesc,ncchset->cryptoDetails.acexSize,ncchset->cryptoDetails.exhdrSize,&ncchset->cryptoDetails,key0,ncch_exhdr); + if(set->cryptoDetails.exhdrSize){ + CryptNcchRegion(exhdr,set->cryptoDetails.exhdrSize,0x0,&set->cryptoDetails,set->keys->aes.ncchKey0,ncch_exhdr); + CryptNcchRegion(acexDesc,set->cryptoDetails.acexSize,set->cryptoDetails.exhdrSize,&set->cryptoDetails,set->keys->aes.ncchKey0,ncch_exhdr); } // Crypting ExeFs Files - if(ncchset->cryptoDetails.exefsSize){ + 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 = key0; + key = set->keys->aes.ncchKey0; else - key = key1; - - u32 offset = u8_to_u32(exefsHdr->fileHdr[i].offset,LE) + 0x200; + 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) - CryptNCCHSection((exefs+offset),align(size,ncchset->options.mediaSize),offset,&ncchset->cryptoDetails,key,ncch_exefs); + CryptNcchRegion((exefs+offset),align(size,set->options.blockSize),offset,&set->cryptoDetails,key,ncch_exefs); } // Crypting ExeFs Header - CryptNCCHSection(exefs,0x200,0x0,&ncchset->cryptoDetails,key0,ncch_exefs); + CryptNcchRegion(exefs,sizeof(exefs_hdr),0x0,&set->cryptoDetails,set->keys->aes.ncchKey0,ncch_exefs); } // Crypting RomFs - if(ncchset->cryptoDetails.romfsSize) - CryptNCCHSection(romfs,ncchset->cryptoDetails.romfsSize,0x0,&ncchset->cryptoDetails,key1,ncch_romfs); + if(set->cryptoDetails.romfsSize) + CryptNcchRegion(romfs,set->cryptoDetails.romfsSize,0x0,&set->cryptoDetails,set->keys->aes.ncchKey1,ncch_romfs); } return 0; } -int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr) +int SetCommonHeaderBasicData(ncch_settings *set, ncch_hdr *hdr) { /* NCCH Magic */ memcpy(hdr->magic,"NCCH",4); /* NCCH Format Version */ - if(!ncchset->options.IsCfa) + if(!set->options.IsCfa) u16_to_u8(hdr->formatVersion,0x2,LE); /* Setting ProgramId/TitleId */ u64 ProgramId = 0; - int result = GetProgramID(&ProgramId,ncchset->rsfSet,false); + int result = GetProgramID(&ProgramId,set->rsfSet,false); if(result) return result; u64_to_u8(hdr->programId,ProgramId,LE); u64_to_u8(hdr->titleId,ProgramId,LE); /* Get Product Code and Maker Code */ - if(ncchset->rsfSet->BasicInfo.ProductCode){ - if(!IsValidProductCode((char*)ncchset->rsfSet->BasicInfo.ProductCode,ncchset->options.FreeProductCode)){ + if(set->rsfSet->BasicInfo.ProductCode){ + if(!IsValidProductCode((char*)set->rsfSet->BasicInfo.ProductCode,set->options.FreeProductCode)){ fprintf(stderr,"[NCCH ERROR] Invalid Product Code\n"); return NCCH_BAD_YAML_SET; } - memcpy(hdr->productCode,ncchset->rsfSet->BasicInfo.ProductCode,strlen((char*)ncchset->rsfSet->BasicInfo.ProductCode)); + memcpy(hdr->productCode,set->rsfSet->BasicInfo.ProductCode,strlen((char*)set->rsfSet->BasicInfo.ProductCode)); } else memcpy(hdr->productCode,"CTR-P-CTAP",10); - if(ncchset->rsfSet->BasicInfo.CompanyCode){ - if(strlen((char*)ncchset->rsfSet->BasicInfo.CompanyCode) != 2){ + if(set->rsfSet->BasicInfo.CompanyCode){ + if(strlen((char*)set->rsfSet->BasicInfo.CompanyCode) != 2){ fprintf(stderr,"[NCCH ERROR] CompanyCode length must be 2\n"); return NCCH_BAD_YAML_SET; } - memcpy(hdr->makerCode,ncchset->rsfSet->BasicInfo.CompanyCode,2); + memcpy(hdr->makerCode,set->rsfSet->BasicInfo.CompanyCode,2); } else memcpy(hdr->makerCode,"00",2); // Setting Encryption Settings - if(!ncchset->options.Encrypt) - hdr->flags[OtherFlag] = (NoCrypto|FixedCryptoKey); - else if(ncchset->keys->aes.ncchKeyX0){ - hdr->flags[OtherFlag] = UnFixedCryptoKey; - if(ncchset->keys->aes.ncchKeyX1 && !ncchset->options.IsCfa) - hdr->flags[SecureCrypto2] = 1; + if(!set->options.Encrypt) + hdr->flags[ncchflag_OTHER_FLAG] = (otherflag_NoCrypto|otherflag_FixedCryptoKey); + else if(set->options.useSecCrypto){ + hdr->flags[ncchflag_OTHER_FLAG] = otherflag_Clear; + hdr->flags[ncchflag_CONTENT_KEYX] = set->options.keyXID; } - else{ - hdr->flags[OtherFlag] = FixedCryptoKey; - u8 *key = GetNCCHKey0(GetNCCHKeyType(hdr),ncchset->keys); - if(!key){ // for detecting absense of fixed aes keys - hdr->flags[OtherFlag] = (NoCrypto|FixedCryptoKey); - fprintf(stderr,"[NCCH WARNING] NCCH AES Key could not be loaded, NCCH will not be encrypted\n"); - } + else + hdr->flags[ncchflag_OTHER_FLAG] = otherflag_FixedCryptoKey; + + if(!SetNcchKeys(set->keys,hdr) && set->options.Encrypt){ + hdr->flags[ncchflag_OTHER_FLAG] = (otherflag_NoCrypto|otherflag_FixedCryptoKey); + set->options.Encrypt = false; + fprintf(stderr,"[NCCH WARNING] NCCH AES Key could not be loaded, NCCH will not be encrypted\n"); } - - /* Set ContentUnitSize */ - hdr->flags[ContentUnitSize] = 0; // 0x200 + hdr->flags[ncchflag_CONTENT_BLOCK_SIZE] = GetCtrBlockSizeFlag(set->options.blockSize); /* Setting ContentPlatform */ - hdr->flags[ContentPlatform] = 1; // CTR + hdr->flags[ncchflag_CONTENT_PLATFORM] = 1; // CTR /* Setting OtherFlag */ - if(!ncchset->options.UseRomFS) - hdr->flags[OtherFlag] |= NoMountRomFs; + if(!set->options.UseRomFS) + hdr->flags[ncchflag_OTHER_FLAG] |= otherflag_NoMountRomFs; /* Setting ContentType */ - hdr->flags[ContentType] = 0; - if(ncchset->options.UseRomFS) hdr->flags[ContentType] |= content_Data; - if(!ncchset->options.IsCfa) hdr->flags[ContentType] |= content_Executable; - if(ncchset->rsfSet->BasicInfo.ContentType){ - if(strcmp(ncchset->rsfSet->BasicInfo.ContentType,"Application") == 0) hdr->flags[ContentType] |= 0; - else if(strcmp(ncchset->rsfSet->BasicInfo.ContentType,"SystemUpdate") == 0) hdr->flags[ContentType] |= content_SystemUpdate; - else if(strcmp(ncchset->rsfSet->BasicInfo.ContentType,"Manual") == 0) hdr->flags[ContentType] |= content_Manual; - else if(strcmp(ncchset->rsfSet->BasicInfo.ContentType,"Child") == 0) hdr->flags[ContentType] |= content_Child; - else if(strcmp(ncchset->rsfSet->BasicInfo.ContentType,"Trial") == 0) hdr->flags[ContentType] |= content_Trial; + hdr->flags[ncchflag_CONTENT_TYPE] = 0; + if(set->options.UseRomFS) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Data; + if(!set->options.IsCfa) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Executable; + if(set->rsfSet->BasicInfo.ContentType){ + if(strcmp(set->rsfSet->BasicInfo.ContentType,"Application") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= 0; + else if(strcmp(set->rsfSet->BasicInfo.ContentType,"SystemUpdate") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= content_SystemUpdate; + else if(strcmp(set->rsfSet->BasicInfo.ContentType,"Manual") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Manual; + else if(strcmp(set->rsfSet->BasicInfo.ContentType,"Child") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Child; + else if(strcmp(set->rsfSet->BasicInfo.ContentType,"Trial") == 0) hdr->flags[ncchflag_CONTENT_TYPE] |= content_Trial; else{ - fprintf(stderr,"[NCCH ERROR] Invalid ContentType '%s'\n",ncchset->rsfSet->BasicInfo.ContentType); + fprintf(stderr,"[NCCH ERROR] Invalid ContentType '%s'\n",set->rsfSet->BasicInfo.ContentType); return NCCH_BAD_YAML_SET; } } @@ -667,17 +665,27 @@ int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr) bool IsValidProductCode(char *ProductCode, bool FreeProductCode) { - if(strlen(ProductCode) > 16) return false; + if(strlen(ProductCode) > 16) + return false; if(FreeProductCode) return true; - - if(strlen(ProductCode) < 10) return false; - if(strncmp(ProductCode,"CTR-",4) != 0) return false; - if(ProductCode[5] != '-') return false; - if(!isdigit(ProductCode[4]) && !isupper(ProductCode[4])) return false; - for(int i = 6; i < 10; i++){ - if(!isdigit(ProductCode[i]) && !isupper(ProductCode[i])) return false; + + if(strlen(ProductCode) < 10) + return false; + + if(strncmp(ProductCode,"CTR",3) != 0) + return false; + + for(int i = 3; i < 10; i++){ + if(i == 3 || i == 5){ + if(ProductCode[i] != '-') + return false; + } + else{ + if(!isdigit(ProductCode[i]) && !isupper(ProductCode[i])) + return false; + } } return true; @@ -685,80 +693,64 @@ bool IsValidProductCode(char *ProductCode, bool FreeProductCode) // NCCH Read Functions -int VerifyNCCH(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput) +int VerifyNcch(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput) { // Setup - u8 Hash[0x20]; - u8 *hdr_sig = ncch; - ncch_hdr* hdr = GetNCCH_CommonHDR(NULL,NULL,ncch); + ncch_hdr* hdr = (ncch_hdr*)ncch; - ncch_struct *ncch_ctx = calloc(1,sizeof(ncch_struct)); - if(!ncch_ctx){ + ncch_info *ncchInfo = calloc(1,sizeof(ncch_info)); + if(!ncchInfo){ fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); return MEM_ERROR; } - GetNCCHStruct(ncch_ctx,hdr); + GetNcchInfo(ncchInfo,hdr); - ncch_key_type keyType = GetNCCHKeyType(hdr); - u8 *key0 = NULL; - u8 *key1 = NULL; - if(keyType != NoKey){ - //memdump(stdout,"ncch: ",ncch,0x200); - SetNcchUnfixedKeys(keys,ncch); - if(GetNCCHKey0(keyType,keys) == NULL){ - if(!SuppressOutput) - fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key.\n"); - return UNABLE_TO_LOAD_NCCH_KEY; - } - key0 = GetNCCHKey0(keyType,keys); - key1 = GetNCCHKey1(keyType,keys); + if(!SetNcchKeys(keys, hdr)){ + fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n"); + return UNABLE_TO_LOAD_NCCH_KEY; } - //memdump(stdout,"key0: ",key0,16); - //memdump(stdout,"key1: ",key1,16); - if(IsCfa(hdr)){ - if(CheckCFASignature(hdr_sig,(u8*)hdr,keys) != Good && !keys->rsa.isFalseSign){ + if(CheckCFASignature(hdr,keys) != Good && !keys->rsa.isFalseSign){ if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CFA Sigcheck Failed\n"); - free(ncch_ctx); + free(ncchInfo); return NCCH_HDR_SIG_BAD; } - if(!ncch_ctx->romfsSize){ + if(!ncchInfo->romfsSize){ if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CFA is corrupt\n"); - free(ncch_ctx); + free(ncchInfo); return NO_ROMFS_IN_CFA; } } else{ // IsCxi // Checking for necessary sections - if(!ncch_ctx->exhdrSize){ + if(!ncchInfo->exhdrSize){ if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); - free(ncch_ctx); + free(ncchInfo); return NO_EXHEADER_IN_CXI; } - if(!ncch_ctx->exefsSize){ + if(!ncchInfo->exefsSize){ if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); - free(ncch_ctx); + free(ncchInfo); return NO_EXEFS_IN_CXI; } // Get ExHeader/AcexDesc - extended_hdr *exHdr = malloc(ncch_ctx->exhdrSize); + extended_hdr *exHdr = malloc(ncchInfo->exhdrSize); if(!exHdr){ fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); - free(ncch_ctx); + free(ncchInfo); return MEM_ERROR; } - memcpy(exHdr,ncch+ncch_ctx->exhdrOffset,ncch_ctx->exhdrSize); - if(key0 != NULL) - CryptNCCHSection((u8*)exHdr,ncch_ctx->exhdrSize,0,ncch_ctx,key0,ncch_exhdr); + memcpy(exHdr,ncch+ncchInfo->exhdrOffset,ncchInfo->exhdrSize); + if(IsNcchEncrypted(hdr)) + CryptNcchRegion((u8*)exHdr,ncchInfo->exhdrSize,0,ncchInfo,keys->aes.ncchKey0,ncch_exhdr); // Checking Exheader Hash to see if decryption was sucessful - ctr_sha(exHdr,0x400,Hash,CTR_SHA_256); - if(memcmp(Hash,hdr->exhdrHash,0x20) != 0){ + if(!VerifySha256(exHdr, ncchInfo->exhdrSize, hdr->exhdrHash)){ //memdump(stdout,"Expected Hash: ",hdr->extended_header_sha_256_hash,0x20); //memdump(stdout,"Actual Hash: ",Hash,0x20); //memdump(stdout,"Exheader: ",(u8*)exHdr,0x400); @@ -766,36 +758,34 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput) fprintf(stderr,"[NCCH ERROR] ExHeader Hashcheck Failed\n"); fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); } - free(ncch_ctx); + free(ncchInfo); free(exHdr); - return ExHeader_Hashfail; + return EXHDR_CORRUPT; } free(exHdr); // Checking RSA Sigs - access_descriptor *acexDesc = malloc(ncch_ctx->acexSize); + access_descriptor *acexDesc = malloc(ncchInfo->acexSize); if(!acexDesc){ fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); - free(ncch_ctx); + free(ncchInfo); free(exHdr); return MEM_ERROR; } - memcpy(acexDesc,ncch+ncch_ctx->acexOffset,ncch_ctx->acexSize); - if(key0 != NULL) - CryptNCCHSection((u8*)acexDesc,ncch_ctx->acexSize,ncch_ctx->exhdrOffset,ncch_ctx,key0,ncch_exhdr); + memcpy(acexDesc,ncch+ncchInfo->acexOffset,ncchInfo->acexSize); + if(IsNcchEncrypted(hdr)) + CryptNcchRegion((u8*)acexDesc,ncchInfo->acexSize,ncchInfo->exhdrSize,ncchInfo,keys->aes.ncchKey0,ncch_exhdr); if(CheckAccessDescSignature(acexDesc,keys) != 0 && !keys->rsa.isFalseSign){ if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] AccessDesc Sigcheck Failed\n"); - free(ncch_ctx); + free(ncchInfo); free(acexDesc); return ACCESSDESC_SIG_BAD; } - - u8 *hdr_pubk = GetAcexNcchPubKey(acexDesc); - - if(CheckCXISignature(hdr_sig,(u8*)hdr,hdr_pubk) != 0 && !keys->rsa.isFalseSign){ + + if(CheckCXISignature(hdr,GetAcexNcchPubKey(acexDesc)) != 0 && !keys->rsa.isFalseSign){ if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI Header Sigcheck Failed\n"); - free(ncch_ctx); + free(ncchInfo); free(acexDesc); return NCCH_HDR_SIG_BAD; } @@ -805,93 +795,70 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput) return 0; /* Checking ExeFs Hash, if present */ - if(ncch_ctx->exefsSize) + if(ncchInfo->exefsSize) { - u8 *ExeFs = malloc(ncch_ctx->exefsHashDataSize); - if(!ExeFs){ + u8 *exefs = malloc(ncchInfo->exefsHashDataSize); + if(!exefs){ fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); - free(ncch_ctx); + free(ncchInfo); return MEM_ERROR; } - memcpy(ExeFs,ncch+ncch_ctx->exefsOffset,ncch_ctx->exefsHashDataSize); - if(key0 != NULL) - CryptNCCHSection(ExeFs,ncch_ctx->exefsHashDataSize,0,ncch_ctx,key0,ncch_exefs); - ctr_sha(ExeFs,ncch_ctx->exefsHashDataSize,Hash,CTR_SHA_256); - free(ExeFs); - if(memcmp(Hash,hdr->exefsHash,0x20) != 0){ + memcpy(exefs,ncch+ncchInfo->exefsOffset,ncchInfo->exefsHashDataSize); + if(IsNcchEncrypted(hdr)) + CryptNcchRegion(exefs,ncchInfo->exefsHashDataSize,0,ncchInfo,keys->aes.ncchKey0,ncch_exefs); + if(!VerifySha256(exefs, ncchInfo->exefsHashDataSize, hdr->exefsHash)){ if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] ExeFs Hashcheck Failed\n"); - free(ncch_ctx); - return ExeFs_Hashfail; + free(ncchInfo); + free(exefs); + return EXEFS_CORRUPT; } + free(exefs); } /* Checking RomFs hash, if present */ - if(ncch_ctx->romfsSize){ - u8 *RomFs = malloc(ncch_ctx->romfsHashDataSize); - if(!RomFs){ + if(ncchInfo->romfsSize){ + u8 *romfs = malloc(ncchInfo->romfsHashDataSize); + if(!romfs){ fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); - free(ncch_ctx); + free(ncchInfo); return MEM_ERROR; } - memcpy(RomFs,ncch+ncch_ctx->romfsOffset,ncch_ctx->romfsHashDataSize); - if(key1 != NULL) - CryptNCCHSection(RomFs,ncch_ctx->romfsHashDataSize,0,ncch_ctx,key1,ncch_romfs); - ctr_sha(RomFs,ncch_ctx->romfsHashDataSize,Hash,CTR_SHA_256); - free(RomFs); - if(memcmp(Hash,hdr->romfsHash,0x20) != 0){ + memcpy(romfs,ncch+ncchInfo->romfsOffset,ncchInfo->romfsHashDataSize); + if(IsNcchEncrypted(hdr)) + CryptNcchRegion(romfs,ncchInfo->romfsHashDataSize,0,ncchInfo,keys->aes.ncchKey1,ncch_romfs); + if(!VerifySha256(romfs,ncchInfo->romfsHashDataSize,hdr->romfsHash)){ if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] RomFs Hashcheck Failed\n"); - free(ncch_ctx); - return ExeFs_Hashfail; + free(ncchInfo); + free(romfs); + return ROMFS_CORRUPT; } + free(romfs); } /* Checking the Logo Hash, if present */ - if(ncch_ctx->logoSize){ - u8 *logo = (ncch+ncch_ctx->logoOffset); - ctr_sha(logo,ncch_ctx->logoSize,Hash,CTR_SHA_256); - if(memcmp(Hash,hdr->logoHash,0x20) != 0){ + if(ncchInfo->logoSize){ + u8 *logo = (ncch+ncchInfo->logoOffset); + if(!VerifySha256(logo,ncchInfo->logoSize,hdr->logoHash)){ if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] Logo Hashcheck Failed\n"); - free(ncch_ctx); - return Logo_Hashfail; + free(ncchInfo); + return LOGO_CORRUPT; } } - free(ncch_ctx); + free(ncchInfo); return 0; } - -u8* RetargetNCCH(FILE *fp, u64 size, u8 *TitleId, u8 *ProgramId, keys_struct *keys) -{ - u8 *ncch = calloc(1,size); - if(!ncch){ - fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); - return NULL; - } - ReadFile_64(ncch,size,0,fp); // Importing - - if(ModifyNcchIds(ncch,TitleId, ProgramId, keys) != 0){ - free(ncch); - return NULL; - } - - return ncch; -} - int ModifyNcchIds(u8 *ncch, u8 *titleId, u8 *programId, keys_struct *keys) { - if(!IsNCCH(NULL,ncch)){ - //free(ncch); + if(!IsNcch(NULL,ncch)) return -1; - } - ncch_hdr *hdr = NULL; - hdr = GetNCCH_CommonHDR(NULL,NULL,ncch); + ncch_hdr *hdr = (ncch_hdr*)ncch; if(/*keys->rsa.requiresPresignedDesc && */!IsCfa(hdr)){ fprintf(stderr,"[NCCH ERROR] CXI's ID cannot be modified without the ability to resign the AccessDesc\n"); // Not yet yet, requires AccessDesc Privk, may implement anyway later - //free(ncch); return -1; } @@ -901,29 +868,19 @@ int ModifyNcchIds(u8 *ncch, u8 *titleId, u8 *programId, keys_struct *keys) if(titleIdMatches && programIdMatches) return 0;// if no modification is required don't do anything - if(titleIdMatches){ // If TitleID Same, no crypto required, just resign. - memcpy(hdr->programId,programId,8); - SignCFA(ncch,(u8*)hdr,keys); - return 0; - } - ncch_key_type keytype = GetNCCHKeyType(hdr); - ncch_struct ncch_struct; - u8 *key = NULL; + ncch_info ncchInfo; u8 *romfs = NULL; //Decrypting if necessary - if(keytype != NoKey){ - GetNCCHStruct(&ncch_struct,hdr); - romfs = (ncch+ncch_struct.romfsOffset); - SetNcchUnfixedKeys(keys, ncch); // For Secure Crypto - key = GetNCCHKey1(keytype,keys); - if(key == NULL){ + if(IsNcchEncrypted(hdr)){ + GetNcchInfo(&ncchInfo,hdr); + romfs = (ncch+ncchInfo.romfsOffset); + if(!SetNcchKeys(keys, hdr)){ fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n"); - //free(ncch); return -1; } - CryptNCCHSection(romfs,ncch_struct.romfsSize,0,&ncch_struct,key,ncch_romfs); + CryptNcchRegion(romfs,ncchInfo.romfsSize,0,&ncchInfo,keys->aes.ncchKey1,ncch_romfs); } // Editing data and resigning @@ -931,192 +888,188 @@ int ModifyNcchIds(u8 *ncch, u8 *titleId, u8 *programId, keys_struct *keys) memcpy(hdr->titleId,titleId,8); if(programId) memcpy(hdr->programId,programId,8); - SignCFA(ncch,(u8*)hdr,keys); - - //Checking New Key Type - keytype = GetNCCHKeyType(hdr); + SignCFA(hdr,keys); // Re-encrypting if necessary - if(keytype != NoKey){ - GetNCCHStruct(&ncch_struct,hdr); - romfs = (ncch+ncch_struct.romfsOffset); - SetNcchUnfixedKeys(keys, ncch); // For Secure Crypto - key = GetNCCHKey1(keytype,keys); - if(key == NULL){ + if(IsNcchEncrypted(hdr)){ + GetNcchInfo(&ncchInfo,hdr); + romfs = (ncch+ncchInfo.romfsOffset); + if(!SetNcchKeys(keys, hdr)){ fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n"); - //free(ncch); return -1; } - CryptNCCHSection(romfs,ncch_struct.romfsSize,0,&ncch_struct,key,ncch_romfs); + CryptNcchRegion(romfs,ncchInfo.romfsSize,0,&ncchInfo,keys->aes.ncchKey1,ncch_romfs); } return 0; } -ncch_hdr* GetNCCH_CommonHDR(void *out, FILE *fp, u8 *buf) +void ReadNcchHdr(ncch_hdr *hdr, FILE *fp) { - if(!fp && !buf) return NULL; - if(fp){ - if(!out) return NULL; - ReadFile_64(out,0x100,0x100,fp); - return (ncch_hdr*)out; - } - else{ - return (ncch_hdr*)(buf+0x100); - } + if(!fp || !hdr) + return; + + ReadFile64(hdr,sizeof(ncch_hdr),0,fp); + + return; } - -bool IsNCCH(FILE *fp, u8 *buf) +u8* GetNcchHdrSig(ncch_hdr *hdr) { - if(!fp && !buf) return false; - ncch_hdr *ncchHDR = NULL; + return (u8*)hdr->signature; +} + +u8* GetNcchHdrData(ncch_hdr *hdr) +{ + return (u8*)hdr->magic; +} + +u32 GetNcchHdrSigLen(ncch_hdr *hdr) +{ + return 0x100; +} + +u32 GetNcchHdrDataLen(ncch_hdr *hdr) +{ + return 0x100; +} + +bool IsNcch(FILE *fp, u8 *buf) +{ + if(!fp && !buf) + return false; + + ncch_hdr *hdr; bool result; + if(fp) { - ncchHDR = malloc(sizeof(ncch_hdr)); - GetNCCH_CommonHDR(ncchHDR,fp,NULL); - result = (memcmp(ncchHDR->magic,"NCCH",4) == 0); - free(ncchHDR); + hdr = malloc(sizeof(ncch_hdr)); + ReadNcchHdr(hdr,fp); + result = (memcmp(hdr->magic,"NCCH",4) == 0); + free(hdr); } else { - ncchHDR = GetNCCH_CommonHDR(ncchHDR,NULL,buf); - result = (memcmp(ncchHDR->magic,"NCCH",4) == 0); + hdr = (ncch_hdr*)buf; + result = (memcmp(hdr->magic,"NCCH",4) == 0); } return result; } bool IsCfa(ncch_hdr* hdr) { - return (((hdr->flags[ContentType] & content_Data) == content_Data) && ((hdr->flags[ContentType] & content_Executable) != content_Executable)); + return (((hdr->flags[ncchflag_CONTENT_TYPE] & content_Data) == content_Data) && ((hdr->flags[ncchflag_CONTENT_TYPE] & content_Executable) != content_Executable)); } -u32 GetNCCH_MediaUnitSize(ncch_hdr* hdr) +bool IsUpdateCfa(ncch_hdr* hdr) { + return (((hdr->flags[ncchflag_CONTENT_TYPE] & content_SystemUpdate) == content_SystemUpdate) && ((hdr->flags[ncchflag_CONTENT_TYPE] & content_Child) != content_Child) && IsCfa(hdr)); +} + +u32 GetNcchBlockSize(ncch_hdr* hdr) +{ + /* u16 formatVersion = u8_to_u16(hdr->formatVersion,LE); - u32 ret = 0; if (formatVersion == 1) - ret = 1; - else if (formatVersion == 2 || formatVersion == 0) - ret = 1 << (hdr->flags[ContentUnitSize] + 9); - return ret; - //return 0x200*pow(2,hdr->flags[ContentUnitSize]); + return 1; + */ + return GetCtrBlockSize(hdr->flags[ncchflag_CONTENT_BLOCK_SIZE]); //formatVersion == 2 || formatVersion == 0 } -u32 GetNCCH_MediaSize(ncch_hdr* hdr) +u64 GetNcchSize(ncch_hdr* hdr) { - return u8_to_u32(hdr->ncchSize,LE); + return (u64)u8_to_u32(hdr->ncchSize,LE) * (u64)GetNcchBlockSize(hdr); } -ncch_key_type GetNCCHKeyType(ncch_hdr* hdr) -{ - // Non-Secure Key Options - if((hdr->flags[OtherFlag] & NoCrypto) == NoCrypto) - return NoKey; - if((hdr->flags[OtherFlag] & FixedCryptoKey) == FixedCryptoKey){ - if((hdr->programId[4] & 0x10) == 0x10) - return KeyIsSystemFixed; - else - return KeyIsNormalFixed; +bool IsNcchEncrypted(ncch_hdr *hdr) +{ + return (hdr->flags[ncchflag_OTHER_FLAG] & otherflag_NoCrypto) != otherflag_NoCrypto; +} + +bool SetNcchKeys(keys_struct *keys, ncch_hdr *hdr) +{ + if(!IsNcchEncrypted(hdr)) + return true; + + if((hdr->flags[ncchflag_OTHER_FLAG] & otherflag_FixedCryptoKey) == otherflag_FixedCryptoKey){ + if((hdr->programId[4] & 0x10) == 0x10 && keys->aes.systemFixedKey){ + memcpy(keys->aes.ncchKey0,keys->aes.systemFixedKey,AES_128_KEY_SIZE); + memcpy(keys->aes.ncchKey1,keys->aes.systemFixedKey,AES_128_KEY_SIZE); + return true; + } + else if(keys->aes.normalKey){ + memcpy(keys->aes.ncchKey0,keys->aes.normalKey,AES_128_KEY_SIZE); + memcpy(keys->aes.ncchKey1,keys->aes.normalKey,AES_128_KEY_SIZE); + return true; + } + return false; } - - // Secure Key Options - if(hdr->flags[SecureCrypto2]) - return KeyIsUnFixed2; - return KeyIsUnFixed; + + if(keys->aes.ncchKeyX[0]) + AesKeyScrambler(keys->aes.ncchKey0,keys->aes.ncchKeyX[0],hdr->signature); + else + return false; + + if(keys->aes.ncchKeyX[hdr->flags[ncchflag_CONTENT_KEYX]]) + AesKeyScrambler(keys->aes.ncchKey1,keys->aes.ncchKeyX[hdr->flags[ncchflag_CONTENT_KEYX]],hdr->signature); + else + return false; + + return true; } -u8* GetNCCHKey0(ncch_key_type keytype, keys_struct *keys) +int GetNcchInfo(ncch_info *info, ncch_hdr *hdr) { - switch(keytype){ - case NoKey: return NULL; - case KeyIsNormalFixed: - return keys->aes.normalKey; - case KeyIsSystemFixed: - return keys->aes.systemFixedKey; - case KeyIsUnFixed: - case KeyIsUnFixed2: - if(keys->aes.ncchKeyX0) - return keys->aes.unFixedKey0; - else - return NULL; - } - return NULL; -} - -u8* GetNCCHKey1(ncch_key_type keytype, keys_struct *keys) -{ - switch(keytype){ - case NoKey: return NULL; - case KeyIsNormalFixed: - return keys->aes.normalKey; - case KeyIsSystemFixed: - return keys->aes.systemFixedKey; - case KeyIsUnFixed: - if(keys->aes.ncchKeyX0) - return keys->aes.unFixedKey0; - else - return NULL; - case KeyIsUnFixed2: - if(keys->aes.ncchKeyX1) - return keys->aes.unFixedKey1; - else - return NULL; - } - return NULL; -} - -int GetNCCHStruct(ncch_struct *ctx, ncch_hdr *header) -{ - memcpy(ctx->titleId,header->titleId,8); - memcpy(ctx->programId,header->programId,8); + memcpy(info->titleId,hdr->titleId,8); + memcpy(info->programId,hdr->programId,8); - u32 media_unit = GetNCCH_MediaUnitSize(header); + u32 media_unit = GetNcchBlockSize(hdr); - ctx->formatVersion = u8_to_u16(header->formatVersion,LE); - if(!IsCfa(header)){ - ctx->exhdrOffset = 0x200; - ctx->exhdrSize = u8_to_u32(header->exhdrSize,LE); - ctx->acexOffset = (ctx->exhdrOffset + ctx->exhdrSize); - ctx->acexSize = sizeof(access_descriptor); - ctx->plainRegionOffset = (u64)(u8_to_u32(header->plainRegionOffset,LE)*media_unit); - ctx->plainRegionSize = (u64)(u8_to_u32(header->plainRegionSize,LE)*media_unit); + info->formatVersion = u8_to_u16(hdr->formatVersion,LE); + if(!IsCfa(hdr)){ + info->exhdrOffset = 0x200; + 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)*media_unit); + info->plainRegionSize = (u64)(u8_to_u32(hdr->plainRegionSize,LE)*media_unit); } - ctx->logoOffset = (u64)(u8_to_u32(header->logoOffset,LE)*media_unit); - ctx->logoSize = (u64)(u8_to_u32(header->logoSize,LE)*media_unit); - ctx->exefsOffset = (u64)(u8_to_u32(header->exefsOffset,LE)*media_unit); - ctx->exefsSize = (u64)(u8_to_u32(header->exefsSize,LE)*media_unit); - ctx->exefsHashDataSize = (u64)(u8_to_u32(header->exefsHashSize,LE)*media_unit); - ctx->romfsOffset = (u64) (u8_to_u32(header->romfsOffset,LE)*media_unit); - ctx->romfsSize = (u64) (u8_to_u32(header->romfsSize,LE)*media_unit); - ctx->romfsHashDataSize = (u64)(u8_to_u32(header->romfsHashSize,LE)*media_unit); + info->logoOffset = (u64)(u8_to_u32(hdr->logoOffset,LE)*media_unit); + info->logoSize = (u64)(u8_to_u32(hdr->logoSize,LE)*media_unit); + info->exefsOffset = (u64)(u8_to_u32(hdr->exefsOffset,LE)*media_unit); + info->exefsSize = (u64)(u8_to_u32(hdr->exefsSize,LE)*media_unit); + info->exefsHashDataSize = (u64)(u8_to_u32(hdr->exefsHashSize,LE)*media_unit); + info->romfsOffset = (u64) (u8_to_u32(hdr->romfsOffset,LE)*media_unit); + info->romfsSize = (u64) (u8_to_u32(hdr->romfsSize,LE)*media_unit); + info->romfsHashDataSize = (u64)(u8_to_u32(hdr->romfsHashSize,LE)*media_unit); return 0; } -void CryptNCCHSection(u8 *buffer, u64 size, u64 src_pos, ncch_struct *ctx, u8 key[16], u8 type) +void CryptNcchRegion(u8 *buffer, u64 size, u64 src_pos, ncch_info *ctx, u8 key[16], u8 type) { if(type < 1 || type > 3) return; u8 counter[0x10]; - ncch_get_counter(ctx,counter,type); ctr_aes_context aes_ctx; memset(&aes_ctx,0x0,sizeof(ctr_aes_context)); + + GetNcchAesCounter(ctx,counter,type); ctr_init_counter(&aes_ctx, key, counter); + if(src_pos > 0){ u32 carry = 0; carry = align(src_pos,0x10); carry /= 0x10; ctr_add_counter(&aes_ctx,carry); } - ctr_crypt_counter(&aes_ctx, buffer, buffer, size); return; } -void ncch_get_counter(ncch_struct *ctx, u8 counter[16], u8 type) +void GetNcchAesCounter(ncch_info *ctx, u8 counter[16], u8 type) { u8 *titleId = ctx->titleId; u32 i; diff --git a/makerom/ncch.h b/makerom/ncch.h index 232a228..e87ae48 100644 --- a/makerom/ncch.h +++ b/makerom/ncch.h @@ -15,10 +15,10 @@ typedef enum ACCESSDESC_SIG_BAD = -10, NCCH_HDR_SIG_BAD = -11, // HashCheck Errors - ExHeader_Hashfail = -12, - Logo_Hashfail = -13, - ExeFs_Hashfail = -14, - RomFs_Hashfail = -15, + EXHDR_CORRUPT = -12, + LOGO_CORRUPT = -13, + EXEFS_CORRUPT = -14, + ROMFS_CORRUPT = -15, // Others NCCH_BAD_YAML_SET = -16, DATA_POS_DNE = -17, @@ -29,34 +29,23 @@ typedef enum ncch_exhdr = 1, ncch_exefs, ncch_romfs, - ncch_Logo, - ncch_PlainRegion, } ncch_section; typedef enum { - NoKey, - KeyIsNormalFixed, - KeyIsSystemFixed, - KeyIsUnFixed, - KeyIsUnFixed2, -} ncch_key_type; - -typedef enum -{ - SecureCrypto2 = 3, - ContentPlatform = 4, - ContentType = 5, - ContentUnitSize = 6, - OtherFlag = 7 + ncchflag_CONTENT_KEYX = 3, + ncchflag_CONTENT_PLATFORM = 4, + ncchflag_CONTENT_TYPE = 5, + ncchflag_CONTENT_BLOCK_SIZE = 6, + ncchflag_OTHER_FLAG = 7 } ncch_flags; typedef enum { - UnFixedCryptoKey = 0x0, - FixedCryptoKey = 0x1, - NoMountRomFs = 0x2, - NoCrypto = 0x4, + otherflag_Clear = 0, + otherflag_FixedCryptoKey = (1 << 0), + otherflag_NoMountRomFs = (1 << 1), + otherflag_NoCrypto = (1 << 2), } ncch_otherflag_bitmask; typedef enum @@ -88,10 +77,11 @@ typedef struct u64 romfsHashDataSize; u8 titleId[8]; u8 programId[8]; -} ncch_struct; +} ncch_info; typedef struct { + u8 signature[0x100]; u8 magic[4]; u8 ncchSize[4]; u8 titleId[8]; @@ -122,109 +112,24 @@ typedef struct u8 romfsHash[0x20]; } ncch_hdr; - -typedef struct -{ - buffer_struct *out; - keys_struct *keys; - rsf_settings *rsfSet; - - struct - { - u32 mediaSize; - bool IncludeExeFsLogo; - bool CompressCode; - bool UseOnSD; - bool Encrypt; - bool FreeProductCode; - bool IsCfa; - bool IsBuildingCodeSection; - bool UseRomFS; - } options; - - struct - { - FILE *elf; - u64 elfSize; - - FILE *banner; - u64 bannerSize; - - FILE *icon; - u64 iconSize; - - FILE *logo; - u64 logoSize; - - FILE *code; - u64 codeSize; - - FILE *exhdr; - u64 exhdrSize; - - FILE *romfs; - u64 romfsSize; - - FILE *plainregion; - u64 plainregionSize; - } componentFilePtrs; - - struct - { - buffer_struct code; - buffer_struct banner; - buffer_struct icon; - } exefsSections; - - struct - { - u32 textAddress; - u32 textSize; - u32 textMaxPages; - u32 roAddress; - u32 roSize; - u32 roMaxPages; - u32 rwAddress; - u32 rwSize; - u32 rwMaxPages; - u32 bssSize; - } codeDetails; - - struct - { - buffer_struct exhdr; - buffer_struct acexDesc; - buffer_struct logo; - buffer_struct plainRegion; - buffer_struct exeFs; - } sections; - - ncch_struct cryptoDetails; - - -} ncch_settings; - -// NCCH Build Functions -int build_NCCH(user_settings *usrset); - - // NCCH Read Functions -int VerifyNCCH(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput); +int VerifyNcch(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput); -u8* RetargetNCCH(FILE *fp, u64 size, u8 *TitleId, u8 *ProgramId, keys_struct *keys); int ModifyNcchIds(u8 *ncch, u8 *titleId, u8 *programId, keys_struct *keys); - -ncch_hdr* GetNCCH_CommonHDR(void *out, FILE *fp, u8 *buf); -bool IsNCCH(FILE *fp, u8 *buf); +void ReadNcchHdr(ncch_hdr *hdr, FILE *fp); +u8* GetNcchHdrSig(ncch_hdr *hdr); +u8* GetNcchHdrData(ncch_hdr *hdr); +u32 GetNcchHdrSigLen(ncch_hdr *hdr); +u32 GetNcchHdrDataLen(ncch_hdr *hdr); +bool IsNcch(FILE *fp, u8 *buf); bool IsCfa(ncch_hdr* hdr); -u32 GetNCCH_MediaUnitSize(ncch_hdr* hdr); -u32 GetNCCH_MediaSize(ncch_hdr* hdr); -ncch_key_type GetNCCHKeyType(ncch_hdr* hdr); - -u8* GetNCCHKey0(ncch_key_type keytype, keys_struct *keys); -u8* GetNCCHKey1(ncch_key_type keytype, keys_struct *keys); - -int GetNCCHStruct(ncch_struct *ctx, ncch_hdr *header); -void ncch_get_counter(ncch_struct *ctx, u8 counter[16], u8 type); -void CryptNCCHSection(u8 *buffer, u64 size, u64 src_pos, ncch_struct *ctx, u8 key[16], u8 type); \ No newline at end of file +bool IsUpdateCfa(ncch_hdr* hdr); +u32 GetNcchBlockSize(ncch_hdr* hdr); +u8 GetBlockSizeFlag(u32 size); +u64 GetNcchSize(ncch_hdr* hdr); +bool IsNcchEncrypted(ncch_hdr *hdr); +bool SetNcchKeys(keys_struct *keys, ncch_hdr *hdr); +int GetNcchInfo(ncch_info *ctx, ncch_hdr *header); +void GetNcchAesCounter(ncch_info *ctx, u8 counter[16], u8 type); +void CryptNcchRegion(u8 *buffer, u64 size, u64 src_pos, ncch_info *ctx, u8 key[16], u8 type); \ No newline at end of file diff --git a/makerom/ncch_build.h b/makerom/ncch_build.h new file mode 100644 index 0000000..96f47c4 --- /dev/null +++ b/makerom/ncch_build.h @@ -0,0 +1,88 @@ +#pragma once +#include "ncch.h" + +typedef struct +{ + buffer_struct *out; + keys_struct *keys; + rsf_settings *rsfSet; + + struct + { + u32 blockSize; + bool verbose; + bool IncludeExeFsLogo; + bool CompressCode; + bool UseOnSD; + bool Encrypt; + bool FreeProductCode; + bool IsCfa; + bool IsBuildingCodeSection; + bool UseRomFS; + + bool useSecCrypto; + u8 keyXID; + } options; + + struct + { + FILE *elf; + u64 elfSize; + + FILE *banner; + u64 bannerSize; + + FILE *icon; + u64 iconSize; + + FILE *logo; + u64 logoSize; + + FILE *code; + u64 codeSize; + + FILE *exhdr; + u64 exhdrSize; + + FILE *romfs; + u64 romfsSize; + + FILE *plainregion; + u64 plainregionSize; + } componentFilePtrs; + + struct + { + buffer_struct code; + buffer_struct banner; + buffer_struct icon; + } exefsSections; + + struct + { + u32 textAddress; + u32 textSize; + u32 textMaxPages; + u32 roAddress; + u32 roSize; + u32 roMaxPages; + u32 rwAddress; + u32 rwSize; + u32 rwMaxPages; + u32 bssSize; + } codeDetails; + + struct + { + buffer_struct exhdr; + buffer_struct acexDesc; + buffer_struct logo; + buffer_struct plainRegion; + buffer_struct exeFs; + } sections; + + ncch_info cryptoDetails; +} ncch_settings; + +// NCCH Build Functions +int build_NCCH(user_settings *usrset); \ No newline at end of file diff --git a/makerom/logo_data.h b/makerom/ncch_logo.h similarity index 100% rename from makerom/logo_data.h rename to makerom/ncch_logo.h diff --git a/makerom/ncch_read.h b/makerom/ncch_read.h new file mode 100644 index 0000000..a185bd0 --- /dev/null +++ b/makerom/ncch_read.h @@ -0,0 +1,2 @@ +#pragma once +#include "ncch.h" \ No newline at end of file diff --git a/makerom/ncsd.c b/makerom/ncsd.c index bb8f3c0..2827f5b 100644 --- a/makerom/ncsd.c +++ b/makerom/ncsd.c @@ -1,684 +1,700 @@ #include "lib.h" -#include "ncch.h" -#include "exheader.h" -#include "ncsd.h" -#include "cia.h" -#include "tmd.h" -// Private Prototypes +#include "ncch_read.h" +#include "exheader_read.h" +#include "tik_read.h" +#include "tmd_read.h" +#include "cia_read.h" -/* RSA Crypto */ -int SignCCI(u8 *Signature, u8 *NCSD_HDR, keys_struct *keys); -int CheckCCISignature(u8 *Signature, u8 *NCSD_HDR, keys_struct *keys); +#include "ncsd_build.h" +#include "cardinfo.h" +#include "titleid.h" -/* cci_settings tools */ -void init_CCISettings(cci_settings *set); -int get_CCISettings(cci_settings *cciset, user_settings *usrset); -void free_CCISettings(cci_settings *set); -/* CCI Data Gen/Write */ -int BuildCCIHeader(cci_settings *cciset, user_settings *usrset); -int BuildCardInfoHeader(cci_settings *cciset, user_settings *usrset); -int WriteHeaderToFile(cci_settings *cciset); -int WriteContentToFile(cci_settings *cciset,user_settings *usrset); -int WriteDummyBytes(cci_settings *cciset); - -/* Get Data from Content Files */ -int CheckContent0(cci_settings *cciset, user_settings *usrset); -int GetDataFromContent0(cci_settings *cciset, user_settings *usrset); -int GetContentFP(cci_settings *cciset, user_settings *usrset); -int ImportNcchPartitions(cci_settings *cciset); -int ImportCverDetails(cci_settings *cciset, user_settings *usrset); - -/* Get Data from YAML Settings */ -int GetNCSDFlags(cci_settings *cciset, rsf_settings *yaml); -int GetMediaSize(cci_settings *cciset, user_settings *usrset); -u64 GetUnusedSize(u64 MediaSize, u8 CardType); -int GetWriteableAddress(cci_settings *cciset, user_settings *usrset); -int GetCardInfoBitmask(cci_settings *cciset, user_settings *usrset); - -int CheckMediaSize(cci_settings *cciset); - -static InternalCCI_Context ctx; const int NCCH0_OFFSET = 0x4000; +const int CCI_BLOCK_SIZE = 0x200; + +void ImportCciSettings(cci_settings *set, user_settings *usrset); +void FreeCciSettings(cci_settings *set); +int ImportCciNcch(cci_settings *set); +int ProcessNcchForCci(cci_settings *set); +int GenCciHdr(cci_settings *set); +int CheckRomConfig(cci_settings *set); +void WriteCciDataToOutput(cci_settings *set); -// Code int build_CCI(user_settings *usrset) { int result = 0; - - // Init Settings - cci_settings *cciset = calloc(1,sizeof(cci_settings)); - if(!cciset) { - fprintf(stderr,"[CCI ERROR] Not enough memory\n"); + cci_settings *set = calloc(1,sizeof(cci_settings)); + if(!set){ + fprintf(stderr,"[CCI ERROR] Not enough memory\n"); return MEM_ERROR; } - init_CCISettings(cciset); + ImportCciSettings(set,usrset); - // Get Settings - result = get_CCISettings(cciset,usrset); - if(result) goto finish; - - // Import Content - result = ImportNcchPartitions(cciset); - if(result) goto finish; - - // Create Output File - cciset->out = fopen(usrset->common.outFileName,"wb"); - if(!cciset->out){ + if(ImportCciNcch(set)){ + result = FAILED_TO_IMPORT_FILE; + goto finish; + } + + if(ProcessNcchForCci(set)){ + result = FAILED_TO_IMPORT_FILE; + goto finish; + } + + if(GenCciHdr(set)){ + result = GEN_HDR_FAIL; + goto finish; + } + + if(CheckRomConfig(set)){ + result = CCI_CONFIG_FAIL; + goto finish; + } + + if(GenCardInfoHdr(set)){ + result = GEN_HDR_FAIL; + goto finish; + } + + set->out = fopen(usrset->common.outFileName,"wb"); + if(!set->out){ fprintf(stderr,"[CCI ERROR] Failed to create '%s'\n",usrset->common.outFileName); result = FAILED_TO_CREATE_OUTFILE; goto finish; } - - // Generate NCSD Header and Additional Header - result = BuildCCIHeader(cciset,usrset); - if(result) goto finish; - BuildCardInfoHeader(cciset,usrset); - // Write to File - WriteHeaderToFile(cciset); - result = WriteContentToFile(cciset,usrset); - if(result) - goto finish; + WriteCciDataToOutput(set); - // Fill out file if necessary - if(cciset->option.fillOutCci) - WriteDummyBytes(cciset); - - // Close output file finish: - if(result != FAILED_TO_CREATE_OUTFILE && cciset->out) fclose(cciset->out); - free_CCISettings(cciset); + FreeCciSettings(set); return result; } - -int SignCCI(u8 *Signature, u8 *NCSD_HDR, keys_struct *keys) +void ImportCciSettings(cci_settings *set, user_settings *usrset) { - return ctr_sig(NCSD_HDR,sizeof(cci_hdr),Signature,keys->rsa.cciCfaPub,keys->rsa.cciCfaPvt,RSA_2048_SHA256,CTR_RSA_SIGN); -} - -int CheckCCISignature(u8 *Signature, u8 *NCSD_HDR, keys_struct *keys) -{ - return ctr_sig(NCSD_HDR,sizeof(cci_hdr),Signature,keys->rsa.cciCfaPub,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY); -} - -void init_CCISettings(cci_settings *set) -{ - memset(set,0,sizeof(cci_settings)); - memset(&ctx,0,sizeof(InternalCCI_Context)); -} - -int get_CCISettings(cci_settings *cciset, user_settings *usrset) -{ - cciset->keys = &usrset->common.keys; - int result = 0; - - /* Importing Data from Content */ - result = CheckContent0(cciset,usrset); - if(result) return result; - - result = GetDataFromContent0(cciset,usrset); - if(result) return result; - - result = GetContentFP(cciset,usrset); - if(result) return result; + set->keys = &usrset->common.keys; + set->rsf = &usrset->common.rsfSet; - - /* Getting Data from YAML */ - result = GetNCSDFlags(cciset,&usrset->common.rsfSet); - if(result) return result; - - result = GetMediaSize(cciset,usrset); - if(result) return result; - - result = CheckMediaSize(cciset); - if(result) return result; - - /** Card Info Header Data **/ - result = GetWriteableAddress(cciset,usrset); - if(result) return result; - - result = GetCardInfoBitmask(cciset,usrset); - if(result) return result; + set->content.data = usrset->common.workingFile.buffer; + set->content.dataLen = usrset->common.workingFile.size; + set->content.dataType = usrset->common.workingFileType; - result = ImportCverDetails(cciset,usrset); - if(result) return result; - - /* All Done */ - return 0; + set->content.path = usrset->common.contentPath; + set->content.dSize = usrset->common.contentSize; + + usrset->common.workingFile.buffer = NULL; + usrset->common.workingFile.size = 0; + + set->options.verbose = usrset->common.verbose; + set->options.padCci = set->rsf->Option.MediaFootPadding; + set->options.noModTid = usrset->cci.dontModifyNcchTitleID; + set->options.useExternalSdkCardInfo = usrset->cci.useSDKStockData; + set->options.closeAlignWR = usrset->cci.closeAlignWritableRegion; + + set->options.cverDataType = usrset->cci.cverDataType; + set->options.cverDataPath = usrset->cci.cverDataPath; + + set->romInfo.blockSize = CCI_BLOCK_SIZE; + set->romInfo.saveSize = 0; } -void free_CCISettings(cci_settings *set) +void FreeCciSettings(cci_settings *set) { - if(set->content.filePtrs){ - for(int i = 1; i < 8; i++) { - if(set->content.filePtrs[i]) fclose(set->content.filePtrs[i]); - } - free(set->content.filePtrs); - } + free(set->options.tmdHdr); + free(set->content.data); + free(set->headers.ccihdr.buffer); + free(set->headers.cardinfohdr.buffer); + if(set->out) + fclose(set->out); free(set); } -int BuildCCIHeader(cci_settings *cciset, user_settings *usrset) +int ImportNcchForCci(cci_settings *set) { - memcpy((u8*)ctx.cciHdr.magic,"NCSD",4); - u32_to_u8((u8*)ctx.cciHdr.mediaSize,(cciset->header.mediaSize/cciset->option.mediaUnit),LE); - memcpy((u8*)ctx.cciHdr.titleId,cciset->header.mediaId,8); - memcpy((u8*)ctx.cciHdr.flags,cciset->header.flags,8); - - // Content - for(int i = 0; i < 8; i++){ - u32_to_u8((u8*)ctx.cciHdr.offset_sizeTable[i].offset,(cciset->content.offset[i]/cciset->option.mediaUnit),LE); - u32_to_u8((u8*)ctx.cciHdr.offset_sizeTable[i].size,(cciset->content.size[i]/cciset->option.mediaUnit),LE); - memcpy((u8*)ctx.cciHdr.contentIdTable[i],cciset->content.titleId[i],8); - ctx.cciHdr.contentFsType[i] = cciset->content.fsType[i]; - ctx.cciHdr.contentCryptoType[i] = cciset->content.cryptoType[i]; + for(int i = 0; i < CCI_MAX_CONTENT; i++){ + if(i == 0){ + set->content.active[i] = true; + set->content.dSize[i] = set->content.dataLen; + set->content.dOffset[i] = 0; + } + else if(set->content.dSize[i] && set->content.path[i]){ + set->content.active[i] = true; + set->content.dOffset[i] = set->content.dataLen; + set->content.dataLen += set->content.dSize[i]; + } + else + set->content.active[i] = false; } - - // Signature - if(SignCCI(ctx.signature,(u8*)&ctx.cciHdr,cciset->keys) != Good){ - fprintf(stderr,"[CCI ERROR] Failed to sign CCI\n"); - return CCI_SIG_FAIL; - } - return 0; -} -int BuildCardInfoHeader(cci_settings *cciset, user_settings *usrset) -{ - u32_to_u8((u8*)ctx.cardinfo.writableAddress,(cciset->cardinfo.writableAddress/cciset->option.mediaUnit),LE); - u32_to_u8((u8*)ctx.cardinfo.cardInfoBitmask,cciset->cardinfo.cardInfoBitmask,BE); - u32_to_u8((u8*)ctx.cardinfo.mediaSizeUsed,cciset->cardinfo.cciTotalSize,LE); - memcpy(ctx.cardinfo.cverTitleId,cciset->cardinfo.cverTitleId,8); - memcpy(ctx.cardinfo.cverTitleVersion,cciset->cardinfo.cverTitleVersion,2); - memcpy((u8*)ctx.cardinfo.ncch0TitleId,cciset->content.titleId[0],8); - memcpy((u8*)ctx.cardinfo.initialData,cciset->cardinfo.initialData,0x30); - memcpy((u8*)ctx.cardinfo.ncch0Hdr,&cciset->cardinfo.ncchHdr,0x100); - memcpy((u8*)ctx.devcardinfo.titleKey,cciset->cardinfo.titleKey,0x10); - - return 0; -} - -int ImportNcchPartitions(cci_settings *cciset) -{ - cciset->content.data->buffer = realloc(cciset->content.data->buffer,cciset->content.data->size); - if(!cciset->content.data->buffer){ + set->content.data = realloc(set->content.data,set->content.dataLen); + if(!set->content.data){ fprintf(stderr,"[CCI ERROR] Not enough memory\n"); return MEM_ERROR; } - ncch_hdr *ncch0hdr = (ncch_hdr*)(cciset->content.data->buffer+0x100); + FILE *ncch; for(int i = 1; i < CCI_MAX_CONTENT; i++){ - if(!cciset->content.size[i]) + if(!set->content.active[i]) continue; - u8 *ncchpos = (u8*)(cciset->content.data->buffer+cciset->content.offset[i]-cciset->content.offset[0]); + u8 *ncchpos = (u8*)(set->content.data+set->content.dOffset[i]); - ReadFile_64(ncchpos, cciset->content.fileSize[i], 0, cciset->content.filePtrs[i]); - if(ModifyNcchIds(ncchpos, cciset->content.titleId[i], ncch0hdr->programId, cciset->keys) != 0) - return -1; - } - return 0; -} - -void WriteCCIDummyData(cci_settings *cciset) -{ - // Creating Buffer of Dummy Bytes - u64 len = NCCH0_OFFSET - 0x1200; - u8 *dummy_bytes = malloc(len); - memset(dummy_bytes,0xff,len); - WriteBuffer(dummy_bytes,len,0x1200,cciset->out); -} - -void WriteDevCardInfoData(cci_settings *cciset) -{ - WriteBuffer((u8*)&ctx.devcardinfo,sizeof(devcardinfo_hdr),0x1200,cciset->out); -} - -int WriteHeaderToFile(cci_settings *cciset) -{ - WriteBuffer(ctx.signature,0x100,0,cciset->out); - WriteBuffer((u8*)&ctx.cciHdr,sizeof(cci_hdr),0x100,cciset->out); - WriteBuffer((u8*)&ctx.cardinfo,sizeof(cardinfo_hdr),0x200,cciset->out); - if(cciset->option.useDevCardInfo) - WriteDevCardInfoData(cciset); - else - WriteCCIDummyData(cciset); + ncch = fopen(set->content.path[i],"rb"); - return 0; -} - -int WriteContentToFile(cci_settings *cciset,user_settings *usrset) -{ - // Write Content 0 - WriteBuffer(cciset->content.data->buffer,cciset->content.data->size,NCCH0_OFFSET,cciset->out); - free(cciset->content.data->buffer); - cciset->content.data->buffer = NULL; - cciset->content.data->size = 0; - return 0; -} - -int WriteDummyBytes(cci_settings *cciset) -{ - // Seeking end of CCI Data - fseek_64(cciset->out,cciset->cardinfo.cciTotalSize); - - // Determining Size of Dummy Bytes - u64 len = cciset->header.mediaSize - cciset->cardinfo.cciTotalSize; - - // Creating Buffer of Dummy Bytes - u8 *dummy_bytes = malloc(cciset->option.mediaUnit); - memset(dummy_bytes,0xff,cciset->option.mediaUnit); - - // Writing Dummy Bytes to file - for(u64 i = 0; i < len; i += cciset->option.mediaUnit) - fwrite(dummy_bytes,cciset->option.mediaUnit,1,cciset->out); - - return 0; -} - -int GetContentFP(cci_settings *cciset, user_settings *usrset) -{ - cciset->content.filePtrs = calloc(8,sizeof(FILE*)); - if(!cciset->content.filePtrs){ - fprintf(stderr,"[CCI ERROR] Not enough memory\n"); - return MEM_ERROR; + ReadFile64(ncchpos, set->content.dSize[i], 0, ncch); + + fclose(ncch); } - for(int i = 1; i < 8; i++){ - if(usrset->common.contentPath[i]){ - if(!AssertFile(usrset->common.contentPath[i])){ // Checking if file could be opened - fprintf(stderr,"[CCI ERROR] Failed to open '%s'\n",usrset->common.contentPath[i]); - return FAILED_TO_OPEN_FILE; - } + return 0; +} - cciset->content.fileSize[i] = GetFileSize_u64(usrset->common.contentPath[i]); - cciset->content.filePtrs[i] = fopen(usrset->common.contentPath[i],"rb"); - /* - if(!cciset->content.filePtrs[i]){ // Checking if file could be opened - fprintf(stderr,"[CCI ERROR] Failed to open '%s'\n",usrset->common.contentPath[i]); - return FAILED_TO_OPEN_FILE; - } - */ - if(!IsNCCH(cciset->content.filePtrs[i],NULL)){ // Checking if NCCH - fprintf(stderr,"[CCI ERROR] Content '%s' is invalid\n",usrset->common.contentPath[i]); - return NCSD_INVALID_NCCH; - } - - // Getting NCCH Header - ncch_hdr *hdr = malloc(sizeof(ncch_hdr)); - GetNCCH_CommonHDR(hdr,cciset->content.filePtrs[i],NULL); - - if(usrset->cci.dontModifyNcchTitleID) - memcpy(&cciset->content.titleId[i], hdr->titleId, 8); - else{ - memcpy(&cciset->content.titleId[i], cciset->header.mediaId, 8); // Set TitleID - u16_to_u8(&cciset->content.titleId[i][6], (i+4), LE); - } +bool CanCiaBeCci(u16 cat, u16 count, tmd_content_chunk *content) +{ + if(cat != PROGRAM_ID_CATEGORY_APPLICATION && cat != PROGRAM_ID_CATEGORY_SYSTEM_APPLICATION) + return false; + + if(count > CCI_MAX_CONTENT) + return false; + + for(int i = 0; i < count; i++){ + if(GetTmdContentIndex(content[i]) >= CCI_MAX_CONTENT) + return false; + } + + return true; +} - u64 contentSize = (u64)GetNCCH_MediaSize(hdr)* (u64)GetNCCH_MediaUnitSize(hdr); - if(contentSize != cciset->content.fileSize[i]){ - fprintf(stderr,"[CCI ERROR] Content '%s' is corrupt\n",usrset->common.contentPath[i]); - return NCSD_INVALID_NCCH; - } - - cciset->content.size[i] = align(contentSize,cciset->option.mediaUnit); - cciset->content.offset[i] = cciset->cardinfo.cciTotalSize; - - cciset->content.data->size += cciset->content.size[i]; - cciset->cardinfo.cciTotalSize += cciset->content.size[i]; - - free(hdr); +void GenRsfInputFromTmd(tmd_hdr *tmd, tmd_content_chunk *info, cci_settings *set) +{ + if(!set->rsf->CardInfo.MediaSize){ + set->rsf->CardInfo.MediaSize = calloc(20,sizeof(char)); + u64 contentSize = NCCH0_OFFSET; + u16 contentNum = GetTmdContentCount(tmd); + for(int i = 0; i < contentNum; i++) + contentSize += GetTmdContentSize(info[i]); + + if(contentSize < (u64)128*MB) + strcpy(set->rsf->CardInfo.MediaSize,"128MB"); + else if(contentSize < (u64)256*MB) + strcpy(set->rsf->CardInfo.MediaSize,"256MB"); + else if(contentSize < (u64)512*MB) + strcpy(set->rsf->CardInfo.MediaSize,"512MB"); + else if(contentSize < (u64)1*GB) + strcpy(set->rsf->CardInfo.MediaSize,"1GB"); + else if(contentSize < (u64)2*GB) + strcpy(set->rsf->CardInfo.MediaSize,"2GB"); + else if(contentSize < (u64)4*GB) + strcpy(set->rsf->CardInfo.MediaSize,"4GB"); + else if(contentSize < (u64)8*GB) + strcpy(set->rsf->CardInfo.MediaSize,"8GB"); + else{ + free(set->rsf->CardInfo.MediaSize); + set->rsf->CardInfo.MediaSize = NULL; } + + if(set->options.verbose && set->rsf->CardInfo.MediaSize) + printf("[CCI] Auto generating RSF setting \"CardInfo/MediaSize: %s\" \n",set->rsf->CardInfo.MediaSize); } - return 0; + + if(!set->rsf->CardInfo.MediaType){ + set->rsf->CardInfo.MediaType = calloc(20,sizeof(char)); + if(set->romInfo.saveSize < (u64)1*MB) + strcpy(set->rsf->CardInfo.MediaType,"Card1"); + else + strcpy(set->rsf->CardInfo.MediaType,"Card2"); + + if(set->options.verbose) + printf("[CCI] Auto generating RSF setting \"CardInfo/MediaType: %s\" \n",set->rsf->CardInfo.MediaType); + } + + if(!set->rsf->CardInfo.CardDevice){ + set->rsf->CardInfo.CardDevice = calloc(20,sizeof(char)); + if(set->romInfo.saveSize < (u64)1*MB && set->romInfo.saveSize > 0) + strcpy(set->rsf->CardInfo.CardDevice,"NorFlash"); + else + strcpy(set->rsf->CardInfo.CardDevice,"None"); + + if(set->options.verbose) + printf("[CCI] Auto generating RSF setting \"CardInfo/CardDevice: %s\" \n",set->rsf->CardInfo.CardDevice); + } + + return; } -int CheckContent0(cci_settings *cciset, user_settings *usrset) +int ProcessCiaForCci(cci_settings *set) { - if(!usrset->common.workingFile.buffer || !usrset->common.workingFile.size) - return NCSD_NO_NCCH0; - cciset->content.data = &usrset->common.workingFile; - - if(!IsNCCH(NULL,cciset->content.data->buffer)) - return NCSD_INVALID_NCCH0; - - return 0; -} - -int GetDataFromContent0(cci_settings *cciset, user_settings *usrset) -{ - cciset->cardinfo.cciTotalSize = NCCH0_OFFSET; - ncch_hdr *hdr; - - hdr = GetNCCH_CommonHDR(NULL,NULL,cciset->content.data->buffer); - - memcpy(&cciset->cardinfo.ncchHdr,hdr,sizeof(ncch_hdr)); - - u16 ncch_format_ver = u8_to_u16(hdr->formatVersion,LE); - if(ncch_format_ver > 2){ - fprintf(stderr,"[CCI ERROR] NCCH type %d not supported\n",ncch_format_ver); + if(!IsCia(set->content.data)){ + fprintf(stderr,"[CCI ERROR] CIA is corrupt\n"); return FAILED_TO_IMPORT_FILE; } - - //memdump(stdout,"ncch0 head: ",(cciset->ncch0+0x100),0x100); - //memdump(stdout,"ncch0 head: ",(u8*)(hdr),0x100); + + tik_hdr *tik = GetTikHdr(GetCiaTik(set->content.data)); + tmd_hdr *tmd = GetTmdHdr(GetCiaTmd(set->content.data)); + tmd_content_chunk *contentInfo = GetTmdContentInfo(GetCiaTmd(set->content.data)); + u64 contentOffset = GetCiaContentOffset((cia_hdr*)set->content.data); - memcpy(cciset->header.mediaId,hdr->titleId,8); - memcpy(&cciset->content.titleId[0],hdr->titleId,8); - if(usrset->cci.useSDKStockData){ - memcpy(cciset->cardinfo.initialData,stock_initial_data,0x30); - memcpy(cciset->cardinfo.titleKey,stock_title_key,0x10); - cciset->option.useDevCardInfo = true; - } - else{ - rndset(cciset->cardinfo.initialData,0x2c); - //rndset(cciset->cardinfo.titleKey,0x10); - //cciset->option.useDevCardInfo = true; + u16 titleCat = (GetTmdTitleId(tmd) >> 32) & 0xffff; + u16 contentCount = GetTmdContentCount(tmd); + set->romInfo.saveSize = GetTmdSaveSize(tmd); + if(set->romInfo.saveSize > 0 && set->romInfo.saveSize < (u64)(128*KB)) + set->romInfo.saveSize = (u64)(128*KB); + else if(set->romInfo.saveSize > (u64)(128*KB) && set->romInfo.saveSize < (u64)(512*KB)) + set->romInfo.saveSize = (u64)(512*KB); + else if(set->romInfo.saveSize > (u64)(512*KB)) + set->romInfo.saveSize = align(set->romInfo.saveSize,MB); + + if(!CanCiaBeCci(titleCat,contentCount,contentInfo)){ + fprintf(stderr,"[CCI ERROR] This CIA cannot be converted to CCI\n"); + return INCOMPAT_CIA; } - cciset->header.flags[MediaUnitSize] = hdr->flags[ContentUnitSize]; - cciset->option.mediaUnit = GetNCCH_MediaUnitSize(hdr); + GenRsfInputFromTmd(tmd,contentInfo,set); - cciset->content.size[0] = (u64)(GetNCCH_MediaSize(hdr) * cciset->option.mediaUnit); - cciset->content.offset[0] = cciset->cardinfo.cciTotalSize; - - cciset->content.data->size = cciset->content.size[0]; - cciset->cardinfo.cciTotalSize += cciset->content.size[0]; - return 0; -} - -int GetMediaSize(cci_settings *cciset, user_settings *usrset) -{ - char *mediaSizeStr = usrset->common.rsfSet.CardInfo.MediaSize; - if(!mediaSizeStr) cciset->header.mediaSize = (u64)GB*2; - else{ - if(strcasecmp(mediaSizeStr,"128MB") == 0) cciset->header.mediaSize = (u64)MB*128; - else if(strcasecmp(mediaSizeStr,"256MB") == 0) cciset->header.mediaSize = (u64)MB*256; - else if(strcasecmp(mediaSizeStr,"512MB") == 0) cciset->header.mediaSize = (u64)MB*512; - else if(strcasecmp(mediaSizeStr,"1GB") == 0) cciset->header.mediaSize = (u64)GB*1; - else if(strcasecmp(mediaSizeStr,"2GB") == 0) cciset->header.mediaSize = (u64)GB*2; - else if(strcasecmp(mediaSizeStr,"4GB") == 0) cciset->header.mediaSize = (u64)GB*4; - else if(strcasecmp(mediaSizeStr,"8GB") == 0) cciset->header.mediaSize = (u64)GB*8; - else if(strcasecmp(mediaSizeStr,"16GB") == 0) cciset->header.mediaSize = (u64)GB*16; - else if(strcasecmp(mediaSizeStr,"32GB") == 0) cciset->header.mediaSize = (u64)GB*32; - else { - fprintf(stderr,"[CCI ERROR] Invalid MediaSize: %s\n",mediaSizeStr); - return INVALID_YAML_OPT; - } + bool canDecrypt; + u8 titleKey[AES_128_KEY_SIZE]; + canDecrypt = GetTikTitleKey(titleKey,tik,set->keys); + if(set->options.verbose){ + if(canDecrypt) + memdump(stdout,"[CCI] CIA title key: ",titleKey,AES_128_KEY_SIZE); + else + fprintf(stdout,"[CCI] CIA title key could not be decrypted\n"); } - cciset->option.fillOutCci = usrset->common.rsfSet.Option.MediaFootPadding; - - return 0; -} - -u64 GetUnusedSize(u64 MediaSize, u8 CardType) -{ - if(CardType == CARD1){ - switch(MediaSize){ - case (u64)MB*128: return (u64)2621440; - case (u64)MB*256: return (u64)5242880; - case (u64)MB*512: return (u64)10485760; - case (u64)GB*1: return (u64)73924608; - case (u64)GB*2: return (u64)147324928; - case (u64)GB*4: return (u64)294649856; - case (u64)GB*8: return (u64)587202560; - //default: return (u64)((MediaSize/MB)*0x11800); // Aprox - default: return 0; - } - } - else if(CardType == CARD2){ - switch(MediaSize){ - case (u64)MB*512: return (u64)37224448; - case (u64)GB*1: return (u64)73924608; - case (u64)GB*2: return (u64)147324928; - case (u64)GB*4: return (u64)294649856; - case (u64)GB*8: return (u64)587202560; - //default: return (u64)((MediaSize/MB)*0x11800); // Aprox - default: return 0; - } - } - return 0; -} - -int GetNCSDFlags(cci_settings *cciset, rsf_settings *yaml) -{ - /* BackupWriteWaitTime */ - cciset->header.flags[FW6x_BackupWriteWaitTime] = 0; - if(yaml->CardInfo.BackupWriteWaitTime){ - u32 WaitTime = strtoul(yaml->CardInfo.BackupWriteWaitTime,NULL,0); - if(WaitTime > 255){ - fprintf(stderr,"[CCI ERROR] Invalid Card BackupWriteWaitTime (%d) : must 0-255\n",WaitTime); - return EXHDR_BAD_YAML_OPT; - } - cciset->header.flags[FW6x_BackupWriteWaitTime] = (u8)WaitTime; - } - - /* MediaType */ - if(!yaml->CardInfo.MediaType) cciset->header.flags[MediaTypeIndex] = CARD1; - else{ - if(strcasecmp(yaml->CardInfo.MediaType,"Card1") == 0) cciset->header.flags[MediaTypeIndex] = CARD1; - else if(strcasecmp(yaml->CardInfo.MediaType,"Card2") == 0) cciset->header.flags[MediaTypeIndex] = CARD2; - else { - fprintf(stderr,"[CCI ERROR] Invalid MediaType: %s\n",yaml->CardInfo.MediaType); - return INVALID_YAML_OPT; - } - } - - /* Platform */ - cciset->header.flags[MediaPlatformIndex] = CTR; - - u8 saveCrypto; - - if(!yaml->CardInfo.SaveCrypto) saveCrypto = 3; - else{ - if(strcasecmp(yaml->CardInfo.SaveCrypto,"fw1") == 0 || strcasecmp(yaml->CardInfo.SaveCrypto,"ctr fail") == 0 ) saveCrypto = 1; - else if(strcasecmp(yaml->CardInfo.SaveCrypto,"fw2") == 0) saveCrypto = 2; - else if(strcasecmp(yaml->CardInfo.SaveCrypto,"fw3") == 0) saveCrypto = 3; - else if(strcasecmp(yaml->CardInfo.SaveCrypto,"fw6") == 0) saveCrypto = 6; - else { - fprintf(stderr,"[CCI ERROR] Invalid SaveCrypto: %s\n",yaml->CardInfo.SaveCrypto); - return INVALID_YAML_OPT; - } - } - - - /* FW6x SaveCrypto */ - cciset->header.flags[FW6x_SaveCryptoFlag] = saveCrypto == 6; - - /* CardDevice */ - if(saveCrypto > 1){ - u8 flag = CardDeviceFlag; - if(saveCrypto == 2) flag = OldCardDeviceFlag; - if(!yaml->CardInfo.CardDevice) cciset->header.flags[flag] = CARD_DEVICE_NONE; - else{ - if(strcmp(yaml->CardInfo.CardDevice,"NorFlash") == 0) { - cciset->header.flags[flag] = CARD_DEVICE_NOR_FLASH; - if(cciset->header.flags[MediaTypeIndex] == CARD2){ - fprintf(stderr,"[CCI WARNING] 'CardDevice: NorFlash' is invalid on Card2\n"); - cciset->header.flags[flag] = CARD_DEVICE_NONE; - } + for(u16 i = 0; i < contentCount; i++){ + u16 index = GetTmdContentIndex(contentInfo[i]); + set->content.active[index] = true; + set->content.dOffset[index] = contentOffset; + set->content.dSize[index] = GetTmdContentSize(contentInfo[i]); + u8 *content = set->content.data + contentOffset; + if(IsTmdContentEncrypted(contentInfo[i])){ + if(canDecrypt){ + CryptContent(content,content,set->content.dSize[index],titleKey,i,DEC); } - else if(strcmp(yaml->CardInfo.CardDevice,"None") == 0) cciset->header.flags[flag] = CARD_DEVICE_NONE; - else if(strcmp(yaml->CardInfo.CardDevice,"BT") == 0) cciset->header.flags[flag] = CARD_DEVICE_BT; - else { - fprintf(stderr,"[CCI ERROR] Invalid CardDevice: %s\n",yaml->CardInfo.CardDevice); - return INVALID_YAML_OPT; - } - } - } - return 0; -} - -int GetWriteableAddress(cci_settings *cciset, user_settings *usrset) -{ - int result = GetSaveDataSizeFromString(&cciset->option.savedataSize,usrset->common.rsfSet.SystemControlInfo.SaveDataSize,"CCI"); - if(result) return result; - - char *WriteableAddressStr = usrset->common.rsfSet.CardInfo.WritableAddress; - - cciset->cardinfo.writableAddress = -1; - if(cciset->header.flags[MediaTypeIndex] != CARD2) return 0; // Can only be set for Card2 Media - - if(WriteableAddressStr){ - if(strncmp(WriteableAddressStr,"0x",2) != 0){ - fprintf(stderr,"[CCI ERROR] WritableAddress requires a Hexadecimal value\n"); - return INVALID_YAML_OPT; - } - cciset->cardinfo.writableAddress = strtoull(WriteableAddressStr,NULL,16); - } - if(cciset->cardinfo.writableAddress == -1){ // If not set manually or is max size - if ((cciset->header.mediaSize / 2) < cciset->option.savedataSize){ // If SaveData size is greater than half the MediaSize - u64 SavedataSize = cciset->option.savedataSize / KB; - fprintf(stderr,"[CCI ERROR] Too large SavedataSize %lldK\n",SavedataSize); - return SAVE_DATA_TOO_LARGE; - } - if (cciset->option.savedataSize > (u64)(2047*MB)){ // Limit set by Nintendo - u64 SavedataSize = cciset->option.savedataSize / KB; - fprintf(stderr,"[CCI ERROR] Too large SavedataSize %lldK\n",SavedataSize); - return SAVE_DATA_TOO_LARGE; - } - if(usrset->cci.closeAlignWritableRegion) - cciset->cardinfo.writableAddress = align(cciset->cardinfo.cciTotalSize, cciset->option.mediaUnit); // invalid for "real" chips - else{ - u64 UnusedSize = GetUnusedSize(cciset->header.mediaSize,cciset->header.flags[MediaTypeIndex]); // Some value related to the physical implementation of gamecards - if(UnusedSize > 0) - cciset->cardinfo.writableAddress = cciset->header.mediaSize - UnusedSize - cciset->option.savedataSize; // Nintendo's method for calculating writable region offset else{ - fprintf(stderr,"[CCI WARNING] Nintendo has no CARD2 writable region configurations for this media size, writable region will be aligned to last ncch partition\n"); - cciset->cardinfo.writableAddress = align(cciset->cardinfo.cciTotalSize, cciset->option.mediaUnit); // invalid for "real" chips + fprintf(stderr,"[CCI ERROR] Failed to decrypt CIA content: 0x%08x\n",GetTmdContentId(contentInfo[i])); + return INCOMPAT_CIA; } } - } - return 0; -} - -int GetCardInfoBitmask(cci_settings *cciset, user_settings *usrset) -{ - char *str = usrset->common.rsfSet.CardInfo.CardType; - if(!str) cciset->cardinfo.cardInfoBitmask |= 0; - else{ - if(strcasecmp(str,"s1") == 0) cciset->cardinfo.cardInfoBitmask |= 0; - else if(strcasecmp(str,"s2") == 0) cciset->cardinfo.cardInfoBitmask |= 0x20; - else { - fprintf(stderr,"[CCI ERROR] Invalid CardType: %s\n",str); - return INVALID_YAML_OPT; + if(!ValidateTmdContent(content,contentInfo[i])){ + fprintf(stderr,"[CCI ERROR] CIA content: 0x%08x is corrupt\n",GetTmdContentId(contentInfo[i])); + return NCSD_INVALID_NCCH; } - } - - str = usrset->common.rsfSet.CardInfo.CryptoType; - if(!str) cciset->cardinfo.cardInfoBitmask |= 0;//(3*0x40); - else{ - int Value = strtol(str,NULL,10); - if(Value < 0 || Value > 3) { - fprintf(stderr,"[CCI ERROR] Invalid CryptoType: %s\n",str); - return INVALID_YAML_OPT; - } - if(Value != 3){ - fprintf(stderr,"[CCI WARNING] Card crypto type = '%d'\n",Value); - } - cciset->cardinfo.cardInfoBitmask |= (Value*0x40); + + contentOffset += set->content.dSize[index]; } return 0; } -int ImportCverDetails(cci_settings *cciset, user_settings *usrset) +int ImportCciNcch(cci_settings *set) { - if(!usrset->cci.cverCiaPath){ - memset(cciset->cardinfo.cverTitleId,0,8); - memset(cciset->cardinfo.cverTitleVersion,0,2); - return 0; + if(set->content.dataType == infile_ncch) + return ImportNcchForCci(set); + else if(set->content.dataType == infile_cia) + return ProcessCiaForCci(set); + else + fprintf(stderr,"[CCI ERROR] Unrecognised input data type\n"); + + if(set->rsf->SystemControlInfo.SaveDataSize) + GetSaveDataSizeFromString(&set->romInfo.saveSize,set->rsf->SystemControlInfo.SaveDataSize,"CCI"); + + return FAILED_TO_IMPORT_FILE; +} + +int ProcessCverDataForCci(cci_settings *set) +{ + u64 tmdSize,tmdOffset; + + u64 dataSize = GetFileSize64(set->options.cverDataPath); + FILE *data = fopen(set->options.cverDataPath,"rb"); + + + if(set->options.cverDataType == CVER_DTYPE_CIA){ + cia_hdr *ciaHdr = calloc(1,sizeof(cia_hdr)); + ReadFile64(ciaHdr,sizeof(cia_hdr),0,data); + + tmdSize = GetCiaTmdSize(ciaHdr); + tmdOffset = GetCiaTmdOffset(ciaHdr); + + free(ciaHdr); } - if(!cciset->content.size[7]){ - fprintf(stderr,"[CCI WARNING] Update Partition (content 7) is not specified, cver details will not be set\n"); - memset(cciset->cardinfo.cverTitleId,0,8); - memset(cciset->cardinfo.cverTitleVersion,0,2); - return 0; + else{ + tmdSize = dataSize; + tmdOffset = 0; } - if(!AssertFile(usrset->cci.cverCiaPath)){ - fprintf(stderr,"[CCI ERROR] Failed to open \"%s\"\n",usrset->cci.cverCiaPath); - return FAILED_TO_IMPORT_FILE; - } - FILE *cia = fopen(usrset->cci.cverCiaPath,"rb"); - cia_hdr *ciaHdr = calloc(1,sizeof(cia_hdr)); - ReadFile_64(ciaHdr,sizeof(cia_hdr),0,cia); - - u64 tmdSize = GetTmdSize(ciaHdr); - u64 tmdOffset = GetTmdOffset(ciaHdr); u8 *tmd = calloc(1,tmdSize); - ReadFile_64(tmd,tmdSize,tmdOffset,cia); - tmd_hdr *tmdHdr = GetTmdHdr(tmd); - //memdump(stdout,"tmd: ",(u8*)tmdHdr,sizeof(tmd_hdr)); - - - endian_memcpy(cciset->cardinfo.cverTitleId,tmdHdr->titleID,8,LE); - endian_memcpy(cciset->cardinfo.cverTitleVersion,tmdHdr->titleVersion,2,LE); - - if(!usrset->cci.dontModifyNcchTitleID) - endian_memcpy(&cciset->content.titleId[7][6],tmdHdr->titleVersion,2,LE); - fclose(cia); - free(ciaHdr); + ReadFile64(tmd,tmdSize,tmdOffset,data); + fclose(data); + + tmd_hdr *tmdHdr = GetTmdHdr(tmd); + if(!tmdHdr){ + fprintf(stderr,"[CCI ERROR] Corrupt cver TMD\n"); + free(tmd); + return FAILED_TO_IMPORT_FILE; + } + + set->options.tmdHdr = calloc(1,sizeof(tmd_hdr)); + memcpy(set->options.tmdHdr,tmdHdr,sizeof(tmd_hdr)); + free(tmd); return 0; } -int CheckMediaSize(cci_settings *cciset) +void GetNewNcchIdForCci(u8 *newTid, u8 *srcTid, u8 index, tmd_hdr *tmdHdr) { - if(cciset->cardinfo.cciTotalSize > cciset->header.mediaSize){ - char *MediaSizeStr = NULL; - switch(cciset->header.mediaSize){ - case (u64)128*MB: MediaSizeStr = " '128MB'"; break; - case (u64)256*MB: MediaSizeStr = " '256MB'"; break; - case (u64)512*MB: MediaSizeStr = " '512MB'"; break; - case (u64)1*GB: MediaSizeStr = " '1GB'"; break; - case (u64)2*GB: MediaSizeStr = " '2GB'"; break; - case (u64)4*GB: MediaSizeStr = " '4GB'"; break; - case (u64)8*GB: MediaSizeStr = " '8GB'"; break; - case (u64)16*GB: MediaSizeStr = " '16GB'"; break; - case (u64)32*GB: MediaSizeStr = " '32GB'"; break; - default: MediaSizeStr = ""; break; + u64 titleId = u8_to_u64(srcTid,LE) & 0xffffffffffff; + if(tmdHdr && index == 7) + titleId |= (u64)(GetTmdVersion(tmdHdr)) << 48; + else + titleId |= (u64)(index+4) << 48; + + u64_to_u8(newTid,titleId,LE); +} + +int ProcessNcchForCci(cci_settings *set) +{ + u8 *ncch; + ncch_hdr *hdr; + + u8 titleId[8]; + u8 srcId[8]; + + if(set->options.cverDataPath && set->content.active[7]){ + if(ProcessCverDataForCci(set)) + return FAILED_TO_IMPORT_FILE; + } + + for(int i = 0; i < CCI_MAX_CONTENT; i++){ + if(set->content.active[i]){ + ncch = set->content.data + set->content.dOffset[i]; + if(!IsNcch(NULL,ncch)){ + fprintf(stderr,"[CCI ERROR] NCCH %d is corrupt\n",i); + return NCSD_INVALID_NCCH; + } + hdr = (ncch_hdr*)ncch; + if(i > 0 && !set->options.noModTid){ + if(set->options.verbose){ + printf("[CCI] Modifying NCCH %d IDs\n",i); + printf("[Old Ids]\n"); + memdump(stdout," > TitleId: 0x",hdr->titleId,8); + memdump(stdout," > ProgramId: 0x",hdr->programId,8); + } + GetNewNcchIdForCci(titleId,srcId,i,set->options.tmdHdr); + if(ModifyNcchIds(ncch, titleId, srcId, set->keys)) + return -1; + if(set->options.verbose){ + printf("[New Ids]\n"); + memdump(stdout," > TitleId: 0x",hdr->titleId,8); + memdump(stdout," > ProgramId: 0x",hdr->programId,8); + } + } + set->content.titleId[i] = u8_to_u64(hdr->titleId,LE); + if(i == 0) + memcpy(srcId,hdr->titleId,8); } - fprintf(stderr,"[CCI ERROR] MediaSize%s is too Small\n",MediaSizeStr); - return INVALID_YAML_OPT; + } + + return 0; +} + +int SetMediaSize(u8 *mediaSize, cci_settings *set) +{ + char *str = set->rsf->CardInfo.MediaSize; + if(!str) + set->romInfo.mediaSize = (u64)GB*2; + else{ + if(strcasecmp(str,"128MB") == 0) set->romInfo.mediaSize = (u64)MB*128; + else if(strcasecmp(str,"256MB") == 0) set->romInfo.mediaSize = (u64)MB*256; + else if(strcasecmp(str,"512MB") == 0) set->romInfo.mediaSize = (u64)MB*512; + else if(strcasecmp(str,"1GB") == 0) set->romInfo.mediaSize = (u64)GB*1; + else if(strcasecmp(str,"2GB") == 0) set->romInfo.mediaSize = (u64)GB*2; + else if(strcasecmp(str,"4GB") == 0) set->romInfo.mediaSize = (u64)GB*4; + else if(strcasecmp(str,"8GB") == 0) set->romInfo.mediaSize = (u64)GB*8; + //else if(strcasecmp(str,"16GB") == 0) set->romInfo.mediaSize = (u64)GB*16; + //else if(strcasecmp(str,"32GB") == 0) set->romInfo.mediaSize = (u64)GB*32; + else { + fprintf(stderr,"[CCI ERROR] Invalid MediaSize: %s\n",str); + return INVALID_RSF_OPT; + } + } + + u32_to_u8(mediaSize,(set->romInfo.mediaSize/set->romInfo.blockSize),LE); + + return 0; +} + +int SetBackupWriteWaitTime(u8 *flag, rsf_settings *rsf) +{ + char *str = rsf->CardInfo.BackupWriteWaitTime; + if(!str) + *flag = 0; + else{ + u32 waitTime = strtoul(str,NULL,0); + if(waitTime > 255){ + fprintf(stderr,"[CCI ERROR] Invalid Card BackupWriteWaitTime (%d) : must 0-255\n",waitTime); + return INVALID_RSF_OPT; + } + *flag = (u8)waitTime; + } + + return 0; +} + +int SetMediaType(u8 *flag, cci_settings *set) +{ + char *str = set->rsf->CardInfo.MediaType; + + if(!str) + *flag = mediatype_CARD1; + else{ + if(strcasecmp(str,"Card1") == 0) + *flag = mediatype_CARD1; + else if(strcasecmp(str,"Card2") == 0) + *flag = mediatype_CARD2; + else { + fprintf(stderr,"[CCI ERROR] Invalid MediaType: %s\n",str); + return INVALID_RSF_OPT; + } + } + + return 0; +} + +int SetCardDevice(u8 *flags, u64 saveSize, rsf_settings *rsf) +{ + u8 saveCrypto; + + if(!rsf->CardInfo.SaveCrypto) + saveCrypto = 3; + else{ + if(strcasecmp(rsf->CardInfo.SaveCrypto,"fw1") == 0 || strcasecmp(rsf->CardInfo.SaveCrypto,"ctr fail") == 0 ) saveCrypto = 1; + else if(strcasecmp(rsf->CardInfo.SaveCrypto,"fw2") == 0) saveCrypto = 2; + else if(strcasecmp(rsf->CardInfo.SaveCrypto,"fw3") == 0) saveCrypto = 3; + else if(strcasecmp(rsf->CardInfo.SaveCrypto,"fw6") == 0) saveCrypto = 6; + else { + fprintf(stderr,"[CCI ERROR] Invalid SaveCrypto: %s\n",rsf->CardInfo.SaveCrypto); + return INVALID_RSF_OPT; + } + } + + + /* FW6x SaveCrypto */ + if(saveCrypto == 6) + flags[cciflag_FW6_SAVE_CRYPTO] = 1; + else + flags[cciflag_FW6_SAVE_CRYPTO] = 0; + + /* CardDevice */ + u8 cardDevice = 0; + if(!rsf->CardInfo.CardDevice) + cardDevice = carddevice_NONE; + else{ + if(strcmp(rsf->CardInfo.CardDevice,"NorFlash") == 0) + cardDevice = carddevice_NOR_FLASH; + else if(strcmp(rsf->CardInfo.CardDevice,"None") == 0) + cardDevice = carddevice_NONE; + else if(strcmp(rsf->CardInfo.CardDevice,"BT") == 0) + cardDevice = carddevice_BT; + else { + fprintf(stderr,"[CCI ERROR] Invalid CardDevice: %s\n",rsf->CardInfo.CardDevice); + return INVALID_RSF_OPT; + } + } + + if(flags[cciflag_MEDIA_TYPE] == mediatype_CARD1){ + if(saveSize != (u64)(128*KB) && saveSize != (u64)(512*KB) && cardDevice == carddevice_NOR_FLASH){ + fprintf(stderr,"[CCI ERROR] 'CardDevice: NorFlash' can only be used with save-data sizes: 128K & 512K\n"); + return INVALID_RSF_OPT; + } + } + if(flags[cciflag_MEDIA_TYPE] == mediatype_CARD2){ + if(cardDevice == carddevice_NOR_FLASH){ + fprintf(stderr,"[CCI WARNING] 'CardDevice: NorFlash' is invalid for Card2\n"); + cardDevice = carddevice_NONE; + } + } + + if(saveCrypto > 1) + flags[saveCrypto == 2? cciflag_CARD_DEVICE_OLD : cciflag_CARD_DEVICE] = cardDevice; + + return 0; +} + +int SetCciFlags(u8 *flags, cci_settings *set) +{ + // Backup Write Wait Time + if(SetBackupWriteWaitTime(&flags[cciflag_BACKUP_WRITE_WAIT_TIME], set->rsf)) + return INVALID_RSF_OPT; + // Platform + flags[cciflag_MEDIA_PLATFORM] = cciplatform_CTR; + // Card Type + if(SetMediaType(&flags[cciflag_MEDIA_TYPE], set)) + return INVALID_RSF_OPT; + // Media Unit + flags[cciflag_MEDIA_BLOCK_SIZE] = GetCtrBlockSizeFlag(set->romInfo.blockSize); + // Card Device + if(SetCardDevice(flags, set->romInfo.saveSize, set->rsf)) + return INVALID_RSF_OPT; + + set->romInfo.mediaType = flags[cciflag_MEDIA_TYPE]; + set->romInfo.cardDevice = flags[cciflag_CARD_DEVICE] | flags[cciflag_CARD_DEVICE_OLD]; + + return 0; +} + +void SetCciNcchInfo(cci_hdr *hdr, cci_settings *set) +{ + u64 ncchSize,ncchOffset; + + ncchOffset = NCCH0_OFFSET; + + for(int i = 0; i < CCI_MAX_CONTENT; i++){ + if(set->content.active[i]){ + set->content.cOffset[i] = ncchOffset; + ncchSize = align(set->content.dSize[i],set->romInfo.blockSize); + + u32_to_u8(hdr->offset_sizeTable[i].offset,(ncchOffset/set->romInfo.blockSize),LE); + u32_to_u8(hdr->offset_sizeTable[i].size,(ncchSize/set->romInfo.blockSize),LE); + u64_to_u8(hdr->ncchIdTable[i],set->content.titleId[i],LE); + + ncchOffset += ncchSize; + } + } + + set->romInfo.usedSize = ncchOffset; + + return; +} + + +int GenCciHdr(cci_settings *set) +{ + set->headers.ccihdr.size = sizeof(cci_hdr); + set->headers.ccihdr.buffer = calloc(1,set->headers.ccihdr.size); + if(!set->headers.ccihdr.buffer){ + set->headers.ccihdr.size = 0; + fprintf(stderr,"[CCI ERROR] Not enough memory\n"); + return MEM_ERROR; + } + + cci_hdr *hdr = (cci_hdr*)set->headers.ccihdr.buffer; + + // Magic & TitleId + memcpy(hdr->magic,"NCSD",4); + u64_to_u8(hdr->titleId,set->content.titleId[0],LE); + + + if(SetMediaSize(hdr->mediaSize,set)) + return GEN_HDR_FAIL; + if(SetCciFlags(hdr->flags,set)) + return GEN_HDR_FAIL; + SetCciNcchInfo(hdr,set); + + // Sign Header + ctr_sig(&hdr->magic,sizeof(cci_hdr)-RSA_2048_KEY_SIZE,hdr->signature,set->keys->rsa.cciCfaPub,set->keys->rsa.cciCfaPvt,RSA_2048_SHA256,CTR_RSA_SIGN); + + return 0; +} + +int CheckRomConfig(cci_settings *set) +{ + u64 cciUsedSize; + if(set->romInfo.mediaType == mediatype_CARD2) + cciUsedSize = set->romInfo.card2SaveOffset + set->romInfo.saveSize; + else + cciUsedSize = set->romInfo.usedSize; + + if(cciUsedSize > set->romInfo.mediaSize){ + char *str = set->rsf->CardInfo.MediaSize; + if(!str) + str = "2GB"; + + fprintf(stderr,"[CCI ERROR] MediaSize '%s' is insufficient for the CCI data\n",str); + return CCI_CONFIG_FAIL; } 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; +} + bool IsCci(u8 *ncsd) { - cci_hdr *hdr = (cci_hdr*)(ncsd+0x100); + cci_hdr *hdr = (cci_hdr*)ncsd; if(!hdr) return false; if(memcmp(hdr->magic,"NCSD",4)!=0) return false; - if(hdr->flags[MediaPlatformIndex] != CTR) return false; - if(hdr->flags[MediaTypeIndex] != CARD1 && hdr->flags[MediaTypeIndex] != CARD2) return false; + if(hdr->flags[cciflag_MEDIA_PLATFORM] != cciplatform_CTR) return false; + if(hdr->flags[cciflag_MEDIA_TYPE] != mediatype_CARD1 && hdr->flags[cciflag_MEDIA_TYPE] != mediatype_CARD2) return false; return true; } -u8* GetPartition(u8 *ncsd, u8 index) -{ - return (u8*)(ncsd+GetPartitionOffset(ncsd,index)); -} - - u64 GetPartitionOffset(u8 *ncsd, u8 index) { - cci_hdr *hdr = (cci_hdr*)(ncsd+0x100); - u32 media_size = 0x200*pow(2,hdr->flags[MediaUnitSize]); + cci_hdr *hdr = (cci_hdr*)ncsd; + u32 media_size = 1 << (hdr->flags[cciflag_MEDIA_BLOCK_SIZE] + 9); u32 offset = u8_to_u64(hdr->offset_sizeTable[index].offset,LE); - return offset*media_size; + return (u64)offset*(u64)media_size; } u64 GetPartitionSize(u8 *ncsd, u8 index) { - cci_hdr *hdr = (cci_hdr*)(ncsd+0x100); - u32 media_size = 0x200*pow(2,hdr->flags[MediaUnitSize]); + cci_hdr *hdr = (cci_hdr*)ncsd; + u32 media_size = 1 << (hdr->flags[cciflag_MEDIA_BLOCK_SIZE] + 9); u32 size = u8_to_u64(hdr->offset_sizeTable[index].size,LE); - return size*media_size; + return (u64)size*(u64)media_size; } + +u8* GetPartition(u8 *ncsd, u8 index) +{ + return ncsd + GetPartitionOffset(ncsd,index); +} \ No newline at end of file diff --git a/makerom/ncsd.h b/makerom/ncsd.h index d86a1bb..3b20f65 100644 --- a/makerom/ncsd.h +++ b/makerom/ncsd.h @@ -1,199 +1,54 @@ #pragma once -// Enums typedef enum { - NCSD_NO_NCCH0 = -1, - NCSD_INVALID_NCCH0 = -2, - NCSD_INVALID_NCCH = -3, - INVALID_YAML_OPT = -4, - CCI_SIG_FAIL = -5, - -} ncsd_errors; + cciflag_BACKUP_WRITE_WAIT_TIME = 0, + cciflag_FW6_SAVE_CRYPTO = 1, + cciflag_CARD_DEVICE = 3, + cciflag_MEDIA_PLATFORM = 4, + cciflag_MEDIA_TYPE = 5, + cciflag_MEDIA_BLOCK_SIZE = 6, + cciflag_CARD_DEVICE_OLD = 7 +} cci_flagindex; typedef enum { - FW6x_BackupWriteWaitTime = 0, - FW6x_SaveCryptoFlag = 1, - CardDeviceFlag = 3, - MediaPlatformIndex = 4, - MediaTypeIndex = 5, - MediaUnitSize = 6, - OldCardDeviceFlag = 7 -} FlagIndex; + carddevice_NOR_FLASH = 1, + carddevice_NONE = 2, + carddevice_BT = 3 +} cci_carddevice; typedef enum { - CARD_DEVICE_NOR_FLASH = 1, - CARD_DEVICE_NONE = 2, - CARD_DEVICE_BT = 3 -} _CardDevice; + cciplatform_CTR = 1, +} cci_platform; typedef enum { - CTR = 1, -} _PlatformIndex; - -typedef enum -{ - INNER_DEVICE, - CARD1, - CARD2, - EXTENDED_DEVICE -} _TypeIndex; + mediatype_INNER_DEVICE, // NAND + mediatype_CARD1, + mediatype_CARD2, + mediatype_EXTENDED_DEVICE +} cci_mediatype; // Structs typedef struct { u8 offset[4]; u8 size[4]; -} partition_offsetsize; - -typedef struct -{ - u8 magic[4]; - u8 mediaSize[4]; - u8 titleId[8]; - u8 partitionsFsType[8]; - u8 partitionsCryptoType[8]; - partition_offsetsize offset_sizeTable[8]; - u8 exhdrHash[0x20]; - u8 additionalHdrSize[0x4]; - u8 sectorZeroOffset[0x4]; - u8 partitionFlags[8]; - u8 partitionIdTable[8][8]; - u8 padding[0x30]; -} ncsd_hdr; - -typedef struct -{ - u8 magic[4]; - u8 mediaSize[4]; - u8 titleId[8]; - u8 contentFsType[8]; - u8 contentCryptoType[8]; - partition_offsetsize offset_sizeTable[8]; - u8 padding0[0x28]; - u8 flags[8]; - u8 contentIdTable[8][8]; - u8 padding1[0x30]; -} cci_hdr; - -typedef struct -{ - u8 writableAddress[4]; - u8 cardInfoBitmask[4]; - // Notes: reserved[0xDF8]; - u8 reserved0[0xf8]; - u8 mediaSizeUsed[8]; - u8 reserved1[0x8]; - u8 unknown[0x4]; - u8 reserved2[0xc]; - u8 cverTitleId[8]; - u8 cverTitleVersion[2]; - u8 reserved3[0xcd6]; - // - u8 ncch0TitleId[8]; - u8 reserved4[8]; - u8 initialData[0x30]; - u8 reserved5[0xc0]; - u8 ncch0Hdr[0x100]; -} cardinfo_hdr; - -typedef struct -{ - u8 cardDeviceReserved1[0x200]; - u8 titleKey[0x10]; - u8 cardDeviceReserved2[0xf0]; -} devcardinfo_hdr; +} ncch_offsetsize; typedef struct { u8 signature[0x100]; - cci_hdr cciHdr; - cardinfo_hdr cardinfo; - devcardinfo_hdr devcardinfo; -} InternalCCI_Context; + u8 magic[4]; + u8 mediaSize[4]; + u8 titleId[8]; + u8 padding0[0x10]; + ncch_offsetsize offset_sizeTable[8]; + u8 padding1[0x28]; + u8 flags[8]; + u8 ncchIdTable[8][8]; + u8 padding2[0x30]; +} cci_hdr; -typedef struct -{ - FILE *out; - keys_struct *keys; - - struct{ - bool fillOutCci; - bool useDevCardInfo; - u32 mediaUnit; - - u64 savedataSize; - } option; - - struct{ - /* Data */ - buffer_struct *data; - - /* Misc Records */ - FILE **filePtrs; - u64 fileSize[CCI_MAX_CONTENT]; - u16 count; - - /* Details for NCSD header */ - u8 fsType[CCI_MAX_CONTENT]; - u8 cryptoType[CCI_MAX_CONTENT]; - u64 offset[CCI_MAX_CONTENT]; - u64 size[CCI_MAX_CONTENT]; - u8 titleId[CCI_MAX_CONTENT][8]; - } content; - - struct{ - u64 mediaSize; - u8 mediaId[8]; - u8 flags[8]; - } header; - - struct{ - u64 writableAddress; - u32 cardInfoBitmask; - - u64 cciTotalSize; - - // cver details - u8 cverTitleId[8]; - u8 cverTitleVersion[2]; - - u8 initialData[0x30]; - ncch_hdr ncchHdr; - u8 titleKey[0x10]; - } cardinfo; -} cci_settings; - -#ifndef PUBLIC_BUILD -static const u8 stock_initial_data[0x30] = -{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xAD, 0x88, - 0xAC, 0x41, 0xA2, 0xB1, 0x5E, 0x8F, - 0x66, 0x9C, 0x97, 0xE5, 0xE1, 0x5E, - 0xA3, 0xEB, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 stock_title_key[0x10] = -{ - 0x6E, 0xC7, 0x5F, 0xB2, 0xE2, 0xB4, - 0x87, 0x46, 0x1E, 0xDD, 0xCB, 0xB8, - 0x97, 0x11, 0x92, 0xBA -}; -#endif - -// Public Prototypes -// Build Functions -int build_CCI(user_settings *usrset); - -// Read Functions -bool IsCci(u8 *ncsd); -u8* GetPartition(u8 *ncsd, u8 index); -u64 GetPartitionOffset(u8 *ncsd, u8 index); -u64 GetPartitionSize(u8 *ncsd, u8 index); \ No newline at end of file diff --git a/makerom/ncsd_build.h b/makerom/ncsd_build.h new file mode 100644 index 0000000..35d2677 --- /dev/null +++ b/makerom/ncsd_build.h @@ -0,0 +1,72 @@ +#pragma once +#include "ncsd.h" +#include "tmd_read.h" + + +// Enums +typedef enum +{ + NCSD_NO_NCCH0 = -1, + NCSD_INVALID_NCCH0 = -2, + NCSD_INVALID_NCCH = -3, + INVALID_RSF_OPT = -4, + GEN_HDR_FAIL = -5, + INCOMPAT_CIA = -6, + CCI_CONFIG_FAIL = -7, +} ncsd_errors; + +typedef struct +{ + rsf_settings *rsf; + keys_struct *keys; + + FILE *out; + + struct{ + bool verbose; + bool padCci; + bool noModTid; + bool useExternalSdkCardInfo; + bool closeAlignWR; + + u8 cverDataType; + char *cverDataPath; + tmd_hdr *tmdHdr; + } options; + + struct{ + u32 blockSize; + + u64 mediaSize; + u64 usedSize; + + u8 mediaType; + u8 cardDevice; + u64 saveSize; + u64 card2SaveOffset; + } romInfo; + + struct{ + u8 *data; + u64 dataLen; + infile_type dataType; + + char **path; + + bool active[CCI_MAX_CONTENT]; + u64 dOffset[CCI_MAX_CONTENT]; + u64 *dSize; + u64 titleId[CCI_MAX_CONTENT]; + + u64 cOffset[CCI_MAX_CONTENT]; + } content; + + struct{ + buffer_struct ccihdr; + buffer_struct cardinfohdr; + } headers; +} cci_settings; + +// Public Prototypes +// Build Functions +int build_CCI(user_settings *usrset); \ No newline at end of file diff --git a/makerom/ncsd_read.h b/makerom/ncsd_read.h new file mode 100644 index 0000000..ac152e3 --- /dev/null +++ b/makerom/ncsd_read.h @@ -0,0 +1,8 @@ +#pragma once +#include "ncsd.h" + +// Read Functions +bool IsCci(u8 *ncsd); +u8* GetPartition(u8 *ncsd, u8 index); +u64 GetPartitionOffset(u8 *ncsd, u8 index); +u64 GetPartitionSize(u8 *ncsd, u8 index); \ No newline at end of file diff --git a/makerom/dpki.h b/makerom/pki/dev.h similarity index 99% rename from makerom/dpki.h rename to makerom/pki/dev.h index 867a707..db7d976 100644 --- a/makerom/dpki.h +++ b/makerom/pki/dev.h @@ -1,7 +1,7 @@ #pragma once #ifdef PKI_LEGACY -#include "dpki_legacy.h" +#include "pki/dev_legacy.h" #endif // AES KEYS diff --git a/makerom/dpki_legacy.h b/makerom/pki/dev_legacy.h similarity index 100% rename from makerom/dpki_legacy.h rename to makerom/pki/dev_legacy.h diff --git a/makerom/ppki.h b/makerom/pki/prod.h similarity index 99% rename from makerom/ppki.h rename to makerom/pki/prod.h index 41380ed..6935a95 100644 --- a/makerom/ppki.h +++ b/makerom/pki/prod.h @@ -1,7 +1,7 @@ #pragma once #ifdef PKI_LEGACY -#include "ppki_legacy.h" +#include "pki/prod_legacy.h" #endif // AES KEYS @@ -13,8 +13,7 @@ static const unsigned char prod_unfixed_ncch_keyX[2][16] = // Dummy static const unsigned char ctr_common_etd_keyX_ppki[16] = // Dummy { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const unsigned char ctr_common_etd_keyY_ppki[6][16] = diff --git a/makerom/ppki_legacy.h b/makerom/pki/prod_legacy.h similarity index 100% rename from makerom/ppki_legacy.h rename to makerom/pki/prod_legacy.h diff --git a/makerom/tpki.h b/makerom/pki/test.h similarity index 100% rename from makerom/tpki.h rename to makerom/pki/test.h diff --git a/makerom/romfs.c b/makerom/romfs.c index b09a2cd..64190c4 100644 --- a/makerom/romfs.c +++ b/makerom/romfs.c @@ -1,8 +1,8 @@ #include "lib.h" #include "dir.h" -#include "ncch.h" +#include "ncch_build.h" #include "romfs.h" -#include "romfs_binary.h" +#include "romfs_gen.h" #include "romfs_import.h" void FreeRomFsCtx(romfs_buildctx *ctx); diff --git a/makerom/romfs_binary.c b/makerom/romfs_gen.c similarity index 98% rename from makerom/romfs_binary.c rename to makerom/romfs_gen.c index b9cc1f0..4971895 100644 --- a/makerom/romfs_binary.c +++ b/makerom/romfs_gen.c @@ -1,6 +1,6 @@ #include "lib.h" #include "dir.h" -#include "ncch.h" +#include "ncch_build.h" #include "romfs.h" const int ROMFS_BLOCK_SIZE = 0x1000; @@ -75,7 +75,10 @@ int PrepareBuildRomFsBinary(ncch_settings *ncchset, romfs_buildctx *ctx) // Print Filtered FS //printf("print filtered FS\n"); - //fs_PrintDir(ctx->fs,0); + if(ncchset->options.verbose){ + printf("[ROMFS] File System:\n"); + fs_PrintDir(ctx->fs,0); + } //printf("predict romfs size\n"); CalcRomfsSize(ctx); @@ -349,7 +352,7 @@ int AddFileToRomfs(romfs_buildctx *ctx, fs_file *file, u32 parent, u32 sibling) u64_to_u8(entry->dataoffset,ctx->u_dataLen,LE); u64_to_u8(entry->datasize,file->size,LE); u8 *data_pos = (ctx->data + ctx->u_dataLen); - ReadFile_64(data_pos,file->size,0,file->fp); + ReadFile64(data_pos,file->size,0,file->fp); ctx->u_dataLen += file->size; // adding file size } else diff --git a/makerom/romfs_binary.h b/makerom/romfs_gen.h similarity index 100% rename from makerom/romfs_binary.h rename to makerom/romfs_gen.h diff --git a/makerom/romfs_import.c b/makerom/romfs_import.c index f4dd71b..48d68f6 100644 --- a/makerom/romfs_import.c +++ b/makerom/romfs_import.c @@ -1,6 +1,6 @@ #include "lib.h" #include "dir.h" -#include "ncch.h" +#include "ncch_build.h" #include "romfs.h" int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx) @@ -11,7 +11,7 @@ int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx ivfc_hdr *hdr = calloc(1,sizeof(ivfc_hdr)); - ReadFile_64(hdr,sizeof(ivfc_hdr),0,ctx->romfsBinary); + 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; @@ -24,7 +24,7 @@ int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx int ImportRomFsBinaryFromFile(romfs_buildctx *ctx) { - ReadFile_64(ctx->output,ctx->romfsSize,0,ctx->romfsBinary); + ReadFile64(ctx->output,ctx->romfsSize,0,ctx->romfsBinary); if(memcmp(ctx->output,"IVFC",4) != 0){ fprintf(stderr,"[ROMFS ERROR] Invalid RomFS Binary.\n"); return INVALID_ROMFS_FILE; diff --git a/makerom/rsf_settings.c b/makerom/rsf_settings.c index 84c3edc..aa7e938 100644 --- a/makerom/rsf_settings.c +++ b/makerom/rsf_settings.c @@ -56,7 +56,7 @@ void GET_Option(ctr_yaml_context *ctx, rsf_settings *rsf) //else if(cmpYamlValue("NoPadding",ctx)) SetBoolYAMLValue(&rsf->Option.NoPadding,"NoPadding",ctx); else if(cmpYamlValue("EnableCrypt",ctx)) SetBoolYAMLValue(&rsf->Option.EnableCrypt,"EnableCrypt",ctx); else if(cmpYamlValue("EnableCompress",ctx)) SetBoolYAMLValue(&rsf->Option.EnableCompress,"EnableCompress",ctx); - else if(cmpYamlValue("FreeProductCode",ctx)) SetBoolYAMLValue(&rsf->Option.EnableCompress,"FreeProductCode",ctx); + else if(cmpYamlValue("FreeProductCode",ctx)) SetBoolYAMLValue(&rsf->Option.FreeProductCode,"FreeProductCode",ctx); else if(cmpYamlValue("UseOnSD",ctx)) SetBoolYAMLValue(&rsf->Option.UseOnSD,"UseOnSD",ctx); else if(cmpYamlValue("PageSize",ctx)) SetSimpleYAMLValue(&rsf->Option.PageSize,"PageSize",ctx,0); //else if(cmpYamlValue("AppendSystemCall",ctx)) rsf->Option.AppendSystemCallNum = SetYAMLSequence(&rsf->Option.AppendSystemCall,"AppendSystemCall",ctx); diff --git a/makerom/tik.c b/makerom/tik.c index ba95e23..352d556 100644 --- a/makerom/tik.c +++ b/makerom/tik.c @@ -1,6 +1,6 @@ #include "lib.h" -#include "cia.h" -#include "tik.h" +#include "cia_build.h" +#include "tik_build.h" // Private Prototypes int SetupTicketBuffer(buffer_struct *tik); @@ -99,3 +99,34 @@ void SetContentIndexData(tik_hdr *hdr, cia_settings *ciaset) // TODO? memset(hdr->contentIndex,0,0xAC); memcpy(hdr->contentIndex,default_contentIndex,0x30); } + +tik_hdr *GetTikHdr(u8 *tik) +{ + u32 sigType = u8_to_u32(tik,BE); + + switch(sigType){ + case(RSA_4096_SHA1): + case(RSA_4096_SHA256): + return (tik_hdr*)(tik+0x240); + case(RSA_2048_SHA1): + case(RSA_2048_SHA256): + return (tik_hdr*)(tik+0x140); + case(ECC_SHA1): + case(ECC_SHA256): + return (tik_hdr*)(tik+0x7C); + } + + return NULL; +} + +bool GetTikTitleKey(u8 *titleKey, tik_hdr *hdr, keys_struct *keys) +{ + if(keys->aes.commonKey[hdr->keyId] == NULL) + return false; + + keys->aes.currentCommonKey = hdr->keyId; + + CryptTitleKey(hdr->encryptedTitleKey, titleKey, hdr->titleId, keys, DEC); + + return true; +} \ No newline at end of file diff --git a/makerom/tik.h b/makerom/tik.h index d6d6b1e..d8b7c05 100644 --- a/makerom/tik.h +++ b/makerom/tik.h @@ -1,15 +1,5 @@ #pragma once -static const unsigned char default_contentIndex[0x30] = -{ - 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC, - 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, - 0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 -}; - typedef enum { lic_Permanent = 0, @@ -63,6 +53,5 @@ typedef struct u8 contentIndex[0xAC]; } tik_hdr; -// Prototypes -int BuildTicket(cia_settings *ciaset); -int CryptTitleKey(u8 *EncTitleKey, u8 *DecTitleKey, u8 *TitleID, keys_struct *keys, u8 mode); \ No newline at end of file + + diff --git a/makerom/tik_build.h b/makerom/tik_build.h new file mode 100644 index 0000000..ecea022 --- /dev/null +++ b/makerom/tik_build.h @@ -0,0 +1,16 @@ +#pragma once +#include "tik.h" + +static const unsigned char default_contentIndex[0x30] = +{ + 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC, + 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, + 0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 +}; + +// Prototypes +int BuildTicket(cia_settings *ciaset); +int CryptTitleKey(u8 *EncTitleKey, u8 *DecTitleKey, u8 *TitleID, keys_struct *keys, u8 mode); \ No newline at end of file diff --git a/makerom/tik_read.h b/makerom/tik_read.h new file mode 100644 index 0000000..ab4c6e1 --- /dev/null +++ b/makerom/tik_read.h @@ -0,0 +1,5 @@ +#pragma once +#include "tik.h" + +tik_hdr *GetTikHdr(u8 *tik); +bool GetTikTitleKey(u8 *titleKey, tik_hdr *hdr, keys_struct *keys); \ No newline at end of file diff --git a/makerom/titleid.c b/makerom/titleid.c index 071b13e..d4479c4 100644 --- a/makerom/titleid.c +++ b/makerom/titleid.c @@ -1,5 +1,5 @@ #include "lib.h" -#include "ncch.h" +#include "ncch_read.h" #include "titleid.h" void SetPIDType(u16 *type); @@ -22,7 +22,7 @@ int GetProgramID(u64 *dest, rsf_settings *rsf, bool IsForExheader) u8 variation; if(rsf->TitleInfo.Category && rsf->TitleInfo.CategoryFlags){ - fprintf(stderr,"[ID ERROR] Can not set \"Cateory\" and \"CategoryFlags\" at the same time.\n"); + fprintf(stderr,"[ID ERROR] Can not set \"Category\" and \"CategoryFlags\" at the same time.\n"); return PID_BAD_RSF_SET; } diff --git a/makerom/tmd.c b/makerom/tmd.c index 173c1e4..e81f668 100644 --- a/makerom/tmd.c +++ b/makerom/tmd.c @@ -1,6 +1,6 @@ #include "lib.h" -#include "cia.h" -#include "tmd.h" +#include "cia_build.h" +#include "tmd_build.h" // Private Prototypes int SetupTMDBuffer(buffer_struct *tik); @@ -85,11 +85,96 @@ int SetupTMDContentRecord(u8 *content_record, cia_settings *ciaset) { for(int i = 0; i < ciaset->content.count; i++){ tmd_content_chunk *ptr = (tmd_content_chunk*)(content_record+sizeof(tmd_content_chunk)*i); - u32_to_u8(ptr->contentID,ciaset->content.id[i],BE); - u16_to_u8(ptr->contentIndex,ciaset->content.index[i],BE); - u16_to_u8(ptr->contentFlags,ciaset->content.flags[i],BE); - u64_to_u8(ptr->contentSize,ciaset->content.size[i],BE); - memcpy(ptr->contentHash,ciaset->content.hash[i],0x20); + u32_to_u8(ptr->id,ciaset->content.id[i],BE); + u16_to_u8(ptr->index,ciaset->content.index[i],BE); + u16_to_u8(ptr->flags,ciaset->content.flags[i],BE); + u64_to_u8(ptr->size,ciaset->content.size[i],BE); + memcpy(ptr->hash,ciaset->content.hash[i],0x20); } return 0; +} + +tmd_hdr *GetTmdHdr(u8 *tmd) +{ + u32 sigType = u8_to_u32(tmd,BE); + + switch(sigType){ + case(RSA_4096_SHA1): + case(RSA_4096_SHA256): + return (tmd_hdr*)(tmd+0x240); + case(RSA_2048_SHA1): + case(RSA_2048_SHA256): + return (tmd_hdr*)(tmd+0x140); + case(ECC_SHA1): + case(ECC_SHA256): + return (tmd_hdr*)(tmd+0x7C); + } + + return NULL; +} + +tmd_content_chunk* GetTmdContentInfo(u8 *tmd) +{ + tmd_hdr *hdr = GetTmdHdr(tmd); + if(!hdr) + return NULL; + + return (tmd_content_chunk*)((u8*)hdr + sizeof(tmd_hdr) + (sizeof(tmd_content_info_record)*64)); +} + +u64 GetTmdTitleId(tmd_hdr *hdr) +{ + return u8_to_u64(hdr->titleID,BE); +} + +u32 GetTmdSaveSize(tmd_hdr *hdr) +{ + return u8_to_u32(hdr->savedataSize,BE); +} + +u16 GetTmdContentCount(tmd_hdr *hdr) +{ + return u8_to_u16(hdr->contentCount,BE); +} + +u16 GetTmdVersion(tmd_hdr *hdr) +{ + return u8_to_u16(hdr->titleVersion,BE); +} + +u32 GetTmdContentId(tmd_content_chunk info) +{ + return u8_to_u32(info.id,BE); +} + +u16 GetTmdContentIndex(tmd_content_chunk info) +{ + return u8_to_u16(info.index,BE); +} + +u16 GetTmdContentFlags(tmd_content_chunk info) +{ + return u8_to_u16(info.flags,BE); +} + +u64 GetTmdContentSize(tmd_content_chunk info) +{ + return u8_to_u64(info.size,BE); +} + +u8* GetTmdContentHash(tmd_content_chunk *info) +{ + return (u8*)info->hash; +} + +bool IsTmdContentEncrypted(tmd_content_chunk info) +{ + return (GetTmdContentFlags(info) & content_Encrypted) == content_Encrypted; +} + +bool ValidateTmdContent(u8 *data, tmd_content_chunk info) +{ + u8 hash[32]; + ctr_sha(data,GetTmdContentSize(info),hash,CTR_SHA_256); + return memcmp(hash,GetTmdContentHash(&info),32) == 0; } \ No newline at end of file diff --git a/makerom/tmd.h b/makerom/tmd.h index 6f16e02..db24cdb 100644 --- a/makerom/tmd.h +++ b/makerom/tmd.h @@ -15,11 +15,11 @@ typedef enum typedef struct { - u8 contentID[4]; - u8 contentIndex[2]; - u8 contentFlags[2]; - u8 contentSize[8]; - u8 contentHash[0x20]; // SHA 256 + u8 id[4]; + u8 index[2]; + u8 flags[2]; + u8 size[8]; + u8 hash[0x20]; // SHA 256 } tmd_content_chunk; typedef struct @@ -58,11 +58,4 @@ typedef struct u8 bootContent[2]; u8 padding3[2]; u8 infoRecordHash[0x20]; // SHA-256 -} tmd_hdr; - -// Prototypes -u32 PredictTMDSize(u16 ContentCount); -int BuildTMD(cia_settings *ciaset); - -// Read TMD -tmd_hdr *GetTmdHdr(u8 *tmd); \ No newline at end of file +} tmd_hdr; \ No newline at end of file diff --git a/makerom/tmd_build.h b/makerom/tmd_build.h new file mode 100644 index 0000000..52c7bb6 --- /dev/null +++ b/makerom/tmd_build.h @@ -0,0 +1,6 @@ +#pragma once +#include "tmd.h" + +// Prototypes +u32 PredictTMDSize(u16 ContentCount); +int BuildTMD(cia_settings *ciaset); diff --git a/makerom/tmd_read.c b/makerom/tmd_read.c deleted file mode 100644 index 5427647..0000000 --- a/makerom/tmd_read.c +++ /dev/null @@ -1,22 +0,0 @@ -#include "lib.h" -#include "cia.h" -#include "tmd.h" - -tmd_hdr *GetTmdHdr(u8 *tmd) -{ - u32 sigType = u8_to_u32(tmd,BE); - - switch(sigType){ - case(RSA_4096_SHA1): - case(RSA_4096_SHA256): - return (tmd_hdr*)(tmd+0x240); - case(RSA_2048_SHA1): - case(RSA_2048_SHA256): - return (tmd_hdr*)(tmd+0x140); - case(ECC_SHA1): - case(ECC_SHA256): - return (tmd_hdr*)(tmd+0x7C); - } - - return NULL; -} \ No newline at end of file diff --git a/makerom/tmd_read.h b/makerom/tmd_read.h new file mode 100644 index 0000000..e09f471 --- /dev/null +++ b/makerom/tmd_read.h @@ -0,0 +1,19 @@ +#pragma once +#include "tmd.h" + +// Read TMD +tmd_hdr *GetTmdHdr(u8 *tmd); +tmd_content_chunk* GetTmdContentInfo(u8 *tmd); +u64 GetTmdTitleId(tmd_hdr *hdr); +u32 GetTmdSaveSize(tmd_hdr *hdr); +u16 GetTmdContentCount(tmd_hdr *hdr); +u16 GetTmdVersion(tmd_hdr *hdr); + +u32 GetTmdContentId(tmd_content_chunk info); +u16 GetTmdContentIndex(tmd_content_chunk info); +u16 GetTmdContentFlags(tmd_content_chunk info); +u64 GetTmdContentSize(tmd_content_chunk info); +u8* GetTmdContentHash(tmd_content_chunk info); + +bool IsTmdContentEncrypted(tmd_content_chunk info); +bool ValidateTmdContent(u8 *data, tmd_content_chunk info); \ No newline at end of file diff --git a/makerom/user_settings.c b/makerom/user_settings.c index 2486c4c..423278b 100644 --- a/makerom/user_settings.c +++ b/makerom/user_settings.c @@ -10,9 +10,9 @@ void PrintArgInvalid(char *arg); void PrintArgReqParam(char *arg, u32 paramNum); void PrintNoNeedParam(char *arg); -int ParseArgs(int argc, char *argv[], user_settings *usr_settings) +int ParseArgs(int argc, char *argv[], user_settings *set) { - if(argv == NULL || usr_settings == NULL) + if(argv == NULL || set == NULL) return USR_PTR_PASS_FAIL; if(argc < 2){ @@ -29,26 +29,23 @@ int ParseArgs(int argc, char *argv[], user_settings *usr_settings) } // Allocating Memory for Content Path Ptrs - usr_settings->common.contentPath = calloc(CIA_MAX_CONTENT,sizeof(char*)); - if(usr_settings->common.contentPath == NULL){ + set->common.contentPath = calloc(CIA_MAX_CONTENT,sizeof(char*)); + if(set->common.contentPath == NULL){ fprintf(stderr,"[SETTING ERROR] Not Enough Memory\n"); return USR_MEM_ERROR; } // Initialise Keys - InitKeys(&usr_settings->common.keys); + InitKeys(&set->common.keys); // Setting Defaults - SetDefaults(usr_settings); + SetDefaults(set); // Parsing Arguments -#ifdef DEBUG - fprintf(stdout,"[DEBUG] Parsing Args\n"); -#endif int set_result; int i = 1; while(i < argc){ - set_result = SetArgument(argc,i,argv,usr_settings); + set_result = SetArgument(argc,i,argv,set); if(set_result < 1){ fprintf(stderr,"[RESULT] Invalid arguments, see '%s -help'\n",argv[0]); return set_result; @@ -57,39 +54,30 @@ int ParseArgs(int argc, char *argv[], user_settings *usr_settings) } // Checking arguments -#ifdef DEBUG - fprintf(stdout,"[DEBUG] Checking Args\n"); -#endif - set_result = CheckArgumentCombination(usr_settings); - if(set_result) return set_result; + if((set_result = CheckArgumentCombination(set)) != 0) + return set_result; // Setting Keys -#ifdef DEBUG - fprintf(stdout,"[DEBUG] Setting Keys\n"); -#endif - set_result = SetKeys(&usr_settings->common.keys); - if(set_result) return set_result; + if((set_result = SetKeys(&set->common.keys)) != 0) + return set_result; -#ifdef DEBUG - fprintf(stdout,"[DEBUG] Generating output path name if required\n"); -#endif - - if(!usr_settings->common.outFileName){ + // Generating outpath if required + if(!set->common.outFileName){ char *source_path = NULL; - if(usr_settings->ncch.buildNcch0) - source_path = usr_settings->common.rsfPath; - else if(usr_settings->common.workingFileType == infile_ncsd || usr_settings->common.workingFileType == infile_srl) - source_path = usr_settings->common.workingFilePath; + if(set->ncch.buildNcch0) + source_path = set->common.rsfPath; + else if(set->common.workingFileType == infile_ncsd || set->common.workingFileType == infile_cia || set->common.workingFileType == infile_srl) + source_path = set->common.workingFilePath; else - source_path = usr_settings->common.contentPath[0]; - u16 outfile_len = strlen(source_path) + 3; - usr_settings->common.outFileName = calloc(outfile_len,sizeof(char)); - if(!usr_settings->common.outFileName){ + source_path = set->common.contentPath[0]; + u16 outfile_len = strlen(source_path) + 0x10; + set->common.outFileName = calloc(outfile_len,sizeof(char)); + if(!set->common.outFileName){ fprintf(stderr,"[SETTING ERROR] Not Enough Memory\n"); return USR_MEM_ERROR; } - usr_settings->common.outFileName_mallocd = true; - append_filextention(usr_settings->common.outFileName,outfile_len,source_path,(char*)&output_extention[usr_settings->common.outFormat-1]); + set->common.outFileName_mallocd = true; + append_filextention(set->common.outFileName,outfile_len,source_path,(char*)&output_extention[set->common.outFormat-1]); } return 0; } @@ -101,12 +89,14 @@ void SetDefaults(user_settings *set) set->common.keys.accessDescSign.presetType = desc_preset_NONE; // Build NCCH Info + set->ncch.useSecCrypto = false; set->ncch.buildNcch0 = false; set->ncch.includeExefsLogo = false; set->common.outFormat = NCCH; set->ncch.ncchType = format_not_set; // RSF Settings + clrmem(&set->common.rsfSet,sizeof(rsf_settings)); set->common.rsfSet.Option.EnableCompress = true; set->common.rsfSet.Option.EnableCrypt = true; set->common.rsfSet.Option.UseOnSD = false; @@ -119,13 +109,15 @@ void SetDefaults(user_settings *set) set->cci.useSDKStockData = false; // CIA Info + set->cia.includeUpdateNcch = false; + set->cia.deviceId = 0; + set->cia.eshopAccId = 0; set->cia.useDataTitleVer = false; set->cia.titleVersion[VER_MAJOR] = MAX_U16; // invalid so changes can be detected set->cia.randomTitleKey = false; set->common.keys.aes.currentCommonKey = MAX_U8 + 1; // invalid so changes can be detected - for(int i = 0; i < CIA_MAX_CONTENT; i++){ + for(int i = 0; i < CIA_MAX_CONTENT; i++) set->cia.contentId[i] = MAX_U32 + 1; // invalid so changes can be detected - } } int SetArgument(int argc, int i, char *argv[], user_settings *set) @@ -137,7 +129,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) // Global Settings if(strcmp(argv[i],"-rsf") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-rsf",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->common.rsfPath = argv[i+1]; @@ -145,7 +137,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-f") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-f",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } if(strcasecmp(argv[i+1],"ncch") == 0) @@ -162,17 +154,25 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-o") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-o",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->common.outFileName = argv[i+1]; set->common.outFileName_mallocd = false; return 2; } + else if(strcmp(argv[i],"-v") == 0){ + if(ParamNum){ + PrintNoNeedParam(argv[i]); + return USR_BAD_ARG; + } + set->common.verbose = true; + return 1; + } // Key Options else if(strcmp(argv[i],"-target") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-target",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } if(strcasecmp(argv[i+1],"test") == 0 || strcasecmp(argv[i+1],"t") == 0) @@ -181,7 +181,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) set->common.keys.keyset = pki_DEVELOPMENT; else if(strcasecmp(argv[i+1],"retail") == 0 || strcasecmp(argv[i+1],"production") == 0 || strcasecmp(argv[i+1],"p") == 0) set->common.keys.keyset = pki_PRODUCTION; - //else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0) + //else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0) // given all known keys are here, this isn't needed // set->common.keys.keyset = pki_CUSTOM; else{ fprintf(stderr,"[SETTING ERROR] Unrecognised target '%s'\n",argv[i+1]); @@ -189,22 +189,36 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } return 2; } - else if(strcmp(argv[i],"-ckeyID") == 0){ + else if(strcmp(argv[i],"-ckeyid") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-ckeyID",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->common.keys.aes.currentCommonKey = strtol(argv[i+1],NULL,0); - if(set->common.keys.aes.currentCommonKey > 0xff) + if(set->common.keys.aes.currentCommonKey > MAX_CMN_KEY) { - fprintf(stderr,"[SETTING ERROR] Invalid Common Key ID: 0x%x\n",set->common.keys.aes.currentCommonKey); + fprintf(stderr,"[SETTING ERROR] Invalid Common Key Index: 0x%x\n",set->common.keys.aes.currentCommonKey); + return USR_BAD_ARG; + } + return 2; + } + else if(strcmp(argv[i],"-ncchseckey") == 0){ + if(ParamNum != 1){ + PrintArgReqParam(argv[i],1); + return USR_ARG_REQ_PARAM; + } + set->ncch.useSecCrypto = true; + set->ncch.keyXID = strtol(argv[i+1],NULL,0); + if(set->ncch.keyXID > MAX_NCCH_KEYX) + { + fprintf(stderr,"[SETTING ERROR] Invalid NCCH KeyX Index: 0x%x\n",set->ncch.keyXID); return USR_BAD_ARG; } return 2; } else if(strcmp(argv[i],"-showkeys") == 0){ if(ParamNum){ - PrintNoNeedParam("-showkeys"); + PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->common.keys.dumpkeys = true; @@ -212,7 +226,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-fsign") == 0){ if(ParamNum){ - PrintNoNeedParam("-fsign"); + PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->common.keys.rsa.isFalseSign = true; @@ -222,7 +236,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) // Ncch Options else if(strcmp(argv[i],"-elf") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-elf",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.elfPath = argv[i+1]; @@ -232,7 +246,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) else if(strcmp(argv[i],"-icon") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-icon",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.iconPath = argv[i+1]; @@ -241,7 +255,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-banner") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-banner",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.bannerPath = argv[i+1]; @@ -250,7 +264,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-logo") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-logo",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.logoPath = argv[i+1]; @@ -259,7 +273,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-desc") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-desc",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } char *tmp = argv[i+1]; @@ -281,7 +295,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) else if(strcasecmp(app_type,"ECApp") == 0) set->common.keys.accessDescSign.presetType = desc_preset_EC_APP; else if(strcasecmp(app_type,"Demo") == 0) set->common.keys.accessDescSign.presetType = desc_preset_DEMO; else if(strcasecmp(app_type,"DlpChild") == 0 || strcasecmp(app_type,"Dlp") == 0) set->common.keys.accessDescSign.presetType = desc_preset_DLP; - //else if(strcasecmp(app_type,"FIRM") == 0) set->common.keys.accessDescSign.presetType = desc_preset_FIRM; + else if(strcasecmp(app_type,"FIRM") == 0) set->common.keys.accessDescSign.presetType = desc_preset_FIRM; else{ fprintf(stderr,"[SETTING ERROR] Accessdesc AppType preset '%s' not valid, please manually configure RSF\n",app_type); return USR_BAD_ARG; @@ -324,7 +338,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-exefslogo") == 0){ if(ParamNum){ - PrintNoNeedParam("-exefslogo"); + PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->ncch.includeExefsLogo = true; @@ -335,7 +349,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) // Ncch Rebuild Options else if(strcmp(argv[i],"-code") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-code",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.codePath = argv[i+1]; @@ -344,16 +358,16 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-exheader") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-exheader",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.exheaderPath = argv[i+1]; set->ncch.ncchType |= CXI; return 2; } - else if(strcmp(argv[i],"-plain-region") == 0){ + else if(strcmp(argv[i],"-plainrgn") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-plain-region",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.plainRegionPath = argv[i+1]; @@ -362,7 +376,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-romfs") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-romfs",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.romfsPath = argv[i+1]; @@ -370,9 +384,9 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) return 2; } // Cci Options - else if(strcmp(argv[i],"-devcardcci") == 0){ + else if(strcmp(argv[i],"-devcci") == 0){ if(ParamNum){ - PrintNoNeedParam("-devcardcci"); + PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->cci.useSDKStockData = true; @@ -380,7 +394,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-nomodtid") == 0){ if(ParamNum){ - PrintNoNeedParam("-nomodtid"); + PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->cci.dontModifyNcchTitleID = true; @@ -388,7 +402,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-alignwr") == 0){ if(ParamNum){ - PrintNoNeedParam("-alignwr"); + PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->cci.closeAlignWritableRegion = true; @@ -396,17 +410,42 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-cverinfo") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-cverinfo",1); + PrintArgReqParam(argv[i],1); return USR_BAD_ARG; } - set->cci.cverCiaPath = argv[i+1]; + char *pos = strstr(argv[i+1],":"); + if(!pos || strlen(pos) < 2){ + fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]); + fprintf(stderr," %s :<'cia'/'tmd'>\n",argv[i]); + return USR_BAD_ARG; + } + + char *dtype = pos + 1; + if(strcasecmp(dtype,"tmd") == 0) + set->cci.cverDataType = CVER_DTYPE_TMD; + else if(strcasecmp(dtype,"cia") == 0) + set->cci.cverDataType = CVER_DTYPE_CIA; + else{ + fprintf(stderr,"[SETTING ERROR] Unrecognised cver data type:\"%s\"\n",dtype); + return USR_BAD_ARG; + } + + u32 path_len = (pos-argv[i+1])+1; + set->cci.cverDataPath = calloc(path_len,sizeof(char)); + strncpy(set->cci.cverDataPath,argv[i+1],path_len-1); + + if(!AssertFile(set->cci.cverDataPath)){ + fprintf(stderr,"[SETTING ERROR] Failed to open '%s'\n",set->cci.cverDataPath); + return USR_BAD_ARG; + } + return 2; } // Cia Options else if(strcmp(argv[i],"-major") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-major",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->cia.useNormTitleVer = true; @@ -420,7 +459,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-minor") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-minor",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->cia.useNormTitleVer = true; @@ -434,7 +473,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-micro") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-micro",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } u32 ver = strtoul(argv[i+1],NULL,10); @@ -447,7 +486,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } else if(strcmp(argv[i],"-dver") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-dver",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->cia.useDataTitleVer = true; @@ -457,31 +496,44 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) return USR_BAD_ARG; } set->cia.titleVersion[VER_MAJOR] = (ver >> 6) & VER_MAJOR_MAX; - set->cia.titleVersion[VER_MINOR] = ver & VER_MAJOR_MAX; + set->cia.titleVersion[VER_MINOR] = ver & VER_MINOR_MAX; + return 2; + } + else if(strcmp(argv[i],"-deviceid") == 0){ + if(ParamNum != 1){ + PrintArgReqParam(argv[i],1); + return USR_ARG_REQ_PARAM; + } + set->cia.deviceId = strtoul(argv[i+1],NULL,16); + return 2; + } + else if(strcmp(argv[i],"-esaccid") == 0){ + if(ParamNum != 1){ + PrintArgReqParam(argv[i],1); + return USR_ARG_REQ_PARAM; + } + set->cia.eshopAccId = strtoul(argv[i+1],NULL,16); return 2; } else if(strcmp(argv[i],"-rand") == 0){ if(ParamNum){ - PrintNoNeedParam("-rand"); + PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } set->cia.randomTitleKey = true; return 1; } - else if(strcmp(argv[i],"-cci") == 0){ - if(ParamNum != 1){ - PrintArgReqParam("-cci",1); - return USR_ARG_REQ_PARAM; + else if(strcmp(argv[i],"-dlc") == 0){ + if(ParamNum){ + PrintNoNeedParam(argv[i]); + return USR_BAD_ARG; } - set->ncch.buildNcch0 = false; - set->common.workingFileType = infile_ncsd; - set->common.workingFilePath = argv[i+1]; - set->common.outFormat = CIA; - return 2; + set->cia.DlcContent = true; + return 1; } else if(strcmp(argv[i],"-srl") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-srl",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } set->ncch.buildNcch0 = false; @@ -491,36 +543,53 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) return 2; } - else if(strcmp(argv[i],"-dlc") == 0){ + + // Ncch Container Conversion + else if(strcmp(argv[i],"-ccitocia") == 0){ + if(ParamNum != 1){ + PrintArgReqParam(argv[i],1); + return USR_ARG_REQ_PARAM; + } + set->ncch.buildNcch0 = false; + set->common.workingFileType = infile_ncsd; + set->common.workingFilePath = argv[i+1]; + set->common.outFormat = CIA; + return 2; + } + else if(strcmp(argv[i],"-ciatocci") == 0){ + if(ParamNum != 1){ + PrintArgReqParam(argv[i],1); + return USR_ARG_REQ_PARAM; + } + set->ncch.buildNcch0 = false; + set->common.workingFileType = infile_cia; + set->common.workingFilePath = argv[i+1]; + set->common.outFormat = CCI; + return 2; + } + else if(strcmp(argv[i],"-inclupd") == 0){ if(ParamNum){ - PrintNoNeedParam("-dlc"); + PrintNoNeedParam(argv[i]); return USR_BAD_ARG; } - set->cia.DlcContent = true; + set->cia.includeUpdateNcch = true; return 1; } - + // Other Setting else if(strcmp(argv[i],"-content") == 0){ if(ParamNum != 1){ - PrintArgReqParam("-content",1); + PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } char *pos = strstr(argv[i+1],":"); - if(!pos){ + if(!pos || strlen(pos) < 2){ fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]); - fprintf(stderr," -content :\n"); + fprintf(stderr," %s :\n",argv[i]); fprintf(stderr," If generating a CIA, then use the format:\n"); - fprintf(stderr," -content ::\n"); + fprintf(stderr," %s ::\n",argv[i]); return USR_BAD_ARG; } - if(strlen(pos) < 2){ - fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]); - fprintf(stderr," -content :\n"); - fprintf(stderr," If generating a CIA, then use the format:\n"); - fprintf(stderr," -content ::\n"); - return USR_BAD_ARG; - } /* Getting Content Index */ u16 content_index = strtol((char*)(pos+1),NULL,0); @@ -528,7 +597,6 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) /* Storing Content Filepath */ u32 path_len = (u32)(pos-argv[i+1])+1; - if(content_index == 0) set->ncch.buildNcch0 = false; if(set->common.contentPath[content_index] != NULL){ fprintf(stderr,"[SETTING ERROR] Content %d is already specified\n",content_index); return USR_BAD_ARG; @@ -539,12 +607,16 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) return USR_MEM_ERROR; } strncpy(set->common.contentPath[content_index],argv[i+1],path_len-1); - + if(!AssertFile(set->common.contentPath[content_index])){ + fprintf(stderr,"[SETTING ERROR] '%s' could not be opened\n",set->common.contentPath[content_index]); + return USR_BAD_ARG; + } + set->common.contentSize[content_index] = GetFileSize64(set->common.contentPath[content_index]); + /* Get ContentID for CIA gen */ char *pos2 = strstr(pos+1,":"); - if(pos2) { + if(pos2) set->cia.contentId[content_index] = strtoul((pos2+1),NULL,0); - } /* Return Next Arg Pos*/ return 2; @@ -563,7 +635,6 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) fprintf(stderr,"[SETTING ERROR] Not enough memory\n"); return MEM_ERROR; } - //memset(set->dname.items,0,sizeof(dname_item)*set->dname.m_items); } else if(set->dname.m_items == set->dname.u_items){ set->dname.m_items *= 2; @@ -655,7 +726,7 @@ int CheckArgumentCombination(user_settings *set) return USR_BAD_ARG; } - if(set->common.outFormat == CIA && set->cci.cverCiaPath){ + if(set->common.outFormat == CIA && set->cci.cverDataPath){ fprintf(stderr,"[SETTING ERROR] You cannot use argument \"-cverinfo\" when generating a CIA\n"); return USR_BAD_ARG; } @@ -700,7 +771,7 @@ int CheckArgumentCombination(user_settings *set) return USR_BAD_ARG; } if(!buildCXI && set->ncch.plainRegionPath){ - PrintArgInvalid("-plain-region"); + PrintArgInvalid("-plainrgn"); return USR_BAD_ARG; } if(!set->ncch.buildNcch0 && set->ncch.includeExefsLogo){ @@ -715,45 +786,47 @@ int CheckArgumentCombination(user_settings *set) return 0; } -void init_UserSettings(user_settings *usr_settings) +void init_UserSettings(user_settings *set) { - memset(usr_settings,0,sizeof(user_settings)); + memset(set,0,sizeof(user_settings)); } -void free_UserSettings(user_settings *usr_settings) +void free_UserSettings(user_settings *set) { // Free Content Paths - if(usr_settings->common.contentPath){ + if(set->common.contentPath){ for(int i = 0; i < CIA_MAX_CONTENT; i++) - free(usr_settings->common.contentPath[i]); - free(usr_settings->common.contentPath); + free(set->common.contentPath[i]); + free(set->common.contentPath); } // free -DNAME=VALUE - for(u32 i = 0; i < usr_settings->dname.u_items; i++){ - free(usr_settings->dname.items[i].name); - free(usr_settings->dname.items[i].value); + for(u32 i = 0; i < set->dname.u_items; i++){ + free(set->dname.items[i].name); + free(set->dname.items[i].value); } - free(usr_settings->dname.items); + free(set->dname.items); + free(set->cci.cverDataPath); + // Free Spec File Setting - free_RsfSettings(&usr_settings->common.rsfSet); + free_RsfSettings(&set->common.rsfSet); // Free Key Data - FreeKeys(&usr_settings->common.keys); + FreeKeys(&set->common.keys); // Free Working File - free(usr_settings->common.workingFile.buffer); + free(set->common.workingFile.buffer); // Free outfile path, if malloc'd - if(usr_settings->common.outFileName_mallocd) - free(usr_settings->common.outFileName); + if(set->common.outFileName_mallocd) + free(set->common.outFileName); // Clear settings - init_UserSettings(usr_settings); + init_UserSettings(set); // Free - free(usr_settings); + free(set); } void PrintNeedsArg(char *arg) @@ -787,53 +860,52 @@ void DisplayHelp(char *app_name) printf("Option Parameter Explanation\n"); printf("GLOBAL OPTIONS:\n"); printf(" -help Display this text\n"); - printf(" -rsf Rom Specification File (*.rsf)\n"); - printf(" -f Output Format, defaults to 'ncch'\n"); - printf(" -o Output File\n"); - //printf(" -v Verbose\n"); - printf(" -DNAME=VALUE Substitute values in Spec file\n"); + printf(" -rsf ROM Spec File (*.rsf)\n"); + printf(" -f Output format, defaults to 'ncch'\n"); + printf(" -o Output file\n"); + printf(" -v Verbose output\n"); + printf(" -DNAME=VALUE Substitute values in RSF file\n"); printf("KEY OPTIONS:\n"); - //printf(" -target Target for crypto, defaults to 't'\n"); printf(" -target Target for crypto, defaults to 't'\n"); printf(" 't' Test(false) Keys & prod Certs\n"); printf(" 'd' Development Keys & Certs\n"); printf(" 'p' Production Keys & Certs\n"); - //printf(" 'c' Custom Keys & Certs\n"); - printf(" -ckeyID Override the automatic commonKey selection\n"); - printf(" -showkeys Display the loaded keychain\n"); + printf(" -ckeyid Override the automatic common key selection\n"); + printf(" -ncchseckey Ncch keyX index ('0'=1.0+, '1'=7.0+)\n"); + printf(" -showkeys Display the loaded key chain\n"); printf(" -fsign Ignore invalid signatures\n"); printf("NCCH OPTIONS:\n"); - printf(" -elf ELF File\n"); - printf(" -icon Icon File\n"); - printf(" -banner Banner File\n"); - printf(" -logo Logo File (Overrides \"BasicInfo/Logo\" in RSF)\n"); - printf(" -desc : Specify Access Descriptor Preset\n"); - //printf(" AppTypes:\n"); - //printf(" 'SDApp' Normal SD Application\n"); - //printf(" 'ECApp' SD Application with DLC Capability\n"); - //printf(" 'Demo' SD Demo Application\n"); - //printf(" 'Dlp' NAND DLP Child Application\n"); - //printf(" 'FIRM' FIRM CXI\n"); - printf(" -exefslogo Include Logo in ExeFs (Required for usage on <5.X Systems)\n"); + printf(" -elf ELF file\n"); + printf(" -icon Icon file\n"); + printf(" -banner Banner file\n"); + printf(" -logo Logo file (Overrides \"BasicInfo/Logo\" in RSF)\n"); + printf(" -desc : Specify Access Descriptor template\n"); + printf(" -exefslogo Include Logo in ExeFS (Required for usage on <5.0 systems)\n"); printf("NCCH REBUILD OPTIONS:\n"); - printf(" -code Specify ExeFs code File\n"); - printf(" -exheader ExHeader Template File\n"); - printf(" -plain-region PlainRegion File\n"); - printf(" -romfs RomFS File\n"); + printf(" -code Decompressed ExeFS \".code\"\n"); + printf(" -exheader Exheader template\n"); + printf(" -plainrgn Plain Region binary\n"); + printf(" -romfs RomFS binary\n"); printf("CCI OPTIONS:\n"); - printf(" -content : Specify content files\n"); - printf(" -devcardcci Use SDK CardInfo Method\n"); + printf(" -content : Specify content files\n"); + printf(" -devcci Use external CTRSDK \"CardInfo\" method\n"); printf(" -nomodtid Don't Modify Content TitleIDs\n"); - printf(" -alignwr Align Writeable Region to the end of last NCCH\n"); - printf(" -cverinfo Include CVer title info\n"); + printf(" -alignwr Align writeable region to the end of last NCCH\n"); + printf(" -cverinfo : Include cver title info\n"); printf("CIA OPTIONS:\n"); - printf(" -content :: Specify content files\n"); - printf(" -major Specify Major Version\n"); - printf(" -minor Specify Minor Version\n"); - printf(" -micro Specify Micro Version\n"); - printf(" -dver Specify Data Title Version\n"); + printf(" -content :: Specify content files\n"); + printf(" -major Major version\n"); + printf(" -minor Minor version\n"); + printf(" -micro Micro version\n"); + printf(" -dver Data-title version\n"); + printf(" -deviceid 3DS unique device ID\n"); + printf(" -esaccid e-Shop account ID\n"); printf(" -rand Use a random title key\n"); - printf(" -cci Convert CCI to CIA\n"); - printf(" -srl Use TWL SRL as Content0\n"); printf(" -dlc Create DLC CIA\n"); + printf(" -srl Package a TWL SRL in a CIA\n"); + printf("NCCH CONTAINER CONVERSION:\n"); + printf(" -ccitocia Convert CCI to CIA\n"); + printf(" -ciatocci Convert CIA to CCI\n"); + printf(" -inclupd Include \"Update NCCH\" in CCI to CIA conversion\n"); + } \ No newline at end of file diff --git a/makerom/user_settings.h b/makerom/user_settings.h index 95d8317..89d9a9e 100644 --- a/makerom/user_settings.h +++ b/makerom/user_settings.h @@ -21,6 +21,12 @@ typedef enum VER_DVER_MAX = 4095, } title_ver_max; +typedef enum +{ + CVER_DTYPE_TMD, + CVER_DTYPE_CIA, +} cver_data_type; + typedef enum { USR_PTR_PASS_FAIL = -1, @@ -37,6 +43,7 @@ typedef enum infile_ncch, infile_ncsd, infile_srl, + infile_cia, } infile_type; typedef enum @@ -49,7 +56,7 @@ typedef enum NCCH } output_format; -static const char output_extention[4][5] = {".cxi",".cfa",".cci",".cia"}; +static const char output_extention[5][5] = {".cxi",".cfa",".cci",".cia",".app"}; /* This does not follow style, so the rsf string names match the variables where they're stored */ typedef struct @@ -246,6 +253,8 @@ typedef struct typedef struct { struct{ + bool verbose; + char *rsfPath; bool outFileName_mallocd; char *outFileName; @@ -259,9 +268,10 @@ typedef struct // Content Details char **contentPath; + u64 contentSize[CIA_MAX_CONTENT]; char *workingFilePath; - infile_type workingFileType; // Could Be ncch/ncsd/srl. This is mainly used for CIA gen + infile_type workingFileType; // Could Be ncch/ncsd/srl/cia. buffer_struct workingFile; } common; @@ -282,23 +292,32 @@ typedef struct char *exheaderPath; // for .code details char *plainRegionPath; // prebuilt Plain Region char *romfsPath; // Prebuild _cleartext_ romfs binary + + bool useSecCrypto; + u8 keyXID; } ncch; // Ncch0 Build struct{ bool useSDKStockData; // incase we want to use the SDK stock data, for whatever reason. bool dontModifyNcchTitleID; bool closeAlignWritableRegion; - char *cverCiaPath; + + u8 cverDataType; + char *cverDataPath; } cci; // CCI Settings struct{ bool randomTitleKey; bool encryptCia; bool DlcContent; + bool includeUpdateNcch; bool useNormTitleVer; bool useDataTitleVer; u16 titleVersion[3]; + + u32 deviceId; + u32 eshopAccId; u64 contentId[CIA_MAX_CONTENT]; // For CIA } cia; // CIA Settings @@ -306,6 +325,6 @@ typedef struct // Prototypes -void init_UserSettings(user_settings *usr_settings); -void free_UserSettings(user_settings *usr_settings); +void init_UserSettings(user_settings *set); +void free_UserSettings(user_settings *set); int ParseArgs(int argc, char *argv[], user_settings *usr_settings); \ No newline at end of file diff --git a/makerom/utils.c b/makerom/utils.c index 1321168..bda3076 100644 --- a/makerom/utils.c +++ b/makerom/utils.c @@ -1,25 +1,9 @@ #include "lib.h" #include "utf.h" -// Memory -void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base) -{ - char tmp[size][2]; - unsigned char *byte_array = malloc(size*sizeof(unsigned char)); - memset(byte_array, 0, size); - memset(destination, 0, size); - memset(tmp, 0, size*2); - - for (int i = 0; i < size; i ++){ - tmp[i][0] = source[(i*2)]; - tmp[i][1] = source[((i*2)+1)]; - tmp[i][2] = '\0'; - byte_array[i] = (unsigned char)strtol(tmp[i], NULL, base); - } - endian_memcpy(destination,byte_array,size,endianness); - free(byte_array); -} +#include "polarssl/base64.h" +// Memory void endian_memcpy(u8 *destination, u8 *source, u32 size, int endianness) { for (u32 i = 0; i < size; i++){ @@ -65,13 +49,13 @@ u64 align(u64 value, u64 alignment) return value; } -u64 min_u64(u64 a, u64 b) +u64 min64(u64 a, u64 b) { if(a < b) return a; return b; } -u64 max_u64(u64 a, u64 b) +u64 max64(u64 a, u64 b) { if(a > b) return a; return b; @@ -187,6 +171,56 @@ int str_utf8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len) } #endif +// Base64 +bool IsValidB64Char(char chr) +{ + return (isalnum(chr) || chr == '+' || chr == '/' || chr == '='); +} + +u32 b64_strlen(char *str) +{ + u32 count = 0; + u32 i = 0; + while(str[i] != 0x0){ + if(IsValidB64Char(str[i])) { + //printf("Is Valid: %c\n",str[i]); + count++; + } + i++; + } + + return count; +} + +void b64_strcpy(char *dst, char *src) +{ + u32 src_len = strlen(src); + u32 j = 0; + for(u32 i = 0; i < src_len; i++){ + if(IsValidB64Char(src[i])){ + dst[j] = src[i]; + j++; + } + } + dst[j] = 0; + + //memdump(stdout,"src: ",(u8*)src,src_len+1); + //memdump(stdout,"dst: ",(u8*)dst,j+1); +} + +int b64_decode(u8 *dst, char *src, u32 dst_size) +{ + int ret; + u32 size = dst_size; + + ret = base64_decode(dst,(size_t*)&size,(const u8*)src,strlen(src)); + + if(size != dst_size) + ret = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL; + + return ret; +} + // Pseudo-Random Number Generator void initRand(void) { @@ -227,7 +261,7 @@ bool AssertFile(char *filename) #endif } -u64 GetFileSize_u64(char *filename) +u64 GetFileSize64(char *filename) { #ifdef _WIN32 struct _stat64 st; @@ -262,7 +296,7 @@ char *getcwdir(char *buffer,int maxlen) #endif } -int TruncateFile_u64(char *filename, u64 filelen) +int TruncateFile64(char *filename, u64 filelen) { #ifdef _WIN32 HANDLE fh; @@ -291,7 +325,7 @@ int TruncateFile_u64(char *filename, u64 filelen) // Wide Char IO #ifdef _WIN32 -u64 wGetFileSize_u64(u16 *filename) +u64 wGetFileSize64(u16 *filename) { struct _stat64 st; _wstat64((wchar_t*)filename, &st); @@ -302,12 +336,10 @@ u64 wGetFileSize_u64(u16 *filename) //IO Misc u8* ImportFile(char *file, u64 size) { - u64 fsize = GetFileSize_u64(file); - if(size > 0){ - if(size != fsize){ - fprintf(stderr,"[!] %s has an invalid size (0x%"PRIx64")\n",file, fsize); - return NULL; - } + u64 fsize = GetFileSize64(file); + if(size > 0 && size != fsize){ + fprintf(stderr,"[!] %s has an invalid size (0x%"PRIx64")\n",file, fsize); + return NULL; } u8 *data = (u8*)calloc(1,fsize); @@ -328,7 +360,7 @@ void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output) fwrite(buffer,size,1,output); } -void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file) +void ReadFile64(void *outbuff, u64 size, u64 offset, FILE *file) { fseek_64(file,offset); fread(outbuff,size,1,file); @@ -368,32 +400,32 @@ u32 u8_to_u32(u8 *value, u8 endianness) u64 u8_to_u64(u8 *value, u8 endianness) { - u64 u64_return = 0; + u64 ret = 0; switch(endianness){ case(BE): - u64_return |= (u64)value[7]<<0; - u64_return |= (u64)value[6]<<8; - u64_return |= (u64)value[5]<<16; - u64_return |= (u64)value[4]<<24; - u64_return |= (u64)value[3]<<32; - u64_return |= (u64)value[2]<<40; - u64_return |= (u64)value[1]<<48; - u64_return |= (u64)value[0]<<56; + ret |= (u64)value[7]<<0; + ret |= (u64)value[6]<<8; + ret |= (u64)value[5]<<16; + ret |= (u64)value[4]<<24; + ret |= (u64)value[3]<<32; + ret |= (u64)value[2]<<40; + ret |= (u64)value[1]<<48; + ret |= (u64)value[0]<<56; break; //return (value[7]<<0) | (value[6]<<8) | (value[5]<<16) | (value[4]<<24) | (value[3]<<32) | (value[2]<<40) | (value[1]<<48) | (value[0]<<56); case(LE): - u64_return |= (u64)value[0]<<0; - u64_return |= (u64)value[1]<<8; - u64_return |= (u64)value[2]<<16; - u64_return |= (u64)value[3]<<24; - u64_return |= (u64)value[4]<<32; - u64_return |= (u64)value[5]<<40; - u64_return |= (u64)value[6]<<48; - u64_return |= (u64)value[7]<<56; + ret |= (u64)value[0]<<0; + ret |= (u64)value[1]<<8; + ret |= (u64)value[2]<<16; + ret |= (u64)value[3]<<24; + ret |= (u64)value[4]<<32; + ret |= (u64)value[5]<<40; + ret |= (u64)value[6]<<48; + ret |= (u64)value[7]<<56; break; //return (value[0]<<0) | (value[1]<<8) | (value[2]<<16) | (value[3]<<24) | (value[4]<<32) | (value[5]<<40) | (value[6]<<48) | (value[7]<<56); } - return u64_return; + return ret; } int u16_to_u8(u8 *out_value, u16 in_value, u8 endianness) diff --git a/makerom/utils.h b/makerom/utils.h index 5d3f10a..8c7d5a4 100644 --- a/makerom/utils.h +++ b/makerom/utils.h @@ -7,7 +7,6 @@ typedef struct } buffer_struct; // Memory -void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base); void endian_memcpy(u8 *destination, u8 *source, u32 size, int endianness); int CopyData(u8 **dest, u8 *source, u64 size); void rndset(void *ptr, u64 num); @@ -15,8 +14,8 @@ void clrmem(void *ptr, u64 num); // MISC u64 align(u64 value, u64 alignment); -u64 min_u64(u64 a, u64 b); -u64 max_u64(u64 a, u64 b); +u64 min64(u64 a, u64 b); +u64 max64(u64 a, u64 b); // Strings void memdump(FILE* fout, const char* prefix, const u8* data, u32 size); @@ -28,6 +27,12 @@ int str_u32_to_u16(u16 **dst, u32 *dst_len, u32 *src, u32 src_len); int str_utf8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len); #endif +// Base64 +bool IsValidB64Char(char chr); +u32 b64_strlen(char *str); +void b64_strcpy(char *dst, char *src); +int b64_decode(u8 *dst, char *src, u32 dst_size); + // Pseudo-Random Number Generator void initRand(void); u8 u8GetRand(void); @@ -37,20 +42,20 @@ u64 u64GetRand(void); //Char IO bool AssertFile(char *filename); -u64 GetFileSize_u64(char *filename); +u64 GetFileSize64(char *filename); int makedir(const char* dir); char *getcwdir(char *buffer,int maxlen); -int TruncateFile_u64(char *filename, u64 filelen); +int TruncateFile64(char *filename, u64 filelen); //Wide Char IO #ifdef _WIN32 -u64 wGetFileSize_u64(u16 *filename); +u64 wGetFileSize64(u16 *filename); #endif //IO Misc u8* ImportFile(char *file, u64 size); void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output); -void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file); +void ReadFile64(void *outbuff, u64 size, u64 offset, FILE *file); int fseek_64(FILE *fp, u64 file_pos); //Data Size conversion diff --git a/makerom/yaml_parser.c b/makerom/yaml_parser.c index 3107cd2..9ebc645 100644 --- a/makerom/yaml_parser.c +++ b/makerom/yaml_parser.c @@ -11,17 +11,14 @@ void CheckEvent(ctr_yaml_context *ctx); void BadYamlFormatting(void); // Code -int GetYamlSettings(user_settings *set) +int GetRsfSettings(user_settings *set) { - memset(&set->common.rsfSet,0,sizeof(rsf_settings)); int ret = 0; if(set->common.rsfPath) { - FILE *rsf = fopen(set->common.rsfPath,"rb"); - if(!rsf) { + if(!AssertFile(set->common.rsfPath)) { fprintf(stderr,"[RSF ERROR] Failed to open %s\n",set->common.rsfPath); return FAILED_TO_OPEN_FILE; } - fclose(rsf); ret = ParseSpecFile(&set->common.rsfSet,set->common.rsfPath, &set->dname); } return ret; diff --git a/makerom/yaml_parser.h b/makerom/yaml_parser.h index 9d9db54..d9cd5d3 100644 --- a/makerom/yaml_parser.h +++ b/makerom/yaml_parser.h @@ -31,7 +31,7 @@ typedef struct } ctr_yaml_context; // Public Prototypes -int GetYamlSettings(user_settings *set); +int GetRsfSettings(user_settings *set); // For scalar events char *GetYamlString(ctr_yaml_context *ctx);