diff --git a/Makefile b/Makefile index 6c9278b..380cf06 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Makerom Sources -UTILS_OBJS = utils.o keyset.o titleid.o +UTILS_OBJS = 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 exefs.o elf.o romfs.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 SETTINGS_OBJS = usersettings.o yamlsettings.o LIB_API_OBJS = crypto.o yaml_ctr.o blz.o @@ -15,13 +15,13 @@ YAML_OBJS = libyaml/api.o libyaml/dumper.o libyaml/emitter.o libyaml/loader.o li # Compiler Settings LIBS = -static-libgcc -static-libstdc++ CXXFLAGS = -I. -CFLAGS = --std=c99 -Wall -I. -DMAKEROM_VER_MAJOR=$(VER_MAJOR) -DMAKEROM_VER_MINOR=$(VER_MINOR) $(MAKEROM_BUILD_FLAGS) +CFLAGS = --std=c99 -Wall -I. -DMAKEROM_VER_MAJOR=$(VER_MAJOR) -DMAKEROM_VER_MINOR=$(VER_MINOR) $(MAKEROM_BUILD_FLAGS) -m64 CC = gcc # MAKEROM Build Settings MAKEROM_BUILD_FLAGS = #-DDEBUG #-DPUBLIC_BUILD VER_MAJOR = 0 -VER_MINOR = 5 +VER_MINOR = 6 OUTPUT = makerom main: build @@ -29,30 +29,12 @@ main: build rebuild: clean build build: $(OBJS) $(POLAR_OBJS) $(YAML_OBJS) - g++ -o $(OUTPUT) $(LIBS) $(OBJS) $(POLAR_OBJS) $(YAML_OBJS) + g++ -o $(OUTPUT) $(LIBS) $(OBJS) $(POLAR_OBJS) $(YAML_OBJS) -m64 clean: rm -rf $(OUTPUT) $(OBJS) $(POLAR_OBJS) $(YAML_OBJS) *.cci *.cia *.cxi *.cfa -# Winfail compatibility +# Windows compatibility rebuildwin: cleanwin build cleanwin: - del /Q objs $(OUTPUT).exe *.o polarssl\*.o libyaml\*.o *.cci *.cia *.cxi *.cfa - -#Test Functions - -ccigen_sdk: - ctr_makerom32 -f card -rsf testdata\Application.rsf -o content_test_sdk.cci -content testdata\app_zeroskey.cxi:0 -content testdata\manual_zeroskey.cfa:1 -content testdata\dlp_zeroskey.cfa:2 -content testdata\update_zeroskey.cfa:7 - del content_test_sdk.cci.xml - -ccigen: - $(OUTPUT) -f card -rsf testdata\Application.rsf -o content_test.cci -content testdata\app_zeroskey.cxi:0 -content testdata\manual_zeroskey.cfa:1 -content testdata\dlp_zeroskey.cfa:2 -content testdata\update_zeroskey.cfa:7 - -ciagen_sdk: - ctr_makecia32 -o content_test.cia -i testdata\app_zeroskey.cxi:0 -i testdata\manual_zeroskey.cfa:1 -i testdata\dlp_zeroskey.cfa:2 - -ciagen: - $(OUTPUT) -f cia -o content_test.cia -content testdata\app_zeroskey.cxi:0 -content testdata\manual_zeroskey.cfa:1 -content testdata\dlp_zeroskey.cfa:2 -encryptcia - -pyramids: - $(OUTPUT) -f cxi -accessdesc app -o pyramids.cxi -code pyramids\code.bin -exheader pyramids\exheader.bin -rsf pyramids\app.rsf -desc pyramids\build.desc -icon pyramids\icon.icn -banner pyramids\banner.bnr -romfs pyramids\romfs.bin + del /Q objs $(OUTPUT).exe *.o polarssl\*.o libyaml\*.o *.cci *.cia *.cxi *.cfa \ No newline at end of file diff --git a/accessdesc.c b/accessdesc.c new file mode 100644 index 0000000..3c3c111 --- /dev/null +++ b/accessdesc.c @@ -0,0 +1,407 @@ +#include "lib.h" +#include "ncch.h" +#include "exheader.h" +#include "accessdesc.h" + +#include "polarssl/base64.h" + +#include "desc_presets.h" +#ifndef PUBLIC_BUILD +#include "desc_dev_sigdata.h" +#include "desc_prod_sigdata.h" +#endif + +const int RSF_RSA_DATA_LEN = 344; +const int RSF_DESC_DATA_LEN = 684; + + +int accessdesc_SignWithKey(exheader_settings *exhdrset, ncch_settings *ncchset); +int accessdesc_GetSignFromRsf(exheader_settings *exhdrset, ncch_settings *ncchset); +int accessdesc_GetSignFromPreset(exheader_settings *exhdrset, ncch_settings *ncchset); +void accessdesc_GetPresetData(u8 **AccessDescData, u8 **DepList, ncch_settings *ncchset); +#ifndef PUBLIC_BUILD +void accessdesc_GetPresetSigData(u8 **AccessDescSig, u8 **CXI_Pubk, u8 **CXI_Privk, ncch_settings *ncchset); +#endif + +bool IsValidB64Char(char chr); +u32 b64_strlen(char *str); +void b64_strcpy(char *dst, char *src); + +int set_AccessDesc(exheader_settings *exhdrset, ncch_settings *ncchset) +{ + if(ncchset->keys->accessDescSign.presetType == not_preset){ + if(ncchset->rsfSet->CommonHeaderKey.Found) // Keydata exists in RSF + return accessdesc_GetSignFromRsf(exhdrset,ncchset); + else if(!ncchset->keys->rsa.requiresPresignedDesc) // Else if The AccessDesc can be signed with key + return accessdesc_SignWithKey(exhdrset,ncchset); + 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"); + return CANNOT_SIGN_ACCESSDESC; + } + } + return accessdesc_GetSignFromPreset(exhdrset,ncchset); +} + +int accessdesc_SignWithKey(exheader_settings *exhdrset, ncch_settings *ncchset) +{ + /* Set RSA Keys */ + memcpy(exhdrset->keys->rsa.cxiHdrPvt,exhdrset->keys->rsa.cciCfaPvt,0x100); + memcpy(exhdrset->keys->rsa.cxiHdrPub,exhdrset->keys->rsa.cciCfaPub,0x100); + memcpy(&exhdrset->exHdr->accessDescriptor.ncchRsaPubKey,exhdrset->keys->rsa.cxiHdrPub,0x100); + /* Copy Data From ExHeader */ + memcpy(&exhdrset->exHdr->accessDescriptor.arm11SystemLocalCapabilities,&exhdrset->exHdr->arm11SystemLocalCapabilities,sizeof(exhdr_ARM11SystemLocalCapabilities)); + u8 *flag = &exhdrset->exHdr->accessDescriptor.arm11SystemLocalCapabilities.flag; + u8 SystemMode = (*flag>>4)&0xF; + u8 AffinityMask = (*flag>>2)&0x3; + u8 IdealProcessor = 1<<((*flag>>0)&0x3); + *flag = (u8)(SystemMode << 4 | AffinityMask << 2 | IdealProcessor); + + memcpy(&exhdrset->exHdr->accessDescriptor.arm11KernelCapabilities,&exhdrset->exHdr->arm11KernelCapabilities,sizeof(exhdr_ARM11KernelCapabilities)); + memcpy(&exhdrset->exHdr->accessDescriptor.arm9AccessControlInfo,&exhdrset->exHdr->arm9AccessControlInfo,sizeof(exhdr_ARM9AccessControlInfo)); + /* Sign AccessDesc */ + return SignAccessDesc(exhdrset->exHdr,exhdrset->keys); +} + +int accessdesc_GetSignFromRsf(exheader_settings *exhdrset, ncch_settings *ncchset) +{ + /* Yaml Option Sanity Checks */ + if(!exhdrset->rsf->CommonHeaderKey.Found){ + fprintf(stderr,"[EXHEADER ERROR] RSF Section \"CommonHeaderKey\" not found\n"); + return COMMON_HEADER_KEY_NOT_FOUND; + } + + if(!exhdrset->rsf->CommonHeaderKey.D){ + ErrorParamNotFound("CommonHeaderKey/D"); + 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)); + return COMMON_HEADER_KEY_NOT_FOUND; + } + + if(!exhdrset->rsf->CommonHeaderKey.Modulus){ + ErrorParamNotFound("CommonHeaderKey/Modulus"); + 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)); + return COMMON_HEADER_KEY_NOT_FOUND; + } + + if(!exhdrset->rsf->CommonHeaderKey.AccCtlDescSign){ + ErrorParamNotFound("CommonHeaderKey/Signature"); + 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)); + return COMMON_HEADER_KEY_NOT_FOUND; + } + + if(!exhdrset->rsf->CommonHeaderKey.AccCtlDescBin){ + ErrorParamNotFound("CommonHeaderKey/Descriptor"); + 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)); + return COMMON_HEADER_KEY_NOT_FOUND; + } + + /* Set RSA Keys */ + int result = 0; + u32 out; + + out = 0x100; + result = base64_decode(exhdrset->keys->rsa.cxiHdrPub,&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,&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; + + /* Set AccessDesc */ + out = 0x100; + result = base64_decode(exhdrset->exHdr->accessDescriptor.signature,&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; + memcpy(exhdrset->exHdr->accessDescriptor.ncchRsaPubKey,exhdrset->keys->rsa.cxiHdrPub,0x100); + + out = 0x200; + result = base64_decode((u8*)&exhdrset->exHdr->accessDescriptor.arm11SystemLocalCapabilities,&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; +} + +int accessdesc_GetSignFromPreset(exheader_settings *exhdrset, ncch_settings *ncchset) +{ + u8 *AccessDescData = NULL; + u8 *DepList = NULL; + + u8 *AccessDescSig = NULL; + u8 *CXI_Pubk = NULL; + u8 *CXI_Privk = NULL; + + accessdesc_GetPresetData(&AccessDescData,&DepList,ncchset); +#ifndef PUBLIC_BUILD + accessdesc_GetPresetSigData(&AccessDescSig,&CXI_Pubk,&CXI_Privk,ncchset); +#endif + + // Error Checking + if(!AccessDescData || !DepList){ + fprintf(stderr,"[EXHEADER ERROR] AccessDesc preset is unavailable, please configure RSF file\n"); + return CANNOT_SIGN_ACCESSDESC; + } + + if((!CXI_Pubk || !CXI_Privk || !AccessDescSig) && ncchset->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"); + return CANNOT_SIGN_ACCESSDESC; + } + + // Setting data in Exheader + // Dependency List + memcpy(exhdrset->exHdr->dependencyList,DepList,0x180); + + // ARM11 Local Capabilities + exhdr_ARM11SystemLocalCapabilities *arm11local = (exhdr_ARM11SystemLocalCapabilities*)(AccessDescData); + // Backing Up Non Preset Details + u8 ProgramID[8]; + memcpy(ProgramID,exhdrset->exHdr->arm11SystemLocalCapabilities.programId,8); + exhdr_StorageInfo StorageInfoBackup; + memcpy(&StorageInfoBackup,&exhdrset->exHdr->arm11SystemLocalCapabilities.storageInfo,sizeof(exhdr_StorageInfo)); + + // Setting Preset Data + memcpy(&exhdrset->exHdr->arm11SystemLocalCapabilities,arm11local,sizeof(exhdr_ARM11SystemLocalCapabilities)); + + // Restoring Non Preset Data + memcpy(exhdrset->exHdr->arm11SystemLocalCapabilities.programId,ProgramID,8); + memcpy(&exhdrset->exHdr->arm11SystemLocalCapabilities.storageInfo,&StorageInfoBackup,sizeof(exhdr_StorageInfo)); + + // Adjusting flags to prevent errors + u8 *flag = &exhdrset->exHdr->arm11SystemLocalCapabilities.flag; + u8 SystemMode = (*flag>>4)&0xF; + u8 AffinityMask = (*flag>>2)&0x3; + u8 IdealProcessor = ((*flag>>0)&0x3)>>1; + *flag = (u8)(SystemMode << 4 | AffinityMask << 2 | IdealProcessor); + exhdrset->exHdr->arm11SystemLocalCapabilities.priority = 0x30; + + // ARM11 Kernel Capabilities + exhdr_ARM11KernelCapabilities *arm11kernel = (exhdr_ARM11KernelCapabilities*)(AccessDescData+sizeof(exhdr_ARM11SystemLocalCapabilities)); + memcpy(&exhdrset->exHdr->arm11KernelCapabilities,arm11kernel,(sizeof(exhdr_ARM11KernelCapabilities))); + + // ARM9 Access Control + exhdr_ARM9AccessControlInfo *arm9 = (exhdr_ARM9AccessControlInfo*)(AccessDescData+sizeof(exhdr_ARM11SystemLocalCapabilities)+sizeof(exhdr_ARM11KernelCapabilities)); + memcpy(&exhdrset->exHdr->arm9AccessControlInfo,arm9,(sizeof(exhdr_ARM9AccessControlInfo))); + + // Setting AccessDesc Area + // Signing normally if possible + if(!ncchset->keys->rsa.requiresPresignedDesc) + return accessdesc_SignWithKey(exhdrset,ncchset); + + // Otherwise set static data & ncch hdr sig info + memcpy(exhdrset->keys->rsa.cxiHdrPub,CXI_Pubk,0x100); + memcpy(exhdrset->keys->rsa.cxiHdrPvt,CXI_Privk,0x100); + memcpy(&exhdrset->exHdr->accessDescriptor.signature,AccessDescSig,0x100); + memcpy(&exhdrset->exHdr->accessDescriptor.ncchRsaPubKey,CXI_Pubk,0x100); + memcpy(&exhdrset->exHdr->accessDescriptor.arm11SystemLocalCapabilities,AccessDescData,0x200); + + return 0; +} + +void accessdesc_GetPresetData(u8 **AccessDescData, u8 **DepList, ncch_settings *ncchset) +{ + if(ncchset->keys->accessDescSign.presetType == app){ + switch(ncchset->keys->accessDescSign.targetFirmware){ + case 1: + *AccessDescData = (u8*)app_1_acex_data; + *DepList = (u8*)sdk1_dep_list; + break; + case 2: + *AccessDescData = (u8*)app_2_acex_data; + *DepList = (u8*)sdk2_dep_list; + break; + case 4: + case 5: + *AccessDescData = (u8*)app_4_acex_data; + *DepList = (u8*)sdk4_dep_list; + break; + case 7: + *AccessDescData = (u8*)app_7_acex_data; + *DepList = (u8*)sdk7_dep_list; + break; + + } + } + else if(ncchset->keys->accessDescSign.presetType == ec_app){ + switch(ncchset->keys->accessDescSign.targetFirmware){ + case 4: + case 5: + *AccessDescData = (u8*)ecapp_4_acex_data; + *DepList = (u8*)sdk4_dep_list; + break; + } + } + else if(ncchset->keys->accessDescSign.presetType == dlp){ + switch(ncchset->keys->accessDescSign.targetFirmware){ + case 1: + *AccessDescData = (u8*)dlp_1_acex_data; + *DepList = (u8*)sdk1_dep_list; + break; + case 2: + *AccessDescData = (u8*)dlp_2_acex_data; + *DepList = (u8*)sdk2_dep_list; + break; + case 4: + case 5: + *AccessDescData = (u8*)dlp_4_acex_data; + *DepList = (u8*)sdk4_dep_list; + break; + } + } + else if(ncchset->keys->accessDescSign.presetType == demo){ + switch(ncchset->keys->accessDescSign.targetFirmware){ + case 4: + case 5: + *AccessDescData = (u8*)demo_4_acex_data; + *DepList = (u8*)sdk4_dep_list; + break; + } + } +} + +#ifndef PUBLIC_BUILD +void accessdesc_GetPresetSigData(u8 **AccessDescSig, u8 **CXI_Pubk, u8 **CXI_Privk, ncch_settings *ncchset) +{ + if(ncchset->keys->accessDescSign.presetType == app){ + switch(ncchset->keys->accessDescSign.targetFirmware){ + case 1: + if(ncchset->keys->keyset == pki_DEVELOPMENT){ + *AccessDescSig = (u8*)app_1_dev_acexsig; + *CXI_Pubk = (u8*)app_1_dev_hdrpub; + *CXI_Privk = (u8*)app_1_dev_hdrpvt; + } + break; + case 2: + if(ncchset->keys->keyset == pki_DEVELOPMENT){ + *AccessDescSig = (u8*)app_2_dev_acexsig; + *CXI_Pubk = (u8*)app_2_dev_hdrpub; + *CXI_Privk = (u8*)app_2_dev_hdrpvt; + } + break; + case 4: + case 5: + if(ncchset->keys->keyset == pki_DEVELOPMENT){ + *AccessDescSig = (u8*)app_4_dev_acexsig; + *CXI_Pubk = (u8*)app_4_dev_hdrpub; + *CXI_Privk = (u8*)app_4_dev_hdrpvt; + } + else if(ncchset->keys->keyset == pki_PRODUCTION){ + *AccessDescSig = (u8*)app_4_prod_acexsig; + *CXI_Pubk = (u8*)app_4_prod_hdrpub; + *CXI_Privk = NULL; + } + break; + case 7: + if(ncchset->keys->keyset == pki_PRODUCTION){ + *AccessDescSig = (u8*)app_7_prod_acexsig; + *CXI_Pubk = (u8*)app_7_prod_hdrpub; + *CXI_Privk = NULL; + } + break; + + } + } + else if(ncchset->keys->accessDescSign.presetType == ec_app){ + switch(ncchset->keys->accessDescSign.targetFirmware){ + case 4: + case 5: + if(ncchset->keys->keyset == pki_PRODUCTION){ + *AccessDescSig = (u8*)ecapp_4_prod_acexsig; + *CXI_Pubk = (u8*)ecapp_4_prod_hdrpub; + *CXI_Privk = NULL; + } + break; + } + } + else if(ncchset->keys->accessDescSign.presetType == dlp){ + switch(ncchset->keys->accessDescSign.targetFirmware){ + case 1: + if(ncchset->keys->keyset == pki_DEVELOPMENT){ + *AccessDescSig = (u8*)dlp_1_dev_acexsig; + *CXI_Pubk = (u8*)dlp_1_dev_hdrpub; + *CXI_Privk = (u8*)dlp_1_dev_hdrpvt; + } + break; + case 2: + if(ncchset->keys->keyset == pki_DEVELOPMENT){ + *AccessDescSig = (u8*)dlp_2_dev_acexsig; + *CXI_Pubk = (u8*)dlp_2_dev_hdrpub; + *CXI_Privk = (u8*)dlp_2_dev_hdrpvt; + } + break; + case 4: + case 5: + if(ncchset->keys->keyset == pki_DEVELOPMENT){ + *AccessDescSig = (u8*)dlp_4_dev_acexsig; + *CXI_Pubk = (u8*)dlp_4_dev_hdrpub; + *CXI_Privk = (u8*)dlp_4_dev_hdrpvt; + } + break; + } + } + else if(ncchset->keys->accessDescSign.presetType == demo){ + switch(ncchset->keys->accessDescSign.targetFirmware){ + case 4: + case 5: + if(ncchset->keys->keyset == pki_DEVELOPMENT){ + *AccessDescSig = (u8*)demo_4_dev_acexsig; + *CXI_Pubk = (u8*)demo_4_dev_hdrpub; + *CXI_Privk = (u8*)demo_4_dev_hdrpvt; + } + break; + } + } +} +#endif + +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/accessdesc.h b/accessdesc.h new file mode 100644 index 0000000..de23839 --- /dev/null +++ b/accessdesc.h @@ -0,0 +1,3 @@ +#pragma once + +int set_AccessDesc(exheader_settings *exhdrset, ncch_settings *ncchset); \ No newline at end of file diff --git a/blz.h b/blz.h index d91ab4e..eb00c17 100644 --- a/blz.h +++ b/blz.h @@ -1,9 +1,6 @@ -#ifndef _BLZ_H_ -#define _BLZ_H_ +#pragma once #define BLZ_NORMAL 0 // normal mode #define BLZ_BEST 1 // best mode -u8 *BLZ_Code(u8 *raw_buffer, int raw_len, u32 *new_len, int best); - -#endif +u8 *BLZ_Code(u8 *raw_buffer, int raw_len, u32 *new_len, int best); \ No newline at end of file diff --git a/certs.h b/certs.h index 3d8ef47..8ee0935 100644 --- a/certs.h +++ b/certs.h @@ -1,5 +1,4 @@ -#ifndef _CERTS_H_ -#define _CERTS_H_ +#pragma once typedef struct { @@ -29,7 +28,6 @@ typedef struct u8 Padding[0x3C]; } ecc_pubk_struct; -#endif // Cert Sizes u32 GetCertSize(u8 *cert); void GetCertSigSectionSizes(u32 *SigSize, u32 *SigPadding, u8 *cert); diff --git a/cia.c b/cia.c index fce6c3f..2b860b4 100644 --- a/cia.c +++ b/cia.c @@ -18,20 +18,22 @@ int get_CIASettings(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, ncch_hdr *NcchHdr, extended_hdr *ExHeader); -int GetMetaRegion(cia_settings *ciaset, extended_hdr *ExHeader, u8 *ExeFs); +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 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); +void GetContentHashes(cia_settings *ciaset); +void EncryptContent(cia_settings *ciaset); + int BuildCIA_CertChain(cia_settings *ciaset); int BuildCIA_Header(cia_settings *ciaset); -int WriteCurrentSectionstoFile(cia_settings *ciaset); -int WriteContentsToFile(cia_settings *ciaset, user_settings *usrset); -int WriteTMDToFile(cia_settings *ciaset); +int WriteCIAtoFile(cia_settings *ciaset); int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, u8 mode); @@ -41,11 +43,14 @@ int build_CIA(user_settings *usrset) int result = 0; // Init Settings - cia_settings *ciaset = malloc(sizeof(cia_settings)); - if(!ciaset) {fprintf(stderr,"[CIA ERROR] MEM ERROR\n"); return MEM_ERROR;} - init_CIASettings(ciaset); + cia_settings *ciaset = calloc(1,sizeof(cia_settings)); + if(!ciaset) { + fprintf(stderr,"[CIA ERROR] MEM ERROR\n"); + return MEM_ERROR; + } // Get Settings + init_CIASettings(ciaset); result = get_CIASettings(ciaset,usrset); if(result) goto finish; @@ -58,6 +63,7 @@ int build_CIA(user_settings *usrset) } // Create CIA Sections + /* Certificate Chain */ result = BuildCIA_CertChain(ciaset); if(result) goto finish; @@ -66,25 +72,17 @@ int build_CIA(user_settings *usrset) result = BuildTicket(ciaset); if(result) goto finish; - /* CIA Header */ - result = BuildCIA_Header(ciaset); - if(result) goto finish; - /* Write To File Current Sections to File */ - /* Explanation : - In order to conserve memory, only one Content is in memory at a time. - This however has the limitation of only being able to generate TMD after all content - has been processed (, encrypted) and written to file. - */ - result = WriteCurrentSectionstoFile(ciaset); - if(result) goto finish; - - result = WriteContentsToFile(ciaset, usrset); - if(result) goto finish; - + /* Title Metadata */ result = BuildTMD(ciaset); if(result) goto finish; - result = WriteTMDToFile(ciaset); + /* CIA Header */ + result = BuildCIA_Header(ciaset); + if(result) goto finish; + + /* Write To File */ + result = WriteCIAtoFile(ciaset); + if(result) goto finish; finish: if(result != FAILED_TO_CREATE_OUTFILE && ciaset->out) fclose(ciaset->out); @@ -124,21 +122,32 @@ int get_CIASettings(cia_settings *ciaset, user_settings *usrset) if(usrset->common.workingFileType == infile_ncch){ result = GetSettingsFromNcch0(ciaset,0); - if(result) return result; + if(result) + return result; result = GetContentFilePtrs(ciaset,usrset); - if(result) return result; + if(result) + return result; + result = ImportNcchContent(ciaset); + if(result) + return result; } else if(usrset->common.workingFileType == infile_srl){ result = GetSettingsFromSrl(ciaset); - if(result) return result; + if(result) + return result; } else if(usrset->common.workingFileType == infile_ncsd){ result = GetSettingsFromCci(ciaset); - if(result) return result; + if(result) + return result; } + GetContentHashes(ciaset); + + if(ciaset->content.encryptCia) + EncryptContent(ciaset); return 0; } @@ -147,8 +156,8 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset) { // General Stuff ciaset->keys = &usrset->common.keys; - ciaset->inFile = usrset->common.workingFile.buffer; - ciaset->inFileSize = usrset->common.workingFile.size; + ciaset->ciaSections.content.buffer = usrset->common.workingFile.buffer; + ciaset->ciaSections.content.size = usrset->common.workingFile.size; u32_to_u8(ciaset->tmd.titleType,TYPE_CTR,BE); ciaset->content.encryptCia = usrset->cia.encryptCia; ciaset->content.IsDlc = usrset->cia.DlcContent; @@ -171,7 +180,7 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset) if(usrset->common.rsfPath) ctr_sha(usrset->common.rsfPath,strlen(usrset->common.rsfPath),hash,CTR_SHA_256); else - ctr_sha(ciaset->inFile,(rand() % 0x200),hash,CTR_SHA_256); + ctr_sha(ciaset->ciaSections.content.buffer,(rand() % 0x200),hash,CTR_SHA_256); // Ticket Data memcpy(ciaset->tik.ticketId,(hash+0x8),8); @@ -199,10 +208,10 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset) int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset) { /* Sanity Checks */ - if(!ciaset->inFile) + if(!ciaset->ciaSections.content.buffer) return CIA_NO_NCCH0; - u8 *ncch0 = (u8*)(ciaset->inFile+ncch0_offset); + u8 *ncch0 = (u8*)(ciaset->ciaSections.content.buffer+ncch0_offset); if(!IsNCCH(NULL,ncch0)){ fprintf(stderr,"[CIA ERROR] Content0 is not NCCH\n"); @@ -227,10 +236,10 @@ int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset) return MEM_ERROR; } memset(ncch_ctx,0x0,sizeof(ncch_struct)); - GetCXIStruct(ncch_ctx,hdr); + GetNCCHStruct(ncch_ctx,hdr); /* Verify Ncch0 (Sig&Hash Checks) */ - int result = VerifyNCCH(ncch0,ciaset->keys,false); + int result = VerifyNCCH(ncch0,ciaset->keys,false,true); if(result == UNABLE_TO_LOAD_NCCH_KEY){ ciaset->content.keyNotFound = true; if(!ciaset->content.IsCfa){ @@ -247,33 +256,38 @@ int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset) endian_memcpy(ciaset->common.titleId,hdr->titleId,8,LE); - /* Getting ExeFs/ExHeader */ - u8 *ExeFs = malloc(ncch_ctx->exefsSize); - if(!ExeFs){ fprintf(stderr,"[CIA ERROR] MEM ERROR\n"); return MEM_ERROR; } - extended_hdr *ExHeader = malloc(ncch_ctx->exhdrSize); - if(!ExHeader){ fprintf(stderr,"[CIA ERROR] MEM ERROR\n"); free(ExeFs); return MEM_ERROR; } + /* Getting ncch key */ + ncch_key_type keyType = GetNCCHKeyType(hdr); + u8 *ncchkey = NULL; + if(!ciaset->content.keyNotFound){ + SetNcchUnfixedKeys(ciaset->keys,ncch0); + ncchkey = GetNCCHKey(keyType,ciaset->keys); + if(keyType == KeyIsUnFixed2) + ncchkey = GetNCCHKey(KeyIsUnFixed,ciaset->keys); + } - if(!(ciaset->content.IsCfa||ciaset->content.keyNotFound)) GetNCCHSection(ExeFs, ncch_ctx->exefsSize, 0, ncch0, ncch_ctx, ciaset->keys, ncch_exefs); - if(!(ciaset->content.IsCfa||ciaset->content.keyNotFound)) GetNCCHSection((u8*)ExHeader, ncch_ctx->exhdrSize, 0, ncch0, ncch_ctx, ciaset->keys, ncch_exhdr); - - result = GetCIADataFromNcch(ciaset,hdr,ExHeader); // Data For TMD + /* Get TMD Data from ncch */ + result = GetCIADataFromNcch(ciaset,ncch0,ncch_ctx,ncchkey); // Data For TMD if(result) goto finish; - result = GetMetaRegion(ciaset,ExHeader,ExeFs); // Meta Region + /* Get META Region from ncch */ + result = GetMetaRegion(ciaset,ncch0,ncch_ctx,ncchkey); // Meta Region /* Finish */ finish: - free(ExeFs); - free(ExHeader); - /* Return */ free(ncch_ctx); return result; } -int GetCIADataFromNcch(cia_settings *ciaset, ncch_hdr *NcchHdr, extended_hdr *ExHeader) +int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key) { + extended_hdr *exhdr = malloc(0x400); + memcpy(exhdr,ncch+ncch_ctx->exhdrOffset,0x400); + if(key != NULL) + CryptNCCHSection((u8*)exhdr,0x400,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) u32_to_u8(ciaset->tmd.savedataSize,0,LE); - else u32_to_u8(ciaset->tmd.savedataSize,(u32)GetSaveDataSize_frm_exhdr(ExHeader),LE); + else u32_to_u8(ciaset->tmd.savedataSize,(u32)GetSaveDataSize_frm_exhdr(exhdr),LE); if(ciaset->content.overrideSaveDataSize){ u64 size = 0; GetSaveDataSizeFromString(&size,ciaset->content.overrideSaveDataSize); @@ -296,19 +310,42 @@ int GetCIADataFromNcch(cia_settings *ciaset, ncch_hdr *NcchHdr, extended_hdr *Ex return CIA_BAD_VERSION; } // Setting remaster ver - ciaset->common.titleVersion[0] = GetRemasterVersion_frm_exhdr(ExHeader); + ciaset->common.titleVersion[0] = GetRemasterVersion_frm_exhdr(exhdr); } u16 version = SetupVersion(ciaset->common.titleVersion[0],ciaset->common.titleVersion[1],ciaset->common.titleVersion[2]); ciaset->tik.version = version; ciaset->tmd.version = version; + + free(exhdr); return 0; } -int GetMetaRegion(cia_settings *ciaset, extended_hdr *ExHeader, u8 *ExeFs) +int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key) { - if(ciaset->content.IsCfa || ciaset->content.keyNotFound) return 0; - ciaset->ciaSections.meta.size = sizeof(cia_metadata) + GetExeFsSectionSize("icon",ExeFs); + if(ciaset->content.IsCfa || ciaset->content.keyNotFound) + return 0; + + extended_hdr *exhdr = malloc(0x400); + memcpy(exhdr,ncch+ncch_ctx->exhdrOffset,0x400); + if(key != NULL) + CryptNCCHSection((u8*)exhdr,0x400,0,ncch_ctx,key,ncch_exhdr); + + exefs_hdr *exefsHdr = malloc(sizeof(exefs_hdr)); + memcpy(exefsHdr,ncch+ncch_ctx->exefsOffset,sizeof(exefs_hdr)); + if(key != NULL) + CryptNCCHSection((u8*)exefsHdr,sizeof(exefs_hdr),0,ncch_ctx,key,ncch_exefs); + + u32 icon_size = 0; + u32 icon_offset = 0; + for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){ + if(strncmp(exefsHdr->fileHdr[i].name,"icon",8) == 0){ + icon_size = u8_to_u32(exefsHdr->fileHdr[i].size,LE); + icon_offset = u8_to_u32(exefsHdr->fileHdr[i].offset,LE) + 0x200; + } + } + + ciaset->ciaSections.meta.size = sizeof(cia_metadata) + icon_size; ciaset->ciaSections.meta.buffer = malloc(ciaset->ciaSections.meta.size); if(!ciaset->ciaSections.meta.buffer){ fprintf(stderr,"[CIA ERROR] Not enough memory\n"); @@ -316,13 +353,18 @@ int GetMetaRegion(cia_settings *ciaset, extended_hdr *ExHeader, u8 *ExeFs) } cia_metadata *hdr = (cia_metadata*)ciaset->ciaSections.meta.buffer; memset(hdr,0,sizeof(cia_metadata)); - GetDependencyList_frm_exhdr(hdr->dependencyList,ExHeader); - GetCoreVersion_frm_exhdr(hdr->coreVersion,ExHeader); - if(DoesExeFsSectionExist("icon",ExeFs)){ + GetDependencyList_frm_exhdr(hdr->dependencyList,exhdr); + GetCoreVersion_frm_exhdr(hdr->coreVersion,exhdr); + if(icon_size > 0){ u8 *IconDestPos = (ciaset->ciaSections.meta.buffer + sizeof(cia_metadata)); - memcpy(IconDestPos,GetExeFsSection("icon",ExeFs),GetExeFsSectionSize("icon",ExeFs)); + memcpy(IconDestPos,ncch+ncch_ctx->exefsOffset+icon_offset,icon_size); + if(key != NULL) + CryptNCCHSection(IconDestPos,icon_size,icon_offset,ncch_ctx,key,ncch_exefs); //memdump(stdout,"Icon: ",IconDestPos,0x10); } + + free(exefsHdr); + free(exhdr); return 0; } @@ -354,9 +396,6 @@ int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset) // Get Data from ncch HDR GetNCCH_CommonHDR(hdr,ciaset->content.contentFilePtrs[j],NULL); - - // Get TitleID - memcpy(ciaset->content.contentTitleId[j],hdr->titleId,8); // Get Size ciaset->content.contentSize[j] = GetNCCH_MediaSize(hdr)*GetNCCH_MediaUnitSize(hdr); @@ -384,10 +423,35 @@ int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset) return 0; } +int ImportNcchContent(cia_settings *ciaset) +{ + ciaset->ciaSections.content.buffer = realloc(ciaset->ciaSections.content.buffer,ciaset->content.totalContentSize); + if(!ciaset->ciaSections.content.buffer){ + fprintf(stderr,"[CIA ERROR] Not enough memory\n"); + return MEM_ERROR; + } + ncch_hdr *ncch0hdr = (ncch_hdr*)(ciaset->ciaSections.content.buffer+0x100); + for(int i = 1; i < ciaset->content.contentCount; i++){ + // Import + fread(ciaset->ciaSections.content.buffer+ciaset->content.contentOffset[i],ciaset->content.contentSize[i],1,ciaset->content.contentFilePtrs[i]); + if(ModifyNcchIds(ciaset->ciaSections.content.buffer+ciaset->content.contentOffset[i], NULL, ncch0hdr->programId, ciaset->keys) != 0) + return -1; + + // Set Additional Flags + if(ciaset->content.IsDlc) + ciaset->content.contentFlags[i] |= content_Optional; + + //if(unknown condition) + // ciaset->content.contentFlags[i] |= content_Shared; + } + ciaset->ciaSections.content.size = ciaset->content.totalContentSize; + return 0; +} + int GetSettingsFromSrl(cia_settings *ciaset) { - SRL_Header *hdr = (SRL_Header*)ciaset->inFile; - if(!hdr || ciaset->inFileSize < sizeof(SRL_Header)) { + srl_hdr *hdr = (srl_hdr*)ciaset->ciaSections.content.buffer; + if(!hdr || ciaset->ciaSections.content.size < sizeof(srl_hdr)) { fprintf(stderr,"[CIA ERROR] Invalid TWL SRL File\n"); return FAILED_TO_IMPORT_FILE; } @@ -406,35 +470,33 @@ int GetSettingsFromSrl(cia_settings *ciaset) ciaset->tmd.twlFlag = ((hdr->reserved_flags[3] & 6) >> 1); // Get Remaster Version - u16 version = SetupVersion(hdr->rom_version,ciaset->common.titleVersion[1],0); + u16 version = SetupVersion(hdr->romVersion,ciaset->common.titleVersion[1],0); ciaset->tik.version = version; ciaset->tmd.version = version; // Get SaveDataSize (Public and Private) - memcpy(ciaset->tmd.savedataSize,hdr->pub_save_data_size,4); - memcpy(ciaset->tmd.privSavedataSize,hdr->priv_save_data_size,4); + memcpy(ciaset->tmd.savedataSize,hdr->pubSaveDataSize,4); + memcpy(ciaset->tmd.privSavedataSize,hdr->privSaveDataSize,4); // Setting CIA Content Settings ciaset->content.contentCount = 1; ciaset->content.contentOffset[0] = 0; - ciaset->content.contentSize[0] = ciaset->inFileSize; - ciaset->content.totalContentSize = ciaset->inFileSize; + ciaset->content.contentSize[0] = ciaset->ciaSections.content.size; + ciaset->content.totalContentSize = ciaset->ciaSections.content.size; return 0; } - - int GetSettingsFromCci(cia_settings *ciaset) { int result = 0; - if(!IsCci(ciaset->inFile)){ + if(!IsCci(ciaset->ciaSections.content.buffer)){ fprintf(stderr,"[CIA ERROR] Invalid CCI file\n"); return FAILED_TO_IMPORT_FILE; } - u32 ncch0_offset = GetPartitionOffset(ciaset->inFile,0); + u32 ncch0_offset = GetPartitionOffset(ciaset->ciaSections.content.buffer,0); if(!ncch0_offset){ fprintf(stderr,"[CIA ERROR] Invalid CCI file (invalid ncch0)\n"); return FAILED_TO_IMPORT_FILE; @@ -445,36 +507,45 @@ int GetSettingsFromCci(cia_settings *ciaset) fprintf(stderr,"Import of Ncch 0 failed(%d)\n",result); return result; } - ciaset->content.contentCount = 1; - ciaset->content.cciContentOffsets[0] = ncch0_offset; - ncch_hdr *hdr = malloc(sizeof(ncch_hdr)); + int j = 1; + + u64 cciContentOffsets[CCI_MAX_CONTENT]; + cciContentOffsets[0] = ncch0_offset; + ncch_hdr *hdr; for(int i = 1; i < 8; i++){ - if(GetPartitionSize(ciaset->inFile,i)){ - ciaset->content.cciContentOffsets[ciaset->content.contentCount] = GetPartitionOffset(ciaset->inFile,i); + if(GetPartitionSize(ciaset->ciaSections.content.buffer,i)){ + cciContentOffsets[j] = GetPartitionOffset(ciaset->ciaSections.content.buffer,i); // Get Data from ncch HDR - GetNCCH_CommonHDR(hdr,NULL,GetPartition(ciaset->inFile,i)); + GetNCCH_CommonHDR(hdr,NULL,GetPartition(ciaset->ciaSections.content.buffer,i)); + hdr = (ncch_hdr*)(ciaset->ciaSections.content.buffer + cciContentOffsets[j] + 0x100); // Get Size - ciaset->content.contentSize[ciaset->content.contentCount] = GetPartitionSize(ciaset->inFile,i); - ciaset->content.contentOffset[ciaset->content.contentCount] = ciaset->content.totalContentSize; + ciaset->content.contentSize[j] = GetPartitionSize(ciaset->ciaSections.content.buffer,i); + ciaset->content.contentOffset[j] = ciaset->content.totalContentSize; - ciaset->content.totalContentSize += ciaset->content.contentSize[ciaset->content.contentCount]; + ciaset->content.totalContentSize += ciaset->content.contentSize[j]; // Get ID u8 hash[0x20]; ctr_sha((u8*)hdr,0x200,hash,CTR_SHA_256); - ciaset->content.contentId[ciaset->content.contentCount] = u8_to_u32(hash,BE); + ciaset->content.contentId[j] = u8_to_u32(hash,BE); // Get Index - ciaset->content.contentIndex[ciaset->content.contentCount] = i; + ciaset->content.contentIndex[j] = i; // Increment Content Count - ciaset->content.contentCount++; + j++; } } - free(hdr); + ciaset->content.contentCount = j; + for(int i = 0; i < ciaset->content.contentCount; i++){ // Re-organising content positions in memory + u8 *cci_pos = (ciaset->ciaSections.content.buffer + cciContentOffsets[i]); + u8 *cia_pos = (ciaset->ciaSections.content.buffer + ciaset->content.contentOffset[i]); + memcpy(cia_pos,cci_pos,ciaset->content.contentSize[i]); + } + ciaset->ciaSections.content.size = ciaset->content.totalContentSize; return 0; } @@ -483,6 +554,21 @@ u16 SetupVersion(u16 Major, u16 Minor, u16 Micro) return (((Major << 10) & 0xFC00) | ((Minor << 4) & 0x3F0) | (Micro & 0xf)); } +void GetContentHashes(cia_settings *ciaset) +{ + for(int i = 0; i < ciaset->content.contentCount; i++) + ctr_sha(ciaset->ciaSections.content.buffer+ciaset->content.contentOffset[i],ciaset->content.contentSize[i],ciaset->content.contentHash[i],CTR_SHA_256); +} + +void EncryptContent(cia_settings *ciaset) +{ + for(int i = 0; i < ciaset->content.contentCount; i++){ + ciaset->content.contentFlags[i] |= content_Encrypted; + u8 *content = ciaset->ciaSections.content.buffer+ciaset->content.contentOffset[i]; + CryptContent(content, content, ciaset->content.contentSize[i], ciaset->common.titleKey, i, ENC); + } +} + int BuildCIA_CertChain(cia_settings *ciaset) { ciaset->ciaSections.certChain.size = GetCertSize(ciaset->keys->certs.caCert) + GetCertSize(ciaset->keys->certs.xsCert) + GetCertSize(ciaset->keys->certs.cpCert); @@ -512,9 +598,6 @@ int BuildCIA_Header(cia_settings *ciaset) // Clearing memset(hdr,0,sizeof(cia_hdr)); - // Predict TMD Size - ciaset->ciaSections.tmd.size = PredictTMDSize(ciaset->content.contentCount); - // Setting Data u32_to_u8(hdr->hdrSize,sizeof(cia_hdr),LE); u16_to_u8(hdr->type,0x0,LE); @@ -526,11 +609,11 @@ int BuildCIA_Header(cia_settings *ciaset) u64_to_u8(hdr->contentSize,ciaset->content.totalContentSize,LE); // Recording Offsets - ciaset->ciaSections.certChainOffset = align_value(sizeof(cia_hdr),0x40); - ciaset->ciaSections.tikOffset = align_value(ciaset->ciaSections.certChainOffset+ciaset->ciaSections.certChain.size,0x40); - ciaset->ciaSections.tmdOffset = align_value(ciaset->ciaSections.tikOffset+ciaset->ciaSections.tik.size,0x40); - ciaset->ciaSections.contentOffset = align_value(ciaset->ciaSections.tmdOffset+ciaset->ciaSections.tmd.size,0x40); - ciaset->ciaSections.metaOffset = align_value(ciaset->ciaSections.contentOffset+ciaset->content.totalContentSize,0x40); + ciaset->ciaSections.certChainOffset = align(sizeof(cia_hdr),0x40); + ciaset->ciaSections.tikOffset = align(ciaset->ciaSections.certChainOffset+ciaset->ciaSections.certChain.size,0x40); + ciaset->ciaSections.tmdOffset = align(ciaset->ciaSections.tikOffset+ciaset->ciaSections.tik.size,0x40); + ciaset->ciaSections.contentOffset = align(ciaset->ciaSections.tmdOffset+ciaset->ciaSections.tmd.size,0x40); + ciaset->ciaSections.metaOffset = align(ciaset->ciaSections.contentOffset+ciaset->content.totalContentSize,0x40); for(int i = 0; i < ciaset->content.contentCount; i++){ // This works by treating the 0x2000 byte index array as an array of 2048 u32 values @@ -553,79 +636,17 @@ int BuildCIA_Header(cia_settings *ciaset) return 0; } -int WriteCurrentSectionstoFile(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); WriteBuffer(ciaset->ciaSections.tik.buffer,ciaset->ciaSections.tik.size,ciaset->ciaSections.tikOffset,ciaset->out); + WriteBuffer(ciaset->ciaSections.tmd.buffer,ciaset->ciaSections.tmd.size,ciaset->ciaSections.tmdOffset,ciaset->out); + WriteBuffer(ciaset->ciaSections.content.buffer,ciaset->ciaSections.content.size,ciaset->ciaSections.contentOffset,ciaset->out); WriteBuffer(ciaset->ciaSections.meta.buffer,ciaset->ciaSections.meta.size,ciaset->ciaSections.metaOffset,ciaset->out); return 0; } -int WriteContentsToFile(cia_settings *ciaset, user_settings *usrset) // re-implement so it's one for loop -{ - u8 *content0 = ciaset->inFile; - if(usrset->common.workingFileType == infile_ncsd) content0 = (u8*)(ciaset->inFile+ciaset->content.cciContentOffsets[0]); - - ctr_sha(content0,ciaset->content.contentSize[0],ciaset->content.contentHash[0],CTR_SHA_256); - if(ciaset->content.encryptCia) { - ciaset->content.contentFlags[0] |= content_Encrypted; - CryptContent(content0,content0,ciaset->content.contentSize[0],ciaset->common.titleKey,ciaset->content.contentIndex[0],ENC); - } - WriteBuffer(content0,ciaset->content.contentSize[0],ciaset->content.contentOffset[0]+ciaset->ciaSections.contentOffset,ciaset->out); - - // Free Buffer if Not CCI, as the rest of the content are in this image - if(usrset->common.workingFileType != infile_ncsd){ - free(usrset->common.workingFile.buffer); - usrset->common.workingFile.buffer = NULL; - usrset->common.workingFile.size = 0; - } - - // Add additional contents, recreating them with their new TitleID - if(usrset->common.workingFileType == infile_ncch){ - u8 TitleId[8]; - endian_memcpy(TitleId,ciaset->common.titleId,8,LE); - for(int i = 1; i < ciaset->content.contentCount; i++){ - u8 *content = RetargetNCCH(ciaset->content.contentFilePtrs[i],ciaset->content.contentSize[i],ciaset->content.contentTitleId[i],TitleId,ciaset->keys); - if(!content){ - fprintf(stderr,"[CIA ERROR] Could not import content %d to CIA\n",i); - return FAILED_TO_IMPORT_FILE; - } - ctr_sha(content,ciaset->content.contentSize[i],ciaset->content.contentHash[i],CTR_SHA_256); - if(ciaset->content.IsDlc) - ciaset->content.contentFlags[i] |= content_Optional; - if(ciaset->content.encryptCia) { - ciaset->content.contentFlags[i] |= content_Encrypted; - CryptContent(content,content,ciaset->content.contentSize[i],ciaset->common.titleKey,ciaset->content.contentIndex[i],ENC); - } - WriteBuffer(content,ciaset->content.contentSize[i],ciaset->content.contentOffset[i]+ciaset->ciaSections.contentOffset,ciaset->out); - free(content); - } - } - else if(usrset->common.workingFileType == infile_ncsd){ // This makes the assumption the CCI is valid - for(int i = 1; i < ciaset->content.contentCount; i++){ - u8 *content = (u8*)(ciaset->inFile+ciaset->content.cciContentOffsets[i]); - ctr_sha(content,ciaset->content.contentSize[i],ciaset->content.contentHash[i],CTR_SHA_256); - if(ciaset->content.encryptCia) { - ciaset->content.contentFlags[i] |= content_Encrypted; - CryptContent(content,content,ciaset->content.contentSize[i],ciaset->common.titleKey,ciaset->content.contentIndex[i],ENC); - } - WriteBuffer(content,ciaset->content.contentSize[i],ciaset->content.contentOffset[i]+ciaset->ciaSections.contentOffset,ciaset->out); - } - free(usrset->common.workingFile.buffer); - usrset->common.workingFile.buffer = NULL; - usrset->common.workingFile.size = 0; - } - - - return 0; -} - -int WriteTMDToFile(cia_settings *ciaset) -{ - WriteBuffer(ciaset->ciaSections.tmd.buffer,ciaset->ciaSections.tmd.size,ciaset->ciaSections.tmdOffset,ciaset->out); - return 0; -} int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, u8 mode) { diff --git a/cia.h b/cia.h index 6b36c2b..2e7d47a 100644 --- a/cia.h +++ b/cia.h @@ -1,3 +1,5 @@ +#pragma once + // Enums typedef enum { @@ -84,7 +86,6 @@ typedef struct bool keyNotFound; FILE **contentFilePtrs; - u64 cciContentOffsets[CCI_MAX_CONTENT]; /* Misc Records */ u16 contentCount; @@ -96,28 +97,26 @@ typedef struct u16 contentIndex[CIA_MAX_CONTENT]; u16 contentFlags[CIA_MAX_CONTENT]; u32 contentId[CIA_MAX_CONTENT]; - u8 contentHash[CIA_MAX_CONTENT][0x20]; - - u8 contentTitleId[CIA_MAX_CONTENT][8]; - + u8 contentHash[CIA_MAX_CONTENT][0x20]; } content; struct{ - COMPONENT_STRUCT ciaHdr; + buffer_struct ciaHdr; u32 certChainOffset; - COMPONENT_STRUCT certChain; + buffer_struct certChain; u32 tikOffset; - COMPONENT_STRUCT tik; + buffer_struct tik; u32 tmdOffset; - COMPONENT_STRUCT tmd; + buffer_struct tmd; u32 metaOffset; - COMPONENT_STRUCT meta; + buffer_struct meta; u64 contentOffset; + buffer_struct content; } ciaSections; } cia_settings; diff --git a/crr.h b/crr.h new file mode 100644 index 0000000..3f87e75 --- /dev/null +++ b/crr.h @@ -0,0 +1,25 @@ +#pragma once + +typedef struct +{ + u8 magic[4]; + u8 reserved0[4]; + u8 node0[4]; + u8 node1[4]; + u8 debugInfoOffset[4]; //s32 + u8 debugInfoSize[4]; //s32 + u8 reserved1[8]; + u8 uniqueIdMask[4]; + u8 uniqueIdPattern[4]; + u8 reserved2[0x18]; + u8 signPublicKey[0x100]; + u8 signPublicKeySign[0x100]; + u8 sign[0x100]; + u8 uniqueId[4]; + u8 size[4]; + u8 reserved3[8]; + u8 hashOffset[4]; + u8 numHash[4]; + u8 moduleIdOffset[4]; + u8 moduleIdSize[4]; +} crr_hdr; \ No newline at end of file diff --git a/crypto.c b/crypto.c index cc7b0fb..8fcd352 100644 --- a/crypto.c +++ b/crypto.c @@ -10,11 +10,11 @@ void ctr_sha(void *data, u64 size, u8 *hash, int mode) } } -u8* AesKeyScrambler(u8 *KeyX, u8 *KeyY) +u8* AesKeyScrambler(u8 *Key, u8 *KeyX, u8 *KeyY) { u32 *KeyX_u32 = (u32*) KeyX; u32 *KeyY_u32 = (u32*) KeyY; - u32 *Key = malloc(16); + u32 *Key_u32 = (u32*) Key; for(int i = 0,j; i < 4; i++) { @@ -40,11 +40,11 @@ u8* AesKeyScrambler(u8 *KeyX, u8 *KeyY) //*/ } - Key[j] = KeyX_u32[i] ^ KeyY_u32[i]; + Key_u32[j] = KeyX_u32[i] ^ KeyY_u32[i]; } // Done Stuff - return (u8*)Key; + return (u8*)Key_u32; } void ctr_add_counter(ctr_aes_context* ctx, u32 carry) diff --git a/crypto.h b/crypto.h index c2c3f98..19b5163 100644 --- a/crypto.h +++ b/crypto.h @@ -1,5 +1,4 @@ -#ifndef _CTR_CRYPTO_H_ -#define _CTR_CRYPTO_H_ +#pragma once #include "polarssl/config.h" #include "polarssl/aes.h" @@ -74,7 +73,7 @@ extern "C" { // SHA void ctr_sha(void *data, u64 size, u8 *hash, int mode); // AES -u8* AesKeyScrambler(u8 *KeyX, u8 *KeyY); +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]); @@ -97,6 +96,4 @@ int ctr_sig(void *data, u64 size, u8 *signature, u8 *modulus, u8 *private_exp, u #ifdef __cplusplus } -#endif - -#endif +#endif \ No newline at end of file diff --git a/desc_dev_sigdata.h b/desc_dev_sigdata.h index 2eb7964..ce21d74 100644 --- a/desc_dev_sigdata.h +++ b/desc_dev_sigdata.h @@ -1,5 +1,4 @@ -#ifndef _DESC_DEV_SIGDATA_H_ -#define _DESC_DEV_SIGDATA_H_ +#pragma once /* CTR_SDK 1 (1.2.0) */ // APP @@ -114,5 +113,4 @@ static const unsigned char dlp_4_dev_hdrpvt[0x100] = static const unsigned char dlp_4_dev_acexsig[0x100] = { 0xAC, 0xE2, 0xA7, 0xC3, 0x00, 0xDE, 0xE8, 0xE9, 0xE0, 0x03, 0xB3, 0x54, 0x08, 0xA8, 0xF8, 0x3A, 0x2E, 0xD8, 0x10, 0x6B, 0xEC, 0xDC, 0x4E, 0xEE, 0x62, 0x10, 0x71, 0x49, 0xD4, 0x43, 0xB1, 0x0E, 0x6B, 0x8C, 0xD7, 0x54, 0xD5, 0x62, 0x28, 0x3F, 0xAA, 0xDE, 0xA9, 0x7D, 0xED, 0x37, 0x7C, 0xE7, 0x89, 0x0B, 0x02, 0xB2, 0x72, 0x4B, 0x17, 0xDB, 0xE2, 0xD3, 0x7C, 0x94, 0x12, 0x3F, 0x2E, 0xA1, 0x08, 0x99, 0xCC, 0x7F, 0x93, 0xE6, 0x38, 0xC9, 0x37, 0x84, 0xD7, 0x11, 0x9D, 0x02, 0x4D, 0x66, 0xB4, 0x70, 0x9F, 0xD8, 0xC6, 0xDD, 0xD5, 0x13, 0x52, 0xF0, 0xA6, 0x78, 0x8C, 0x8E, 0x15, 0xA0, 0xA1, 0xF3, 0xC4, 0xC3, 0x48, 0x45, 0xA5, 0xBE, 0xC9, 0x7A, 0x8B, 0xD3, 0x95, 0xA5, 0x4C, 0xF1, 0xB3, 0x0C, 0x6C, 0x76, 0xA7, 0x57, 0xA1, 0x77, 0xDF, 0x2F, 0xC8, 0x06, 0xA6, 0x0D, 0x1A, 0x09, 0xE4, 0x38, 0x64, 0x07, 0xBE, 0x6A, 0xD2, 0xA0, 0xC0, 0xEC, 0x09, 0x64, 0x9F, 0x0D, 0x93, 0x0C, 0x89, 0xA2, 0x71, 0xD6, 0xC6, 0xC2, 0x54, 0x79, 0x2A, 0xA4, 0x31, 0x28, 0x24, 0x1A, 0xF3, 0x56, 0x78, 0x63, 0x99, 0x97, 0xA5, 0xCE, 0x8F, 0x52, 0x7A, 0x79, 0x51, 0xEE, 0x4C, 0x8B, 0x00, 0x9D, 0x5C, 0x3E, 0xD5, 0xAA, 0x24, 0x9C, 0x94, 0xC6, 0xA3, 0x99, 0x1B, 0x2D, 0xD4, 0xFF, 0xB4, 0x25, 0x73, 0x13, 0x33, 0x9F, 0x03, 0x6F, 0x1E, 0x75, 0xC4, 0x70, 0xF4, 0x07, 0x4F, 0x18, 0xFE, 0xBD, 0x8F, 0x2C, 0x9B, 0x33, 0xD4, 0x30, 0xA7, 0x18, 0x4A, 0xF1, 0xA4, 0xDD, 0x78, 0x41, 0xA0, 0xB8, 0x02, 0x8D, 0x51, 0x96, 0xBE, 0xE7, 0x17, 0x94, 0x66, 0x65, 0x27, 0xF7, 0x69, 0x48, 0x7E, 0xA9, 0x08, 0x71, 0x20, 0x76, 0xB7, 0x8E, 0xD2, 0xBF, 0x5C, 0x7E, 0x5E, 0x06, 0x45, 0xAB, 0x7E, 0x2E -}; -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/desc_presets.h b/desc_presets.h index d9d6198..9a2e459 100644 --- a/desc_presets.h +++ b/desc_presets.h @@ -1,5 +1,4 @@ -#ifndef _DESC_PRESETS_H_ -#define _DESC_PRESETS_H_ +#pragma once /* CTR_SDK 1 (1.2.0) */ // DependencyList @@ -80,6 +79,4 @@ static const unsigned char sdk7_dep_list[0x180] = static const unsigned char app_7_acex_data[0x200] = { 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x18, 0x9E, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x68, 0x69, 0x6F, 0x46, 0x49, 0x4F, 0x00, 0x24, 0x68, 0x6F, 0x73, 0x74, 0x69, 0x6F, 0x30, 0x24, 0x68, 0x6F, 0x73, 0x74, 0x69, 0x6F, 0x31, 0x63, 0x66, 0x67, 0x3A, 0x75, 0x00, 0x00, 0x00, 0x66, 0x73, 0x3A, 0x55, 0x53, 0x45, 0x52, 0x00, 0x67, 0x73, 0x70, 0x3A, 0x3A, 0x47, 0x70, 0x75, 0x68, 0x69, 0x64, 0x3A, 0x55, 0x53, 0x45, 0x52, 0x6E, 0x64, 0x6D, 0x3A, 0x75, 0x00, 0x00, 0x00, 0x70, 0x78, 0x69, 0x3A, 0x64, 0x65, 0x76, 0x00, 0x41, 0x50, 0x54, 0x3A, 0x41, 0x00, 0x00, 0x00, 0x61, 0x63, 0x3A, 0x75, 0x00, 0x00, 0x00, 0x00, 0x61, 0x63, 0x74, 0x3A, 0x75, 0x00, 0x00, 0x00, 0x61, 0x6D, 0x3A, 0x61, 0x70, 0x70, 0x00, 0x00, 0x62, 0x6F, 0x73, 0x73, 0x3A, 0x55, 0x00, 0x00, 0x63, 0x61, 0x6D, 0x3A, 0x75, 0x00, 0x00, 0x00, 0x63, 0x65, 0x63, 0x64, 0x3A, 0x75, 0x00, 0x00, 0x64, 0x6C, 0x70, 0x3A, 0x46, 0x4B, 0x43, 0x4C, 0x64, 0x6C, 0x70, 0x3A, 0x53, 0x52, 0x56, 0x52, 0x64, 0x73, 0x70, 0x3A, 0x3A, 0x44, 0x53, 0x50, 0x66, 0x72, 0x64, 0x3A, 0x75, 0x00, 0x00, 0x00, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x43, 0x00, 0x00, 0x69, 0x72, 0x3A, 0x55, 0x53, 0x45, 0x52, 0x00, 0x6C, 0x64, 0x72, 0x3A, 0x72, 0x6F, 0x00, 0x00, 0x6D, 0x69, 0x63, 0x3A, 0x75, 0x00, 0x00, 0x00, 0x6E, 0x65, 0x77, 0x73, 0x3A, 0x75, 0x00, 0x00, 0x6E, 0x69, 0x6D, 0x3A, 0x61, 0x6F, 0x63, 0x00, 0x6E, 0x77, 0x6D, 0x3A, 0x3A, 0x55, 0x44, 0x53, 0x70, 0x74, 0x6D, 0x3A, 0x75, 0x00, 0x00, 0x00, 0x73, 0x6F, 0x63, 0x3A, 0x55, 0x00, 0x00, 0x00, 0x73, 0x73, 0x6C, 0x3A, 0x43, 0x00, 0x00, 0x00, 0x79, 0x32, 0x72, 0x3A, 0x75, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x9F, 0xFA, 0xF0, 0xFF, 0xBF, 0xFF, 0xF1, 0xE7, 0x3F, 0x00, 0xF2, 0x00, 0xF0, 0x91, 0xFF, 0x00, 0xF6, 0x91, 0xFF, 0x50, 0xFF, 0x81, 0xFF, 0x58, 0xFF, 0x81, 0xFF, 0x70, 0xFF, 0x81, 0xFF, 0x78, 0xFF, 0x81, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0x00, 0x02, 0x00, 0xFE, 0x27, 0x02, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/desc_prod_sigdata.h b/desc_prod_sigdata.h index 73826ca..5e7d0e2 100644 --- a/desc_prod_sigdata.h +++ b/desc_prod_sigdata.h @@ -1,5 +1,4 @@ -#ifndef _DESC_PROD_SIGDATA_H_ -#define _DESC_PROD_SIGDATA_H_ +#pragma once /* CTR_SDK 4/5 (4.2.8) */ // APP @@ -35,4 +34,3 @@ static const unsigned char app_7_prod_acexsig[0x100] = { 0x06, 0xDD, 0x68, 0x17, 0xAA, 0x40, 0x3A, 0x75, 0xD2, 0xCF, 0xA2, 0x5A, 0xC8, 0x1B, 0x74, 0x9D, 0x91, 0xCD, 0x38, 0x4E, 0xCA, 0x19, 0x60, 0x8E, 0x39, 0x71, 0x6C, 0xB9, 0xF9, 0x9F, 0x68, 0x44, 0xCF, 0x33, 0x94, 0x54, 0x72, 0xCC, 0xC6, 0x33, 0x96, 0x9F, 0x12, 0x07, 0xE9, 0x38, 0x87, 0x70, 0x11, 0x51, 0xFD, 0xBF, 0xD9, 0x2D, 0xFA, 0x3F, 0x70, 0x42, 0x75, 0x39, 0xE3, 0x97, 0x85, 0xAF, 0x7B, 0xC5, 0x87, 0x9B, 0x0B, 0xF9, 0xE4, 0x1C, 0xC5, 0x6B, 0x44, 0x2A, 0x10, 0x14, 0x86, 0xAA, 0xFE, 0x9E, 0x5B, 0x1D, 0x15, 0xBA, 0x8C, 0x34, 0xA2, 0xAF, 0x14, 0xD0, 0xD4, 0x0E, 0x7B, 0x3A, 0xD5, 0x3C, 0x53, 0xDB, 0x7C, 0xBE, 0x44, 0x58, 0x79, 0x42, 0x23, 0x3A, 0x77, 0xA3, 0x2C, 0xB9, 0xEB, 0x62, 0x19, 0x94, 0x2B, 0xA0, 0x67, 0x94, 0xC6, 0xB2, 0x90, 0xC6, 0x61, 0xFD, 0x43, 0xEC, 0xEA, 0x27, 0x7E, 0xA6, 0xB1, 0xED, 0xA9, 0x67, 0xED, 0x56, 0x91, 0x90, 0xF9, 0x32, 0x4E, 0xC3, 0x29, 0x5A, 0x84, 0x4C, 0xAB, 0x99, 0x75, 0x40, 0x8E, 0x19, 0xD9, 0x12, 0xD1, 0x06, 0x2D, 0xD0, 0x2C, 0xD9, 0x6C, 0x41, 0x35, 0x64, 0xDB, 0x80, 0x63, 0xB2, 0x01, 0xF8, 0x29, 0xAB, 0xF5, 0x70, 0x79, 0x4E, 0x0F, 0xFA, 0x23, 0x20, 0x2E, 0x04, 0x75, 0x48, 0x15, 0x9B, 0x71, 0xD5, 0x85, 0x09, 0x67, 0x7D, 0xAC, 0x6A, 0xFA, 0xC0, 0x16, 0xAF, 0x58, 0x26, 0xCD, 0x6F, 0x1F, 0xB8, 0xF5, 0x8D, 0xD1, 0x7D, 0x3D, 0x70, 0x2F, 0x08, 0xB8, 0x23, 0x61, 0x24, 0xAE, 0x94, 0x31, 0xA3, 0xBD, 0x1E, 0x18, 0xD7, 0x82, 0x92, 0xDD, 0x11, 0x79, 0x7D, 0x1F, 0xEC, 0x03, 0x08, 0x82, 0xCC, 0x52, 0x62, 0xC9, 0x27, 0x2D, 0x08, 0xD5, 0x6B, 0x4E, 0x86, 0x2E, 0x3F, 0x50, 0x5C, 0xA3, 0xC1, 0xDF, 0xF5 }; -#endif \ No newline at end of file diff --git a/dir.c b/dir.c new file mode 100644 index 0000000..68e5524 --- /dev/null +++ b/dir.c @@ -0,0 +1,327 @@ +#include "lib.h" +#include "dir.h" +#include "utf.h" + +/* This is mainly a FS interface for ROMFS generation */ + + +int fs_InitDir(u16 *path, u32 pathlen, fs_dir *dir); +int fs_ManageDirSlot(fs_dir *dir); +int fs_ManageFileSlot(fs_dir *dir); +void fs_chdirUp(void); +fs_entry* fs_GetEntry(fs_DIR *dp); +void fs_FreeEntry(fs_entry *entry); +bool fs_EntryIsDirNav(fs_entry *entry); +int fs_AddDir(fs_entry *entry, fs_dir *dir); +int fs_AddFile(fs_entry *entry, fs_dir *dir); + +int fs_InitDir(u16 *path, u32 pathlen, fs_dir *dir) +{ + dir->name_len = pathlen; + dir->name = calloc(dir->name_len+2,1); + memcpy(dir->name,path,dir->name_len); + + + dir->m_dir = 10; + dir->u_dir = 0; + dir->dir = calloc(dir->m_dir,sizeof(fs_dir)); + + dir->m_file = 10; + dir->u_file = 0; + dir->file = calloc(dir->m_file,sizeof(fs_file)); + + return 0; +} + +int fs_ManageDirSlot(fs_dir *dir) +{ + if(dir->u_dir >= dir->m_dir) + { + dir->m_dir *= 2; + fs_dir *tmp = calloc(dir->m_dir,sizeof(fs_dir)); + memcpy(tmp,dir->dir,sizeof(fs_dir)*dir->u_dir); + free(dir->dir); + dir->dir = tmp; + } + return 0; +} + +int fs_ManageFileSlot(fs_dir *dir) +{ + if(dir->u_file >= dir->m_file) + { + dir->m_file *= 2; + fs_file *tmp = calloc(dir->m_file,sizeof(fs_file)); + memcpy(tmp,dir->file,sizeof(fs_file)*dir->u_file); + free(dir->file); + dir->file = tmp; + } + return 0; +} + +void fs_chdirUp(void) +{ +#ifdef _WIN32 + fs_chdir(L".."); +#else + fs_chdir(".."); +#endif +} + +fs_entry* fs_GetEntry(fs_DIR *dp) +{ + // Directory structs + struct fs_dirent *tmp_entry; + fs_DIR *tmp_dptr; + u32 namlen = 0; + + //printf("get api dir entry from dir ptr\n"); + tmp_entry = fs_readdir(dp); + + //printf("if null, return\n"); + if(!tmp_entry) + return NULL; + +#ifdef _WIN32 + namlen = tmp_entry->d_namlen; +#else + namlen = strlen(tmp_entry->d_name); +#endif + + //printf("allocate memory for entry\n"); + fs_entry *entry = malloc(sizeof(fs_entry)); + memset(entry,0,sizeof(fs_entry)); + + //Copy FS compatible Entry name + entry->fs_name = malloc(sizeof(fs_char)*(namlen+1)); + memset(entry->fs_name,0,sizeof(fs_char)*(namlen+1)); + memcpy(entry->fs_name,tmp_entry->d_name,sizeof(fs_char)*namlen); + + // Convert Entry name into RomFS u16 char (windows wchar_t, thanks Nintendo) +#if _WIN32 + str_u16_to_u16(&entry->name,&entry->name_len,tmp_entry->d_name,namlen); +#else + str_utf8_to_u16(&entry->name,&entry->name_len,(u8*)tmp_entry->d_name,namlen); +#endif + + //printf("get dir entry from dir ptr to check if dir\n"); + tmp_dptr = fs_opendir(entry->fs_name); + if(tmp_dptr) + { + //printf("is dir\n"); + fs_closedir(tmp_dptr); + entry->IsDir = true; + entry->size = 0; + entry->fp = NULL; + } + else // Open file if it is a file + { + entry->IsDir = false; +#ifdef _WIN32 + entry->size = wGetFileSize_u64(entry->fs_name); + entry->fp = _wfopen(entry->fs_name,L"rb"); +#else + entry->size = GetFileSize_u64(entry->fs_name); + entry->fp = fopen(entry->fs_name,"rb"); +#endif + } + //printf("fs_GetEntry() return\n"); + return entry; +} + +void fs_FreeEntry(fs_entry *entry) +{ + free(entry->fs_name); + free(entry->name); + free(entry); +} + +bool fs_EntryIsDirNav(fs_entry *entry) +{ + //memdump(stdout,"Entry RomFS Name: ",(u8*)entry->name,entry->name_len); + const fs_romfs_char currentdir = 0x2E; + const fs_romfs_char upperdir[2] = {0x2E,0x2E}; + if(entry->name_len == sizeof(fs_romfs_char)*1 && memcmp(entry->name,¤tdir,sizeof(fs_romfs_char)*1) == 0) + return true; + if(entry->name_len == sizeof(fs_romfs_char)*2 && memcmp(entry->name,upperdir,sizeof(fs_romfs_char)*2) == 0) + return true; + return false; + +} + +int fs_AddDir(fs_entry *entry, fs_dir *dir) +{ + fs_ManageDirSlot(dir); + u32 current_slot = dir->u_dir; + dir->u_dir++; + fs_dir *tmp = (fs_dir*)dir->dir; + return fs_OpenDir(entry->fs_name,entry->name,entry->name_len,&tmp[current_slot]); +} + +int fs_AddFile(fs_entry *entry, fs_dir *dir) +{ + fs_ManageFileSlot(dir); + dir->file[dir->u_file].name_len = entry->name_len; + dir->file[dir->u_file].name = malloc(entry->name_len+2); + memset(dir->file[dir->u_file].name,0,entry->name_len+2); + memcpy(dir->file[dir->u_file].name,entry->name,entry->name_len); + + dir->file[dir->u_file].size = entry->size; + dir->file[dir->u_file].fp = entry->fp; + + dir->u_file++; + return 0; +} + +int fs_OpenDir(fs_char *fs_path, fs_romfs_char *path, u32 pathlen, fs_dir *dir) +{ + //printf("init open dir\n"); + int ret = 0; + fs_DIR *dp; + fs_entry *entry; + + //printf("check if path exists\n"); + dp = fs_opendir(fs_path); + if(!dp) + { + //wprintf(L"[!] Failed to open directory: \"%s\"\n",path); + return -1; + } + + //printf("do some more init\n"); + fs_InitDir(path,pathlen,dir); + //wprintf(L" rec: \"%s\" (%d)\n",dir->name,dir->name_len); + + //printf("chdir\n"); + fs_chdir(fs_path); + + //printf("read entries\n"); + while((entry = fs_GetEntry(dp))) + { + if(!entry) + { + ret = -1; + break; + } + + if(entry->IsDir) + { + //printf("Found Dir "); + if(!fs_EntryIsDirNav(entry)) + { +#ifdef _WIN32 + //wprintf(L"is a dir: \"%s\" (%d)\n",entry->fs_name,entry->name_len); +#else + //printf("is a dir: \"%s\" (%d)\n",entry->fs_name,entry->name_len); +#endif + ret = fs_AddDir(entry,dir); + } + else + { + //printf("Not wanted dir\n"); + ret = 0; + } + } + else + { +#ifdef _WIN32 + //wprintf(L"is a file: \"%s\" (%d)\n",entry->fs_name,entry->name_len); +#else + //printf("is a file: \"%s\" (%d)\n",entry->fs_name,entry->name_len); +#endif + ret = fs_AddFile(entry,dir); + } + + //printf("free entry\n"); + fs_FreeEntry(entry); + + if(ret) + { + //printf("error parsing entry\n"); + break; + } + } + //printf("close dir ptr\n"); + fs_closedir(dp); + //printf("return up dir\n"); + fs_chdirUp(); + //printf("return from fs_OpenDir();\n"); + return ret; +} + + +void fs_PrintDir(fs_dir *dir, u32 depth) // This is just for simple debugging, please don't shoot me +{ + for(u32 i = 0; i < depth; i++) + printf(" "); + +#ifdef _WIN32 + wprintf(L"%s\n",dir->name); +#else + char *name = (char*)dir->name; + for(u32 i = 0; i < dir->name_len; i+=2) + putchar(name[i]); + putchar('\n'); +#endif + + if(dir->u_file) + { + for(u32 i = 0; i < dir->u_file; i++) + { + for(u32 j = 0; j < depth+1; j++) + printf(" "); + +#ifdef _WIN32 + wprintf(L"%s (0x%lx)\n",dir->file[i].name,dir->file[i].size); +#else + name = (char*)dir->file[i].name; + for(u32 j = 0; j < dir->file[i].name_len; j+=2) + putchar(name[j]); + printf(" (0x%lx)\n",dir->file[i].size); +#endif + } + } + if(dir->u_dir) + { + fs_dir *tmp = (fs_dir*)dir->dir; + for(u32 i = 0; i < dir->u_dir; i++) + fs_PrintDir(&tmp[i],depth+1); + } +} + +void fs_FreeDir(fs_dir *dir) +{ + //printf("DIR!! free file names\n"); + for(u32 i = 0; i < dir->u_file; i++) + { + free(dir->file[i].name); + } + //printf("free file struct\n"); + free(dir->file); + + + fs_dir *tmp = (fs_dir*)dir->dir; + //printf("free dir names\n"); + for(u32 i = 0; i < dir->u_dir; i++) + { + //wprintf(L"freeing: %s\n",tmp[i].name); + free(tmp[i].name); + fs_FreeDir(&tmp[i]); + } + //printf("free dir struct\n"); + free(dir->dir); + +} + +void fs_FreeFiles(fs_dir *dir) +{ + for(u32 i = 0; i < dir->u_file; i++) + { + if(dir->file[i].fp) + fclose(dir->file[i].fp); + } + + fs_dir *tmp = (fs_dir*)dir->dir; + for(u32 i = 0; i < dir->u_dir; i++) + fs_FreeFiles(&tmp[i]); +} \ No newline at end of file diff --git a/dir.h b/dir.h new file mode 100644 index 0000000..6ee72e1 --- /dev/null +++ b/dir.h @@ -0,0 +1,64 @@ +#pragma once + +#ifdef _WIN32 + #define fs_romfs_char u16 + #define fs_char wchar_t + #define fs_dirent _wdirent + #define fs_DIR _WDIR + #define fs_readdir _wreaddir + #define fs_chdir _wchdir + #define fs_opendir _wopendir + #define fs_closedir _wclosedir +#else + #define fs_romfs_char u16 + #define fs_char char + #define fs_dirent dirent + #define fs_DIR DIR + #define fs_readdir readdir + #define fs_chdir chdir + #define fs_opendir opendir + #define fs_closedir closedir +#endif + + +typedef struct +{ + bool IsDir; + fs_char *fs_name; + fs_romfs_char *name; + u32 name_len; + u64 size; + FILE *fp; +} fs_entry; + +typedef struct +{ + u16 *name; + u32 name_len; + u64 size; + FILE *fp; +} fs_file; + +typedef struct +{ + u16 *name; + u32 name_len; + + void *dir; // treated as type 'fs_dir'. This officially type 'void' to prevent self referencing problems + u32 m_dir; + u32 u_dir; + + fs_file *file; + u32 m_file; + u32 u_file; +} fs_dir; + + +int fs_u8String_to_u16String(u16 **dst, u32 *dst_len, u8 *src, u32 src_len); +int fs_u16String_to_u16String(u16 **dst, u32 *dst_len, u16 *src, u32 src_len); +int fs_u32String_to_u16String(u16 **dst, u32 *dst_len, u32 *src, u32 src_len); + +int fs_OpenDir(fs_char *fs_path, fs_romfs_char *path, u32 pathlen, fs_dir *dir); +void fs_PrintDir(fs_dir *dir, u32 depth); +void fs_FreeDir(fs_dir *dir); +void fs_FreeFiles(fs_dir *dir); \ No newline at end of file diff --git a/dpki.h b/dpki.h index 337b0db..cd31344 100644 --- a/dpki.h +++ b/dpki.h @@ -1,5 +1,4 @@ -#ifndef _DPKI_H_ -#define _DPKI_H_ +#pragma once #ifdef PKI_LEGACY #include "dpki_legacy.h" @@ -381,7 +380,7 @@ static const unsigned char dev_acex_pub[0x100] = 0x29, 0x78, 0xBF, 0x2A, 0x3C, 0x3B, 0xB6, 0xB1 }; -static const unsigned char dev_crr_cert_pub[0x100] = +static const unsigned char dev_crr_cert_pub[0x100] = // key to verify dev_crr_cert { 0xC5, 0xF7, 0x09, 0x80, 0x5F, 0xDA, 0xDC, 0xBD, 0x46, 0x07, 0x52, 0xAA, 0x6D, 0xCD, 0x72, 0xB2, @@ -417,7 +416,7 @@ static const unsigned char dev_crr_cert_pub[0x100] = 0x11, 0xE1, 0x53, 0x4E, 0x99, 0xDB, 0xAC, 0x53 }; -static const unsigned char dev_crr_cert[0x100] = +static const unsigned char dev_crr_cert[0x100] = // signature over crr rsa key { 0x96, 0x5C, 0xBE, 0x5E, 0xEF, 0x08, 0x0B, 0x29, 0xEF, 0x95, 0x12, 0xA4, 0x80, 0x36, 0x47, 0xD5, @@ -453,7 +452,7 @@ static const unsigned char dev_crr_cert[0x100] = 0xCA, 0x03, 0xFE, 0x35, 0xB3, 0x66, 0xAF, 0x82 }; -static const unsigned char dev_crr_priv[0x100] = +static const unsigned char dev_crr_priv[0x100] = // pre signed rsakey { 0x8D, 0x27, 0x29, 0x6B, 0xC7, 0xA7, 0xED, 0xCD, 0x94, 0x2D, 0x36, 0x5E, 0x86, 0xA8, 0x26, 0xE7, @@ -489,7 +488,7 @@ static const unsigned char dev_crr_priv[0x100] = 0xF7, 0x01, 0x65, 0xF6, 0x2D, 0x36, 0x6E, 0x71 }; -static const unsigned char dev_crr_pub[0x100] = +static const unsigned char dev_crr_pub[0x100] = // pre signed rsakey { 0xE2, 0xAD, 0xA6, 0xEA, 0xCA, 0xA3, 0xE8, 0xCC, 0xA9, 0x70, 0x1D, 0x2E, 0x23, 0x4B, 0xC6, 0x55, @@ -892,6 +891,4 @@ static const unsigned char cpA_dpki_cert[0x300] = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/dpki_legacy.h b/dpki_legacy.h index a91e54f..8b97ad6 100644 --- a/dpki_legacy.h +++ b/dpki_legacy.h @@ -1,5 +1,4 @@ -#ifndef _DPKI_LEGACY_H_ -#define _DPKI_LEGACY_H_ +#pragma once // AES Keys static const unsigned char rvl_twl_common_etd_key_dpki[1][16] = @@ -196,6 +195,4 @@ static const unsigned char ng1f5_dpki_cert[0x180] = static const unsigned char ms8_dpki_cert[0x240] = { 0x00, 0x01, 0x00, 0x01, 0xA6, 0x5A, 0x2B, 0x92, 0xC0, 0xE7, 0xAF, 0x0C, 0x11, 0xD2, 0x5A, 0x9A, 0x6D, 0xC2, 0x9B, 0xC3, 0xDD, 0xBF, 0x0F, 0x30, 0x17, 0xB1, 0xBE, 0x1F, 0xD5, 0x29, 0xE9, 0x99, 0x73, 0x06, 0x67, 0x52, 0x04, 0x05, 0xCF, 0x34, 0x0C, 0x28, 0x6D, 0xBB, 0xA7, 0x69, 0x2E, 0x7E, 0xD2, 0x1F, 0x44, 0x43, 0xCA, 0x15, 0x22, 0x68, 0xB4, 0x6F, 0x7D, 0x03, 0x63, 0xFB, 0xAA, 0x89, 0x3D, 0x0B, 0x6D, 0xC0, 0xBC, 0x2D, 0x89, 0x3C, 0xB5, 0xE6, 0xF8, 0x97, 0x97, 0x94, 0x09, 0xBC, 0x4D, 0x1B, 0x56, 0x18, 0xD4, 0x50, 0x9D, 0xC2, 0xCE, 0x1B, 0xC3, 0x97, 0x22, 0xC1, 0x38, 0xA2, 0x29, 0x2C, 0x11, 0x42, 0xE0, 0xBB, 0x14, 0xAA, 0x7A, 0xD8, 0x6B, 0xB3, 0x28, 0x76, 0xA6, 0xF1, 0xBD, 0x7D, 0x80, 0x99, 0xD0, 0xEA, 0x7A, 0xF5, 0xC4, 0x47, 0x52, 0x01, 0x28, 0x6B, 0x27, 0x08, 0xAE, 0xFA, 0x68, 0x97, 0x50, 0x2D, 0x91, 0x4D, 0x89, 0x96, 0xC9, 0xDE, 0xAC, 0x4A, 0x4F, 0x31, 0x7F, 0xB8, 0x7C, 0xDE, 0xFD, 0x59, 0xE8, 0xC7, 0xA0, 0x65, 0xB7, 0x73, 0xAA, 0xB0, 0xEA, 0x80, 0xE6, 0x58, 0x2B, 0xC0, 0xF7, 0x89, 0xA8, 0x84, 0x3D, 0xB6, 0x59, 0xAC, 0xB5, 0xB2, 0x43, 0x0E, 0x20, 0xA7, 0xAA, 0xC3, 0x93, 0xA0, 0x8F, 0x66, 0x37, 0xE8, 0xF3, 0x83, 0x14, 0x28, 0x71, 0x1A, 0x0B, 0x47, 0x8D, 0x21, 0xE6, 0x5A, 0xC1, 0xF3, 0x26, 0xD2, 0x41, 0x75, 0x90, 0xDA, 0xB1, 0x05, 0x64, 0xBC, 0xD4, 0xFE, 0xD0, 0xCB, 0x9B, 0x92, 0xD8, 0x27, 0xDC, 0x93, 0x05, 0xC1, 0x21, 0xAC, 0x59, 0xB1, 0x08, 0xDC, 0xFF, 0xEC, 0xD5, 0x53, 0x56, 0xB4, 0xC3, 0x90, 0x32, 0xA0, 0xC4, 0xFE, 0xE4, 0x8A, 0x57, 0xA5, 0xAD, 0x32, 0x9D, 0x94, 0x1E, 0x16, 0x29, 0xEA, 0x57, 0x10, 0x87, 0x82, 0x54, 0xC7, 0xEC, 0xC1, 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, 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, 0x52, 0x6F, 0x6F, 0x74, 0x2D, 0x43, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x32, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x4D, 0x53, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x36, 0xC6, 0xAC, 0x01, 0xEE, 0xFF, 0xD1, 0x3D, 0x2B, 0x54, 0xC4, 0x4D, 0xE5, 0xE9, 0x28, 0x5E, 0x16, 0x98, 0x20, 0xDC, 0x0E, 0x61, 0x54, 0x62, 0xC7, 0x23, 0x90, 0x0B, 0xA7, 0xBA, 0xC3, 0x2B, 0x5A, 0x00, 0xFE, 0x7A, 0xB1, 0x38, 0x5C, 0x83, 0x15, 0xF5, 0x27, 0x40, 0x2A, 0x8B, 0xFC, 0x50, 0x11, 0x82, 0x80, 0x89, 0x6C, 0xF8, 0x24, 0x9E, 0x9D, 0x0D, 0x42, 0xF0, 0xDA, 0xED, 0x31, 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, 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 -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/elf.c b/elf.c index 2a7e98d..561b3fa 100644 --- a/elf.c +++ b/elf.c @@ -147,7 +147,7 @@ finish: int ImportPlainRegionFromFile(ncch_settings *ncchset) { - ncchset->sections.plainRegion.size = align_value(ncchset->componentFilePtrs.plainregionSize,ncchset->options.mediaSize); + 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] MEM ERROR\n"); return MEM_ERROR;} ReadFile_64(ncchset->sections.plainRegion.buffer,ncchset->componentFilePtrs.plainregionSize,0,ncchset->componentFilePtrs.plainregion); @@ -187,7 +187,7 @@ u32 GetPageSize(ncch_settings *ncchset) u32 SizeToPage(u32 memorySize, ElfContext *elf) { - return align_value(memorySize,elf->pageSize)/elf->pageSize; + return align(memorySize,elf->pageSize)/elf->pageSize; } @@ -226,7 +226,7 @@ int ImportPlainRegionFromElf(ElfContext *elf, u8 *ElfFile, ncch_settings *ncchse } /* Creating Output Buffer */ - ncchset->sections.plainRegion.size = align_value(TotalSize,ncchset->options.mediaSize); + 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] MEM ERROR\n"); return MEM_ERROR;} memset(ncchset->sections.plainRegion.buffer,0,ncchset->sections.plainRegion.size); @@ -395,7 +395,7 @@ ElfSegment** GetContinuousSegments(u16 *ContinuousSegmentNum, ElfContext *elf, c u32 vAddr = Segments[0]->vAddr + Segments[0]->header->sizeInMemory; for (int i = 1; i < SegmentNum; i++){ - if (Segments[i]->vAddr != (u32)align_value(vAddr,Segments[i]->header->alignment)){ //Each Segment must start after each other + if (Segments[i]->vAddr != (u32)align(vAddr,Segments[i]->header->alignment)){ //Each Segment must start after each other fprintf(stderr,"[ELF ERROR] %s segment and %s segment are not continuous\n", Segments[i]->name, Segments[i - 1]->name); free(Segments); *ContinuousSegmentNum = 0xffff; // Signify to function that an error occured @@ -938,7 +938,7 @@ int CreateElfSegments(ElfContext *elf, u8 *ElfFile) if(size == 0) size = elf->sections[j].size; else - size = align_value(size,elf->sections[j].alignment) + elf->sections[j].size; + size = align(size,elf->sections[j].alignment) + elf->sections[j].size; //printf("Section Name: %s",elf->sections[j].name); //printf(" 0x%lx",elf->sections[j].size); diff --git a/elf.h b/elf.h index d16e881..735b9a8 100644 --- a/elf.h +++ b/elf.h @@ -1,5 +1,4 @@ -#ifndef _ELF_H_ -#define _ELF_H_ +#pragma once typedef enum { @@ -82,6 +81,4 @@ typedef struct } ElfContext; -#endif - int BuildExeFsCode(ncch_settings *ncchset); \ No newline at end of file diff --git a/elf_hdr.h b/elf_hdr.h index e4be2c3..878a7ad 100644 --- a/elf_hdr.h +++ b/elf_hdr.h @@ -1,5 +1,4 @@ -#ifndef _ELF_HDR_H_ -#define _ELF_HDR_H_ +#pragma once static const u32 ELF_MAGIC = 0x7f454c46; @@ -174,5 +173,4 @@ typedef struct u8 p_filesz[8]; /* Segment size in file */ u8 p_memsz[8]; /* Segment size in memory */ u8 p_align[8]; /* Segment alignment */ -} elf_64_phdr; -#endif \ No newline at end of file +} elf_64_phdr; \ No newline at end of file diff --git a/exefs.c b/exefs.c index f931e08..4225ef8 100644 --- a/exefs.c +++ b/exefs.c @@ -3,21 +3,21 @@ #include "exefs.h" // Private Prototypes -u32 PredictExeFS_Size(ExeFs_BuildContext *ctx); -int GenerateExeFS_Header(ExeFs_BuildContext *ctx, u8 *outbuff); -void InitialiseExeFSContext(ExeFs_BuildContext *ctx); -void FreeExeFSContext(ExeFs_BuildContext *ctx); -int ImportDatatoExeFS(ExeFs_BuildContext *ctx, u8 *outbuff); -int ImportToExeFSContext(ExeFs_BuildContext *ctx, char *lable, u8 *buffer, u32 size); +u32 PredictExeFS_Size(exefs_buildctx *ctx); +int GenerateExeFS_Header(exefs_buildctx *ctx, u8 *outbuff); +void InitialiseExeFSContext(exefs_buildctx *ctx); +void FreeExeFSContext(exefs_buildctx *ctx); +int ImportDatatoExeFS(exefs_buildctx *ctx, u8 *outbuff); +int ImportToExeFSContext(exefs_buildctx *ctx, char *name, u8 *buffer, u32 size); // ExeFs Build Functions int BuildExeFs(ncch_settings *ncchset) { /* Intialising ExeFs Build Context */ - ExeFs_BuildContext *ctx = malloc(sizeof(ExeFs_BuildContext)); + exefs_buildctx *ctx = malloc(sizeof(exefs_buildctx)); if(!ctx) {fprintf(stderr,"[EXEFS ERROR] MEM ERROR\n"); return MEM_ERROR;} InitialiseExeFSContext(ctx); - ctx->media_unit = ncchset->options.mediaSize; + ctx->mediaUnit = ncchset->options.mediaSize; /* Importing ExeFs */ if(ncchset->exefsSections.code.size) @@ -47,98 +47,98 @@ int BuildExeFs(ncch_settings *ncchset) return 0; } -u32 PredictExeFS_Size(ExeFs_BuildContext *ctx) +u32 PredictExeFS_Size(exefs_buildctx *ctx) { u32 exefs_size = 0x200; // Size of header - for(int i = 0; i < ctx->section_count; i++){ - exefs_size += align_value(ctx->section_size[i],ctx->media_unit); + for(int i = 0; i < ctx->fileCount; i++){ + exefs_size += align(ctx->fileSize[i],ctx->mediaUnit); } - //exefs_size = align_value(ctx->exefs_size,ctx->media_unit); + //exefs_size = align(ctx->exefs_size,ctx->mediaUnit); return exefs_size; } -int GenerateExeFS_Header(ExeFs_BuildContext *ctx, u8 *outbuff) +int GenerateExeFS_Header(exefs_buildctx *ctx, u8 *outbuff) { - for(int i = 0; i < ctx->section_count; i++){ + for(int i = 0; i < ctx->fileCount; i++){ if(i == 0) - ctx->section_offset[i] = 0; + ctx->fileOffset[i] = 0; else - ctx->section_offset[i] = align_value((ctx->section_offset[i-1]+ctx->section_size[i-1]),ctx->media_unit); + ctx->fileOffset[i] = align((ctx->fileOffset[i-1]+ctx->fileSize[i-1]),ctx->mediaUnit); - memcpy(ctx->file_header[i].name,ctx->lable[i],8); - u32_to_u8(ctx->file_header[i].offset,ctx->section_offset[i],LE); - u32_to_u8(ctx->file_header[i].size,ctx->section_size[i],LE); - ctr_sha(ctx->section[i],ctx->section_size[i],ctx->file_hashes[9-i],CTR_SHA_256); + memcpy(ctx->fileHdr[i].name,ctx->fileName[i],8); + u32_to_u8(ctx->fileHdr[i].offset,ctx->fileOffset[i],LE); + u32_to_u8(ctx->fileHdr[i].size,ctx->fileSize[i],LE); + ctr_sha(ctx->file[i],ctx->fileSize[i],ctx->fileHashes[9-i],CTR_SHA_256); } - memcpy(outbuff,ctx->file_header,sizeof(ExeFs_FileHeader)*10); - memcpy(outbuff+0xc0,ctx->file_hashes,0x20*10); + memcpy(outbuff,ctx->fileHdr,sizeof(exefs_filehdr)*10); + memcpy(outbuff+0xc0,ctx->fileHashes,0x20*10); return 0; } -void InitialiseExeFSContext(ExeFs_BuildContext *ctx) +void InitialiseExeFSContext(exefs_buildctx *ctx) { - memset(ctx,0,sizeof(ExeFs_BuildContext)); + memset(ctx,0,sizeof(exefs_buildctx)); } -void FreeExeFSContext(ExeFs_BuildContext *ctx) +void FreeExeFSContext(exefs_buildctx *ctx) { /* if(ctx->outbuff != NULL) free(ctx->outbuff); for(int i = 0; i < 10; i++){ - if(ctx->section[i] != NULL) - free(ctx->section[i]); + if(ctx->file[i] != NULL) + free(ctx->file[i]); } */ - memset(ctx,0,sizeof(ExeFs_BuildContext)); + memset(ctx,0,sizeof(exefs_buildctx)); free(ctx); } -int ImportDatatoExeFS(ExeFs_BuildContext *ctx, u8 *outbuff) +int ImportDatatoExeFS(exefs_buildctx *ctx, u8 *outbuff) { - for(int i = 0; i < ctx->section_count; i++){ - memcpy(outbuff+ctx->section_offset[i]+0x200,ctx->section[i],ctx->section_size[i]); + for(int i = 0; i < ctx->fileCount; i++){ + memcpy(outbuff+ctx->fileOffset[i]+0x200,ctx->file[i],ctx->fileSize[i]); } return 0; } -int ImportToExeFSContext(ExeFs_BuildContext *ctx, char *lable, u8 *buffer, u32 size) +int ImportToExeFSContext(exefs_buildctx *ctx, char *name, u8 *buffer, u32 size) { - if(ctx == NULL || lable == NULL || buffer == NULL){ + if(ctx == NULL || name == NULL || buffer == NULL){ printf("[!] PTR ERROR\n"); return PTR_ERROR; } - if(ctx->section_count >= 10){ + if(ctx->fileCount >= MAX_EXEFS_SECTIONS){ printf("[!] Maximum ExeFS Capacity Reached\n"); return EXEFS_MAX_REACHED; } - if(strlen(lable) > 8){ - printf("[!] ExeFS Section Name: '%s' is too large\n",lable); + if(strlen(name) > 8){ + printf("[!] ExeFS File Name: '%s' is too large\n",name); return EXEFS_SECTION_NAME_ERROR; } - ctx->section_count++; - ctx->section[ctx->section_count - 1] = buffer; - ctx->section_size[ctx->section_count - 1] = size; - strcpy(ctx->lable[ctx->section_count - 1],lable); + ctx->fileCount++; + ctx->file[ctx->fileCount - 1] = buffer; + ctx->fileSize[ctx->fileCount - 1] = size; + strcpy(ctx->fileName[ctx->fileCount - 1],name); return 0; } // ExeFs Read Functions bool DoesExeFsSectionExist(char *section, u8 *ExeFs) { - ExeFs_Header *hdr = (ExeFs_Header*) ExeFs; + exefs_hdr *hdr = (exefs_hdr*) ExeFs; for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){ - if(strncmp(hdr->SectionHdr[i].name,section,8) == 0) return true; + if(strncmp(hdr->fileHdr[i].name,section,8) == 0) return true; } return false; } u8* GetExeFsSection(char *section, u8 *ExeFs) { - ExeFs_Header *hdr = (ExeFs_Header*) ExeFs; + exefs_hdr *hdr = (exefs_hdr*) ExeFs; for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){ - if(strncmp(hdr->SectionHdr[i].name,section,8) == 0){ - u32 offset = u8_to_u32(hdr->SectionHdr[i].offset,LE) + sizeof(ExeFs_Header); + if(strncmp(hdr->fileHdr[i].name,section,8) == 0){ + u32 offset = u8_to_u32(hdr->fileHdr[i].offset,LE) + sizeof(exefs_hdr); return (u8*)(ExeFs+offset); } } @@ -147,10 +147,10 @@ u8* GetExeFsSection(char *section, u8 *ExeFs) u8* GetExeFsSectionHash(char *section, u8 *ExeFs) { - ExeFs_Header *hdr = (ExeFs_Header*) ExeFs; + exefs_hdr *hdr = (exefs_hdr*) ExeFs; for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){ - if(strncmp(hdr->SectionHdr[i].name,section,8) == 0){ - return (u8*)(hdr->SectionHashes[MAX_EXEFS_SECTIONS-1-i]); + if(strncmp(hdr->fileHdr[i].name,section,8) == 0){ + return (u8*)(hdr->fileHashes[MAX_EXEFS_SECTIONS-1-i]); } } return NULL; @@ -158,10 +158,10 @@ u8* GetExeFsSectionHash(char *section, u8 *ExeFs) u32 GetExeFsSectionSize(char *section, u8 *ExeFs) { - ExeFs_Header *hdr = (ExeFs_Header*) ExeFs; + exefs_hdr *hdr = (exefs_hdr*) ExeFs; for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){ - if(strncmp(hdr->SectionHdr[i].name,section,8) == 0){ - return u8_to_u32(hdr->SectionHdr[i].size,LE); + if(strncmp(hdr->fileHdr[i].name,section,8) == 0){ + return u8_to_u32(hdr->fileHdr[i].size,LE); } } return 0; @@ -169,10 +169,10 @@ u32 GetExeFsSectionSize(char *section, u8 *ExeFs) u32 GetExeFsSectionOffset(char *section, u8 *ExeFs) { - ExeFs_Header *hdr = (ExeFs_Header*) ExeFs; + exefs_hdr *hdr = (exefs_hdr*) ExeFs; for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){ - if(strncmp(hdr->SectionHdr[i].name,section,8) == 0){ - return u8_to_u32(hdr->SectionHdr[i].offset,LE) + sizeof(ExeFs_Header); + if(strncmp(hdr->fileHdr[i].name,section,8) == 0){ + return u8_to_u32(hdr->fileHdr[i].offset,LE) + sizeof(exefs_hdr); } } return 0; diff --git a/exefs.h b/exefs.h index 4564fc5..52afe84 100644 --- a/exefs.h +++ b/exefs.h @@ -1,5 +1,4 @@ -#ifndef _EXEFS_H_ -#define _EXEFS_H_ +#pragma once #define MAX_EXEFS_SECTIONS 10 // DO NOT CHANGE @@ -16,32 +15,30 @@ typedef struct char name[8]; u8 offset[4]; u8 size[4]; -} ExeFs_FileHeader; +} exefs_filehdr; + +typedef struct +{ + exefs_filehdr fileHdr[MAX_EXEFS_SECTIONS]; + u8 reserved[0x20]; + u8 fileHashes[MAX_EXEFS_SECTIONS][0x20]; +} exefs_hdr; typedef struct { //Input - int section_count; - u8 *section[10]; - u32 section_size[10]; - u32 section_offset[10]; - char lable[10][8]; - u32 media_unit; + 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_FileHeader file_header[10]; - u8 file_hashes[10][0x20]; + exefs_filehdr fileHdr[MAX_EXEFS_SECTIONS]; + u8 fileHashes[MAX_EXEFS_SECTIONS][0x20]; -} ExeFs_BuildContext; - -typedef struct -{ - ExeFs_FileHeader SectionHdr[MAX_EXEFS_SECTIONS]; - u8 Reserved[0x20]; - u8 SectionHashes[MAX_EXEFS_SECTIONS][0x20]; -} ExeFs_Header; - -#endif +} exefs_buildctx; /* ExeFs Build Functions */ int BuildExeFs(ncch_settings *ncchset); diff --git a/exheader.c b/exheader.c index 24ae023..6630b8a 100644 --- a/exheader.c +++ b/exheader.c @@ -1,15 +1,9 @@ #include "lib.h" #include "ncch.h" #include "exheader.h" - +#include "accessdesc.h" #include "titleid.h" -#include "polarssl/base64.h" -#include "desc_presets.h" -#ifndef PUBLIC_BUILD -#include "desc_dev_sigdata.h" -#include "desc_prod_sigdata.h" -#endif /* Prototypes */ void init_ExHeaderSettings(exheader_settings *exhdrset); @@ -56,16 +50,6 @@ void AllocateARM11KernelDescMemory(ARM11KernelCapabilityDescriptor *desc, u16 Nu u32 GetDescPrefixMask(int numPrefixBits); u32 GetDescPrefixBits(int numPrefixBits, u32 PrefixVal); int get_ExHeaderARM9AccessControlInfo(exhdr_ARM9AccessControlInfo *arm9, rsf_settings *rsf); -int set_AccessDesc(exheader_settings *exhdrset, ncch_settings *ncchset); -int accessdesc_SignWithKey(exheader_settings *exhdrset, ncch_settings *ncchset); -int accessdesc_GetSignFromRsf(exheader_settings *exhdrset, ncch_settings *ncchset); -int accessdesc_GetSignFromPreset(exheader_settings *exhdrset, ncch_settings *ncchset); -void accessdesc_GetPresetData(u8 **AccessDescData, u8 **DepList, ncch_settings *ncchset); -#ifndef PUBLIC_BUILD -void accessdesc_GetPresetSigData(u8 **AccessDescSig, u8 **CXI_Pubk, u8 **CXI_Privk, ncch_settings *ncchset); -#endif - -void ErrorParamNotFound(char *string); /* ExHeader Signature Functions */ int SignAccessDesc(extended_hdr *exHdr, keys_struct *keys) @@ -104,8 +88,6 @@ int BuildExHeader(ncch_settings *ncchset) result = set_AccessDesc(exhdrset,ncchset); if(result) goto finish; - exhdrset->exHdr->accessDescriptor.arm11SystemLocalCapabilities.flags[6] = 5; - finish: if(result) fprintf(stderr,"[EXHEADER ERROR] Failed to create ExHeader\n"); free_ExHeaderSettings(exhdrset); @@ -169,9 +151,9 @@ int get_ExHeaderSettingsFromNcchset(exheader_settings *exhdrset, ncch_settings * /* Set Simple Flags */ if(ncchset->options.CompressCode) - exhdrset->exHdr->codeSetInfo.flags.flag |= Compress; + exhdrset->exHdr->codeSetInfo.flag |= Compress; if(ncchset->options.UseOnSD) - exhdrset->exHdr->codeSetInfo.flags.flag |= RetailSDAppFlag; + exhdrset->exHdr->codeSetInfo.flag |= RetailSDAppFlag; if(!ncchset->options.UseRomFS) // Move this later exhdrset->exHdr->arm11SystemLocalCapabilities.storageInfo.otherAttributes |= attribute_NOT_USE_ROMFS; @@ -233,10 +215,10 @@ int get_ExHeaderCodeSetInfo(exhdr_CodeSetInfo *CodeSetInfo, rsf_settings *rsf) /* Remaster Version */ if(rsf->SystemControlInfo.RemasterVersion){ u16 RemasterVersion = strtol(rsf->SystemControlInfo.RemasterVersion,NULL,0); - u16_to_u8(CodeSetInfo->flags.remasterVersion,RemasterVersion,LE); + u16_to_u8(CodeSetInfo->remasterVersion,RemasterVersion,LE); } else{ - u16_to_u8(CodeSetInfo->flags.remasterVersion,0,LE); + u16_to_u8(CodeSetInfo->remasterVersion,0,LE); } return 0; } @@ -325,14 +307,14 @@ int SetARM11SystemLocalInfoFlags(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_ /* Core Version */ if(rsf->AccessControlInfo.CoreVersion){ u32 Version = strtoul(rsf->AccessControlInfo.CoreVersion,NULL,0); - u32_to_u8(&arm11->flags[0],Version,LE); + u32_to_u8(arm11->coreVersion,Version,LE); } else{ ErrorParamNotFound("AccessControlInfo/CoreVersion"); return EXHDR_BAD_YAML_OPT; } - /* Byte[6] */ + /* Flag */ u8 AffinityMask = 0; u8 IdealProcessor = 0; u8 SystemMode = 0; @@ -357,7 +339,7 @@ int SetARM11SystemLocalInfoFlags(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_ return EXHDR_BAD_YAML_OPT; } } - arm11->flags[6] = (u8)(SystemMode << 4 | AffinityMask << 2 | IdealProcessor); + arm11->flag = (u8)(SystemMode << 4 | AffinityMask << 2 | IdealProcessor); /* Thread Priority */ if(rsf->AccessControlInfo.Priority){ @@ -371,7 +353,7 @@ int SetARM11SystemLocalInfoFlags(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_ fprintf(stderr,"[EXHEADER ERROR] Invalid Priority: %d\n",Priority); return EXHDR_BAD_YAML_OPT; } - arm11->flags[7] = Priority; + arm11->priority = Priority; } else{ ErrorParamNotFound("AccessControlInfo/Priority"); @@ -1162,336 +1144,7 @@ int get_ExHeaderARM9AccessControlInfo(exhdr_ARM9AccessControlInfo *arm9, rsf_set -int set_AccessDesc(exheader_settings *exhdrset, ncch_settings *ncchset) -{ - if(ncchset->keys->accessDescSign.presetType == not_preset){ - if(ncchset->rsfSet->CommonHeaderKey.Found) // Keydata exists in RSF - return accessdesc_GetSignFromRsf(exhdrset,ncchset); - else if(!ncchset->keys->rsa.requiresPresignedDesc) // Else if The AccessDesc can be signed with key - return accessdesc_SignWithKey(exhdrset,ncchset); - 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"); - return CANNOT_SIGN_ACCESSDESC; - } - } - return accessdesc_GetSignFromPreset(exhdrset,ncchset); -} -int accessdesc_SignWithKey(exheader_settings *exhdrset, ncch_settings *ncchset) -{ - /* Set RSA Keys */ - memcpy(exhdrset->keys->rsa.cxiHdrPvt,exhdrset->keys->rsa.cciCfaPvt,0x100); - memcpy(exhdrset->keys->rsa.cxiHdrPub,exhdrset->keys->rsa.cciCfaPub,0x100); - memcpy(&exhdrset->exHdr->accessDescriptor.ncchRsaPubKey,exhdrset->keys->rsa.cxiHdrPub,0x100); - /* Copy Data From ExHeader */ - memcpy(&exhdrset->exHdr->accessDescriptor.arm11SystemLocalCapabilities,&exhdrset->exHdr->arm11SystemLocalCapabilities,sizeof(exhdr_ARM11SystemLocalCapabilities)); - u8 *byte6 = &exhdrset->exHdr->accessDescriptor.arm11SystemLocalCapabilities.flags[6]; - u8 SystemMode = (*byte6>>4)&0xF; - u8 AffinityMask = (*byte6>>2)&0x3; - u8 IdealProcessor = ((*byte6>>0)&0x3)+1; - *byte6 = (u8)(SystemMode << 4 | AffinityMask << 2 | IdealProcessor); - - memcpy(&exhdrset->exHdr->accessDescriptor.arm11KernelCapabilities,&exhdrset->exHdr->arm11KernelCapabilities,sizeof(exhdr_ARM11KernelCapabilities)); - memcpy(&exhdrset->exHdr->accessDescriptor.arm9AccessControlInfo,&exhdrset->exHdr->arm9AccessControlInfo,sizeof(exhdr_ARM9AccessControlInfo)); - /* Sign AccessDesc */ - return SignAccessDesc(exhdrset->exHdr,exhdrset->keys); -} - -int accessdesc_GetSignFromRsf(exheader_settings *exhdrset, ncch_settings *ncchset) -{ - /* Yaml Option Sanity Checks */ - if(!exhdrset->rsf->CommonHeaderKey.Found){ - fprintf(stderr,"[EXHEADER ERROR] RSF Section \"CommonHeaderKey\" not found\n"); - return COMMON_HEADER_KEY_NOT_FOUND; - } - if(!exhdrset->rsf->CommonHeaderKey.D){ - ErrorParamNotFound("CommonHeaderKey/D"); - return COMMON_HEADER_KEY_NOT_FOUND; - } - if(strlen(exhdrset->rsf->CommonHeaderKey.D) != 350){ - fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/D\" has invalid length (%d)\n",strlen(exhdrset->rsf->CommonHeaderKey.D)); - return COMMON_HEADER_KEY_NOT_FOUND; - } - if(!exhdrset->rsf->CommonHeaderKey.Modulus){ - ErrorParamNotFound("CommonHeaderKey/Modulus"); - return COMMON_HEADER_KEY_NOT_FOUND; - } - if(strlen(exhdrset->rsf->CommonHeaderKey.Modulus) != 350){ - fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Modulus\" has invalid length (%d)\n",strlen(exhdrset->rsf->CommonHeaderKey.Modulus)); - return COMMON_HEADER_KEY_NOT_FOUND; - } - if(!exhdrset->rsf->CommonHeaderKey.AccCtlDescSign){ - ErrorParamNotFound("CommonHeaderKey/Signature"); - return COMMON_HEADER_KEY_NOT_FOUND; - } - if(strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign) != 350){ - fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Signature\" has invalid length (%d)\n",strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign)); - return COMMON_HEADER_KEY_NOT_FOUND; - } - if(!exhdrset->rsf->CommonHeaderKey.AccCtlDescBin){ - ErrorParamNotFound("CommonHeaderKey/Descriptor"); - return COMMON_HEADER_KEY_NOT_FOUND; - } - if(strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin) != 695){ - fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Descriptor\" has invalid length (%d)\n",strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin)); - return COMMON_HEADER_KEY_NOT_FOUND; - } - /* Set RSA Keys */ - int result = 0; - u32 out = 0x500; - u8 *tmp = malloc(0x500); - result = base64_decode(tmp,&out,(const u8*)exhdrset->rsf->CommonHeaderKey.Modulus,strlen(exhdrset->rsf->CommonHeaderKey.Modulus)); - if(result) goto finish; - memcpy(exhdrset->keys->rsa.cxiHdrPub,tmp,0x100); - out = 0x500; - result = base64_decode(tmp,&out,(const u8*)exhdrset->rsf->CommonHeaderKey.D,strlen(exhdrset->rsf->CommonHeaderKey.D)); - if(result) goto finish; - memcpy(exhdrset->keys->rsa.cxiHdrPvt,tmp,0x100); - /* Set AccessDesc */ - out = 0x500; - result = base64_decode(tmp,&out,(const u8*)exhdrset->rsf->CommonHeaderKey.AccCtlDescSign,strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign)); - if(result) goto finish; - memcpy(exhdrset->exHdr->accessDescriptor.signature,tmp,0x100); - memcpy(exhdrset->exHdr->accessDescriptor.ncchRsaPubKey,exhdrset->keys->rsa.cxiHdrPub,0x100); - out = 0x500; - result = base64_decode(tmp,&out,(const u8*)exhdrset->rsf->CommonHeaderKey.AccCtlDescBin,strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin)); - if(result) goto finish; - memcpy(&exhdrset->exHdr->accessDescriptor.arm11SystemLocalCapabilities,tmp,0x200); -finish: - free(tmp); - return result; -} - -int accessdesc_GetSignFromPreset(exheader_settings *exhdrset, ncch_settings *ncchset) -{ - u8 *AccessDescData = NULL; - u8 *DepList = NULL; - - u8 *AccessDescSig = NULL; - u8 *CXI_Pubk = NULL; - u8 *CXI_Privk = NULL; - - accessdesc_GetPresetData(&AccessDescData,&DepList,ncchset); -#ifndef PUBLIC_BUILD - accessdesc_GetPresetSigData(&AccessDescSig,&CXI_Pubk,&CXI_Privk,ncchset); -#endif - - // Error Checking - if(!AccessDescData || !DepList){ - fprintf(stderr,"[EXHEADER ERROR] AccessDesc preset is unavailable, please configure RSF file\n"); - return CANNOT_SIGN_ACCESSDESC; - } - - if((!CXI_Pubk || !CXI_Privk || !AccessDescSig) && ncchset->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"); - return CANNOT_SIGN_ACCESSDESC; - } - - // Setting data in Exheader - // Dependency List - memcpy(exhdrset->exHdr->dependencyList,DepList,0x180); - - // ARM11 Local Capabilities - exhdr_ARM11SystemLocalCapabilities *arm11local = (exhdr_ARM11SystemLocalCapabilities*)(AccessDescData); - // Backing Up Non Preset Details - u8 ProgramID[8]; - memcpy(ProgramID,exhdrset->exHdr->arm11SystemLocalCapabilities.programId,8); - exhdr_StorageInfo StorageInfoBackup; - memcpy(&StorageInfoBackup,&exhdrset->exHdr->arm11SystemLocalCapabilities.storageInfo,sizeof(exhdr_StorageInfo)); - - // Setting Preset Data - memcpy(&exhdrset->exHdr->arm11SystemLocalCapabilities,arm11local,sizeof(exhdr_ARM11SystemLocalCapabilities)); - - // Restoring Non Preset Data - memcpy(exhdrset->exHdr->arm11SystemLocalCapabilities.programId,ProgramID,8); - memcpy(&exhdrset->exHdr->arm11SystemLocalCapabilities.storageInfo,&StorageInfoBackup,sizeof(exhdr_StorageInfo)); - - // Adjusting flags to prevent errors - u8 *byte6 = &exhdrset->exHdr->arm11SystemLocalCapabilities.flags[6]; - u8 SystemMode = (*byte6>>4)&0xF; - u8 AffinityMask = (*byte6>>2)&0x3; - u8 IdealProcessor = ((*byte6>>0)&0x3)-1; - *byte6 = (u8)(SystemMode << 4 | AffinityMask << 2 | IdealProcessor); - exhdrset->exHdr->arm11SystemLocalCapabilities.flags[7] = 0x30; - - // ARM11 Kernel Capabilities - exhdr_ARM11KernelCapabilities *arm11kernel = (exhdr_ARM11KernelCapabilities*)(AccessDescData+sizeof(exhdr_ARM11SystemLocalCapabilities)); - memcpy(&exhdrset->exHdr->arm11KernelCapabilities,arm11kernel,(sizeof(exhdr_ARM11KernelCapabilities))); - - // ARM9 Access Control - exhdr_ARM9AccessControlInfo *arm9 = (exhdr_ARM9AccessControlInfo*)(AccessDescData+sizeof(exhdr_ARM11SystemLocalCapabilities)+sizeof(exhdr_ARM11KernelCapabilities)); - memcpy(&exhdrset->exHdr->arm9AccessControlInfo,arm9,(sizeof(exhdr_ARM9AccessControlInfo))); - - // Setting AccessDesc Area - // Signing normally if possible - if(!ncchset->keys->rsa.requiresPresignedDesc) - return accessdesc_SignWithKey(exhdrset,ncchset); - - // Otherwise set static data & ncch hdr sig info - memcpy(exhdrset->keys->rsa.cxiHdrPub,CXI_Pubk,0x100); - memcpy(exhdrset->keys->rsa.cxiHdrPvt,CXI_Privk,0x100); - memcpy(&exhdrset->exHdr->accessDescriptor.signature,AccessDescSig,0x100); - memcpy(&exhdrset->exHdr->accessDescriptor.ncchRsaPubKey,CXI_Pubk,0x100); - memcpy(&exhdrset->exHdr->accessDescriptor.arm11SystemLocalCapabilities,AccessDescData,0x200); - - return 0; -} - -void accessdesc_GetPresetData(u8 **AccessDescData, u8 **DepList, ncch_settings *ncchset) -{ - if(ncchset->keys->accessDescSign.presetType == app){ - switch(ncchset->keys->accessDescSign.targetFirmware){ - case 1: - *AccessDescData = (u8*)app_1_acex_data; - *DepList = (u8*)sdk1_dep_list; - break; - case 2: - *AccessDescData = (u8*)app_2_acex_data; - *DepList = (u8*)sdk2_dep_list; - break; - case 4: - case 5: - *AccessDescData = (u8*)app_4_acex_data; - *DepList = (u8*)sdk4_dep_list; - break; - case 7: - *AccessDescData = (u8*)app_7_acex_data; - *DepList = (u8*)sdk7_dep_list; - break; - - } - } - else if(ncchset->keys->accessDescSign.presetType == ec_app){ - switch(ncchset->keys->accessDescSign.targetFirmware){ - case 4: - case 5: - *AccessDescData = (u8*)ecapp_4_acex_data; - *DepList = (u8*)sdk4_dep_list; - break; - } - } - else if(ncchset->keys->accessDescSign.presetType == dlp){ - switch(ncchset->keys->accessDescSign.targetFirmware){ - case 1: - *AccessDescData = (u8*)dlp_1_acex_data; - *DepList = (u8*)sdk1_dep_list; - break; - case 2: - *AccessDescData = (u8*)dlp_2_acex_data; - *DepList = (u8*)sdk2_dep_list; - break; - case 4: - case 5: - *AccessDescData = (u8*)dlp_4_acex_data; - *DepList = (u8*)sdk4_dep_list; - break; - } - } - else if(ncchset->keys->accessDescSign.presetType == demo){ - switch(ncchset->keys->accessDescSign.targetFirmware){ - case 4: - case 5: - *AccessDescData = (u8*)demo_4_acex_data; - *DepList = (u8*)sdk4_dep_list; - break; - } - } -} - -#ifndef PUBLIC_BUILD -void accessdesc_GetPresetSigData(u8 **AccessDescSig, u8 **CXI_Pubk, u8 **CXI_Privk, ncch_settings *ncchset) -{ - if(ncchset->keys->accessDescSign.presetType == app){ - switch(ncchset->keys->accessDescSign.targetFirmware){ - case 1: - if(ncchset->keys->keyset == pki_DEVELOPMENT){ - *AccessDescSig = (u8*)app_1_dev_acexsig; - *CXI_Pubk = (u8*)app_1_dev_hdrpub; - *CXI_Privk = (u8*)app_1_dev_hdrpvt; - } - break; - case 2: - if(ncchset->keys->keyset == pki_DEVELOPMENT){ - *AccessDescSig = (u8*)app_2_dev_acexsig; - *CXI_Pubk = (u8*)app_2_dev_hdrpub; - *CXI_Privk = (u8*)app_2_dev_hdrpvt; - } - break; - case 4: - case 5: - if(ncchset->keys->keyset == pki_DEVELOPMENT){ - *AccessDescSig = (u8*)app_4_dev_acexsig; - *CXI_Pubk = (u8*)app_4_dev_hdrpub; - *CXI_Privk = (u8*)app_4_dev_hdrpvt; - } - else if(ncchset->keys->keyset == pki_PRODUCTION){ - *AccessDescSig = (u8*)app_4_prod_acexsig; - *CXI_Pubk = (u8*)app_4_prod_hdrpub; - *CXI_Privk = NULL; - } - break; - case 7: - if(ncchset->keys->keyset == pki_PRODUCTION){ - *AccessDescSig = (u8*)app_7_prod_acexsig; - *CXI_Pubk = (u8*)app_7_prod_hdrpub; - *CXI_Privk = NULL; - } - break; - - } - } - else if(ncchset->keys->accessDescSign.presetType == ec_app){ - switch(ncchset->keys->accessDescSign.targetFirmware){ - case 4: - case 5: - if(ncchset->keys->keyset == pki_PRODUCTION){ - *AccessDescSig = (u8*)ecapp_4_prod_acexsig; - *CXI_Pubk = (u8*)ecapp_4_prod_hdrpub; - *CXI_Privk = NULL; - } - break; - } - } - else if(ncchset->keys->accessDescSign.presetType == dlp){ - switch(ncchset->keys->accessDescSign.targetFirmware){ - case 1: - if(ncchset->keys->keyset == pki_DEVELOPMENT){ - *AccessDescSig = (u8*)dlp_1_dev_acexsig; - *CXI_Pubk = (u8*)dlp_1_dev_hdrpub; - *CXI_Privk = (u8*)dlp_1_dev_hdrpvt; - } - break; - case 2: - if(ncchset->keys->keyset == pki_DEVELOPMENT){ - *AccessDescSig = (u8*)dlp_2_dev_acexsig; - *CXI_Pubk = (u8*)dlp_2_dev_hdrpub; - *CXI_Privk = (u8*)dlp_2_dev_hdrpvt; - } - break; - case 4: - case 5: - if(ncchset->keys->keyset == pki_DEVELOPMENT){ - *AccessDescSig = (u8*)dlp_4_dev_acexsig; - *CXI_Pubk = (u8*)dlp_4_dev_hdrpub; - *CXI_Privk = (u8*)dlp_4_dev_hdrpvt; - } - break; - } - } - else if(ncchset->keys->accessDescSign.presetType == demo){ - switch(ncchset->keys->accessDescSign.targetFirmware){ - case 4: - case 5: - if(ncchset->keys->keyset == pki_DEVELOPMENT){ - *AccessDescSig = (u8*)demo_4_dev_acexsig; - *CXI_Pubk = (u8*)demo_4_dev_hdrpub; - *CXI_Privk = (u8*)demo_4_dev_hdrpvt; - } - break; - } - } -} -#endif /* Generic Exheader Errors */ void ErrorParamNotFound(char *string) @@ -1531,7 +1184,7 @@ u8* GetAccessDesc_frm_exhdr(extended_hdr *hdr) u16 GetRemasterVersion_frm_exhdr(extended_hdr *hdr) { - return u8_to_u16(hdr->codeSetInfo.flags.remasterVersion,LE); + return u8_to_u16(hdr->codeSetInfo.remasterVersion,LE); } u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr) @@ -1539,9 +1192,9 @@ u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr) return u8_to_u64(hdr->systemInfo.savedataSize,LE); } -int GetCoreVersion_frm_exhdr(u8 *Dest, extended_hdr *hdr) +void GetCoreVersion_frm_exhdr(u8 *Dest, extended_hdr *hdr) { - return (int) memcpy(Dest,hdr->arm11SystemLocalCapabilities.flags,4); + memcpy(Dest,hdr->arm11SystemLocalCapabilities.coreVersion,4); } int GetDependencyList_frm_exhdr(u8 *Dest, extended_hdr *hdr) diff --git a/exheader.h b/exheader.h index e16fe99..aee01fa 100644 --- a/exheader.h +++ b/exheader.h @@ -1,5 +1,4 @@ -#ifndef _EXHEADER_H_ -#define _EXHEADER_H_ +#pragma once typedef enum { @@ -94,13 +93,6 @@ typedef enum arm9cap_USE_DIRECT_SDMC = (1 << 9), } arm9_capability; -typedef struct -{ - u8 reserved[5]; - u8 flag; - u8 remasterVersion[2]; // le u16 -} exhdr_SystemInfoFlags; - typedef struct { u8 address[4]; // le u32 @@ -111,11 +103,13 @@ typedef struct typedef struct { u8 name[8]; - exhdr_SystemInfoFlags flags; + u8 padding0[5]; + u8 flag; + u8 remasterVersion[2]; // le u16 exhdr_CodeSegmentInfo textSectionInfo; u8 stackSize[4]; // le u32 exhdr_CodeSegmentInfo readOnlySectionInfo; - u8 padding0[4]; + u8 padding1[4]; exhdr_CodeSegmentInfo dataSectionInfo; u8 bssSize[4]; // le u32 } exhdr_CodeSetInfo; @@ -139,11 +133,14 @@ typedef struct typedef struct { u8 programId[8]; - u8 flags[8]; + u8 coreVersion[4]; + u8 padding0[2]; + u8 flag; + u8 priority; u8 resourceLimitDescriptor[16][2]; exhdr_StorageInfo storageInfo; - u8 serviceAccessControl[32][8]; // Those char[8] svc handles - u8 padding0[0x1f]; + u8 serviceAccessControl[32][8]; // Those char[8] server names + u8 padding1[0x1f]; u8 resourceLimitCategory; } exhdr_ARM11SystemLocalCapabilities; @@ -208,7 +205,7 @@ typedef struct extended_hdr *exHdr; // is the exheader output buffer ptr(in ncchset) cast as exheader struct ptr; } exheader_settings; -#endif + /* ExHeader Signature Functions */ int SignAccessDesc(extended_hdr *ExHdr, keys_struct *keys); int CheckaccessDescSignature(extended_hdr *ExHdr, keys_struct *keys); @@ -226,9 +223,11 @@ u8* GetAccessDesc_frm_exhdr(extended_hdr *hdr); u16 GetRemasterVersion_frm_exhdr(extended_hdr *hdr); u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr); int GetDependencyList_frm_exhdr(u8 *Dest,extended_hdr *hdr); -int GetCoreVersion_frm_exhdr(u8 *Dest, extended_hdr *hdr); +void GetCoreVersion_frm_exhdr(u8 *Dest, extended_hdr *hdr); /* ExHeader Settings Read from Yaml */ int GetSaveDataSize_rsf(u64 *SaveDataSize, user_settings *usrset); int GetSaveDataSizeFromString(u64 *out, char *string); int GetRemasterVersion_rsf(u16 *RemasterVersion, user_settings *usrset); + +void ErrorParamNotFound(char *string); \ No newline at end of file diff --git a/keyset.c b/keyset.c index f50a267..f9e5cbe 100644 --- a/keyset.c +++ b/keyset.c @@ -13,6 +13,7 @@ int SetunFixedKey(keys_struct *keys, u8 *unFixedKey); void InitcommonKeySlots(keys_struct *keys); FILE* keyset_OpenFile(char *dir, char *name, bool FileRequired); +void keysetOpenError(char *file); int SetTIK_RsaKey(keys_struct *keys, u8 *PrivateExp, u8 *PublicMod); int SetTMD_RsaKey(keys_struct *keys, u8 *PrivateExp, u8 *PublicMod); @@ -32,14 +33,13 @@ void InitKeys(keys_struct *keys) InitcommonKeySlots(keys); keys->rsa.cxiHdrPub = malloc(RSA_2048_KEY_SIZE); keys->rsa.cxiHdrPvt = malloc(RSA_2048_KEY_SIZE); - keys->aes.supportUnFixedKeys = false; keys->aes.unFixedKey0 = malloc(16); keys->aes.unFixedKey1 = malloc(16); } void PrintBadKeySize(char *path, u32 size) { - fprintf(stderr,"[KEYSET ERROR] %s is has invalid size (0x%x)\n",path,size); + fprintf(stderr,"[KEYSET ERROR] %s has invalid size (0x%x)\n",path,size); } int SetKeys(keys_struct *keys) @@ -47,12 +47,14 @@ int SetKeys(keys_struct *keys) if(keys->keyset == pki_TEST){ // Ergo False Sign /* AES Keys */ // CIA - //SetcommonKey(keys,(u8*)zeros_aesKey,1); + //SetCommonKey(keys,(u8*)zeros_aesKey,1); if(keys->aes.currentCommonKey > 0xff) - SetcurrentCommonKey(keys,0); + SetCurrentCommonKey(keys,0); // NCCH keys->aes.normalKey = (u8*)zeros_aesKey; + keys->aes.systemFixedKey = NULL; + //SetSystemFixedKey(keys,(u8*)zeros_aesKey); /* RSA Keys */ keys->rsa.isFalseSign = true; @@ -70,33 +72,17 @@ int SetKeys(keys_struct *keys) SetTmdCert(keys,(u8*)cpB_tpki_cert); } else if(keys->keyset == pki_CUSTOM){ - int keydir_pathlen = strlen(keys->keydir); - char *path = NULL; -#ifdef _WIN32 - char slash = '\\'; -#else - char slash = '/'; -#endif - if(keys->keydir[keydir_pathlen-1] != slash){ - path = malloc(sizeof(char)*(keydir_pathlen+1)); - memset(path,0,sizeof(char)*(keydir_pathlen+1)); - sprintf(path,"%s%c",keys->keydir,slash); - } - else{ - path = malloc(sizeof(char)*(keydir_pathlen)); - memset(path,0,sizeof(char)*(keydir_pathlen)); - sprintf(path,"%s",keys->keydir); - } + char *cwd = calloc(100,sizeof(char)); + getcwdir(cwd,100); - FILE *fp = NULL; + chdir(keys->keydir); // NCCH keys->aes.normalKey = (u8*)zeros_aesKey; - fp = keyset_OpenFile(path,"systemfixed.aesKey",false); - if(fp){ - keys->aes.systemFixedKey = malloc(16); - fread(keys->aes.systemFixedKey,16,1,fp); - fclose(fp); + if(DoesFileExist("systemfixed.aesKey")){ + keys->aes.systemFixedKey = ImportFile("systemfixed.aesKey",16); + if(!keys->aes.systemFixedKey) + return FAILED_TO_IMPORT_FILE; } // commonKeys @@ -104,165 +90,129 @@ int SetKeys(keys_struct *keys) for(int i = 0; i < 256; i++){ memset(common_key_name,0,sizeof(char)*30); sprintf(common_key_name,"common_etd_%d.aesKey",i); - fp = keyset_OpenFile(path,common_key_name,false); - if(fp){ - keys->aes.commonKey[i] = malloc(16); - fread(keys->aes.commonKey[i],16,1,fp); + if(DoesFileExist(common_key_name)){ + keys->aes.commonKey[i] = ImportFile(common_key_name,16); + if(!keys->aes.commonKey[i]) + return FAILED_TO_IMPORT_FILE; if(keys->aes.currentCommonKey > 0xff) - SetcurrentCommonKey(keys,i); - fclose(fp); + SetCurrentCommonKey(keys,i); } } // Certs - fp = keyset_OpenFile(path,"ca_cpki.cert",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - keys->certs.caCert = malloc(size); - fread(keys->certs.caCert,size,1,fp); - fclose(fp); + if(DoesFileExist("ca_cpki.cert")){ + keys->certs.caCert = ImportFile("ca_cpki.cert",0); + if(!keys->certs.caCert) + return FAILED_TO_IMPORT_FILE; } - else + else{ + keysetOpenError("ca_cpki.cert"); return FAILED_TO_IMPORT_FILE; + } - fp = keyset_OpenFile(path,"xs_cpki.cert",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - keys->certs.xsCert = malloc(size); - fread(keys->certs.xsCert,size,1,fp); - fclose(fp); + if(DoesFileExist("xs_cpki.cert")){ + keys->certs.xsCert = ImportFile("xs_cpki.cert",0); + if(!keys->certs.xsCert) + return FAILED_TO_IMPORT_FILE; } - else + else{ + keysetOpenError("xs_cpki.cert"); return FAILED_TO_IMPORT_FILE; + } - fp = keyset_OpenFile(path,"cp_cpki.cert",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - keys->certs.cpCert = malloc(size); - fread(keys->certs.cpCert,size,1,fp); - fclose(fp); + if(DoesFileExist("cp_cpki.cert")){ + keys->certs.cpCert = ImportFile("cp_cpki.cert",0); + if(!keys->certs.cpCert) + return FAILED_TO_IMPORT_FILE; } - else + else{ + keysetOpenError("cp_cpki.cert"); return FAILED_TO_IMPORT_FILE; + } // RSA Keys - fp = keyset_OpenFile(path,"cp_cpki.rsaPubKey",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - if(size != RSA_2048_KEY_SIZE){ - PrintBadKeySize("cp_cpki.rsaPubKey",size); + if(DoesFileExist("cp_cpki.rsaPubKey")){ + keys->rsa.cpPub = ImportFile("cp_cpki.rsaPubKey",RSA_2048_KEY_SIZE); + if(!keys->rsa.cpPub) return FAILED_TO_IMPORT_FILE; - } - keys->rsa.cpPub = malloc(size); - fread(keys->rsa.cpPub,size,1,fp); - fclose(fp); } - else + else{ + keysetOpenError("cp_cpki.rsaPubKey"); return FAILED_TO_IMPORT_FILE; + } - fp = keyset_OpenFile(path,"cp_cpki.rsaPvtKey",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - if(size != RSA_2048_KEY_SIZE){ - PrintBadKeySize("cp_cpki.rsaPvtKey",size); + if(DoesFileExist("cp_cpki.rsaPvtKey")){ + keys->rsa.cpPvt = ImportFile("cp_cpki.rsaPvtKey",RSA_2048_KEY_SIZE); + if(!keys->rsa.cpPvt) return FAILED_TO_IMPORT_FILE; - } - keys->rsa.cpPvt = malloc(size); - fread(keys->rsa.cpPvt,size,1,fp); - fclose(fp); } - else + else{ + keysetOpenError("cp_cpki.rsaPvtKey"); return FAILED_TO_IMPORT_FILE; + } - fp = keyset_OpenFile(path,"xs_cpki.rsaPubKey",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - if(size != RSA_2048_KEY_SIZE){ - PrintBadKeySize("xs_cpki.rsaPubKey",size); + if(DoesFileExist("xs_cpki.rsaPubKey")){ + keys->rsa.xsPub = ImportFile("xs_cpki.rsaPubKey",RSA_2048_KEY_SIZE); + if(!keys->rsa.xsPub) return FAILED_TO_IMPORT_FILE; - } - keys->rsa.xsPub = malloc(size); - fread(keys->rsa.xsPub,size,1,fp); - fclose(fp); } - else + else{ + keysetOpenError("xs_cpki.rsaPubKey"); return FAILED_TO_IMPORT_FILE; + } - fp = keyset_OpenFile(path,"xs_cpki.rsaPvtKey",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - if(size != RSA_2048_KEY_SIZE){ - PrintBadKeySize("xs_cpki.rsaPvtKey",size); + if(DoesFileExist("xs_cpki.rsaPvtKey")){ + keys->rsa.xsPvt = ImportFile("xs_cpki.rsaPvtKey",RSA_2048_KEY_SIZE); + if(!keys->rsa.xsPvt) return FAILED_TO_IMPORT_FILE; - } - keys->rsa.xsPvt = malloc(size); - fread(keys->rsa.xsPvt,size,1,fp); - fclose(fp); } - else + else{ + keysetOpenError("xs_cpki.rsaPvtKey"); return FAILED_TO_IMPORT_FILE; + } - fp = keyset_OpenFile(path,"ncsd_cfa.rsaPubKey",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - if(size != RSA_2048_KEY_SIZE){ - PrintBadKeySize("ncsd_cfa.rsaPubKey",size); + if(DoesFileExist("ncsd_cfa.rsaPubKey")){ + keys->rsa.cciCfaPub = ImportFile("ncsd_cfa.rsaPubKey",RSA_2048_KEY_SIZE); + if(!keys->rsa.cciCfaPub) return FAILED_TO_IMPORT_FILE; - } - keys->rsa.cciCfaPub = malloc(size); - fread(keys->rsa.cciCfaPub,size,1,fp); - fclose(fp); } - else + else{ + keysetOpenError("ncsd_cfa.rsaPubKey"); return FAILED_TO_IMPORT_FILE; + } - fp = keyset_OpenFile(path,"ncsd_cfa.rsaPvtKey",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - if(size != RSA_2048_KEY_SIZE){ - PrintBadKeySize("ncsd_cfa.rsaPvtKey",size); + if(DoesFileExist("ncsd_cfa.rsaPvtKey")){ + keys->rsa.cciCfaPvt = ImportFile("ncsd_cfa.rsaPvtKey",RSA_2048_KEY_SIZE); + if(!keys->rsa.cciCfaPvt) return FAILED_TO_IMPORT_FILE; - } - keys->rsa.cciCfaPvt = malloc(size); - fread(keys->rsa.cciCfaPvt,size,1,fp); - fclose(fp); } - else + else{ + keysetOpenError("ncsd_cfa.rsaPvtKey"); return FAILED_TO_IMPORT_FILE; - - fp = keyset_OpenFile(path,"acex.rsaPubKey",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - if(size != RSA_2048_KEY_SIZE){ - PrintBadKeySize("acex.rsaPubKey",size); + } + + if(DoesFileExist("acex.rsaPubKey")){ + keys->rsa.acexPub = ImportFile("acex.rsaPubKey",RSA_2048_KEY_SIZE); + if(!keys->rsa.acexPub) return FAILED_TO_IMPORT_FILE; - } - keys->rsa.acexPub = malloc(size); - fread(keys->rsa.acexPub,size,1,fp); - fclose(fp); } - else + else{ + keysetOpenError("acex.rsaPubKey"); return FAILED_TO_IMPORT_FILE; + } - fp = keyset_OpenFile(path,"acex.rsaPvtKey",true); - if(fp){ - u32 size = GetFileSize_u32(fp); - if(size != RSA_2048_KEY_SIZE){ - PrintBadKeySize("acex.rsaPvtKey",size); + if(DoesFileExist("acex.rsaPvtKey")){ + keys->rsa.acexPvt = ImportFile("acex.rsaPvtKey",RSA_2048_KEY_SIZE); + if(!keys->rsa.acexPvt) return FAILED_TO_IMPORT_FILE; - } - keys->rsa.acexPvt = malloc(size); - fread(keys->rsa.acexPvt,size,1,fp); - fclose(fp); } - else + else{ + keysetOpenError("acex.rsaPvtKey"); return FAILED_TO_IMPORT_FILE; + } -#ifdef DEBUG - fprintf(stdout,"[DEBUG] Set Keys, free path now\n"); -#endif - - free(path); + chdir(cwd); + free(cwd); #ifdef DEBUG fprintf(stdout,"[DEBUG] freed path\n"); #endif @@ -272,17 +222,18 @@ int SetKeys(keys_struct *keys) /* AES Keys */ // CIA for(int i = 0; i < 2; i++){ - SetcommonKey(keys,(u8*)ctr_common_etd_key_dpki[i],i); + SetCommonKey(keys,(u8*)ctr_common_etd_key_dpki[i],i); } if(keys->aes.currentCommonKey > 0xff) - SetcurrentCommonKey(keys,0); + SetCurrentCommonKey(keys,0); // NCCH keys->aes.normalKey = (u8*)ctr_fixed_ncch_key_dpki[0]; - SetsystemFixedKey(keys,(u8*)ctr_fixed_ncch_key_dpki[1]); - keys->aes.supportUnFixedKeys = true; + SetSystemFixedKey(keys,(u8*)ctr_fixed_ncch_key_dpki[1]); + /* keys->aes.ncchKeyX0 = (u8*)ctr_unfixed_ncch_keyX_dpki[0]; keys->aes.ncchKeyX1 = (u8*)ctr_unfixed_ncch_keyX_dpki[1]; + */ /* RSA Keys */ // CIA @@ -302,14 +253,14 @@ int SetKeys(keys_struct *keys) /* AES Keys */ // CIA for(int i = 0; i < 6; i++){ - keys->aes.commonKey[i] = AesKeyScrambler((u8*)ctr_common_etd_keyX_ppki,(u8*)ctr_common_etd_keyY_ppki[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); + SetCurrentCommonKey(keys,1); // NCCH keys->aes.normalKey = (u8*)zeros_aesKey; /* - keys->aes.supportUnFixedKeys = true; keys->aes.ncchKeyX0 = (u8*)ctr_unfixed_ncch_keyX_ppki[0]; keys->aes.ncchKeyX1 = (u8*)ctr_unfixed_ncch_keyX_ppki[1]; */ @@ -399,6 +350,11 @@ FILE* keyset_OpenFile(char *dir, char *name, bool FileRequired) return fp; } +void keysetOpenError(char *file) +{ + fprintf(stderr,"[KEYSET ERROR] Failed to open: %s\n",file); +} + void FreeKeys(keys_struct *keys) { // AES @@ -447,7 +403,7 @@ 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); @@ -461,19 +417,35 @@ void InitcommonKeySlots(keys_struct *keys) } } -int SetcurrentCommonKey(keys_struct *keys, u8 Index) +int SetCurrentCommonKey(keys_struct *keys, u8 Index) { if(!keys) return -1; keys->aes.currentCommonKey = Index; return 0; } -int SetsystemFixedKey(keys_struct *keys, u8 *systemFixedKey) +int SetSystemFixedKey(keys_struct *keys, u8 *systemFixedKey) { if(!keys) return -1; 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/keyset.h b/keyset.h index 6c6eff5..88837e5 100644 --- a/keyset.h +++ b/keyset.h @@ -1,6 +1,4 @@ -#ifndef _KEYSET_H_ -#define _KEYSET_H_ - +#pragma once typedef enum { RSA_1024_KEY_SIZE = 0x80, @@ -51,7 +49,6 @@ typedef struct u8 *normalKey; u8 *systemFixedKey; - bool supportUnFixedKeys; u8 *ncchKeyX0; u8 *ncchKeyX1; u8 *unFixedKey0; @@ -88,13 +85,13 @@ typedef struct } certs; } keys_struct; -#endif - // Public Prototypes void InitKeys(keys_struct *keys); int SetKeys(keys_struct *keys); void FreeKeys(keys_struct *keys); -int SetcommonKey(keys_struct *keys, u8 *commonKey, u8 Index); -int SetcurrentCommonKey(keys_struct *keys, u8 Index); -int SetsystemFixedKey(keys_struct *keys, u8 *systemFixedKey); +int SetCommonKey(keys_struct *keys, u8 *commonKey, u8 Index); +int SetCurrentCommonKey(keys_struct *keys, u8 Index); +int SetSystemFixedKey(keys_struct *keys, u8 *systemFixedKey); + +int SetNcchUnfixedKeys(keys_struct *keys, u8 *ncchSig); \ No newline at end of file diff --git a/lib.h b/lib.h index 4dda1ab..419fb86 100644 --- a/lib.h +++ b/lib.h @@ -11,15 +11,16 @@ #include #include #include +#include +#include +#include +#include + #ifdef _WIN32 #include #include #include - //#include -#else - #include - #include #endif diff --git a/logo_data.h b/logo_data.h index 66ec98a..f8d71c4 100644 --- a/logo_data.h +++ b/logo_data.h @@ -1,5 +1,4 @@ -#ifndef _LOGO_DATA_H_ -#define _LOGO_DATA_H_ +#pragma once static const unsigned char Nintendo_LZ[0x2000] = { @@ -24,6 +23,4 @@ static const unsigned char iQue_with_ISBN_LZ[0x2000] = static const unsigned char iQue_without_ISBN_LZ[0x2000] = { 0x11, 0x48, 0x65, 0x00, 0x00, 0x64, 0x61, 0x72, 0x63, 0xFF, 0xFE, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x28, 0x65, 0x00, 0x00, 0x83, 0x30, 0x09, 0x1C, 0x04, 0x00, 0x00, 0x40, 0x20, 0x03, 0x30, 0x13, 0xAB, 0x30, 0x18, 0x15, 0x20, 0x1D, 0x02, 0xA0, 0x0B, 0x06, 0x20, 0x2B, 0x30, 0x18, 0x5A, 0x09, 0x20, 0x35, 0x10, 0x20, 0x39, 0x30, 0x2B, 0xF8, 0x20, 0x41, 0x54, 0x85, 0x30, 0x0B, 0x05, 0x00, 0x00, 0xEC, 0x20, 0x4D, 0x98, 0x30, 0x17, 0xD0, 0x20, 0x28, 0x30, 0x17, 0xDC, 0x30, 0x23, 0x07, 0x00, 0x00, 0xCC, 0x09, 0x0C, 0x00, 0x00, 0x20, 0x20, 0x51, 0x20, 0x14, 0x20, 0x2B, 0xA0, 0x20, 0x0B, 0x64, 0x20, 0x5D, 0x80, 0x20, 0x00, 0x00, 0x4C, 0x99, 0x20, 0x5C, 0xA8, 0x01, 0x50, 0x53, 0x20, 0x22, 0x00, 0xB2, 0x20, 0x75, 0x34, 0xE0, 0x22, 0x20, 0x13, 0x20, 0x74, 0xE2, 0x20, 0x81, 0xA0, 0x25, 0x13, 0x00, 0x00, 0x3C, 0x20, 0x68, 0x12, 0x02, 0x50, 0x77, 0x30, 0x8F, 0x41, 0x1C, 0x20, 0x90, 0x00, 0x36, 0x00, 0x00, 0x28, 0x20, 0xAB, 0x4D, 0x3E, 0x20, 0x9C, 0x80, 0x3A, 0x20, 0x0B, 0x20, 0xAD, 0x60, 0x30, 0x17, 0x54, 0x3C, 0x50, 0x17, 0x82, 0x30, 0x17, 0x40, 0x20, 0x23, 0x08, 0x00, 0x2D, 0x00, 0xA4, 0x30, 0x2F, 0x49, 0x20, 0x67, 0x20, 0xE9, 0xC4, 0x30, 0x3B, 0x56, 0x4A, 0x50, 0x17, 0xDC, 0x30, 0x3B, 0x52, 0x20, 0x47, 0x20, 0xE0, 0xF4, 0xB2, 0x30, 0x53, 0x55, 0x20, 0x53, 0x30, 0xD4, 0x00, 0x2E, 0x21, 0x13, 0x61, 0x02, 0x00, 0x6E, 0x00, 0x69, 0x00, 0x6D, 0x21, 0x1D, 0x4E, 0x82, 0x20, 0x07, 0x6E, 0x00, 0x74, 0x00, 0x65, 0x20, 0x11, 0x64, 0x0A, 0x00, 0x6F, 0x00, 0x4C, 0x20, 0x03, 0x67, 0x20, 0x07, 0x5F, 0x28, 0x00, 0x44, 0x20, 0x03, 0x30, 0x20, 0x01, 0x5F, 0x00, 0x53, 0x20, 0x00, 0x63, 0x40, 0x1F, 0x65, 0x00, 0x4F, 0x00, 0x75, 0xAB, 0x20, 0x2B, 0x41, 0x20, 0x43, 0x62, 0x20, 0x13, 0x6C, 0x40, 0x47, 0x02, 0x50, 0x43, 0x57, 0x42, 0x03, 0x20, 0x43, 0x43, 0x01, 0x80, 0x87, 0x55, 0x03, 0x20, 0xCB, 0x00, 0x90, 0x43, 0x01, 0x90, 0xCB, 0xD7, 0x00, 0x90, 0x87, 0xF0, 0xCB, 0x62, 0x21, 0x5D, 0x79, 0x21, 0x97, 0x01, 0x31, 0xA1, 0x71, 0x8D, 0xEA, 0x00, 0xF0, 0x2F, 0x71, 0x05, 0xD0, 0x2F, 0x74, 0x42, 0x09, 0x67, 0x23, 0x29, 0x33, 0xBD, 0x22, 0x01, 0x73, 0xA2, 0x01, 0xB0, 0x5B, 0x52, 0x2D, 0x00, 0x10, 0x21, 0x31, 0x01, 0x00, 0x21, 0x55, 0x32, 0x01, 0x00, 0x43, 0x33, 0xE0, 0x65, 0x4C, 0x23, 0x71, 0x4D, 0x22, 0xA3, 0x1F, 0x73, 0x00, 0x6B, 0x00, 0x40, 0x85, 0x30, 0x1F, 0x00, 0xB0, 0x17, 0xF0, 0x93, 0xF2, 0xE3, 0x41, 0x5F, 0x20, 0xB5, 0x32, 0x00, 0x38, 0x00, 0x78, 0x23, 0x68, 0x60, 0x34, 0xE0, 0xE1, 0x70, 0x02, 0x43, 0x4C, 0x41, 0x4E, 0xFF, 0x46, 0xFE, 0x23, 0xD0, 0x00, 0x02, 0x02, 0x34, 0x03, 0x33, 0x96, 0x70, 0x1D, 0x61, 0x74, 0x31, 0x23, 0x82, 0x44, 0x3E, 0x34, 0x59, 0x28, 0x33, 0x73, 0x10, 0xFF, 0xFF, 0xFF, 0x34, 0x4C, 0x53, 0x63, 0x65, 0x6E, 0x04, 0x65, 0x4F, 0x75, 0x74, 0x41, 0x24, 0x71, 0x47, 0x5F, 0x0C, 0x41, 0x5F, 0x30, 0x30, 0xA0, 0x4C, 0x40, 0x3B, 0x69, 0x31, 0xCD, 0x33, 0xA3, 0x50, 0x3F, 0x02, 0x00, 0x30, 0x59, 0x34, 0x9D, 0x68, 0x24, 0xA1, 0x00, 0x50, 0x5F, 0x4E, 0x69, 0x6E, 0x4C, 0x6F, 0x67, 0x70, 0x6F, 0xA0, 0x35, 0x34, 0xA0, 0x34, 0xBD, 0x43, 0x4C, 0x56, 0x43, 0x8F, 0x74, 0x3F, 0x00, 0x10, 0x02, 0x40, 0x87, 0x40, 0x0B, 0xD0, 0x5D, 0x20, 0x76, 0x20, 0x7F, 0x43, 0x34, 0xEC, 0x4E, 0x5F, 0x52, 0x6F, 0x6F, 0x73, 0x74, 0xD0, 0x7E, 0x00, 0x70, 0x4B, 0x80, 0x57, 0x00, 0x20, 0x20, 0x3B, 0x50, 0x3F, 0xF8, 0x00, 0x30, 0xFF, 0x34, 0xF7, 0xB0, 0xFF, 0x24, 0xD2, 0x80, 0xFF, 0x00, 0x00, 0x1E, 0xD5, 0x45, 0x4C, 0x70, 0xFF, 0x42, 0x40, 0xFF, 0x42, 0x00, 0x40, 0xFF, 0x9C, 0x80, 0x2D, 0xB2, 0x90, 0xFF, 0x5C, 0x01, 0xE0, 0xFF, 0x90, 0xB3, 0x34, 0xC2, 0x02, 0xD0, 0xF3, 0xC8, 0xFD, 0x20, 0xAA, 0xD0, 0xF3, 0x00, 0x70, 0xFF, 0xF1, 0xFF, 0x31, 0x39, 0x71, 0xFF, 0x65, 0x23, 0x31, 0xC5, 0xB1, 0xFF, 0x31, 0x84, 0x47, 0x5F, 0x43, 0x00, 0x81, 0xFF, 0x0F, 0xE1, 0xFF, 0x99, 0x02, 0x90, 0xFF, 0x12, 0xC3, 0x02, 0x31, 0xF3, 0x92, 0x3F, 0x80, 0xBF, 0x91, 0xF3, 0x7B, 0x60, 0x32, 0xB6, 0x00, 0x80, 0xFF, 0x36, 0xDF, 0x03, 0x32, 0xFF, 0x7C, 0x27, 0x27, 0x53, 0x3F, 0x55, 0x0D, 0x42, 0xFF, 0x48, 0x27, 0x9D, 0xB0, 0x27, 0xA1, 0xA4, 0x27, 0x8D, 0x60, 0x24, 0x27, 0x88, 0x36, 0xCB, 0x30, 0x03, 0x00, 0x00, 0xBC, 0xAD, 0x20, 0x03, 0x24, 0x27, 0xAB, 0x88, 0x37, 0x73, 0x27, 0x94, 0xB0, 0x26, 0xE7, 0x02, 0x74, 0x0A, 0x00, 0x00, 0x78, 0x0B, 0x32, 0xDF, 0x57, 0xF9, 0x00, 0x03, 0x5B, 0x37, 0x32, 0x27, 0x6E, 0x26, 0xB1, 0x33, 0xB7, 0x50, 0x41, 0x83, 0x2F, 0x71, 0x02, 0xF2, 0xE3, 0x73, 0xDB, 0x01, 0x13, 0x07, 0x50, 0x5F, 0x33, 0x00, 0x80, 0x67, 0x77, 0xB8, 0x60, 0x67, 0x20, 0xAA, 0x43, 0xC7, 0x38, 0x63, 0xC7, 0x30, 0x6F, 0x93, 0x9F, 0x53, 0xA0, 0x24, 0x0A, 0xA0, 0x27, 0xA5, 0x80, 0xBE, 0x24, 0x39, 0x23, 0x16, 0x23, 0xA0, 0xC0, 0x48, 0x79, 0x06, 0x02, 0x00, 0x30, 0x37, 0x70, 0x23, 0x00, 0x33, 0x33, 0xB3, 0x3F, 0xFC, 0x2D, 0xEC, 0xBC, 0x8C, 0x70, 0x0B, 0x0A, 0xD7, 0x23, 0x20, 0x0B, 0x30, 0x2F, 0x80, 0x3F, 0xBC, 0x48, 0xA9, 0x07, 0x01, 0xD0, 0x2F, 0xF4, 0x2F, 0xB0, 0x6B, 0x39, 0x0C, 0x40, 0x9D, 0x6F, 0x1C, 0x30, 0x97, 0x61, 0xEF, 0xCC, 0x28, 0x45, 0x30, 0x9B, 0x70, 0xF3, 0x24, 0x87, 0xDC, 0xE4, 0xB9, 0x71, 0x5B, 0x50, 0xF1, 0x5B, 0x29, 0x39, 0xD4, 0x8B, 0x70, 0xC1, 0x14, 0xCD, 0xCC, 0xCC, 0x20, 0xEB, 0x20, 0x24, 0x02, 0xF8, 0xC1, 0xF9, 0x00, 0x31, 0x67, 0x00, 0x14, 0xBB, 0x30, 0x7F, 0x30, 0x2F, 0x71, 0x73, 0x44, 0x73, 0xF5, 0x38, 0x94, 0x01, 0x90, 0x7F, 0x3C, 0xC2, 0x20, 0x7F, 0x3E, 0x02, 0xD0, 0x7F, 0x52, 0x65, 0x70, 0x64, 0x01, 0x70, 0xFF, 0xC1, 0xEB, 0x45, 0x43, 0xC2, 0xB7, 0x6D, 0xDB, 0xAE, 0x20, 0x7F, 0x8C, 0x25, 0x02, 0x20, 0x00, 0x40, 0xFF, 0x91, 0xF7, 0xB6, 0x1B, 0x5C, 0xA0, 0xA4, 0x87, 0xB4, 0x35, 0x3E, 0x00, 0x92, 0x24, 0xE9, 0xC0, 0xBD, 0x60, 0x8B, 0x31, 0x00, 0x32, 0xE7, 0x35, 0x33, 0xF2, 0xE7, 0x92, 0x53, 0xF0, 0x26, 0x82, 0x7F, 0x20, 0x25, 0x1B, 0x90, 0x0B, 0x50, 0x97, 0x34, 0xEF, 0x00, 0x50, 0x97, 0x96, 0x53, 0x30, 0x3B, 0xAF, 0x77, 0x04, 0xAA, 0xF1, 0x17, 0x32, 0x02, 0x13, 0x73, 0x32, 0xF7, 0x50, 0x8B, 0x00, 0x96, 0x7B, 0xF9, 0x33, 0x1B, 0x57, 0x78, 0x00, 0x31, 0x7F, 0x3B, 0x90, 0x57, 0x07, 0x54, 0x53, 0x2A, 0xEE, 0xB7, 0x47, 0x73, 0x4C, 0x37, 0x8B, 0x2B, 0xD9, 0x94, 0x63, 0x8B, 0x3B, 0x87, 0x3B, 0xD1, 0x61, 0x24, 0x4B, 0xD5, 0x00, 0x01, 0x97, 0xC0, 0x39, 0x8E, 0xE3, 0x2B, 0x39, 0xE8, 0x51, 0x5B, 0x5B, 0xFD, 0x01, 0x20, 0x23, 0x03, 0xF7, 0x6B, 0x40, 0x41, 0x9E, 0x11, 0x15, 0x8D, 0xBD, 0x31, 0xA3, 0x9A, 0x99, 0xB9, 0x2B, 0x7D, 0xAA, 0x2C, 0x5A, 0x04, 0x01, 0x10, 0x23, 0x01, 0x01, 0x20, 0x8F, 0x01, 0x01, 0x20, 0x8F, 0x01, 0xAD, 0x00, 0x10, 0x8F, 0xC1, 0x20, 0x8F, 0x3D, 0x60, 0x8F, 0x44, 0x5B, 0x01, 0x00, 0x10, 0x8F, 0x82, 0x00, 0x00, 0x23, 0x50, 0x5F, 0x42, 0x6C, 0x6B, 0x03, 0xE1, 0x63, 0x9A, 0x03, 0x99, 0x19, 0xC0, 0x0E, 0x74, 0xDA, 0x00, 0xC1, 0x63, 0x00, 0x40, 0x23, 0xFE, 0x04, 0x61, 0x63, 0x00, 0x30, 0x8F, 0xF1, 0x63, 0x00, 0x40, 0x23, 0x03, 0x81, 0x63, 0x00, 0x13, 0xBB, 0x00, 0x32, 0xC7, 0x58, 0xAA, 0x2E, 0x9D, 0x88, 0x66, 0x4F, 0xE8, 0x2E, 0xA9, 0x18, 0x2E, 0x95, 0x48, 0xBE, 0x2E, 0x99, 0x78, 0x62, 0xC7, 0xE3, 0xD3, 0x56, 0x3F, 0x60, 0x0B, 0x52, 0xD3, 0xF0, 0xF7, 0xC2, 0xD3, 0x01, 0xC0, 0x2F, 0x22, 0xDF, 0xD4, 0x33, 0x40, 0x68, 0x03, 0x50, 0x0B, 0x52, 0xEB, 0x7F, 0xF0, 0xC2, 0xEB, 0x01, 0xB0, 0x2F, 0x32, 0xF7, 0x01, 0xB0, 0xBF, 0x33, 0x03, 0x01, 0xC0, 0x2F, 0x00, 0x10, 0xBF, 0xFF, 0x46, 0x73, 0x70, 0x0B, 0x53, 0x1B, 0x40, 0xBF, 0x83, 0x1B, 0x01, 0xB0, 0x2F, 0x63, 0x27, 0x03, 0xC1, 0xC3, 0xFF, 0x33, 0x27, 0x75, 0x97, 0x93, 0x33, 0x00, 0x91, 0xC3, 0x01, 0x00, 0x2F, 0x05, 0xE1, 0xC3, 0x00, 0xF0, 0xBF, 0xF1, 0xC3, 0xFF, 0x01, 0x00, 0x2F, 0x05, 0x01, 0xC3, 0x00, 0x16, 0xB7, 0x00, 0x36, 0x4F, 0x35, 0xCC, 0x33, 0x8B, 0x36, 0x53, 0x33, 0x8F, 0x5F, 0xA0, 0x69, 0xE3, 0xD0, 0x6D, 0xAB, 0xE6, 0xCF, 0x59, 0xC7, 0x26, 0x43, 0x00, 0x40, 0x17, 0xFF, 0x26, 0x37, 0xD6, 0xFF, 0x63, 0x57, 0x26, 0x2B, 0x00, 0x30, 0x17, 0x36, 0x1F, 0x00, 0x30, 0x5F, 0x36, 0x13, 0xFF, 0x00, 0x40, 0x17, 0x00, 0x10, 0x5F, 0x49, 0x6B, 0x35, 0xFB, 0x00, 0x30, 0x17, 0x65, 0xEF, 0x03, 0xC1, 0x03, 0x82, 0xC7, 0xFF, 0xE1, 0x03, 0x82, 0xDF, 0x02, 0xE1, 0x03, 0x73, 0x27, 0xF1, 0x03, 0x80, 0x17, 0x01, 0xE1, 0x03, 0x00, 0xFD, 0xDF, 0x6E, 0x54, 0xEC, 0xDF, 0x02, 0x7E, 0xDF, 0x04, 0x2F, 0xA4, 0x5F, 0x0D, 0xDC, 0xDF, 0x50, 0xAA, 0x2F, 0xCC, 0xB8, 0x2F, 0xD0, 0x20, 0x2F, 0xBC, 0xA0, 0x2F, 0xC0, 0x2C, 0xAA, 0x2C, 0xE3, 0xAC, 0x2C, 0xE7, 0x10, 0x2C, 0xDF, 0x74, 0x2C, 0xDF, 0xD8, 0x5F, 0x07, 0x2D, 0x17, 0x09, 0x2C, 0x31, 0x2C, 0xE3, 0x02, 0x9C, 0xDF, 0x3E, 0xCF, 0x00, 0xFC, 0xDF, 0xD7, 0x9E, 0xF3, 0x00, 0xBC, 0xDF, 0x7C, 0xEC, 0xDF, 0x2C, 0x6D, 0x5B, 0xDD, 0x4F, 0x4C, 0xE3, 0xFF, 0x8C, 0xD3, 0xD0, 0x17, 0x9C, 0xBB, 0x00, 0x30, 0x17, 0x00, 0x9F, 0xD3, 0x3F, 0xFD, 0x01, 0x1C, 0x8B, 0x00, 0x0D, 0xE7, 0xBF, 0xC3, 0xA3, 0xA0, 0x2C, 0x7B, 0x00, 0x5C, 0x7F, 0xD0, 0x23, 0x01, 0x1C, 0x73, 0x03, 0xD0, 0x67, 0x02, 0x7C, 0x5B, 0x6F, 0x70, 0x2B, 0xCB, 0x7C, 0x5B, 0x20, 0x3B, 0xDB, 0x00, 0xED, 0x5B, 0x3E, 0x67, 0x7F, 0xD7, 0xEF, 0x5B, 0xCF, 0x00, 0xFC, 0x4F, 0x00, 0xDC, 0xDB, 0xF0, 0x2D, 0xCB, 0x80, 0x7F, 0x01, 0x2C, 0xDB, 0x30, 0x2F, 0xBF, 0x7F, 0xFB, 0xC8, 0x2F, 0x03, 0x7C, 0xDB, 0x5B, 0xE7, 0xAC, 0xDB, 0x00, 0x4C, 0x4F, 0x03, 0x3D, 0x67, 0xFF, 0x00, 0x1E, 0x67, 0xDD, 0x67, 0x04, 0x1C, 0x67, 0x41, 0xA3, 0x79, 0x93, 0x9D, 0x43, 0xCC, 0x67, 0x00, 0x60, 0x23, 0xFF, 0xCC, 0x67, 0x31, 0xEB, 0x89, 0x7B, 0x28, 0x2F, 0x00, 0x3C, 0x67, 0x00, 0x50, 0x23, 0xDC, 0x67, 0x00, 0x50, 0x8F, 0xFF, 0xDC, 0x67, 0x00, 0x60, 0x23, 0x00, 0x10, 0x8F, 0x79, 0x4B, 0x30, 0x8F, 0x00, 0x2C, 0x67, 0x00, 0x50, 0x23, 0x04, 0x1C, 0x67, 0x3F, 0x70, 0xC2, 0xA9, 0x33, 0x00, 0x81, 0x63, 0x00, 0x40, 0x23, 0x04, 0x61, 0x63, 0x00, 0x30, 0x8F, 0xF1, 0x63, 0xFF, 0x00, 0x40, 0x23, 0x03, 0x81, 0x63, 0x01, 0x5C, 0x67, 0x01, 0x9F, 0x2F, 0x43, 0xEB, 0x6F, 0x2F, 0x9F, 0x97, 0xDF, 0x2F, 0xFF, 0x00, 0x60, 0x23, 0xCF, 0x2F, 0x34, 0x33, 0x7F, 0x2F, 0x38, 0x2F, 0x00, 0x3F, 0x2F, 0x00, 0x50, 0x23, 0xDF, 0x2F, 0xFF, 0x00, 0x50, 0x8F, 0xDF, 0x2F, 0x00, 0x60, 0x23, 0x00, 0x10, 0x8F, 0x6F, 0x2F, 0x40, 0x8F, 0x00, 0x2F, 0x2F, 0x00, 0x50, 0x23, 0xFF, 0x01, 0x7C, 0x07, 0x01, 0xB1, 0x63, 0x9F, 0x2F, 0x00, 0x91, 0x63, 0x00, 0x40, 0x23, 0x04, 0x61, 0x63, 0x00, 0x30, 0x8F, 0xF1, 0x63, 0xFF, 0x00, 0x40, 0x23, 0x03, 0x81, 0x63, 0x01, 0x5B, 0xA7, 0x01, 0x95, 0x8F, 0x46, 0x27, 0x6F, 0x23, 0x9F, 0xDF, 0xD5, 0x8F, 0xFF, 0x00, 0x60, 0x23, 0xC5, 0x8F, 0x4F, 0xDF, 0x6F, 0x0B, 0x4F, 0xDF, 0x00, 0x25, 0x8F, 0x00, 0x50, 0x23, 0xD5, 0x8F, 0xFF, 0x00, 0x50, 0x8F, 0xD5, 0x8F, 0x00, 0x60, 0x23, 0x00, 0x10, 0x8F, 0x6E, 0xDB, 0x40, 0x8F, 0x00, 0x25, 0x8F, 0x00, 0x50, 0x23, 0xFF, 0x01, 0x7C, 0x07, 0x01, 0xB1, 0x63, 0x9E, 0xC3, 0x00, 0x91, 0x63, 0x00, 0x40, 0x23, 0x04, 0x61, 0x63, 0x00, 0x30, 0x8F, 0xF1, 0x63, 0xEF, 0x00, 0x40, 0x23, 0x03, 0x61, 0x63, 0x00, 0x7C, 0x5F, 0x4C, 0x2C, 0x5C, 0xBC, 0x5F, 0x3E, 0x51, 0x7C, 0x5F, 0x18, 0x65, 0x00, 0x73, 0xCC, 0x5F, 0x3B, 0x9C, 0x47, 0x5F, 0x43, 0xAF, 0x00, 0x4C, 0x5F, 0xFC, 0x2E, 0xBB, 0x0F, 0x5B, 0x58, 0x4C, 0x5F, 0x3C, 0x82, 0x3B, 0xAB, 0x55, 0xBC, 0x2F, 0xFF, 0xFC, 0x2F, 0xF8, 0x3C, 0x2E, 0xDB, 0x7C, 0x2E, 0xDF, 0x7C, 0xBC, 0x2E, 0xE3, 0x00, 0x3C, 0x47, 0x3E, 0xC7, 0x5E, 0xFB, 0x00, 0x7A, 0x3B, 0x80, 0xBF, 0xBD, 0x9A, 0x3B, 0x60, 0x88, 0xC7, 0x00, 0x3C, 0x2B, 0x00, 0x70, 0x4B, 0x9F, 0x2B, 0xCA, 0x2A, 0xB7, 0xDF, 0x00, 0x9B, 0xCB, 0x01, 0x10, 0x3F, 0xF2, 0xA0, 0x3F, 0x00, 0x1B, 0xA3, 0x01, 0xD0, 0x3F, 0x00, 0x29, 0xEF, 0x01, 0x00, 0xBF, 0x7B, 0x8E, 0x2B, 0x77, 0x70, 0xFF, 0x00, 0x27, 0x67, 0x01, 0x00, 0xFF, 0x24, 0xF0, 0x3F, 0xDF, 0x83, 0xB2, 0x01, 0x01, 0x3F, 0x30, 0x00, 0x8E, 0xBB, 0x5E, 0xBF, 0x59, 0x54, 0x7E, 0xBF, 0xA8, 0xA1, 0x2E, 0xBC, 0x10, 0x2F, 0xFB, 0x6C, 0x79, 0x74, 0x31, 0x3E, 0xD1, 0x90, 0x4A, 0x9E, 0x00, 0xA0, 0x2D, 0xE7, 0x70, 0x43, 0x74, 0x78, 0x36, 0x6C, 0x31, 0x3F, 0xDF, 0x3F, 0xBF, 0x04, 0x2F, 0xFF, 0x2D, 0x55, 0x74, 0x00, 0x65, 0x6E, 0x64, 0x6F, 0x5F, 0x31, 0x32, 0x38, 0x00, 0x78, 0x36, 0x34, 0x2E, 0x62, 0x63, 0x6C, 0x69, 0x57, 0x6D, 0x2F, 0xFF, 0x6D, 0x2E, 0xFB, 0x60, 0x62, 0x23, 0x30, 0x4B, 0x4D, 0x7F, 0x08, 0x4C, 0x6F, 0x67, 0x6F, 0xAE, 0xE9, 0xFF, 0xFF, 0xFF, 0xDF, 0x30, 0x03, 0x00, 0x40, 0x02, 0x15, 0x5F, 0xE0, 0x30, 0x62, 0xAF, 0x72, 0x3E, 0x07, 0x5E, 0x0B, 0x08, 0x70, 0x61, 0x6E, 0x31, 0x3B, 0x4F, 0x01, 0x04, 0xFF, 0x00, 0x00, 0x52, 0x6F, 0x6F, 0x74, 0x50, 0x61, 0x6E, 0x70, 0x65, 0x00, 0xB0, 0xDF, 0x00, 0x50, 0x47, 0x50, 0xD3, 0x70, 0x61, 0x73, 0x31, 0xD3, 0x3B, 0xA3, 0x70, 0x53, 0x03, 0x20, 0x53, 0x4E, 0x5F, 0x30, 0x55, 0x00, 0x0F, 0x96, 0xD0, 0x01, 0x20, 0x53, 0x4C, 0xD3, 0x42, 0x80, 0x53, 0x69, 0x63, 0x31, 0x80, 0x9F, 0x3C, 0x0F, 0x07, 0xFF, 0x00, 0x41, 0x03, 0x7E, 0xE0, 0x2D, 0x5B, 0x82, 0x1F, 0x00, 0x20, 0xEF, 0x9E, 0x2F, 0x63, 0x80, 0x42, 0xF1, 0x2B, 0x71, 0x99, 0xCF, 0x23, 0xC1, 0x27, 0x80, 0x0C, 0x3F, 0x70, 0x61, 0x65, 0x60, 0xDB, 0x50, 0x07, 0x67, 0x72, 0x30, 0x70, 0x31, 0x3C, 0x97, 0x31, 0x33, 0x47, 0x72, 0x6F, 0x75, 0xCE, 0x3C, 0x8F, 0x7F, 0xE7, 0x67, 0x72, 0x51, 0x07, 0x30, 0x23, 0x34, 0x57, 0x47, 0x3F, 0x5F, 0x41, 0xCF, 0xD3, 0x3F, 0xCF, 0xF1, 0x17, 0xF1, 0xD7, 0x30, 0x5F, 0x3F, 0xDF, 0x1F, 0x47, 0x5F, 0x42, 0xCF, 0x6D, 0x3F, 0xE7, 0x00, 0x90, 0x2B, 0xD4, 0x9F, 0x3F, 0xFB, 0x9A, 0xF1, 0x7F, 0x67, 0x72, 0x50, 0xC7, 0x01, 0x32, 0xBF, 0x3C, 0x22, 0xBC, 0x22, 0xB5, 0x00, 0x02, 0xBF, 0xC8, 0x82, 0xBF, 0x3D, 0x7F, 0x07, 0x64, 0xBB, 0x2D, 0x2F, 0xFF, 0x9D, 0x2F, 0x08, 0x00, 0x4F, 0x34, 0xA1, 0x32, 0xF3, 0x2F, 0xFF, 0x78, 0x2F, 0xFB, 0x1D, 0x33, 0x64, 0x73, 0x62, 0xAD, 0x62, 0xD2, 0x80, 0x10, 0x31, 0xF0, 0x10, 0x53, 0x32, 0xF0, 0x21, 0x33, 0x63, 0x05, 0x4C, 0x54, 0x90, 0x3E, 0x30, 0x0B, 0x83, 0x70, 0x39, 0x4C, 0x54, 0x4D, 0x61, 0x73, 0x3C, 0xCC, 0x63, 0x2D, 0x82, 0x33, 0x2B, 0xA8, 0x06, 0x00, 0x00, 0x0B, 0x2F, 0xFC, 0x38, 0xAA, 0x2F, 0xFF, 0x88, 0x2F, 0xFB, 0x08, 0x2F, 0xF4, 0x88, 0x2F, 0xF8, 0x08, 0xAA, 0x2F, 0xD4, 0x88, 0x2F, 0xD8, 0x4C, 0x2F, 0x10, 0xE8, 0x2F, 0x14, 0xAC, 0x9D, 0x23, 0x74, 0x48, 0x05, 0x2F, 0xD7, 0x20, 0x2F, 0x00, 0x35, 0x47, 0xAA, 0x53, 0x57, 0xBB, 0x00, 0x83, 0x53, 0x02, 0x00, 0xA3, 0x53, 0x00, 0x35, 0x57, 0x00, 0xB3, 0xA3, 0xD5, 0x20, 0xB3, 0x00, 0xB3, 0xA3, 0x68, 0x40, 0x24, 0x20, 0x30, 0x03, 0x11, 0x2F, 0xFB, 0x74, 0x06, 0x00, 0x61, 0x04, 0x30, 0x03, 0x30, 0x0B, 0x65, 0x06, 0x00, 0x01, 0x30, 0x03, 0xE9, 0x30, 0x17, 0x31, 0x87, 0x5E, 0x03, 0x05, 0x2F, 0x47, 0x4F, 0x5F, 0x31, 0x32, 0xB0, 0x01, 0xB0, 0x7F, 0x01, 0x03, 0xE0, 0x7F, 0xD2, 0xB5, 0x00, 0x00, 0x8C, 0x8C, 0x77, 0x8C, 0x05, 0xA0, 0x7F, 0x00, 0x16, 0x97, 0x00, 0xF1, 0x7F, 0x03, 0x03, 0xC1, 0x7F, 0x00, 0x16, 0xD7, 0x45, 0xA7, 0xCB, 0x2F, 0xB4, 0x00, 0x25, 0xA7, 0x80, 0x3F, 0x23, 0x44, 0x04, 0x25, 0xA3, 0x30, 0x03, 0x00, 0x06, 0x00, 0x06, 0x06, 0x73, 0x09, 0xED, 0xBE, 0xC3, 0x30, 0x03, 0x3F, 0xFB, 0x3A, 0x57, 0xDE, 0x40, 0x30, 0x03, 0xE0, 0x13, 0x70, 0xC0, 0x30, 0x03, 0x00, 0x75, 0xD3, 0x78, 0x54, 0x10, 0x04, 0x00, 0x01, 0x0A, 0x10, 0x04, 0x10, 0x02, 0xA2, 0x37, 0x46, 0xF2, 0x37, 0x26, 0x0F, 0x06, 0x02, 0x05, 0x66, 0x23, 0x33, 0x00, 0x12, 0x43, 0x4D, 0x5F, 0x00, 0x35, 0xB6, 0x96, 0x00, 0x36, 0x6A, 0x80, 0xEA, 0x23, 0x77, 0x05, 0x26, 0x67, 0x30, 0x03, 0x30, 0x1F, 0x8E, 0xE3, 0xBE, 0x30, 0x03, 0xB0, 0xBF, 0xE0, 0x13, 0xC0, 0xBF, 0x50, 0xA7, 0x78, 0x00, 0x00, 0xC0, 0xA7, 0x00, 0x21, 0x5F, 0xCF, 0x5F, 0x01, 0xB1, 0x5F, 0x2F, 0xA1, 0xBD, 0x61, 0xBF, 0x30, 0x03, 0x3F, 0xF7, 0xCE, 0x95, 0x17, 0x41, 0x30, 0x03, 0xBC, 0xE0, 0x13, 0xC1, 0x30, 0x03, 0x05, 0x21, 0x5F, 0x00, 0x00, 0xC3, 0x01, 0x31, 0x5F, 0x61, 0x0B, 0x3F, 0xB6, 0xBF, 0x30, 0x03, 0xB0, 0xBF, 0xE0, 0x13, 0xC0, 0xBF, 0x02, 0x61, 0x5F, 0xCD, 0xF7, 0xFF, 0x01, 0xB2, 0xBF, 0x3F, 0xF7, 0x50, 0x03, 0x5D, 0xA7, 0x50, 0x03, 0xC0, 0x13, 0x4F, 0xF7, 0x05, 0x22, 0xBF, 0xFF, 0x00, 0x00, 0xC3, 0x01, 0x32, 0xBF, 0x3F, 0xE3, 0x3F, 0xE7, 0xB0, 0xBF, 0xE0, 0x13, 0xC0, 0xBF, 0x01, 0xF2, 0xBF, 0xFF, 0x03, 0x59, 0x73, 0x57, 0x87, 0x00, 0x59, 0x73, 0x00, 0x1C, 0x63, 0x99, 0x1F, 0x40, 0x03, 0x00, 0x79, 0x1F, 0x3F, 0x93, 0xAC, 0xC9, 0x73, 0xA0, 0x4E, 0xC7, 0xF5, 0x00, 0x84, 0xD3, 0x70, 0x53, 0x46, 0x31, 0x74, 0x32, 0x00, 0x63, 0x2F, 0x58, 0x2F, 0xFA, 0x9F, 0x05, 0x4F, 0xF1, 0x00, 0x00, 0x13, 0xCD, 0xCC, 0x4C, 0x28, 0x36, 0x80, 0x3F, 0x50, 0x07, 0x40, 0x0F, 0xFF, 0x4A, 0x9B, 0x50, 0x07, 0x9F, 0xEC, 0xE0, 0x0B, 0x40, 0x03, 0x00, 0x0A, 0x1B, 0x2A, 0xC3, 0x00, 0xA4, 0xB7, 0xBE, 0x60, 0xFB, 0x20, 0x01, 0xC0, 0xA7, 0x27, 0x62, 0x01, 0x00, 0xA7, 0x8A, 0x1B, 0x81, 0x2F, 0x91, 0xC5, 0x00, 0x84, 0xA3, 0x71, 0x83, 0x10, 0xF4, 0xBF, 0x01, 0xC1, 0x2F, 0x07, 0x04, 0xD1, 0x2F, 0xDF, 0x00, 0x80, 0xA7, 0x01, 0xF1, 0x2F, 0x08, 0x02, 0x41, 0x2F, 0x00, 0x5D, 0x8B, 0xE1, 0xB7, 0xEB, 0xD7, 0x00, 0xD2, 0x5F, 0x77, 0x09, 0x04, 0xD2, 0x5F, 0x00, 0xB0, 0xA7, 0x01, 0xC3, 0x07, 0x0A, 0x01, 0xE2, 0x5F, 0x92, 0xE7, 0x00, 0x1F, 0xFB, 0xAD, 0xDD, 0x07, 0xA0, 0x00, 0x68, 0x1F, 0x10, 0x43, 0xE3, 0x00, 0x5D, 0x03, 0x50, 0x43, 0x83, 0x1F, 0x00, 0x00, 0x44, 0x6D, 0x03, 0x30, 0x0F, 0x3E, 0x2B, 0x30, 0x0F, 0x2D, 0x03, 0x9B, 0x6D, 0x83, 0x03, 0x05, 0x6D, 0x83, 0x00, 0x4D, 0xD6, 0xF8, 0x3F, 0x1F, 0x00, 0xA0, 0x7F, 0x5E, 0x80, 0x00, 0x40, 0x7F, 0x01, 0x01, 0x4D, 0x83, 0x00, 0x3E, 0x0B, 0x00, 0x1A, 0xEB, 0x01, 0x94, 0xEB, 0x80, 0x7B, 0x41, 0xFF, 0x37, 0x5F, 0xE9, 0x00, 0xEE, 0x0B, 0x7E, 0x8B, 0x01, 0x50, 0x7F, 0xFA, 0xEB, 0xBD, 0x02, 0xB0, 0x7F, 0x03, 0x8E, 0x8B, 0x9E, 0x7B, 0xFE, 0x9B, 0x00, 0x02, 0x0F, 0x03, 0x3F, 0x13, 0xFD, 0x00, 0x1A, 0xF3, 0x01, 0x51, 0x8F, 0x3F, 0x13, 0x00, 0x12, 0x0F, 0x2A, 0x3A, 0x04, 0x8F, 0x13, 0xDC, 0x00, 0x2F, 0x13, 0x7F, 0x0C, 0x4F, 0x13, 0xD6, 0xB7, 0xFD, 0x97, 0xFD, 0x57, 0xFC, 0xE7, 0xFC, 0x77, 0xFC, 0x07, 0xFE, 0xFB, 0x97, 0xFA, 0xE3, 0xFA, 0x57, 0xF9, 0xA3, 0xF9, 0x17, 0xF8, 0x63, 0x3F, 0xEF, 0xCC, 0xEB, 0x00, 0x2F, 0xB3, 0x3E, 0x8F, 0x0A, 0x30, 0xCB, 0x2C, 0x41, 0xA7, 0x43, 0xCF, 0x1B, 0x37, 0x0D, 0x98, 0xF8, 0x5F, 0x67, 0x72, 0x56, 0xFF, 0x04, 0x40, 0x02, 0x60, 0x00, 0x5A, 0x3C, 0xF8, 0xFA, 0x34, 0x9F, 0x2C, 0x5F, 0x4F, 0x27, 0x00, 0x0C, 0x91, 0x82, 0xA0, 0x00, 0xFC, 0xFF, 0x5F, 0x00, 0xFE, 0x00, 0xFF, 0x5A, 0xC0, 0x48, 0xBE, 0xED, 0x75, 0xDF, 0x00, 0x28, 0xF9, 0x20, 0xFF, 0x4C, 0xFE, 0x3F, 0xDD, 0x1A, 0xEF, 0x68, 0x74, 0x08, 0x40, 0x04, 0x20, 0x50, 0x84, 0x3F, 0xFF, 0xF6, 0x40, 0xFF, 0x26, 0x2F, 0xFF, 0x63, 0x03, 0x00, 0x00, 0xC0, 0xF4, 0x00, 0x10, 0xFD, 0xFF, 0xE8, 0x80, 0x2F, 0xB8, 0xF5, 0xF0, 0xFF, 0xFF, 0x20, 0x50, 0xFF, 0x12, 0xFF, 0x30, 0x20, 0x58, 0x09, 0x9F, 0x6F, 0x9F, 0xD9, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0x6F, 0xAF, 0xBF, 0xE9, 0xF2, 0x60, 0x86, 0x5F, 0xEF, 0x0E, 0x8F, 0xFF, 0xF9, 0x51, 0x37, 0x3F, 0xFF, 0xF5, 0x0C, 0xF2, 0xFF, 0xFF, 0xF2, 0x20, 0x03, 0x4F, 0xE3, 0x26, 0x00, 0x64, 0x22, 0x4F, 0xEB, 0x29, 0x82, 0xFF, 0x58, 0x28, 0xE3, 0x06, 0xFF, 0x06, 0xFF, 0x2F, 0x2F, 0x00, 0x00, 0x30, 0x03, 0x4F, 0xFF, 0x22, 0xA0, 0xA0, 0x1F, 0xC1, 0x50, 0x77, 0x0A, 0x0A, 0x00, 0x30, 0x0A, 0x14, 0x0A, 0xD0, 0xF3, 0x6F, 0xE6, 0x64, 0x4F, 0xEE, 0x46, 0x00, 0x20, 0x00, 0xE3, 0x24, 0x2A, 0x8F, 0x9F, 0x00, 0x66, 0xFF, 0x06, 0xF4, 0x2D, 0xDF, 0xC0, 0xC6, 0x90, 0x6F, 0xBF, 0xFB, 0x04, 0xC7, 0x01, 0x52, 0x1C, 0x20, 0xB7, 0x20, 0x00, 0xF0, 0x20, 0xEB, 0x30, 0x03, 0x2F, 0xB1, 0x60, 0xF8, 0x30, 0xCB, 0x20, 0xB6, 0xFF, 0x66, 0x00, 0x66, 0x00, 0x70, 0x02, 0x20, 0xE3, 0x20, 0x6E, 0x2F, 0xC7, 0x00, 0x04, 0xFF, 0xFF, 0x20, 0x0D, 0x8F, 0x7F, 0xDC, 0xF7, 0x30, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x30, 0x00, 0x19, 0xFF, 0x00, 0xAA, 0xE6, 0xC1, 0x61, 0xE7, 0x2E, 0xF9, 0xC0, 0xF5, 0xF9, 0xFF, 0xDF, 0x20, 0xD5, 0x00, 0x07, 0x10, 0xFC, 0xFC, 0xAF, 0xDF, 0xFF, 0x02, 0x21, 0x9F, 0x6F, 0x3A, 0x6E, 0x35, 0x00, 0xD7, 0x02, 0x30, 0x41, 0x18, 0x00, 0xFF, 0xFD, 0x40, 0xEF, 0x21, 0x3B, 0x00, 0x00, 0xF9, 0x00, 0xF2, 0x01, 0x0B, 0x20, 0x00, 0xCF, 0xFF, 0x21, 0x02, 0xFF, 0xA8, 0x00, 0x5A, 0x00, 0x20, 0x21, 0x63, 0x20, 0x80, 0x2F, 0xA5, 0x0B, 0x0A, 0xF6, 0xF6, 0x0A, 0x0C, 0xF6, 0x00, 0xF2, 0xF7, 0x8E, 0xFF, 0xFF, 0x21, 0x00, 0x69, 0x02, 0x00, 0x8F, 0xFF, 0xA2, 0x06, 0x12, 0x3F, 0xC3, 0x4F, 0x01, 0xFF, 0x00, 0xDF, 0xFF, 0x00, 0x1C, 0xFF, 0x3F, 0xCD, 0x00, 0x00, 0x00, 0xC3, 0xFF, 0xFC, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0xA9, 0x00, 0xFB, 0xFF, 0xFF, 0x4F, 0x6A, 0xAB, 0x2F, 0x74, 0x0A, 0x3F, 0x7A, 0x09, 0x9F, 0xF9, 0x03, 0x04, 0x82, 0x70, 0xEF, 0xFE, 0x81, 0x7F, 0x9C, 0xF6, 0xFF, 0xFF, 0x10, 0x00, 0xC6, 0x3F, 0xA4, 0x1C, 0x6F, 0xFF, 0x00, 0xA0, 0x88, 0x05, 0x00, 0x8F, 0x01, 0x5C, 0xC1, 0x43, 0x4C, 0x04, 0x49, 0x4D, 0xFF, 0xFE, 0x14, 0x32, 0x7C, 0x02, 0x28, 0xC1, 0x29, 0xF7, 0x3B, 0x5D, 0x69, 0x6D, 0x61, 0x67, 0x10, 0x4B, 0xE4, 0x18, 0x20, 0x00, 0x0D, 0x42, 0x30, 0x07, 0x03, 0x8B, 0xA0, 0x00, 0x71, 0x05, 0x00, 0x88, 0xFE, 0xFF, 0xFF, 0x25, 0xCE, 0xC0, 0x2E, 0xCB, 0x01, 0xC0, 0xC0, 0xAF, 0x9F, 0x00, 0x00, 0x9F, 0x20, 0x03, 0x03, 0x00, 0x88, 0x00, 0x88, 0xFF, 0xCC, 0x20, 0x17, 0x70, 0x07, 0x81, 0xFF, 0xC0, 0x78, 0x00, 0x02, 0xFF, 0xFC, 0x3E, 0x4F, 0x9B, 0x87, 0x3F, 0xEE, 0x90, 0x90, 0xDF, 0xDF, 0x30, 0x03, 0x01, 0xA1, 0xD7, 0x40, 0x6F, 0xC8, 0x30, 0x6B, 0x40, 0x6F, 0x00, 0xB0, 0x43, 0xCF, 0xDF, 0xFF, 0x55, 0x0A, 0xFF, 0xD7, 0x00, 0xEE, 0x00, 0x0E, 0xCE, 0x55, 0x20, 0x17, 0xEE, 0xE8, 0x20, 0x17, 0x70, 0x07, 0x40, 0x6F, 0x80, 0x90, 0x6F, 0xC5, 0xFF, 0xCF, 0x1E, 0x7F, 0xDE, 0x00, 0x95, 0x9D, 0xC1, 0x7F, 0x2F, 0x63, 0xB1, 0x7F, 0x20, 0x3A, 0x00, 0x10, 0x51, 0x7F, 0xB9, 0x8A, 0x06, 0xC5, 0x30, 0x50, 0xA8, 0x42, 0x70, 0xC2, 0x28, 0x4E, 0x2E, 0x06, 0x10, 0x00, 0x43, 0xFD, 0x3A, 0xAF, 0x76, 0x24, 0x00, 0x98, 0x6F, 0xC8, 0xCE, 0x47, 0x2D, 0xA3, 0xFF, 0x7A, 0x22, 0xFF, 0x45, 0x4F, 0xFE, 0xAA, 0x00, 0xBB, 0x4A, 0xCF, 0xBB, 0x8A, 0x50, 0x07, 0xFF, 0x23, 0xEF, 0x3F, 0x96, 0x00, 0x23, 0xDE, 0x53, 0x8A, 0x4F, 0xFF, 0x9A, 0x00, 0x68, 0x4A, 0xEF, 0x24, 0x35, 0x23, 0xAD, 0x14, 0xFF, 0xFF, 0xC8, 0x3A, 0xFB, 0xB3, 0x33, 0x2F, 0xFF, 0xFF, 0x87, 0x66, 0x67, 0x27, 0xFF, 0x00, 0x4B, 0x83, 0x4F, 0x7B, 0xA7, 0x21, 0xD1, 0xE0, 0x2E, 0x0D, 0x37, 0xCA, 0x08, 0x46, 0x42, 0x21, 0xF6, 0x22, 0xFF, 0xF7, 0x44, 0xF7, 0x00, 0x15, 0x7F, 0x22, 0xFF, 0x32, 0x4F, 0x7A, 0x43, 0xFF, 0x60, 0x97, 0x6B, 0xE7, 0x36, 0x6A, 0x10, 0xE7, 0xF2, 0xF4, 0xFF, 0xF8, 0x34, 0xBA, 0x40, 0x03, 0x9F, 0x9B, 0x25, 0x32, 0x8F, 0xA8, 0x0C, 0x09, 0xFF, 0x40, 0x4F, 0x25, 0x2D, 0xAD, 0xBF, 0x04, 0x28, 0xFF, 0x00, 0x62, 0x6C, 0x06, 0xF4, 0x37, 0xFF, 0xCF, 0xD6, 0x00, 0xDD, 0x00, 0x4C, 0xFC, 0xDD, 0x35, 0x00, 0xEE, 0x34, 0x4A, 0x31, 0xEF, 0x54, 0x00, 0x45, 0x1F, 0xB8, 0x38, 0x0B, 0x48, 0x51, 0x41, 0xEF, 0xFD, 0xA0, 0x97, 0x1F, 0x10, 0x00, 0xFE, 0x18, 0xFC, 0x10, 0xA0, 0x23, 0xF1, 0x6F, 0xFF, 0x2C, 0xEF, 0x00, 0x05, 0x03, 0xFF, 0xFF, 0x1E, 0x8F, 0xA1, 0x1B, 0xEF, 0x21, 0x1F, 0xCE, 0xC7, 0x69, 0x04, 0xD8, 0x4B, 0xA1, 0xF2, 0x27, 0xCB, 0x20, 0x03, 0x7F, 0xD5, 0xE1, 0x84, 0x40, 0xD7, 0x37, 0xFF, 0x01, 0xBE, 0x4D, 0xAF, 0x58, 0x00, 0x44, 0x23, 0x4F, 0x7B, 0x64, 0xFF, 0xA7, 0x47, 0xEF, 0xDC, 0xFF, 0x59, 0xED, 0x79, 0xA0, 0xDE, 0x24, 0xA0, 0x37, 0x04, 0xCC, 0xFF, 0x50, 0xCF, 0x10, 0x21, 0x00, 0x32, 0x42, 0xDF, 0x33, 0x00, 0x33, 0x00, 0x13, 0x00, 0x73, 0x30, 0x26, 0xAA, 0xFF, 0xFF, 0x40, 0x04, 0x63, 0x3F, 0x9C, 0x46, 0xD7, 0x7A, 0xEF, 0x35, 0x94, 0x72, 0xEF, 0x26, 0xF5, 0x2F, 0x05, 0x5C, 0x4D, 0x2F, 0xCA, 0x6B, 0x03, 0xE4, 0x0C, 0x09, 0x55, 0xFF, 0x08, 0xC0, 0x7F, 0x91, 0x00, 0x01, 0x00, 0xF3, 0xF3, 0x00, 0x99, 0x00, 0x99, 0x5F, 0xB7, 0xFC, 0x20, 0x0B, 0x20, 0x0F, 0x8F, 0xC7, 0x70, 0x17, 0x60, 0x1F, 0x8F, 0xE7, 0x56, 0xFF, 0x34, 0x55, 0x01, 0x3A, 0xFD, 0x90, 0x1F, 0x78, 0x4F, 0xFF, 0x55, 0xFF, 0x46, 0x65, 0x4A, 0x2F, 0x97, 0xFF, 0xFC, 0x35, 0x5C, 0x29, 0x23, 0x02, 0xC6, 0x34, 0x07, 0x3F, 0xFF, 0x8B, 0xFF, 0x03, 0x44, 0x10, 0x28, 0x4D, 0xD4, 0xD0, 0x80, 0x5F, 0x3F, 0xF0, 0x17, 0x9F, 0xF5, 0xEF, 0xFF, 0x07, 0xCF, 0xD1, 0x45, 0x6F, 0x2B, 0x59, 0x3E, 0xFB, 0x5F, 0x30, 0x20, 0xFB, 0x5F, 0x87, 0x12, 0xF3, 0xF9, 0xF8, 0x90, 0x3F, 0x31, 0xB7, 0x22, 0x97, 0x00, 0x60, 0x75, 0x85, 0xBF, 0x2F, 0xFF, 0xAF, 0x0D, 0xFF, 0x9E, 0xFF, 0x45, 0x45, 0x4F, 0x79, 0xA9, 0x00, 0x9A, 0x45, 0xBF, 0x89, 0x55, 0xA7, 0x10, 0xFF, 0x22, 0xFF, 0x3E, 0x9F, 0x00, 0xFF, 0x75, 0xFF, 0x52, 0xDA, 0x4F, 0xE3, 0x23, 0x3A, 0xDB, 0x5E, 0x7F, 0x95, 0x9F, 0x7F, 0x3E, 0x8F, 0x52, 0x23, 0x0C, 0x0D, 0x92, 0x31, 0xE1, 0xEF, 0xE1, 0xFF, 0x7F, 0xC7, 0x02, 0xF8, 0x2C, 0xE9, 0x30, 0x03, 0xF0, 0x0F, 0x01, 0x1D, 0xA6, 0x45, 0x3E, 0x00, 0xFB, 0xB0, 0xB7, 0x3A, 0x47, 0xFE, 0x2B, 0x83, 0x8C, 0x57, 0xD0, 0x28, 0x8B, 0x25, 0x31, 0x77, 0x11, 0x60, 0x0D, 0xA5, 0x1B, 0x96, 0x44, 0x00, 0x00, 0xFC, 0xFB, 0x01, 0x30, 0x07, 0xF8, 0x3B, 0xB6, 0x56, 0x45, 0x0E, 0x50, 0x00, 0x2F, 0x51, 0x3F, 0x2C, 0x8F, 0xE5, 0x2C, 0xC3, 0x00, 0xFA, 0x30, 0x2B, 0xBB, 0x43, 0x6F, 0x76, 0x87, 0x18, 0xEF, 0x00, 0x38, 0x77, 0x77, 0xC2, 0x5F, 0x85, 0xAE, 0x4B, 0x6B, 0xFF, 0x01, 0xAF, 0x47, 0xCF, 0x15, 0x32, 0x6B, 0xDC, 0x26, 0x89, 0x00, 0x3E, 0x67, 0x3A, 0x0D, 0xB4, 0x2F, 0x04, 0xF1, 0xFF, 0x7F, 0xEB, 0xA0, 0xB0, 0xA1, 0x26, 0x73, 0xF4, 0x79, 0x7C, 0x00, 0x60, 0xFB, 0xFF, 0x28, 0x32, 0xC0, 0x00, 0xB0, 0x01, 0x24, 0x07, 0x4F, 0x08, 0x2F, 0x1F, 0x00, 0x00, 0x72, 0x0D, 0x3D, 0x04, 0x7D, 0xFB, 0xFE, 0xE5, 0x00, 0xD8, 0x5C, 0xA7, 0xA5, 0xB7, 0x3F, 0x93, 0x61, 0x00, 0x1C, 0xBF, 0x38, 0x93, 0x40, 0x96, 0x9E, 0x2A, 0x03, 0x4F, 0xF4, 0x4B, 0xFE, 0x28, 0xAF, 0xD0, 0xE1, 0x3E, 0xFF, 0x1A, 0x27, 0x87, 0x3E, 0x05, 0x18, 0x00, 0x00, 0x3F, 0x2B, 0x55, 0x98, 0xBE, 0x04, 0x07, 0xFF, 0x17, 0xFF, 0x08, 0x06, 0x0E, 0x53, 0xFF, 0x20, 0x4A, 0xBF, 0x3F, 0xB6, 0xB3, 0xFF, 0x1C, 0xDE, 0xFF, 0xDD, 0x55, 0x42, 0x60, 0x17, 0x7F, 0xD6, 0xDD, 0xFF, 0x03, 0xED, 0xFF, 0x00, 0x31, 0x00, 0x95, 0x7A, 0xDB, 0x60, 0x37, 0x24, 0xEE, 0x12, 0x2E, 0xBF, 0x50, 0xFD, 0xDA, 0x11, 0xFF, 0xBD, 0x24, 0xFF, 0x69, 0x45, 0xE7, 0x14, 0x6B, 0x9B, 0x0F, 0x8E, 0x5E, 0x34, 0x01, 0x9F, 0x6F, 0xD3, 0x00, 0x1C, 0x2A, 0x35, 0x2F, 0x8F, 0xFC, 0xFC, 0x09, 0x00, 0xAD, 0x00, 0x47, 0x5A, 0x6F, 0xFD, 0x74, 0x4E, 0x97, 0x1E, 0xB9, 0xFF, 0xDC, 0x4F, 0xFF, 0x2F, 0x44, 0x2B, 0xB2, 0x4F, 0x3C, 0xBB, 0x6A, 0xFF, 0x2B, 0xAA, 0x2D, 0x64, 0x10, 0x60, 0xB7, 0x32, 0x35, 0xDC, 0x10, 0x15, 0x00, 0xB4, 0xEC, 0x2F, 0xF3, 0xF9, 0x7B, 0x78, 0xEF, 0x68, 0x9F, 0x10, 0x8B, 0xFF, 0x25, 0xAB, 0x8F, 0x6D, 0xFF, 0x8F, 0x02, 0xBD, 0x4E, 0xDD, 0x6C, 0x01, 0xEC, 0xAC, 0xCE, 0x7F, 0x2D, 0x16, 0xBE, 0x7F, 0x80, 0x7E, 0x7F, 0xC0, 0x9D, 0x2E, 0x04, 0x0F, 0xBD, 0xFF, 0xEF, 0xEF, 0x8A, 0xAF, 0x8E, 0x00, 0x47, 0x24, 0xDD, 0x78, 0xDD, 0x77, 0x33, 0x11, 0x01, 0x33, 0x11, 0x8D, 0x7D, 0x13, 0x13, 0x7D, 0x20, 0x03, 0xBF, 0x8A, 0xBF, 0x77, 0x50, 0x17, 0x70, 0x07, 0xFF, 0xFF, 0x30, 0x2B, 0xB0, 0x2F, 0xF0, 0x0F, 0xB7, 0x01, 0xBF, 0x7F, 0xA8, 0x6D, 0xEA, 0x7F, 0x7F, 0x10, 0x6D, 0xFF, 0x27, 0xB0, 0x04, 0xA1, 0x00, 0xA0, 0x0D, 0xB0, 0x01, 0x02, 0x60, 0xED, 0x61, 0xFF, 0x2C, 0xFF, 0xBE, 0x35, 0xFF, 0xF0, 0x3E, 0xB7, 0x00, 0xC0, 0xFF, 0x19, 0x00, 0x21, 0x1D, 0x01, 0x28, 0xFA, 0x18, 0xCC, 0xFF, 0x3A, 0x3B, 0x92, 0x40, 0x3F, 0x17, 0xFF, 0x6B, 0x8D, 0x27, 0x4C, 0x84, 0xFF, 0xE9, 0xBD, 0xB9, 0x3C, 0xB8, 0xFD, 0x23, 0x34, 0xE2, 0x30, 0x62, 0x4C, 0xDA, 0x40, 0x13, 0xF7, 0xFF, 0xF1, 0x20, 0x03, 0xEF, 0x08, 0xFF, 0xE8, 0xFF, 0xE0, 0x20, 0x03, 0xE1, 0xFF, 0xD9, 0x38, 0xFF, 0xD3, 0x50, 0x95, 0x2E, 0xE1, 0x21, 0x87, 0x57, 0xFF, 0x86, 0x34, 0xFF, 0xD1, 0x93, 0x69, 0x30, 0x41, 0xFA, 0x31, 0x9F, 0xAC, 0xFF, 0x44, 0xC7, 0x41, 0xA5, 0xD9, 0xFF, 0xE4, 0x50, 0x5B, 0xF6, 0xFF, 0x41, 0xF2, 0x20, 0x5D, 0xFB, 0xFF, 0xEE, 0xFF, 0xEA, 0x2F, 0x23, 0x54, 0xF5, 0x20, 0x05, 0xE4, 0x23, 0x97, 0xEA, 0x2E, 0x2E, 0xDA, 0xFF, 0x10, 0xDB, 0xFF, 0xD5, 0x2C, 0x6E, 0xC6, 0xFF, 0xD0, 0xFF, 0x05, 0xCB, 0xFF, 0xC1, 0xFF, 0xBC, 0x27, 0xE7, 0xE1, 0x20, 0x11, 0x41, 0xD2, 0x24, 0x7A, 0xDA, 0xFF, 0xCD, 0xFF, 0xCA, 0x20, 0x19, 0x04, 0xC1, 0xFF, 0xB7, 0xFF, 0xB3, 0x20, 0xFE, 0xBA, 0xFF, 0x14, 0xAF, 0xFF, 0xAB, 0x05, 0xD1, 0xFF, 0x5F, 0x62, 0x6D, 0x03, 0xFF, 0x51, 0x29, 0x20, 0xC2, 0xC2, 0xE1, 0x7F, 0x05, 0xFF, 0x9F, 0x22, 0x8D, 0x5B, 0x07, 0x21, 0x61, 0xA7, 0x20, 0x9A, 0x5F, 0xE9, 0x8A, 0xD9, 0x48, 0x38, 0x99, 0x50, 0xFE, 0x41, 0x01, 0xF7, 0x25, 0x34, 0xEA, 0xFF, 0xE0, 0x8D, 0xA2, 0xD1, 0x73, 0xF6, 0x80, 0x27, 0xF7, 0xFF, 0xEB, 0x25, 0x56, 0xE0, 0xA8, 0x21, 0x1D, 0xE9, 0x21, 0x25, 0xDE, 0x2F, 0x4A, 0xD4, 0xFF, 0xD3, 0x28, 0xFF, 0xC9, 0x2F, 0x52, 0xD3, 0x2B, 0x3D, 0xC9, 0xFF, 0xC8, 0xA8, 0x25, 0x49, 0xBD, 0x21, 0x07, 0xFC, 0x27, 0x46, 0xF0, 0xFF, 0xE6, 0xA2, 0x20, 0x2D, 0xE2, 0x25, 0x9E, 0xD5, 0xFF, 0xE3, 0x21, 0x95, 0xD6, 0xAA, 0x2D, 0xB0, 0xD0, 0x20, 0x21, 0xC3, 0x25, 0x10, 0xDA, 0x21, 0x3B, 0xCD, 0x28, 0xFF, 0xC5, 0x21, 0x4D, 0xC4, 0x25, 0x7B, 0xB6, 0xFF, 0xBF, 0x80, 0x21, 0x3D, 0xB2, 0xFF, 0xAB, 0xFF, 0xB0, 0xFF, 0xA9, 0x0A, 0xFF, 0xA3, 0xFF, 0x9C, 0x21, 0x51, 0xC0, 0x22, 0x4A, 0xB5, 0xA8, 0x21, 0x53, 0xAE, 0x21, 0xA8, 0xA2, 0x21, 0x59, 0xAA, 0xFF, 0xA8, 0xA0, 0x20, 0xC8, 0xA0, 0x2F, 0xE0, 0x95, 0xFF, 0x8C, 0xFF, 0xA6, 0x80, 0x2B, 0x49, 0x9A, 0xFF, 0x92, 0xFF, 0x96, 0xFF, 0x8F, 0xA8, 0x25, 0x33, 0x84, 0x20, 0x05, 0x87, 0x22, 0x2C, 0x7C, 0xFF, 0x7F, 0x2A, 0xFF, 0x79, 0x2B, 0x43, 0x6E, 0x22, 0x86, 0xB8, 0x20, 0x4B, 0xAA, 0x8C, 0x20, 0x53, 0xAD, 0xFF, 0xA4, 0x21, 0x00, 0x30, 0x53, 0x96, 0xFF, 0x54, 0x90, 0x2B, 0xFF, 0x92, 0x20, 0xFC, 0x85, 0x20, 0x4B, 0xA4, 0xFF, 0x41, 0x9B, 0x20, 0x3D, 0xA0, 0xFF, 0x9D, 0xFF, 0x93, 0x20, 0x17, 0x04, 0x8D, 0xFF, 0x89, 0xFF, 0x80, 0x20, 0x3F, 0x86, 0xFF, 0x50, 0x83, 0x20, 0x41, 0x76, 0x20, 0x0D, 0x83, 0xFF, 0x7D, 0xFF, 0x14, 0x77, 0xFF, 0x7E, 0x20, 0x4F, 0x72, 0x25, 0x87, 0x72, 0xFF, 0x04, 0x6C, 0xFF, 0x67, 0xFF, 0x62, 0x40, 0x03, 0x5C, 0xFF, 0x00, 0x58, 0xFF, 0x74, 0xFF, 0x70, 0xFF, 0x69, 0xFF, 0x50, 0x65, 0x25, 0xA1, 0x6A, 0x20, 0x15, 0x5F, 0xFF, 0x5E, 0xFF, 0x04, 0x5A, 0xFF, 0x53, 0xFF, 0x50, 0x22, 0x6C, 0x54, 0xFF, 0x14, 0x4D, 0xFF, 0x4A, 0x00, 0xD3, 0xFF, 0x16, 0x24, 0x1D, 0x6B, 0xFF, 0x6A, 0x15, 0x22, 0x66, 0x72, 0xD7, 0x85, 0x2F, 0xA8, 0xED, 0x5F, 0x95, 0xF9, 0xAA, 0x2E, 0xCE, 0xF0, 0x94, 0x3F, 0x75, 0x21, 0xBF, 0xD5, 0x84, 0x4D, 0x3D, 0xD5, 0x2F, 0xD0, 0xAF, 0xAC, 0xFD, 0x22, 0xFB, 0xE8, 0x26, 0x3B, 0xE0, 0x2F, 0xE7, 0x55, 0xF8, 0x2F, 0x06, 0xF1, 0x23, 0x03, 0xD9, 0x23, 0x01, 0xD3, 0x21, 0x7F, 0x55, 0xF0, 0x28, 0xC8, 0xE6, 0x21, 0x77, 0xD6, 0x23, 0x0F, 0xCC, 0x22, 0xD1, 0x55, 0xDD, 0x21, 0x89, 0xD5, 0x22, 0xBF, 0xC3, 0x22, 0xF6, 0xBB, 0x22, 0xB1, 0x55, 0xBF, 0x21, 0x61, 0xB5, 0x22, 0xB1, 0xA8, 0x21, 0x59, 0x9F, 0x22, 0xBB, 0x55, 0xAB, 0x21, 0x69, 0xA2, 0x21, 0x5F, 0x95, 0x2D, 0x23, 0x8C, 0x42, 0xD5, 0x5A, 0xD2, 0x21, 0x9F, 0xBF, 0x21, 0x95, 0x30, 0x1B, 0xCB, 0x27, 0x21, 0xC4, 0xAA, 0x21, 0xA7, 0xB0, 0x21, 0x9D, 0xA9, 0x21, 0x9F, 0xA6, 0x21, 0x7D, 0x9E, 0xAB, 0x21, 0x7F, 0x8F, 0x23, 0xA2, 0x87, 0x21, 0x77, 0x96, 0x26, 0xB9, 0x30, 0x0B, 0x51, 0x7F, 0x21, 0x19, 0x78, 0x21, 0x7F, 0x9E, 0xFF, 0x94, 0x20, 0x01, 0x45, 0x8A, 0x26, 0xCF, 0x82, 0xFF, 0x81, 0x20, 0x11, 0x8B, 0x20, 0x05, 0x62, 0x82, 0x20, 0x19, 0x30, 0x1B, 0x6E, 0xFF, 0x66, 0x21, 0xA5, 0x71, 0xA2, 0x21, 0x41, 0x68, 0x21, 0x3D, 0x63, 0xFF, 0x60, 0x21, 0x3B, 0x66, 0xA0, 0x21, 0x41, 0x5E, 0x2D, 0xBD, 0x57, 0xFF, 0x51, 0xFF, 0x4F, 0x2A, 0xFF, 0x48, 0x21, 0xC5, 0x70, 0x20, 0x21, 0x68, 0x80, 0x17, 0x6A, 0xAA, 0x20, 0x25, 0x63, 0x21, 0x63, 0x57, 0x20, 0x1D, 0x50, 0x20, 0x1F, 0x55, 0x20, 0xFF, 0x4E, 0x20, 0x01, 0x46, 0xFF, 0x47, 0xFF, 0x40, 0x0A, 0xFF, 0x3F, 0xFF, 0x39, 0x20, 0x07, 0x3F, 0x20, 0x09, 0x39, 0xA2, 0x20, 0x09, 0x32, 0x20, 0x01, 0x2C, 0xFF, 0x5D, 0x23, 0xF6, 0x53, 0xC0, 0x20, 0x23, 0x30, 0x03, 0x49, 0xFF, 0x44, 0xFF, 0x4B, 0xFF, 0x10, 0x45, 0xFF, 0x42, 0x21, 0x3E, 0x40, 0xFF, 0x3C, 0xFF, 0x05, 0x38, 0xFF, 0x34, 0xFF, 0x4A, 0x20, 0x39, 0x41, 0x21, 0x4E, 0x50, 0x43, 0x20, 0x05, 0x3B, 0x20, 0x11, 0x38, 0xFF, 0x35, 0xFF, 0x00, 0x31, 0xFF, 0x2E, 0xFF, 0x33, 0xFF, 0x30, 0xFF, 0x55, 0x2B, 0x23, 0x46, 0x3B, 0x20, 0x0F, 0x33, 0x20, 0x0F, 0x30, 0x24, 0xD2, 0x05, 0x2A, 0xFF, 0x26, 0xFF, 0x2D, 0x2B, 0x94, 0x27, 0x2D, 0xA5, 0x01, 0x23, 0xFF, 0x20, 0xFF, 0x1E, 0xFF, 0x1B, 0x23, 0x68, 0x50, 0x26, 0x40, 0x0B, 0x24, 0x2D, 0xB9, 0x1E, 0xFF, 0x1C, 0xFF, 0x05, 0x1D, 0xFF, 0x1A, 0xFF, 0x18, 0x21, 0xD2, 0x18, 0x24, 0xB8, 0x15, 0x13, 0xFF, 0x12, 0x33, 0x8B, 0x00, 0x20, 0x36, 0xD2, 0x6B, 0xF6, 0xB5, 0x34, 0x85, 0x00, 0x24, 0x87, 0x64, 0xB3, 0xFA, 0x2C, 0x0B, 0xEA, 0x24, 0x61, 0x55, 0xE4, 0x24, 0x57, 0xCC, 0x24, 0x59, 0xC6, 0x27, 0xFF, 0xDF, 0x24, 0x75, 0x52, 0xDA, 0x24, 0x5F, 0xC1, 0x24, 0x4D, 0xBC, 0x00, 0x22, 0xB6, 0x00, 0xC5, 0x23, 0x56, 0x43, 0x7B, 0xFE, 0xFF, 0xF2, 0x34, 0xA5, 0x00, 0x23, 0x4E, 0xAA, 0x24, 0xFD, 0xED, 0x2A, 0x35, 0xEA, 0x2C, 0x67, 0xD5, 0x24, 0xE9, 0xD2, 0xAA, 0x24, 0x91, 0xB7, 0x24, 0x8F, 0xB2, 0x29, 0x02, 0xCD, 0x24, 0xA5, 0xCA, 0xAA, 0x25, 0x7E, 0xAF, 0x24, 0x81, 0xAB, 0x25, 0x86, 0xB0, 0x23, 0x01, 0xAA, 0xAA, 0x23, 0x4B, 0x96, 0x23, 0x4D, 0x90, 0x23, 0x5B, 0xA4, 0x23, 0x09, 0x9F, 0xAA, 0x2E, 0xFF, 0x8A, 0x23, 0x35, 0x85, 0x22, 0xED, 0x7D, 0x22, 0xE9, 0x77, 0xAA, 0x22, 0xDB, 0x67, 0x22, 0xD9, 0x62, 0x22, 0xE7, 0x72, 0x23, 0x39, 0x6D, 0xAA, 0x22, 0xE3, 0x5C, 0x22, 0xE5, 0x57, 0x23, 0x6B, 0x9A, 0x23, 0x37, 0x96, 0xAA, 0x23, 0x17, 0x80, 0x23, 0x19, 0x7C, 0x23, 0x77, 0x93, 0x23, 0x29, 0x90, 0xAA, 0x25, 0x4A, 0x79, 0x23, 0x21, 0x76, 0x22, 0xFF, 0x6A, 0x23, 0x01, 0x65, 0xAA, 0x24, 0x7A, 0x53, 0x22, 0xF9, 0x50, 0x28, 0xA9, 0x62, 0x23, 0x09, 0x5F, 0xAA, 0x25, 0x6C, 0x4D, 0x23, 0x01, 0x4A, 0x21, 0x7F, 0x53, 0x25, 0x78, 0x4E, 0xA2, 0x21, 0x77, 0x42, 0x21, 0x79, 0x3D, 0xFF, 0x52, 0x21, 0x85, 0x4E, 0xAA, 0x21, 0x87, 0x40, 0x21, 0x7D, 0x3C, 0x21, 0x7F, 0x3A, 0x21, 0x69, 0x35, 0xAA, 0x21, 0x6F, 0x2D, 0x25, 0xA4, 0x28, 0x2E, 0xFD, 0x30, 0x21, 0x65, 0x2C, 0xAA, 0x41, 0x53, 0x1E, 0x21, 0x61, 0x1B, 0x21, 0x9F, 0x41, 0x21, 0xDD, 0x3D, 0xAA, 0x21, 0xAB, 0x31, 0x21, 0x99, 0x2D, 0x21, 0xA7, 0x3B, 0x21, 0xAF, 0x38, 0xAA, 0x21, 0x9F, 0x2B, 0x21, 0xA1, 0x29, 0x24, 0xE8, 0x23, 0x21, 0x95, 0x20, 0xAA, 0x21, 0x77, 0x18, 0x21, 0x79, 0x15, 0x21, 0x87, 0x1E, 0x2F, 0x43, 0x1C, 0xAA, 0x21, 0x83, 0x13, 0x23, 0x5E, 0x12, 0x2F, 0x4F, 0x1D, 0x40, 0x1B, 0x19, 0x8A, 0x23, 0x6C, 0x14, 0xFF, 0x11, 0x26, 0x72, 0x14, 0x23, 0x76, 0x11, 0xA8, 0x20, 0x09, 0x0E, 0x20, 0x01, 0x0B, 0x21, 0xA3, 0x10, 0xFF, 0x0F, 0x20, 0xFF, 0x0D, 0x40, 0x03, 0x0B, 0xFF, 0x0A, 0xFF, 0x0C, 0xAA, 0x20, 0x03, 0x09, 0x25, 0x24, 0x08, 0x25, 0x28, 0x06, 0x25, 0x32, 0x13, 0xAA, 0x20, 0x1D, 0x10, 0x20, 0x1F, 0x0C, 0x20, 0x15, 0x0A, 0x25, 0x3C, 0x0F, 0xAB, 0x20, 0x33, 0x0D, 0x20, 0x27, 0x08, 0x20, 0x1D, 0x07, 0x25, 0x52, 0x50, 0x25, 0x56, 0x04, 0x20, 0x01, 0x03, 0x25, 0x76, 0x02, 0x80, 0x07, 0x50, 0x01, 0x01, 0xAC, 0x00, 0xB9, 0x7F, 0x20, 0x2C, 0x1D, 0x03, 0x04, 0xE9, 0x7F, 0x10, 0x04, 0x80, 0x59, 0x30, 0xC2, 0x30, 0xFE, 0xE2, 0x2C, 0x3A, 0x3A, 0x46, 0x20, 0xF8, 0xE9, 0xFF, 0x0C, 0x00, 0x95, 0x00, 0xDC, 0x00, 0x3E, 0x2E, 0x03, 0x1F, 0xA9, 0x80, 0xF2, 0x18, 0x00, 0x10, 0xF9, 0x38, 0xEF, 0x4F, 0x02, 0x50, 0x90, 0xFF, 0x1F, 0xFF, 0xC0, 0xD0, 0x00, 0xDE, 0x98, 0xBF, 0x1B, 0xCB, 0xFF, 0x2F, 0x23, 0xF2, 0x7F, 0xE2, 0x4B, 0xFF, 0x01, 0xCF, 0x27, 0x10, 0x5B, 0x20, 0x2B, 0x10, 0x00, 0x11, 0x49, 0x71, 0x11, 0xFD, 0x60, 0x07, 0xF9, 0x7E, 0x70, 0x17, 0x0B, 0x10, 0x1F, 0x3A, 0x6E, 0x0C, 0xBA, 0x5C, 0x40, 0x41, 0xCD, 0x00, 0x30, 0xE3, 0xFF, 0x20, 0xF9, 0xB7, 0xFF, 0xFF, 0x00, 0xAF, 0xCF, 0x03, 0xD1, 0xF8, 0xFF, 0x7F, 0xFE, 0x00, 0xFF, 0x0C, 0x05, 0x06, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x90, 0x80, 0xED, 0xFF, 0xEE, 0xFF, 0x79, 0x0A, 0x00, 0x77, 0x00, 0xEE, 0x20, 0x07, 0x77, 0x20, 0x07, 0x00, 0x01, 0xAA, 0x00, 0x07, 0xFF, 0xFF, 0x3F, 0xCF, 0x2B, 0x90, 0x06, 0xA5, 0x00, 0x00, 0xF9, 0xF8, 0x70, 0x17, 0x80, 0x1F, 0x4A, 0x00, 0x00, 0xA0, 0x6F, 0x6F, 0xF0, 0x30, 0x00, 0x9B, 0x07, 0x00, 0x00, 0xEF, 0x23, 0x00, 0x80, 0x37, 0x80, 0x3F, 0xEA, 0x05, 0x8B, 0x00, 0x30, 0x1F, 0x80, 0xE8, 0xAB, 0x59, 0xF7, 0x59, 0x00, 0x60, 0x3F, 0x3B, 0xFC, 0xE0, 0x6B, 0xF2, 0x00, 0xE0, 0x5F, 0x00, 0x90, 0x7F, 0xA2, 0x00, 0x6A, 0xF4, 0xF3, 0x2A, 0x9F, 0x8F, 0x90, 0xBF, 0xDE, 0x20, 0xDF, 0x97, 0xDC, 0x48, 0x01, 0x00, 0x20, 0x10, 0x7B, 0xFF, 0x02, 0xAF, 0xFC, 0x30, 0x20, 0xFF, 0xFA, 0x39, 0xE3, 0x4E, 0xFF, 0x00, 0x04, 0x00, 0x00, 0x65, 0x50, 0x01, 0xA9, 0x88, 0x05, 0x04, 0xFF, 0x02, 0xF6, 0x1E, 0x8F, 0xB0, 0x50, 0xEF, 0x00, 0x4A, 0x9F, 0x01, 0x4B, 0x05, 0x08, 0x3C, 0x8F, 0x70, 0x90, 0x21, 0xCF, 0x70, 0xA1, 0xFA, 0x41, 0x45, 0x0C, 0xFF, 0xEF, 0x02, 0x00, 0x20, 0xC5, 0x2A, 0xD9, 0x80, 0x80, 0x80, 0x30, 0x03, 0xFF, 0xFE, 0x05, 0x0B, 0xF8, 0xE1, 0x6F, 0x81, 0x2B, 0x97, 0x80, 0x90, 0x00, 0x05, 0x60, 0x00, 0x2F, 0x66, 0x00, 0xB6, 0xFF, 0xFF, 0x25, 0x06, 0x06, 0x1F, 0xF8, 0x08, 0xF8, 0x9F, 0xF8, 0xF7, 0x2F, 0x73, 0x06, 0x07, 0xBB, 0x90, 0x21, 0x06, 0xD0, 0x40, 0x3B, 0xBB, 0xB8, 0x00, 0x6F, 0x6F, 0x00, 0x70, 0xF0, 0x6F, 0x6F, 0xE0, 0xE0, 0x68, 0xDF, 0x02, 0x50, 0xA0, 0xDF, 0xDF, 0x90, 0x90, 0x20, 0x0B, 0xF0, 0x08, 0x4B, 0x00, 0xB0, 0x00, 0x20, 0x0B, 0xA0, 0x9B, 0x00, 0x00, 0x70, 0x00, 0x89, 0xFF, 0xB6, 0x8D, 0xFF, 0xFF, 0x00, 0x04, 0x03, 0xAD, 0xFD, 0x23, 0x2F, 0xF3, 0xF3, 0x24, 0x9F, 0xAF, 0x20, 0x0B, 0x04, 0xBB, 0x2D, 0xB5, 0xF3, 0xF3, 0x00, 0xAF, 0xBF, 0xB2, 0x00, 0x8B, 0x00, 0xE8, 0xB0, 0x00, 0xFF, 0xEF, 0xC0, 0xC0, 0xFF, 0xFF, 0x49, 0x10, 0x0C, 0x81, 0xFD, 0x90, 0xC1, 0x2B, 0x9B, 0x20, 0x0B, 0x90, 0x00, 0x00, 0xBB, 0x00, 0xA0, 0x21, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xB3, 0x00, 0xCC, 0x07, 0x7C, 0xFA, 0x68, 0xAC, 0x00, 0xFB, 0x89, 0x00, 0x0A, 0x95, 0xFA, 0x5F, 0x48, 0x00, 0xF8, 0xF9, 0x03, 0x06, 0x72, 0xFA, 0xBD, 0x21, 0x00, 0x9D, 0x01, 0x17, 0x0D, 0xF9, 0xF9, 0x01, 0x00, 0x00, 0xB7, 0x00, 0x58, 0xDF, 0xDB, 0xD8, 0x4F, 0x3F, 0x00, 0x30, 0x20, 0x3A, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x01, 0x38, 0x6A, 0x4F, 0x4F, 0x20, 0x30, 0x3B, 0x2E, 0x19, 0x04, 0xFF, 0xFF, 0x4A, 0x0B, 0xBB, 0x2E, 0x18, 0x70, 0xFA, 0x00, 0xCC, 0x5E, 0xFF, 0xFF, 0x09, 0x08, 0xFA, 0xFA, 0x00, 0x8F, 0x8F, 0xF3, 0xF3, 0x8F, 0x7F, 0xFF, 0xFC, 0x00, 0x08, 0x3D, 0x91, 0x00, 0xDD, 0x00, 0xF3, 0xF9, 0x00, 0x8F, 0x9F, 0xBA, 0x00, 0x6B, 0x00, 0x00, 0xB0, 0x00, 0xC7, 0xAF, 0xF4, 0xF7, 0x6F, 0x7F, 0xDC, 0x70, 0x00, 0x19, 0xDF, 0x30, 0x30, 0xFF, 0xFF, 0xF5, 0xC0, 0x00, 0x6F, 0x9F, 0x10, 0x00, 0xD8, 0x00, 0x30, 0x60, 0x01, 0xFF, 0xEF, 0xDB, 0x12, 0x2A, 0x00, 0x31, 0x2E, 0x70, 0x20, 0x09, 0x0C, 0x34, 0xF2, 0xFF, 0xFE, 0x00, 0x10, 0xFD, 0x22, 0xFF, 0x09, 0x5B, 0xEB, 0x40, 0x40, 0xB0, 0x20, 0x2B, 0xFF, 0x0D, 0x9F, 0x1E, 0x08, 0x09, 0x20, 0x1F, 0xAE, 0x7F, 0x05, 0x09, 0xE4, 0x31, 0x08, 0x40, 0x00, 0xFF, 0xE4, 0x3F, 0x49, 0x9F, 0xFF, 0x02, 0x07, 0xBF, 0xFA, 0x30, 0xFF, 0xC8, 0x00, 0x0F, 0x49, 0x23, 0xFC, 0x24, 0x02, 0x7F, 0xEE, 0x24, 0x02, 0x40, 0x07, 0x00, 0x05, 0xFA, 0x60, 0x17, 0x70, 0x1F, 0x00, 0x05, 0xFA, 0x09, 0x90, 0x1F, 0x60, 0x87, 0xD0, 0xBF, 0x55, 0xFA, 0x20, 0xFB, 0xF9, 0xFF, 0xFF, 0x02, 0x8C, 0xAF, 0x03, 0xFF, 0x5E, 0x04, 0x10, 0x16, 0x4D, 0xE6, 0x43, 0x02, 0x4C, 0x49, 0x4D, 0xFF, 0xFE, 0x14, 0x2F, 0xFF, 0x02, 0x30, 0x02, 0x28, 0x26, 0xF7, 0x38, 0x90, 0x69, 0x6D, 0x61, 0x67, 0xA8, 0x37, 0x02, 0x80, 0x27, 0xBE, 0x0D, 0x67, 0x0F, 0x47, 0x06, 0x16, 0x00, 0x8A, 0x12, 0x3A, 0x5B, 0x41, 0xDB, 0x11, 0xF4, 0x00, 0xAC, 0xCF, 0xDD, 0x96, 0xDB, 0x5F, 0xAA, 0xAE, 0x00, 0x6D, 0x3C, 0x2E, 0x7F, 0x8B, 0x72, 0xA3, 0x56, 0x00, 0x47, 0x7A, 0xF8, 0x43, 0x6B, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0x00, 0x00, 0x00, 0x00 -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/makerom.c b/makerom.c index 6b85a8c..90b1376 100644 --- a/makerom.c +++ b/makerom.c @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) } fclose(fp); u64 size = GetFileSize_u64(usrset->common.workingFilePath); - usrset->common.workingFile.size = align_value(size,0x10); + usrset->common.workingFile.size = align(size,0x10); usrset->common.workingFile.buffer = malloc(usrset->common.workingFile.size); fp = fopen(usrset->common.workingFilePath,"rb"); ReadFile_64(usrset->common.workingFile.buffer,size,0,fp); diff --git a/ncch.c b/ncch.c index d5caeb1..c1db03f 100644 --- a/ncch.c +++ b/ncch.c @@ -22,8 +22,9 @@ int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset); int ImportNonCodeExeFsSections(ncch_settings *ncchset); int ImportLogo(ncch_settings *ncchset); +int SetupNcch(ncch_settings *ncchset, romfs_buildctx *romfs); +int FinaliseNcch(ncch_settings *ncchset); int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr); -int SetCommonHeaderSectionData(ncch_settings *ncchset, ncch_hdr *hdr); bool IsValidProductCode(char *ProductCode, bool FreeProductCode); int BuildCommonHeader(ncch_settings *ncchset); @@ -58,79 +59,59 @@ int CheckCXISignature(u8 *Signature, u8 *CXI_HDR, u8 *PubK) int build_NCCH(user_settings *usrset) { int result; -#ifdef DEBUG - printf("[DEBUG] Init Settings\n"); -#endif - // Init Settings + + // Init Settings\n"); ncch_settings *ncchset = malloc(sizeof(ncch_settings)); - if(!ncchset) {fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} + if(!ncchset) { + fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); + return MEM_ERROR; + } init_NCCHSettings(ncchset); -#ifdef DEBUG - printf("[DEBUG] Get Settings\n"); -#endif - // Get Settings + // Get Settings\n"); result = get_NCCHSettings(ncchset,usrset); if(result) goto finish; -#ifdef DEBUG - printf("[DEBUG] Build ExeFS Code/PlainRegion\n"); -#endif - // Build ExeFs Code Section - result = BuildExeFsCode(ncchset); - if(result) goto finish; -#ifdef ELF_DEBUG - FILE *code = fopen("code.bin","wb"); - fwrite(ncchset->exefsSections.code.buffer,ncchset->exefsSections.code.size,1,code); - fclose(code); - u8 hash[0x20]; - ctr_sha(ncchset->exefsSections.code.buffer,ncchset->exefsSections.code.size,hash,CTR_SHA_256); - printf("BSS Size: 0x%x\n",ncchset->codeDetails.bssSize); - printf("Code Size: 0x%x\n",ncchset->exefsSections.code.size); - memdump(stdout,"Code Hash: ",hash,0x20); -#endif - -#ifdef DEBUG - printf("[DEBUG] Build Exheader\n"); -#endif - // Build ExHeader - result = BuildExHeader(ncchset); - if(result) goto finish; -#ifdef DEBUG - printf("[DEBUG] Exefs\n"); -#endif - // Build ExeFs/RomFs + if(!ncchset->options.IsCfa){ // CXI Specfic Sections + // Build ExeFs Code Section\n"); + result = BuildExeFsCode(ncchset); + if(result) goto finish; + + // Build ExHeader\n"); + result = BuildExHeader(ncchset); + if(result) goto finish; + } + + + // Build ExeFs\n"); result = BuildExeFs(ncchset); if(result) goto finish; -#ifdef DEBUG - printf("[DEBUG] Build Romfs\n"); -#endif - result = BuildRomFs(ncchset); + + + // Prepare for RomFs\n"); + romfs_buildctx romfs_ctx; + memset(&romfs_ctx,0,sizeof(romfs_buildctx)); + result = SetupRomFs(ncchset,&romfs_ctx); + if(result) goto finish; + + + // Setup NCCH including final memory allocation\n"); + result = SetupNcch(ncchset,&romfs_ctx); + if(result) goto finish; + + // Build RomFs\n"); + result = BuildRomFs(&romfs_ctx); if(result) goto finish; - // Final Steps -#ifdef DEBUG - printf("[DEBUG] Build common header\n"); -#endif - result = BuildCommonHeader(ncchset); - if(result) goto finish; -#ifdef DEBUG - printf("[DEBUG] Encrypt Sections\n"); -#endif - result = EncryptNCCHSections(ncchset); - if(result) goto finish; -#ifdef DEBUG - printf("[DEBUG] Write Sections\n"); -#endif - result = WriteNCCHSectionsToBuffer(ncchset); + // Finalise NCCH (Hashes/Signatures and crypto)\n"); + result = FinaliseNcch(ncchset); if(result) goto finish; + finish: -#ifdef DEBUG - printf("[DEBUG] Finish Building\n"); -#endif - if(result) fprintf(stderr,"[NCCH ERROR] NCCH Build Process Failed\n"); + if(result) + fprintf(stderr,"[NCCH ERROR] NCCH Build Process Failed\n"); free_NCCHSettings(ncchset); return result; } @@ -155,12 +136,10 @@ void free_NCCHSettings(ncch_settings *set) if(set->exefsSections.banner.size) free(set->exefsSections.banner.buffer); if(set->exefsSections.icon.size) free(set->exefsSections.icon.buffer); - if(set->sections.ncchHdr.size) free(set->sections.ncchHdr.buffer); if(set->sections.exhdr.size) free(set->sections.exhdr.buffer); if(set->sections.logo.size) free(set->sections.logo.buffer); if(set->sections.plainRegion.size) free(set->sections.plainRegion.buffer); if(set->sections.exeFs.size) free(set->sections.exeFs.buffer); - if(set->sections.romFs.size) free(set->sections.romFs.buffer); memset(set,0,sizeof(ncch_settings)); @@ -171,6 +150,7 @@ int get_NCCHSettings(ncch_settings *ncchset, user_settings *usrset) { int result = 0; ncchset->out = &usrset->common.workingFile; + ncchset->rsfSet = &usrset->common.rsfSet; ncchset->keys = &usrset->common.keys; @@ -216,7 +196,7 @@ int SetBasicOptions(ncch_settings *ncchset, user_settings *usrset) ncchset->options.UseRomFS = ((ncchset->rsfSet->Rom.HostRoot && strlen(ncchset->rsfSet->Rom.HostRoot) > 0) || usrset->ncch.romfsPath); if(ncchset->options.IsCfa && !ncchset->options.UseRomFS){ - fprintf(stderr,"[NCCH ERROR] 'Rom/HostRoot' must be set\n"); + fprintf(stderr,"[NCCH ERROR] \"Rom/HostRoot\" must be set\n"); return NCCH_BAD_YAML_SET; } @@ -318,15 +298,15 @@ int ImportNonCodeExeFsSections(ncch_settings *ncchset) int ImportLogo(ncch_settings *ncchset) { - if(ncchset->options.IsCfa) return 0; if(ncchset->componentFilePtrs.logo){ - ncchset->sections.logo.size = ncchset->componentFilePtrs.logoSize; + 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) { fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR; } - ReadFile_64(ncchset->sections.logo.buffer,ncchset->sections.logo.size,0,ncchset->componentFilePtrs.logo); + memset(ncchset->sections.logo.buffer,0,ncchset->sections.logo.size); + ReadFile_64(ncchset->sections.logo.buffer,ncchset->componentFilePtrs.logoSize,0,ncchset->componentFilePtrs.logo); } else if(ncchset->rsfSet->BasicInfo.Logo){ if(strcasecmp(ncchset->rsfSet->BasicInfo.Logo,"nintendo") == 0){ @@ -382,8 +362,224 @@ int ImportLogo(ncch_settings *ncchset) return 0; } +int SetupNcch(ncch_settings *ncchset, romfs_buildctx *romfs) +{ + u64 ncchSize = 0; + u64 exhdrSize,logoSize,plnRgnSize,exefsSize,romfsSize; + u64 exhdrOffset,logoOffset,plnRgnOffset,exefsOffset,romfsOffset; + u32 exefsHashSize,romfsHashSize; + + ncchSize += 0x200; // Sig+Hdr + + // Sizes for NCCH hdr + if(ncchset->sections.exhdr.size){ + exhdrSize = 0x400; + exhdrOffset = ncchSize; + ncchSize += ncchset->sections.exhdr.size; + } + else + exhdrSize = 0; + + if(ncchset->sections.logo.size){ + logoSize = ncchset->sections.logo.size; + logoOffset = align(ncchSize,ncchset->options.mediaSize); + 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); + ncchSize = plnRgnOffset + plnRgnSize; + } + else + plnRgnSize = 0; + + if(ncchset->sections.exeFs.size){ + exefsHashSize = ncchset->options.mediaSize; + exefsSize = align(ncchset->sections.exeFs.size,ncchset->options.mediaSize); + exefsOffset = align(ncchSize,ncchset->options.mediaSize); + ncchSize = exefsOffset + exefsSize; + } + else + exefsSize = 0; + + if(romfs->romfsSize){ + romfsHashSize = ncchset->options.mediaSize; + romfsSize = align(romfs->romfsSize,ncchset->options.mediaSize); + if(ncchSize == 0x200) + romfsOffset = ncchSize; + else + romfsOffset = align(ncchSize,ncchset->options.mediaSize*8); + ncchSize = romfsOffset + romfsSize; + } + else + romfsSize = 0; + + + + // Aligning Total NCCH Size + ncchSize = align(ncchSize,ncchset->options.mediaSize); + u8 *ncch = calloc(1,ncchSize); + if(!ncch){ + fprintf(stderr,"[NCCH ERROR] Not enough memory\n"); + return MEM_ERROR; + } + + // Setting up hdr\n"); + ncch_hdr *hdr = (ncch_hdr*)(ncch+0x100); + int ret = SetCommonHeaderBasicData(ncchset,hdr); + if(ret != 0){ + free(ncch); + return ret; + } + u32_to_u8(hdr->ncchSize,ncchSize/ncchset->options.mediaSize,LE); + + + // Copy already built sections to ncch\n"); + if(exhdrSize){ + memcpy((u8*)(ncch+exhdrOffset),ncchset->sections.exhdr.buffer,ncchset->sections.exhdr.size); + free(ncchset->sections.exhdr.buffer); + ncchset->sections.exhdr.buffer = NULL; + u32_to_u8(hdr->exhdrSize,exhdrSize,LE); + } + + 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); + } + + 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); + } + + if(exefsSize){ + memcpy((u8*)(ncch+exefsOffset),ncchset->sections.exeFs.buffer,ncchset->sections.exeFs.size); + free(ncchset->sections.exeFs.buffer); + + ncchset->sections.exeFs.buffer = NULL; + + u32_to_u8(hdr->exefsOffset,exefsOffset/ncchset->options.mediaSize,LE); + + u32_to_u8(hdr->exefsSize,exefsSize/ncchset->options.mediaSize,LE); + + u32_to_u8(hdr->exefsHashSize,exefsHashSize/ncchset->options.mediaSize,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); + } + + ncchset->out->buffer = ncch; + ncchset->out->size = ncchSize; + + GetNCCHStruct(&ncchset->cryptoDetails,hdr); + + return 0; +} + +int FinaliseNcch(ncch_settings *ncchset) +{ + u8 *ncch = ncchset->out->buffer; + + ncch_hdr *hdr = (ncch_hdr*)(ncch + 0x100); + u8 *exhdr = (u8*)(ncch + ncchset->cryptoDetails.exhdrOffset); + u8 *logo = (u8*)(ncch + ncchset->cryptoDetails.logoOffset); + u8 *exefs = (u8*)(ncch + ncchset->cryptoDetails.exefsOffset); + u8 *romfs = (u8*)(ncch + ncchset->cryptoDetails.romfsOffset); + + // Taking Hashes\n"); + if(ncchset->cryptoDetails.exhdrSize) + ctr_sha(exhdr,0x400,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); + + // Signing NCCH\n"); + 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(sig_result != Good){ + fprintf(stderr,"[NCCH ERROR] Failed to sign %s header\n",ncchset->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 = GetNCCHKey(keyType, ncchset->keys); + u8 *key1 = GetNCCHKey(keyType, ncchset->keys); + if(keyType == KeyIsUnFixed2) + key0 = GetNCCHKey(KeyIsUnFixed, ncchset->keys); + + if(key0 == NULL || key1 == NULL){ + fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n"); + free(ncch); + return -1; + } + + //memdump(stdout,"key0: ",key0,16); + //memdump(stdout,"key1: ",key1,16); + + // Crypting Exheader + if(ncchset->cryptoDetails.exhdrSize) + CryptNCCHSection(exhdr,ncchset->cryptoDetails.exhdrSize,0x0,&ncchset->cryptoDetails,key0,ncch_exhdr); + + // Crypting ExeFs Files + if(ncchset->cryptoDetails.exefsSize){ + for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){ + u8 *key = NULL; + exefs_filehdr *exefsFile = (exefs_filehdr*)(exefs+sizeof(exefs_filehdr)*i); + if(strncmp(exefsFile->name,"icon",8) == 0 ||strncmp(exefsFile->name,"banner",8) == 0) + key = key0; + else + key = key1; + + u32 offset = u8_to_u32(exefsFile->offset,LE) + 0x200; + u32 size = u8_to_u32(exefsFile->size,LE); + + if(size) + CryptNCCHSection((exefs+offset),align(size,ncchset->options.mediaSize),offset,&ncchset->cryptoDetails,key,ncch_exefs); + + } + // Crypting ExeFs Header + CryptNCCHSection(exefs,0x200,0x0,&ncchset->cryptoDetails,key0,ncch_exefs); + } + + // Crypting RomFs + if(ncchset->cryptoDetails.romfsSize) + CryptNCCHSection(romfs,ncchset->cryptoDetails.romfsSize,0x0,&ncchset->cryptoDetails,key1,ncch_romfs); + } + + return 0; +} + int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr) { + /* NCCH Magic */ + memcpy(hdr->magic,"NCCH",4); + /* NCCH Format titleVersion */ u16_to_u8(hdr->formatVersion,0x2,LE); @@ -414,6 +610,17 @@ int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr) } 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] = 0; + if(ncchset->keys->aes.ncchKeyX1) + hdr->flags[SecureCrypto2] = 1; + } + else + hdr->flags[OtherFlag] = FixedCryptoKey; + /* Set ContentUnitSize */ hdr->flags[ContentUnitSize] = 0; // 0x200 @@ -421,14 +628,13 @@ int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr) hdr->flags[ContentPlatform] = 1; // CTR /* Setting OtherFlag */ - hdr->flags[OtherFlag] = FixedCryptoKey; - if(!ncchset->options.Encrypt) hdr->flags[OtherFlag] |= NoCrypto; - if(!ncchset->sections.romFs.size) hdr->flags[OtherFlag] |= NoMountRomFs; + if(!ncchset->options.UseRomFS) + hdr->flags[OtherFlag] |= NoMountRomFs; /* Setting ContentType */ hdr->flags[ContentType] = 0; - if(ncchset->sections.romFs.size || ncchset->options.IsCfa) hdr->flags[ContentType] |= content_Data; + 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; @@ -445,74 +651,6 @@ int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr) return 0; } -int SetCommonHeaderSectionData(ncch_settings *ncchset, ncch_hdr *hdr) -{ - /* Set Sizes/Hashes to Hdr */ - - u32 ExHeaderSize,LogoSize,PlainRegionSize,ExeFsSize,ExeFsHashSize,RomFsSize,RomFsHashSize; - - ExHeaderSize = ncchset->sections.exhdr.size ? ((u32) ncchset->sections.exhdr.size - 0x400) : 0; - LogoSize = ncchset->sections.logo.size ? ((u32) (ncchset->sections.logo.size/ncchset->options.mediaSize)) : 0; - PlainRegionSize = ncchset->sections.plainRegion.size ? ((u32) (ncchset->sections.plainRegion.size/ncchset->options.mediaSize)) : 0; - ExeFsSize = ncchset->sections.exeFs.size ? ((u32) (ncchset->sections.exeFs.size/ncchset->options.mediaSize)) : 0; - ExeFsHashSize = (u32) ExeFsSize? ncchset->options.mediaSize/ncchset->options.mediaSize : 0; - RomFsSize = ncchset->sections.romFs.size ? ((u32) (ncchset->sections.romFs.size/ncchset->options.mediaSize)) : 0; - RomFsHashSize = (u32) RomFsSize? ncchset->options.mediaSize/ncchset->options.mediaSize : 0; - - - u32_to_u8(hdr->exhdrSize,ExHeaderSize,LE); - if(ExHeaderSize) ctr_sha(ncchset->sections.exhdr.buffer,ExHeaderSize,hdr->exhdrHash,CTR_SHA_256); - - u32_to_u8(hdr->logoSize,LogoSize,LE); - if(LogoSize) ctr_sha(ncchset->sections.logo.buffer,ncchset->sections.logo.size,hdr->logoHash,CTR_SHA_256); - - u32_to_u8(hdr->plainRegionSize,PlainRegionSize,LE); - - u32_to_u8(hdr->exefsSize,ExeFsSize,LE); - u32_to_u8(hdr->exefsHashSize,ExeFsHashSize,LE); - if(ExeFsSize) ctr_sha(ncchset->sections.exeFs.buffer,ncchset->options.mediaSize,hdr->exefsHash,CTR_SHA_256); - - u32_to_u8(hdr->romfsSize,RomFsSize,LE); - u32_to_u8(hdr->romfsHashSize,RomFsHashSize,LE); - if(RomFsSize) ctr_sha(ncchset->sections.romFs.buffer,ncchset->options.mediaSize,hdr->romfsHash,CTR_SHA_256); - - - /* Get Section Offsets */ - u32 size = 1; - if (ExHeaderSize) - size += 4; - - if (LogoSize){ - u32_to_u8(hdr->logoOffset,size,LE); - ncchset->sections.logoOffset = size*ncchset->options.mediaSize; - size += LogoSize; - } - - if(PlainRegionSize){ - u32_to_u8(hdr->plainRegionOffset,size,LE); - ncchset->sections.plainRegionOffset = size*ncchset->options.mediaSize; - size += PlainRegionSize; - } - - if (ExeFsSize){ - u32_to_u8(hdr->exefsOffset,size,LE); - ncchset->sections.exeFsOffset = size*ncchset->options.mediaSize; - size += ExeFsSize; - } - - if (RomFsSize){ - u32_to_u8(hdr->romfsOffset,size,LE); - ncchset->sections.romFsOffset = size*ncchset->options.mediaSize; - size += RomFsSize; - } - - u32_to_u8(hdr->ncchSize,size,LE); - - ncchset->sections.totalNcchSize = size * ncchset->options.mediaSize; - - return 0; -} - bool IsValidProductCode(char *ProductCode, bool FreeProductCode) { if(strlen(ProductCode) > 16) return false; @@ -531,104 +669,9 @@ bool IsValidProductCode(char *ProductCode, bool FreeProductCode) return true; } -int BuildCommonHeader(ncch_settings *ncchset) -{ - int result = 0; - - // Initialising Header - ncchset->sections.ncchHdr.size = 0x100 + sizeof(ncch_hdr); - ncchset->sections.ncchHdr.buffer = malloc(ncchset->sections.ncchHdr.size); - if(!ncchset->sections.ncchHdr.buffer) { fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR; } - memset(ncchset->sections.ncchHdr.buffer,0,ncchset->sections.ncchHdr.size); - - // Creating Ptrs - u8 *sig = ncchset->sections.ncchHdr.buffer; - ncch_hdr *hdr = (ncch_hdr*)(ncchset->sections.ncchHdr.buffer+0x100); - - // Setting Data in Hdr - memcpy(hdr->magic,"NCCH",4); - - result = SetCommonHeaderBasicData(ncchset,hdr); - if(result) return result; - - result = SetCommonHeaderSectionData(ncchset,hdr); - if(result) return result; - - - // Signing Hdr - int sig_result = Good; - if(ncchset->options.IsCfa) sig_result = SignCFA(sig,(u8*)hdr,ncchset->keys); - else sig_result = SignCXI(sig,(u8*)hdr,ncchset->keys); - if(sig_result != Good){ - fprintf(stderr,"[NCCH ERROR] Failed to sign %s header\n",ncchset->options.IsCfa ? "CFA" : "CXI"); - return sig_result; - } - - return 0; -} - -int EncryptNCCHSections(ncch_settings *ncchset) -{ - if(!ncchset->options.Encrypt) return 0; - - /* Getting ncch_struct */ - ncch_hdr *hdr = GetNCCH_CommonHDR(NULL,NULL,ncchset->sections.ncchHdr.buffer); - ncch_struct *ncch = malloc(sizeof(ncch_struct)); - if(!ncch) { fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - memset(ncch,0,sizeof(ncch_struct)); - GetCXIStruct(ncch,hdr); - - u8 *ncch_key = GetNCCHKey(hdr,ncchset->keys); - - if(ncchset->sections.exhdr.size) - CryptNCCHSection(ncchset->sections.exhdr.buffer,ncchset->sections.exhdr.size,0,ncch,ncch_key,ncch_exhdr); - - if(ncchset->sections.exeFs.size) - CryptNCCHSection(ncchset->sections.exeFs.buffer,ncchset->sections.exeFs.size,0,ncch,ncch_key,ncch_exefs); - - if(ncchset->sections.romFs.size) - CryptNCCHSection(ncchset->sections.romFs.buffer,ncchset->sections.romFs.size,0,ncch,ncch_key,ncch_romfs); - - return 0; -} - -int WriteNCCHSectionsToBuffer(ncch_settings *ncchset) -{ - /* Allocating Memory for NCCH, and clearing */ - ncchset->out->size = ncchset->sections.totalNcchSize; - ncchset->out->buffer = malloc(ncchset->out->size); - if(!ncchset->out->buffer) { fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - memset(ncchset->out->buffer,0,ncchset->out->size); - - /* Copy Header+Sig */ - memcpy(ncchset->out->buffer,ncchset->sections.ncchHdr.buffer,ncchset->sections.ncchHdr.size); - - /* Copy Exheader+AccessDesc */ - if(ncchset->sections.exhdr.size) - memcpy(ncchset->out->buffer+0x200,ncchset->sections.exhdr.buffer,ncchset->sections.exhdr.size); - - /* Copy Logo */ - if(ncchset->sections.logo.size) - memcpy(ncchset->out->buffer+ncchset->sections.logoOffset,ncchset->sections.logo.buffer,ncchset->sections.logo.size); - - /* Copy PlainRegion */ - if(ncchset->sections.plainRegion.size) - memcpy(ncchset->out->buffer+ncchset->sections.plainRegionOffset,ncchset->sections.plainRegion.buffer,ncchset->sections.plainRegion.size); - - /* Copy ExeFs */ - if(ncchset->sections.exeFs.size) - memcpy(ncchset->out->buffer+ncchset->sections.exeFsOffset,ncchset->sections.exeFs.buffer,ncchset->sections.exeFs.size); - - /* Copy RomFs */ - if(ncchset->sections.romFs.size) - memcpy(ncchset->out->buffer+ncchset->sections.romFsOffset,ncchset->sections.romFs.buffer,ncchset->sections.romFs.size); - - return 0; -} - // NCCH Read Functions -int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput) +int VerifyNCCH(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput) { // Setup u8 Hash[0x20]; @@ -638,16 +681,38 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput) ncch_struct *ncch_ctx = malloc(sizeof(ncch_struct)); if(!ncch_ctx){ fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR; } memset(ncch_ctx,0x0,sizeof(ncch_struct)); - GetCXIStruct(ncch_ctx,hdr); + GetNCCHStruct(ncch_ctx,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(GetNCCHKey(keyType,keys) == NULL){ + if(!SuppressOutput) + fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key.\n"); + return UNABLE_TO_LOAD_NCCH_KEY; + } + key0 = GetNCCHKey(keyType,keys); + key1 = GetNCCHKey(keyType,keys); + if(keyType == KeyIsUnFixed2) + key0 = GetNCCHKey(KeyIsUnFixed,keys); + } + + //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(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CFA Sigcheck Failed\n"); + if(!SuppressOutput) + fprintf(stderr,"[NCCH ERROR] CFA Sigcheck Failed\n"); free(ncch_ctx); return NCCH_HDR_SIG_BAD; } if(!ncch_ctx->romfsSize){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CFA is corrupt\n"); + if(!SuppressOutput) + fprintf(stderr,"[NCCH ERROR] CFA is corrupt\n"); free(ncch_ctx); return NO_ROMFS_IN_CFA; } @@ -655,12 +720,14 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput) else{ // IsCxi // Checking for necessary sections if(!ncch_ctx->exhdrSize){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); + if(!SuppressOutput) + fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); free(ncch_ctx); return NO_EXHEADER_IN_CXI; } if(!ncch_ctx->exefsSize){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); + if(!SuppressOutput) + fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); free(ncch_ctx); return NO_EXEFS_IN_CXI; } @@ -671,19 +738,9 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput) free(ncch_ctx); return MEM_ERROR; } - int ret = GetNCCHSection((u8*)ExHeader,ncch_ctx->exhdrSize,0,ncch,ncch_ctx,keys,ncch_exhdr); - if(ret != 0 && ret != UNABLE_TO_LOAD_NCCH_KEY){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); - free(ncch_ctx); - free(ExHeader); - return CXI_CORRUPT; - } - else if(ret == UNABLE_TO_LOAD_NCCH_KEY){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key.\n"); - free(ncch_ctx); - free(ExHeader); - return UNABLE_TO_LOAD_NCCH_KEY; - } + memcpy(ExHeader,ncch+ncch_ctx->exhdrOffset,ncch_ctx->exhdrSize); + if(key0 != NULL) + CryptNCCHSection((u8*)ExHeader,ncch_ctx->exhdrSize,0,ncch_ctx,key0,ncch_exhdr); // Checking Exheader Hash to see if decryption was sucessful ctr_sha(ExHeader,0x400,Hash,CTR_SHA_256); @@ -717,6 +774,10 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput) } free(ExHeader); } + + if(!CheckHash) + return 0; + /* Checking ExeFs Hash, if present */ if(ncch_ctx->exefsSize) { @@ -726,7 +787,9 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput) free(ncch_ctx); return MEM_ERROR; } - GetNCCHSection(ExeFs,ncch_ctx->exefsHashDataSize,0,ncch,ncch_ctx,keys,ncch_exefs); + 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){ @@ -744,7 +807,9 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput) free(ncch_ctx); return MEM_ERROR; } - GetNCCHSection(RomFs,ncch_ctx->romfsHashDataSize,0,ncch,ncch_ctx,keys,ncch_romfs); + 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){ @@ -780,10 +845,20 @@ u8* RetargetNCCH(FILE *fp, u64 size, u8 *TitleId, u8 *ProgramId, keys_struct *ke } ReadFile_64(ncch,size,0,fp); // Importing - if(!IsNCCH(NULL,ncch)){ + 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); + return -1; + } ncch_hdr *hdr = NULL; hdr = GetNCCH_CommonHDR(NULL,NULL,ncch); @@ -791,63 +866,65 @@ u8* RetargetNCCH(FILE *fp, u64 size, u8 *TitleId, u8 *ProgramId, keys_struct *ke 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 NULL; + return -1; } - if((memcmp(TitleId,hdr->titleId,8) == 0) && (memcmp(ProgramId,hdr->programId,8) == 0)) - return ncch;// if no modification is required don't do anything + bool titleIdMatches = titleId == NULL? true : memcmp(titleId,hdr->titleId,8) == 0; + bool programIdMatches = programId == NULL? true : memcmp(programId,hdr->programId,8) == 0; - if(memcmp(TitleId,hdr->titleId,8) == 0){ // If TitleID Same, no crypto required, just resign. - memcpy(hdr->programId,ProgramId,8); + 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 ncch; + return 0; } ncch_key_type keytype = GetNCCHKeyType(hdr); - u8 *key = NULL; - - if(keytype == KeyIsUnFixed || keytype == KeyIsUnFixed2){ - fprintf(stderr,"[NCCH ERROR] Unknown aes key\n"); - free(ncch); - return NULL; - } - - ncch_struct ncch_struct; - if(keytype != NoKey){ //Decrypting if necessary - GetCXIStruct(&ncch_struct,hdr); - u8 *romfs = (ncch+ncch_struct.romfsOffset); - key = GetNCCHKey(hdr,keys); + u8 *key = NULL; + 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 = GetNCCHKey(keytype,keys); if(key == NULL){ fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n"); free(ncch); - return NULL; + return -1; } CryptNCCHSection(romfs,ncch_struct.romfsSize,0,&ncch_struct,key,ncch_romfs); } - - memcpy(hdr->titleId,TitleId,8); - memcpy(hdr->programId,ProgramId,8); - - //Checking New Fixed Key Type + // Editing data and resigning + if(titleId) + memcpy(hdr->titleId,titleId,8); + if(programId) + memcpy(hdr->programId,programId,8); + SignCFA(ncch,(u8*)hdr,keys); + + //Checking New Key Type keytype = GetNCCHKeyType(hdr); - if(keytype != NoKey){ // Re-encrypting if necessary - GetCXIStruct(&ncch_struct,hdr); - u8 *romfs = (ncch+ncch_struct.romfsOffset); - key = GetNCCHKey(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 = GetNCCHKey(keytype,keys); if(key == NULL){ fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n"); free(ncch); - return NULL; + return -1; } CryptNCCHSection(romfs,ncch_struct.romfsSize,0,&ncch_struct,key,ncch_romfs); } - - SignCFA(ncch,(u8*)hdr,keys); - - return ncch; + + return 0; } @@ -923,23 +1000,23 @@ ncch_key_type GetNCCHKeyType(ncch_hdr* hdr) return KeyIsUnFixed; } -u8* GetNCCHKey(ncch_hdr* hdr, keys_struct *keys) +u8* GetNCCHKey(ncch_key_type keytype, keys_struct *keys) { - ncch_key_type keytype = GetNCCHKeyType(hdr); switch(keytype){ case NoKey: return NULL; case KeyIsNormalFixed: return keys->aes.normalKey; case KeyIsSystemFixed: - if(!keys->aes.systemFixedKey) fprintf(stderr,"[NCCH WARNING] Unable to load SystemFixed Key\n"); return keys->aes.systemFixedKey; case KeyIsUnFixed: - fprintf(stderr,"[NCCH WARNING] Unable to load UnFixed Key\n"); - return NULL; - //if(!keys->aes.unFixedKey0) fprintf(stderr,"[NCCH WARNING] Unable to load UnFixed Key\n"); - //return keys->aes.unFixedKey0; + if(keys->aes.ncchKeyX0) + return keys->aes.unFixedKey0; + else + return NULL; case KeyIsUnFixed2: - fprintf(stderr,"[NCCH WARNING] Crypto method (Secure2) not supported yet\n"); - return NULL; + if(keys->aes.ncchKeyX1) + return keys->aes.unFixedKey1; + else + return NULL; } return NULL; } @@ -952,7 +1029,7 @@ int GetNCCHSection(u8 *dest, u64 dest_max_size, u64 src_pos, u8 *ncch, ncch_stru ncch_key_type keytype = GetNCCHKeyType(hdr); if(keytype != NoKey && (section == ncch_exhdr || section == ncch_exefs || section == ncch_romfs)){ - key = GetNCCHKey(hdr,keys); + key = GetNCCHKey(keytype,keys); if(key == NULL){ //fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key.\n"); return UNABLE_TO_LOAD_NCCH_KEY; @@ -1003,7 +1080,7 @@ int GetNCCHSection(u8 *dest, u64 dest_max_size, u64 src_pos, u8 *ncch, ncch_stru return 0; } -int GetCXIStruct(ncch_struct *ctx, ncch_hdr *header) +int GetNCCHStruct(ncch_struct *ctx, ncch_hdr *header) { memcpy(ctx->titleId,header->titleId,8); memcpy(ctx->programId,header->programId,8); @@ -1041,7 +1118,7 @@ void CryptNCCHSection(u8 *buffer, u64 size, u64 src_pos, ncch_struct *ctx, u8 ke ctr_init_counter(&aes_ctx, key, counter); if(src_pos > 0){ u32 carry = 0; - carry = align_value(src_pos,0x10); + carry = align(src_pos,0x10); carry /= 0x10; ctr_add_counter(&aes_ctx,carry); } diff --git a/ncch.h b/ncch.h index d5f761e..9757a96 100644 --- a/ncch.h +++ b/ncch.h @@ -1,5 +1,4 @@ -#ifndef _NCCH_H_ -#define _NCCH_H_ +#pragma once typedef enum { @@ -123,9 +122,10 @@ typedef struct typedef struct { + buffer_struct *out; keys_struct *keys; rsf_settings *rsfSet; - COMPONENT_STRUCT *out; + struct { @@ -169,9 +169,9 @@ typedef struct struct { - COMPONENT_STRUCT code; - COMPONENT_STRUCT banner; - COMPONENT_STRUCT icon; + buffer_struct code; + buffer_struct banner; + buffer_struct icon; } exefsSections; struct @@ -190,31 +190,27 @@ typedef struct struct { - u64 totalNcchSize; - COMPONENT_STRUCT ncchHdr; - COMPONENT_STRUCT exhdr; - u64 logoOffset; - COMPONENT_STRUCT logo; - u64 plainRegionOffset; - COMPONENT_STRUCT plainRegion; - u64 exeFsOffset; - COMPONENT_STRUCT exeFs; - u64 romFsOffset; - COMPONENT_STRUCT romFs; + buffer_struct exhdr; + buffer_struct logo; + buffer_struct plainRegion; + buffer_struct exeFs; } sections; + + ncch_struct cryptoDetails; + } ncch_settings; -#endif - // NCCH Build Functions int build_NCCH(user_settings *usrset); // NCCH Read Functions -int VerifyNCCH(u8 *ncch, keys_struct *keys, 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); @@ -224,8 +220,8 @@ u32 GetNCCH_MediaSize(ncch_hdr* hdr); ncch_key_type GetNCCHKeyType(ncch_hdr* hdr); int GetNCCHSection(u8 *dest, u64 dest_max_size, u64 src_pos, u8 *ncch, ncch_struct *ncch_ctx, keys_struct *keys, ncch_section section); -u8* GetNCCHKey(ncch_hdr* hdr, keys_struct *keys); +u8* GetNCCHKey(ncch_key_type keytype, keys_struct *keys); -int GetCXIStruct(ncch_struct *ctx, ncch_hdr *header); +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 diff --git a/ncch_backup.c b/ncch_backup.c deleted file mode 100644 index a9efac4..0000000 --- a/ncch_backup.c +++ /dev/null @@ -1,1104 +0,0 @@ -#include "lib.h" -#include "ncch.h" -#include "exheader.h" -#include "elf.h" -#include "exefs.h" -#include "romfs.h" -#include "titleid.h" - -#include "logo_data.h" // Contains Logos - -// 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); - -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); -int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset); -int ImportNonCodeExeFsSections(ncch_settings *ncchset); -int ImportLogo(ncch_settings *ncchset); - -int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr); -int SetCommonHeaderSectionData(ncch_settings *ncchset, ncch_hdr *hdr); -bool IsValidProductCode(char *ProductCode, bool FreeProductCode); - -int BuildCommonHeader(ncch_settings *ncchset); -int EncryptNCCHSections(ncch_settings *ncchset); -int WriteNCCHSectionsToBuffer(ncch_settings *ncchset); - -// Code - -int SignCFA(u8 *Signature, u8 *CFA_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); -} - -int CheckCFASignature(u8 *Signature, u8 *CFA_HDR, keys_struct *keys) -{ - return ctr_sig(CFA_HDR,sizeof(ncch_hdr),Signature,keys->rsa.cciCfaPub,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY); -} - -int SignCXI(u8 *Signature, u8 *CXI_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); -} - -int CheckCXISignature(u8 *Signature, u8 *CXI_HDR, u8 *PubK) -{ - int result = ctr_sig(CXI_HDR,sizeof(ncch_hdr),Signature,PubK,NULL,RSA_2048_SHA256,CTR_RSA_VERIFY); - return result; -} - -// NCCH Build Functions - -int build_NCCH(user_settings *usrset) -{ - int result; -#ifdef DEBUG - printf("[DEBUG] Init Settings\n"); -#endif - // Init Settings - ncch_settings *ncchset = malloc(sizeof(ncch_settings)); - if(!ncchset) {fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - init_NCCHSettings(ncchset); - -#ifdef DEBUG - printf("[DEBUG] Get Settings\n"); -#endif - // Get Settings - result = get_NCCHSettings(ncchset,usrset); - if(result) goto finish; -#ifdef DEBUG - printf("[DEBUG] Build ExeFS Code/PlainRegion\n"); -#endif - // Build ExeFs Code Section - result = BuildExeFsCode(ncchset); - if(result) goto finish; - -#ifdef ELF_DEBUG - FILE *code = fopen("code.bin","wb"); - fwrite(ncchset->ExeFs_Sections.Code.buffer,ncchset->ExeFs_Sections.Code.size,1,code); - fclose(code); - u8 hash[0x20]; - ctr_sha(ncchset->ExeFs_Sections.Code.buffer,ncchset->ExeFs_Sections.Code.size,hash,CTR_SHA_256); - printf("BSS Size: 0x%x\n",ncchset->CodeDetails.BSS_Size); - printf("Code Size: 0x%x\n",ncchset->ExeFs_Sections.Code.size); - memdump(stdout,"Code Hash: ",hash,0x20); -#endif - -#ifdef DEBUG - printf("[DEBUG] Build Exheader\n"); -#endif - // Build ExHeader - result = BuildExHeader(ncchset); - if(result) goto finish; - - -#ifdef DEBUG - printf("[DEBUG] Exefs\n"); -#endif - // Build ExeFs/RomFs - result = BuildExeFs(ncchset); - if(result) goto finish; -#ifdef DEBUG - printf("[DEBUG] Build Romfs\n"); -#endif - result = BuildRomFs(ncchset); - if(result) goto finish; - - // Final Steps -#ifdef DEBUG - printf("[DEBUG] Build common header\n"); -#endif - result = BuildCommonHeader(ncchset); - if(result) goto finish; -#ifdef DEBUG - printf("[DEBUG] Encrypt Sections\n"); -#endif - result = EncryptNCCHSections(ncchset); - if(result) goto finish; -#ifdef DEBUG - printf("[DEBUG] Write Sections\n"); -#endif - result = WriteNCCHSectionsToBuffer(ncchset); - if(result) goto finish; -finish: -#ifdef DEBUG - printf("[DEBUG] Finish Building\n"); -#endif - if(result) fprintf(stderr,"[NCCH ERROR] NCCH Build Process Failed\n"); - free_NCCHSettings(ncchset); - return result; -} - -void init_NCCHSettings(ncch_settings *set) -{ - memset(set,0,sizeof(ncch_settings)); -} - -void free_NCCHSettings(ncch_settings *set) -{ - if(set->ComponentFilePtrs.elf) fclose(set->ComponentFilePtrs.elf); - if(set->ComponentFilePtrs.banner) fclose(set->ComponentFilePtrs.banner); - if(set->ComponentFilePtrs.icon) fclose(set->ComponentFilePtrs.icon); - if(set->ComponentFilePtrs.logo) fclose(set->ComponentFilePtrs.logo); - if(set->ComponentFilePtrs.code) fclose(set->ComponentFilePtrs.code); - if(set->ComponentFilePtrs.exheader) fclose(set->ComponentFilePtrs.exheader); - if(set->ComponentFilePtrs.romfs) fclose(set->ComponentFilePtrs.romfs); - if(set->ComponentFilePtrs.plainregion) fclose(set->ComponentFilePtrs.plainregion); - - if(set->ExeFs_Sections.Code.size) free(set->ExeFs_Sections.Code.buffer); - if(set->ExeFs_Sections.Banner.size) free(set->ExeFs_Sections.Banner.buffer); - if(set->ExeFs_Sections.Icon.size) free(set->ExeFs_Sections.Icon.buffer); - - if(set->Sections.CommonHeader.size) free(set->Sections.CommonHeader.buffer); - if(set->Sections.ExHeader.size) free(set->Sections.ExHeader.buffer); - if(set->Sections.Logo.size) free(set->Sections.Logo.buffer); - if(set->Sections.PlainRegion.size) free(set->Sections.PlainRegion.buffer); - if(set->Sections.ExeFs.size) free(set->Sections.ExeFs.buffer); - if(set->Sections.RomFs.size) free(set->Sections.RomFs.buffer); - - memset(set,0,sizeof(ncch_settings)); - - free(set); -} - -int get_NCCHSettings(ncch_settings *ncchset, user_settings *usrset) -{ - int result = 0; - ncchset->out = &usrset->Content0; - ncchset->yaml_set = &usrset->yaml_set; - ncchset->keys = &usrset->keys; - - result = SetBasicOptions(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 result = 0; - - /* Options */ - ncchset->Options.MediaSize = 0x200; - - ncchset->Options.IncludeExeFsLogo = usrset->include_exefs_logo; - - if(usrset->yaml_set.Option.EnableCompress != -1) ncchset->Options.CompressCode = usrset->yaml_set.Option.EnableCompress; - else ncchset->Options.CompressCode = true; - - if(usrset->yaml_set.Option.UseOnSD != -1) ncchset->Options.UseOnSD = usrset->yaml_set.Option.UseOnSD; - else ncchset->Options.UseOnSD = false; - usrset->yaml_set.Option.UseOnSD = ncchset->Options.UseOnSD; - - if(usrset->yaml_set.Option.EnableCrypt != -1) ncchset->Options.Encrypt = usrset->yaml_set.Option.EnableCrypt; - else ncchset->Options.Encrypt = true; - - if(usrset->yaml_set.Option.FreeProductCode != -1) ncchset->Options.FreeProductCode = usrset->yaml_set.Option.FreeProductCode; - else ncchset->Options.FreeProductCode = false; - - ncchset->Options.IsCfa = (usrset->build_ncch_type == CFA); - - ncchset->Options.IsBuildingCodeSection = (usrset->elf_path != NULL); - - ncchset->Options.UseRomFS = ((ncchset->yaml_set->Rom.HostRoot && strlen(ncchset->yaml_set->Rom.HostRoot) > 0) || usrset->romfs_path); - - if(ncchset->Options.IsCfa && !ncchset->Options.UseRomFS){ - fprintf(stderr,"[NCCH ERROR] 'Rom/HostRoot' must be set\n"); - return NCCH_BAD_YAML_SET; - } - - return result; -} - -int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset) -{ - if(usrset->romfs_path){ - ncchset->ComponentFilePtrs.romfs_size = GetFileSize_u64(usrset->romfs_path); - ncchset->ComponentFilePtrs.romfs = fopen(usrset->romfs_path,"rb"); - if(!ncchset->ComponentFilePtrs.romfs){ - fprintf(stderr,"[NCCH ERROR] Failed to open RomFs file '%s'\n",usrset->romfs_path); - return FAILED_TO_IMPORT_FILE; - } - } - if(ncchset->Options.IsCfa) return 0; - if(usrset->elf_path){ - ncchset->ComponentFilePtrs.elf_size = GetFileSize_u64(usrset->elf_path); - ncchset->ComponentFilePtrs.elf = fopen(usrset->elf_path,"rb"); - if(!ncchset->ComponentFilePtrs.elf){ - fprintf(stderr,"[NCCH ERROR] Failed to open elf file '%s'\n",usrset->elf_path); - return FAILED_TO_IMPORT_FILE; - } - } - if(usrset->banner_path){ - ncchset->ComponentFilePtrs.banner_size = GetFileSize_u64(usrset->banner_path); - ncchset->ComponentFilePtrs.banner = fopen(usrset->banner_path,"rb"); - if(!ncchset->ComponentFilePtrs.banner){ - fprintf(stderr,"[NCCH ERROR] Failed to open banner file '%s'\n",usrset->banner_path); - return FAILED_TO_IMPORT_FILE; - } - } - if(usrset->icon_path){ - ncchset->ComponentFilePtrs.icon_size = GetFileSize_u64(usrset->icon_path); - ncchset->ComponentFilePtrs.icon = fopen(usrset->icon_path,"rb"); - if(!ncchset->ComponentFilePtrs.icon){ - fprintf(stderr,"[NCCH ERROR] Failed to open icon file '%s'\n",usrset->icon_path); - return FAILED_TO_IMPORT_FILE; - } - } - if(usrset->logo_path){ - ncchset->ComponentFilePtrs.logo_size = GetFileSize_u64(usrset->logo_path); - ncchset->ComponentFilePtrs.logo = fopen(usrset->logo_path,"rb"); - if(!ncchset->ComponentFilePtrs.logo){ - fprintf(stderr,"[NCCH ERROR] Failed to open logo file '%s'\n",usrset->logo_path); - return FAILED_TO_IMPORT_FILE; - } - } - - if(usrset->exefs_code_path){ - ncchset->ComponentFilePtrs.code_size = GetFileSize_u64(usrset->exefs_code_path); - ncchset->ComponentFilePtrs.code = fopen(usrset->exefs_code_path,"rb"); - if(!ncchset->ComponentFilePtrs.code){ - fprintf(stderr,"[NCCH ERROR] Failed to open ExeFs Code file '%s'\n",usrset->exefs_code_path); - return FAILED_TO_IMPORT_FILE; - } - } - if(usrset->exheader_path){ - ncchset->ComponentFilePtrs.exheader_size = GetFileSize_u64(usrset->exheader_path); - ncchset->ComponentFilePtrs.exheader = fopen(usrset->exheader_path,"rb"); - if(!ncchset->ComponentFilePtrs.exheader){ - fprintf(stderr,"[NCCH ERROR] Failed to open ExHeader file '%s'\n",usrset->exheader_path); - return FAILED_TO_IMPORT_FILE; - } - } - if(usrset->plain_region_path){ - ncchset->ComponentFilePtrs.plainregion_size = GetFileSize_u64(usrset->plain_region_path); - ncchset->ComponentFilePtrs.plainregion = fopen(usrset->plain_region_path,"rb"); - if(!ncchset->ComponentFilePtrs.plainregion){ - fprintf(stderr,"[NCCH ERROR] Failed to open PlainRegion file '%s'\n",usrset->plain_region_path); - return FAILED_TO_IMPORT_FILE; - } - } - return 0; -} - -int ImportNonCodeExeFsSections(ncch_settings *ncchset) -{ - if(ncchset->Options.IsCfa) return 0; - if(ncchset->ComponentFilePtrs.banner){ - ncchset->ExeFs_Sections.Banner.size = ncchset->ComponentFilePtrs.banner_size; - ncchset->ExeFs_Sections.Banner.buffer = malloc(ncchset->ExeFs_Sections.Banner.size); - if(!ncchset->ExeFs_Sections.Banner.buffer) {fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - ReadFile_64(ncchset->ExeFs_Sections.Banner.buffer,ncchset->ExeFs_Sections.Banner.size,0,ncchset->ComponentFilePtrs.banner); - } - if(ncchset->ComponentFilePtrs.icon){ - ncchset->ExeFs_Sections.Icon.size = ncchset->ComponentFilePtrs.icon_size; - ncchset->ExeFs_Sections.Icon.buffer = malloc(ncchset->ExeFs_Sections.Icon.size); - if(!ncchset->ExeFs_Sections.Icon.buffer) {fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - ReadFile_64(ncchset->ExeFs_Sections.Icon.buffer,ncchset->ExeFs_Sections.Icon.size,0,ncchset->ComponentFilePtrs.icon); - } - return 0; -} - -int ImportLogo(ncch_settings *ncchset) -{ - if(ncchset->Options.IsCfa) return 0; - if(ncchset->ComponentFilePtrs.logo){ - ncchset->sections.logo.size = ncchset->ComponentFilePtrs.logo_size; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) {fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - ReadFile_64(ncchset->sections.logo.buffer,ncchset->sections.logo.size,0,ncchset->ComponentFilePtrs.logo); - } - else if(ncchset->yaml_set->BasicInfo.Logo){ - if(strcasecmp(ncchset->yaml_set->BasicInfo.Logo,"nintendo") == 0){ - ncchset->sections.logo.size = 0x2000; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) {fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - memcpy(ncchset->sections.logo.buffer,Nintendo_LZ,0x2000); - } - else if(strcasecmp(ncchset->yaml_set->BasicInfo.Logo,"licensed") == 0){ - ncchset->sections.logo.size = 0x2000; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) {fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - memcpy(ncchset->sections.logo.buffer,Nintendo_LicensedBy_LZ,0x2000); - } - else if(strcasecmp(ncchset->yaml_set->BasicInfo.Logo,"distributed") == 0){ - ncchset->sections.logo.size = 0x2000; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) {fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - memcpy(ncchset->sections.logo.buffer,Nintendo_DistributedBy_LZ,0x2000); - } - else if(strcasecmp(ncchset->yaml_set->BasicInfo.Logo,"ique") == 0){ - ncchset->sections.logo.size = 0x2000; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) {fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - memcpy(ncchset->sections.logo.buffer,iQue_with_ISBN_LZ,0x2000); - } - else if(strcasecmp(ncchset->yaml_set->BasicInfo.Logo,"iqueforsystem") == 0){ - ncchset->sections.logo.size = 0x2000; - ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size); - if(!ncchset->sections.logo.buffer) {fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - memcpy(ncchset->sections.logo.buffer,iQue_without_ISBN_LZ,0x2000); - } - else if(strcasecmp(ncchset->yaml_set->BasicInfo.Logo,"none") != 0){ - fprintf(stderr,"[NCCH ERROR] Invalid logo name\n"); - return NCCH_BAD_YAML_SET; - } - } - return 0; -} - -int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr) -{ - /* NCCH Format titleVersion */ - u16_to_u8(hdr->titleVersion,0x2,LE); - - /* Setting ProgramId/TitleId */ - u64 ProgramId = 0; - int result = GetProgramID(&ProgramId,ncchset->yaml_set,false); - if(result) return result; - - u64_to_u8(hdr->program_id,ProgramId,LE); - u64_to_u8(hdr->title_id,ProgramId,LE); - - /* Get Product Code and Maker Code */ - if(ncchset->yaml_set->BasicInfo.ProductCode){ - if(!IsValidProductCode((char*)ncchset->yaml_set->BasicInfo.ProductCode,ncchset->Options.FreeProductCode)){ - fprintf(stderr,"[NCCH ERROR] Invalid Product Code\n"); - return NCCH_BAD_YAML_SET; - } - memcpy(hdr->product_code,ncchset->yaml_set->BasicInfo.ProductCode,strlen((char*)ncchset->yaml_set->BasicInfo.ProductCode)); - } - else memcpy(hdr->product_code,"CTR-P-CTAP",10); - - if(ncchset->yaml_set->BasicInfo.CompanyCode){ - if(strlen((char*)ncchset->yaml_set->BasicInfo.CompanyCode) != 2){ - fprintf(stderr,"[NCCH ERROR] Company code length must be 2\n"); - return NCCH_BAD_YAML_SET; - } - memcpy(hdr->maker_code,ncchset->yaml_set->BasicInfo.CompanyCode,2); - } - else memcpy(hdr->maker_code,"00",2); - - /* Set ContentUnitSize */ - hdr->flags[ContentUnitSize] = 0; - - /* Setting ContentPlatform */ - if(ncchset->yaml_set->TitleInfo.Platform){ - if(strcasecmp(ncchset->yaml_set->TitleInfo.Platform,"ctr") == 0) hdr->flags[ContentPlatform] = 1; - else{ - fprintf(stderr,"[NCCH ERROR] Invalid Platform: %s\n",ncchset->yaml_set->TitleInfo.Platform); - return NCCH_BAD_YAML_SET; - } - } - else - hdr->flags[ContentPlatform] = 1; // CTR - - /* Setting OtherFlag */ - hdr->flags[OtherFlag] = FixedCryptoKey; - if(!ncchset->Options.Encrypt) hdr->flags[OtherFlag] |= NoCrypto; - if(!ncchset->sections.romFs.size) hdr->flags[OtherFlag] |= NoMountRomFs; - - - /* Setting ContentType */ - hdr->flags[ContentType] = 0; - if(ncchset->sections.romFs.size) hdr->flags[ContentType] |= RomFS; - if(ncchset->sections.exeFs.size) hdr->flags[ContentType] |= ExeFS; - if(ncchset->yaml_set->BasicInfo.ContentType){ - if(strcmp(ncchset->yaml_set->BasicInfo.ContentType,"Application") == 0) hdr->flags[ContentType] |= 0; - else if(strcmp(ncchset->yaml_set->BasicInfo.ContentType,"SystemUpdate") == 0) hdr->flags[ContentType] |= SystemUpdate; - else if(strcmp(ncchset->yaml_set->BasicInfo.ContentType,"Manual") == 0) hdr->flags[ContentType] |= Manual; - else if(strcmp(ncchset->yaml_set->BasicInfo.ContentType,"Child") == 0) hdr->flags[ContentType] |= Child; - else if(strcmp(ncchset->yaml_set->BasicInfo.ContentType,"Trial") == 0) hdr->flags[ContentType] |= Trial; - else{ - fprintf(stderr,"[NCCH ERROR] Invalid ContentType '%s'\n",ncchset->yaml_set->BasicInfo.ContentType); - return NCCH_BAD_YAML_SET; - } - } - - return 0; -} - -int SetCommonHeaderSectionData(ncch_settings *ncchset, ncch_hdr *hdr) -{ - /* Set Sizes/Hashes to Hdr */ - - u32 ExHeaderSize,LogoSize,PlainRegionSize,ExeFsSize,ExeFsHashSize,RomFsSize,RomFsHashSize; - - if(ncchset->Options.IsCfa) - { - if(ncchset->sections.exhdr.size) - { - free(ncchset->sections.exhdr.buffer); - } - ncchset->sections.exhdr.size = 0; - if(ncchset->sections.logo.size) - { - free(ncchset->sections.logo.buffer); - } - ncchset->sections.logo.size = 0; - if(ncchset->sections.exeFs.size) - { - free(ncchset->sections.exeFs.buffer); - } - ncchset->sections.exeFs.size = 0; - } - - ExHeaderSize = ncchset->sections.exhdr.size ? ((u32) ncchset->sections.exhdr.size - 0x400) : 0; - LogoSize = ncchset->sections.logo.size ? ((u32) (ncchset->sections.logo.size/ncchset->Options.MediaSize)) : 0; - PlainRegionSize = ncchset->sections.plainRegion.size ? ((u32) (ncchset->sections.plainRegion.size/ncchset->Options.MediaSize)) : 0; - ExeFsSize = ncchset->sections.exeFs.size ? ((u32) (ncchset->sections.exeFs.size/ncchset->Options.MediaSize)) : 0; - ExeFsHashSize = (u32) ExeFsSize? ncchset->Options.MediaSize/ncchset->Options.MediaSize : 0; - RomFsSize = ncchset->sections.romFs.size ? ((u32) (ncchset->sections.romFs.size/ncchset->Options.MediaSize)) : 0; - RomFsHashSize = (u32) RomFsSize? ncchset->Options.MediaSize/ncchset->Options.MediaSize : 0; - - - u32_to_u8(hdr->extended_header_size,ExHeaderSize,LE); - if(ExHeaderSize) ctr_sha(ncchset->sections.exhdr.buffer,ExHeaderSize,hdr->extended_header_sha_256_hash,CTR_SHA_256); - - u32_to_u8(hdr->logo_region_size,LogoSize,LE); - if(LogoSize) ctr_sha(ncchset->sections.logo.buffer,ncchset->sections.logo.size,hdr->logo_sha_256_hash,CTR_SHA_256); - - u32_to_u8(hdr->plain_region_size,PlainRegionSize,LE); - - u32_to_u8(hdr->exefs_size,ExeFsSize,LE); - u32_to_u8(hdr->exefs_hash_size,ExeFsHashSize,LE); - if(ExeFsSize) ctr_sha(ncchset->sections.exeFs.buffer,ncchset->Options.MediaSize,hdr->exefs_sha_256_hash,CTR_SHA_256); - - u32_to_u8(hdr->romfs_size,RomFsSize,LE); - u32_to_u8(hdr->romfs_hash_size,RomFsHashSize,LE); - if(RomFsSize) ctr_sha(ncchset->sections.romFs.buffer,ncchset->Options.MediaSize,hdr->romfs_sha_256_hash,CTR_SHA_256); - - - /* Get Section Offsets */ - u32 size = 1; - if (ExHeaderSize) - size += 4; - - if (LogoSize){ - u32_to_u8(hdr->logo_region_offset,size,LE); - ncchset->sections.logoOffset = size*ncchset->Options.MediaSize; - size += LogoSize; - } - - if(PlainRegionSize){ - u32_to_u8(hdr->plain_region_offset,size,LE); - ncchset->sections.plainRegionOffset = size*ncchset->Options.MediaSize; - size += PlainRegionSize; - } - - if (ExeFsSize){ - u32_to_u8(hdr->exefs_offset,size,LE); - ncchset->sections.exeFsOffset = size*ncchset->Options.MediaSize; - size += ExeFsSize; - } - - if (RomFsSize){ - u32_to_u8(hdr->romfs_offset,size,LE); - ncchset->sections.romFsOffset = size*ncchset->Options.MediaSize; - size += RomFsSize; - } - - u32_to_u8(hdr->content_size,size,LE); - - ncchset->Sections.TotalContentSize = size * ncchset->Options.MediaSize; - - return 0; -} - -bool IsValidProductCode(char *ProductCode, bool FreeProductCode) -{ - 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; - } - - return true; -} - -int BuildCommonHeader(ncch_settings *ncchset) -{ - int result = 0; - - // Initialising Header - ncchset->sections.ncchHdr.size = 0x100 + sizeof(ncch_hdr); - ncchset->sections.ncchHdr.buffer = malloc(ncchset->sections.ncchHdr.size); - if(!ncchset->sections.ncchHdr.buffer) { fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR; } - memset(ncchset->sections.ncchHdr.buffer,0,ncchset->sections.ncchHdr.size); - - // Creating Ptrs - u8 *sig = ncchset->sections.ncchHdr.buffer; - ncch_hdr *hdr = (ncch_hdr*)(ncchset->sections.ncchHdr.buffer+0x100); - - // Setting Data in Hdr - memcpy(hdr->magic,"NCCH",4); - - result = SetCommonHeaderBasicData(ncchset,hdr); - if(result) return result; - - result = SetCommonHeaderSectionData(ncchset,hdr); - if(result) return result; - - - // Signing Hdr - int sig_result = Good; - if(ncchset->Options.IsCfa) sig_result = SignCFA(sig,(u8*)hdr,ncchset->keys); - else sig_result = SignCXI(sig,(u8*)hdr,ncchset->keys); - if(sig_result != Good){ - fprintf(stderr,"[NCCH ERROR] Failed to sign %s header\n",ncchset->Options.IsCfa ? "CFA" : "CXI"); - return sig_result; - } - - return 0; -} - -int EncryptNCCHSections(ncch_settings *ncchset) -{ - if(!ncchset->Options.Encrypt) return 0; - - /* Getting ncch_struct */ - ncch_hdr *hdr = GetNCCH_CommonHDR(NULL,NULL,ncchset->sections.ncchHdr.buffer); - ncch_struct *ncch = malloc(sizeof(ncch_struct)); - if(!ncch) { fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - memset(ncch,0,sizeof(ncch_struct)); - GetCXIStruct(ncch,hdr); - - u8 *ncch_key = GetNCCHKey(hdr,ncchset->keys); - - if(ncchset->sections.exhdr.size) - CryptNCCHSection(ncchset->sections.exhdr.buffer,ncchset->sections.exhdr.size,0,ncch,ncch_key,ncch_ExHeader); - - if(ncchset->sections.exeFs.size) - CryptNCCHSection(ncchset->sections.exeFs.buffer,ncchset->sections.exeFs.size,0,ncch,ncch_key,ncch_exefs); - - if(ncchset->sections.romFs.size) - CryptNCCHSection(ncchset->sections.romFs.buffer,ncchset->sections.romFs.size,0,ncch,ncch_key,ncch_romfs); - - return 0; -} - -int WriteNCCHSectionsToBuffer(ncch_settings *ncchset) -{ - /* Allocating Memory for NCCH, and clearing */ - ncchset->out->size = ncchset->Sections.TotalContentSize; - ncchset->out->buffer = malloc(ncchset->out->size); - if(!ncchset->out->buffer) { fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR;} - memset(ncchset->out->buffer,0,ncchset->out->size); - - /* Copy Header+Sig */ - memcpy(ncchset->out->buffer,ncchset->sections.ncchHdr.buffer,ncchset->sections.ncchHdr.size); - - /* Copy Exheader+AccessDesc */ - if(ncchset->sections.exhdr.size) - memcpy(ncchset->out->buffer+0x200,ncchset->sections.exhdr.buffer,ncchset->sections.exhdr.size); - - /* Copy Logo */ - if(ncchset->sections.logo.size) - memcpy(ncchset->out->buffer+ncchset->sections.logoOffset,ncchset->sections.logo.buffer,ncchset->sections.logo.size); - - /* Copy PlainRegion */ - if(ncchset->sections.plainRegion.size) - memcpy(ncchset->out->buffer+ncchset->sections.plainRegionOffset,ncchset->sections.plainRegion.buffer,ncchset->sections.plainRegion.size); - - /* Copy ExeFs */ - if(ncchset->sections.exeFs.size) - memcpy(ncchset->out->buffer+ncchset->sections.exeFsOffset,ncchset->sections.exeFs.buffer,ncchset->sections.exeFs.size); - - /* Copy RomFs */ - if(ncchset->sections.romFs.size) - memcpy(ncchset->out->buffer+ncchset->sections.romFsOffset,ncchset->sections.romFs.buffer,ncchset->sections.romFs.size); - - return 0; -} - -// NCCH Read Functions - -int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput) -{ - // Setup - u8 Hash[0x20]; - u8 *hdr_sig = ncch; - ncch_hdr* hdr = GetNCCH_CommonHDR(NULL,NULL,ncch); - - ncch_struct *ncch_ctx = malloc(sizeof(ncch_struct)); - if(!ncch_ctx){ fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR; } - memset(ncch_ctx,0x0,sizeof(ncch_struct)); - GetCXIStruct(ncch_ctx,hdr); - - if(IsCfa(hdr)){ - if(CheckCFASignature(hdr_sig,(u8*)hdr,keys) != Good && !keys->rsa.isFalseSign){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CFA Sigcheck Failed\n"); - free(ncch_ctx); - return NCCH_HDR_SIG_BAD; - } - if(!ncch_ctx->romfs_size){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CFA is corrupt\n"); - free(ncch_ctx); - return NO_ROMFS_IN_CFA; - } - u8 *RomFs = malloc(ncch_ctx->romfs_hash_src_size); - if(!RomFs){ - fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); - free(ncch_ctx); - return MEM_ERROR; - } - int ret = GetNCCHSection(RomFs,ncch_ctx->romfs_hash_src_size,0,ncch,ncch_ctx,keys,ncch_romfs); - if(ret != 0 && ret != UNABLE_TO_LOAD_NCCH_KEY){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CFA is corrupt\n"); - free(ncch_ctx); - free(RomFs); - return CXI_CORRUPT; - } - else if(ret == UNABLE_TO_LOAD_NCCH_KEY){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key.\n"); - free(ncch_ctx); - free(RomFs); - return UNABLE_TO_LOAD_NCCH_KEY; - } - - ctr_sha(RomFs,ncch_ctx->romfs_hash_src_size,Hash,CTR_SHA_256); - free(RomFs); - if(memcmp(Hash,hdr->romfs_sha_256_hash,0x20) != 0){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] RomFs Hashcheck Failed\n"); - free(ncch_ctx); - return ExeFs_Hashfail; - } - } - else{ // IsCxi - // Checking for necessary sections - if(!ncch_ctx->exheader_size){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); - free(ncch_ctx); - return NO_EXHEADER_IN_CXI; - } - if(!ncch_ctx->exefs_size){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); - free(ncch_ctx); - return NO_EXEFS_IN_CXI; - } - // Get ExHeader - ExtendedHeader_Struct *ExHeader = malloc(ncch_ctx->exheader_size); - if(!ExHeader){ - fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); - free(ncch_ctx); - return MEM_ERROR; - } - int ret = GetNCCHSection((u8*)ExHeader,ncch_ctx->exheader_size,0,ncch,ncch_ctx,keys,ncch_ExHeader); - if(ret != 0 && ret != UNABLE_TO_LOAD_NCCH_KEY){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); - free(ncch_ctx); - free(ExHeader); - return CXI_CORRUPT; - } - else if(ret == UNABLE_TO_LOAD_NCCH_KEY){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key.\n"); - free(ncch_ctx); - free(ExHeader); - return UNABLE_TO_LOAD_NCCH_KEY; - } - - // Checking Exheader Hash to see if decryption was sucessful - ctr_sha(ExHeader,0x400,Hash,CTR_SHA_256); - if(memcmp(Hash,hdr->extended_header_sha_256_hash,0x20) != 0){ - //memdump(stdout,"Expected Hash: ",hdr->extended_header_sha_256_hash,0x20); - //memdump(stdout,"Actual Hash: ",Hash,0x20); - //memdump(stdout,"Exheader: ",(u8*)ExHeader,0x400); - if(!SuppressOutput) { - fprintf(stderr,"[NCCH ERROR] ExHeader Hashcheck Failed\n"); - fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n"); - } - free(ncch_ctx); - free(ExHeader); - return ExHeader_Hashfail; - } - - // Checking RSA Sigs - u8 *hdr_pubk = GetNcchHdrPubKey_frm_exhdr(ExHeader); - - if(CheckaccessDescSignature(ExHeader,keys) != 0 && !keys->rsa.isFalseSign){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] AccessDesc Sigcheck Failed\n"); - free(ncch_ctx); - free(ExHeader); - return ACCESSDESC_SIG_BAD; - } - if(CheckCXISignature(hdr_sig,(u8*)hdr,hdr_pubk) != 0 /* && !keys->rsa.isFalseSign*/){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI Header Sigcheck Failed\n"); - free(ncch_ctx); - free(ExHeader); - return NCCH_HDR_SIG_BAD; - } - free(ExHeader); - - // It is assumed by this point, everything is fine - - /* Checking ExeFs Hash */ - u8 *ExeFs = malloc(ncch_ctx->exefs_hash_src_size); - if(!ExeFs){ - fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); - free(ncch_ctx); - return MEM_ERROR; - } - GetNCCHSection(ExeFs,ncch_ctx->exefs_hash_src_size,0,ncch,ncch_ctx,keys,ncch_exefs); - ctr_sha(ExeFs,ncch_ctx->exefs_hash_src_size,Hash,CTR_SHA_256); - free(ExeFs); - if(memcmp(Hash,hdr->exefs_sha_256_hash,0x20) != 0){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] ExeFs Hashcheck Failed\n"); - free(ncch_ctx); - return ExeFs_Hashfail; - } - - /* Checking RomFs hash, if present */ - if(ncch_ctx->romfs_size){ - u8 *RomFs = malloc(ncch_ctx->romfs_hash_src_size); - if(!RomFs){ - fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); - free(ncch_ctx); - return MEM_ERROR; - } - GetNCCHSection(RomFs,ncch_ctx->romfs_hash_src_size,0,ncch,ncch_ctx,keys,ncch_romfs); - ctr_sha(RomFs,ncch_ctx->romfs_hash_src_size,Hash,CTR_SHA_256); - free(RomFs); - if(memcmp(Hash,hdr->romfs_sha_256_hash,0x20) != 0){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] RomFs Hashcheck Failed\n"); - free(ncch_ctx); - return ExeFs_Hashfail; - } - } - - /* Checking the Logo Hash, if present */ - if(ncch_ctx->logo_size){ - u8 *logo = (ncch+ncch_ctx->logo_offset); - ctr_sha(logo,ncch_ctx->logo_size,Hash,CTR_SHA_256); - if(memcmp(Hash,hdr->logo_sha_256_hash,0x20) != 0){ - if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] Logo Hashcheck Failed\n"); - free(ncch_ctx); - return Logo_Hashfail; - } - } - } - - free(ncch_ctx); - return 0; -} - - -u8* RetargetNCCH(FILE *fp, u64 size, u8 *TitleId, u8 *ProgramId, keys_struct *keys) -{ - u8 *ncch = malloc(size); - if(!ncch){ - fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); - return NULL; - } - ReadFile_64(ncch,size,0,fp); // Importing - - if(!IsNCCH(NULL,ncch)){ - free(ncch); - return NULL; - } - - ncch_hdr *hdr = NULL; - hdr = GetNCCH_CommonHDR(NULL,NULL,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 NULL; - } - - if((memcmp(TitleId,hdr->title_id,8) == 0) && (memcmp(ProgramId,hdr->program_id,8) == 0)) - return ncch;// if no modification is required don't do anything - - if(memcmp(TitleId,hdr->title_id,8) == 0){ // If TitleID Same, no crypto required, just resign. - memcpy(hdr->program_id,ProgramId,8); - SignCFA(ncch,(u8*)hdr,keys); - return ncch; - } - - ncch_key_type keytype = GetNCCHKeyType(hdr); - u8 *key = NULL; - - if(keytype == KeyIsUnFixed || keytype == KeyIsUnFixed2){ - fprintf(stderr,"[NCCH ERROR] Unknown aes key\n"); - free(ncch); - return NULL; - } - - - ncch_struct ncch_struct; - if(keytype != NoKey){ //Decrypting if necessary - GetCXIStruct(&ncch_struct,hdr); - u8 *romfs = (ncch+ncch_struct.romfs_offset); - key = GetNCCHKey(hdr,keys); - if(key == NULL){ - fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n"); - free(ncch); - return NULL; - } - CryptNCCHSection(romfs,ncch_struct.romfs_size,0,&ncch_struct,key,ncch_romfs); - } - - - memcpy(hdr->title_id,TitleId,8); - memcpy(hdr->program_id,ProgramId,8); - - //Checking New Fixed Key Type - keytype = GetNCCHKeyType(hdr); - - if(keytype != NoKey){ // Re-encrypting if necessary - GetCXIStruct(&ncch_struct,hdr); - u8 *romfs = (ncch+ncch_struct.romfs_offset); - key = GetNCCHKey(hdr,keys); - if(key == NULL){ - fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n"); - free(ncch); - return NULL; - } - CryptNCCHSection(romfs,ncch_struct.romfs_size,0,&ncch_struct,key,ncch_romfs); - } - - SignCFA(ncch,(u8*)hdr,keys); - - return ncch; -} - - -ncch_hdr* GetNCCH_CommonHDR(void *out, FILE *fp, u8 *buf) -{ - 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); - } -} - - -bool IsNCCH(FILE *fp, u8 *buf) -{ - if(!fp && !buf) return false; - ncch_hdr *ncchHDR = NULL; - bool result; - if(fp) { - ncchHDR = malloc(sizeof(ncch_hdr)); - GetNCCH_CommonHDR(ncchHDR,fp,NULL); - result = (memcmp(ncchHDR->magic,"NCCH",4) == 0); - free(ncchHDR); - } - else { - ncchHDR = GetNCCH_CommonHDR(ncchHDR,NULL,buf); - result = (memcmp(ncchHDR->magic,"NCCH",4) == 0); - } - return result; -} - -bool IsCfa(ncch_hdr* hdr) -{ - return (((hdr->flags[ContentType] & RomFS) == RomFS) && ((hdr->flags[ContentType] & ExeFS) != ExeFS)); -} - -u32 GetNCCH_MediaUnitSize(ncch_hdr* hdr) -{ - u16 titleVersion = u8_to_u16(hdr->titleVersion,LE); - u32 ret = 0; - if (titleVersion == 1) - ret = 1; - else if (titleVersion == 2 || titleVersion == 0) - ret = 1 << (hdr->flags[ContentUnitSize] + 9); - return ret; - //return 0x200*pow(2,hdr->flags[ContentUnitSize]); -} - -u32 GetNCCH_MediaSize(ncch_hdr* hdr) -{ - return u8_to_u32(hdr->content_size,LE); -} - -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->program_id[4] & 0x10) == 0x10) return KeyIsSystemFixed; - else return KeyIsNormalFixed; - } - - // Secure Key Options - if(hdr->flags[SecureCrypto2] == 1) return KeyIsUnFixed2; - return KeyIsUnFixed; -} - -u8* GetNCCHKey(ncch_hdr* hdr, keys_struct *keys) -{ - ncch_key_type keytype = GetNCCHKeyType(hdr); - switch(keytype){ - case NoKey: return NULL; - case KeyIsNormalFixed: return keys->aes.normalKey; - case KeyIsSystemFixed: - if(!keys->aes.systemFixedKey) fprintf(stderr,"[NCCH WARNING] Unable to load SystemFixed Key\n"); - return keys->aes.systemFixedKey; - case KeyIsUnFixed: - if(!keys->aes.unFixedKey) fprintf(stderr,"[NCCH WARNING] Unable to load UnFixed Key\n"); - return keys->aes.unFixedKey; - case KeyIsUnFixed2: - fprintf(stderr,"[NCCH WARNING] Crypto method (Secure2) not supported yet\n"); - return NULL; - } - return NULL; -} - -int GetNCCHSection(u8 *dest, u64 dest_max_size, u64 src_pos, u8 *ncch, ncch_struct *ncch_ctx, keys_struct *keys, ncch_section section) -{ - if(!ncch) return MEM_ERROR; - u8 *key = NULL; - ncch_hdr* hdr = GetNCCH_CommonHDR(NULL,NULL,ncch); - ncch_key_type keytype = GetNCCHKeyType(hdr); - - if(keytype != NoKey && (section == ncch_ExHeader || section == ncch_exefs || section == ncch_romfs)){ - key = GetNCCHKey(hdr,keys); - if(key == NULL){ - //fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key.\n"); - return UNABLE_TO_LOAD_NCCH_KEY; - } - } - //printf("detecting section type\n"); - u64 offset = 0; - u64 size = 0; - switch(section){ - case ncch_ExHeader: - offset = ncch_ctx->exheader_offset; - size = ncch_ctx->exheader_size; - break; - case ncch_Logo: - offset = ncch_ctx->logo_offset; - size = ncch_ctx->logo_size; - break; - case ncch_PlainRegion: - offset = ncch_ctx->plain_region_offset; - size = ncch_ctx->plain_region_size; - break; - case ncch_exefs: - offset = ncch_ctx->exefs_offset; - size = ncch_ctx->exefs_size; - break; - case ncch_romfs: - offset = ncch_ctx->romfs_offset; - size = ncch_ctx->romfs_size; - break; - } - if(!offset || !size) return NCCH_SECTION_NOT_EXIST; - - if(src_pos > size) return DATA_POS_DNE; - - size = min_u64(size-src_pos,dest_max_size); - - //printf("Copying data\n"); - u8 *section_pos = (ncch + offset + src_pos); - memcpy(dest,section_pos,size); - - //printf("decrypting if needed\n"); - if(keytype != NoKey && (section == ncch_ExHeader || section == ncch_exefs || section == ncch_romfs)){ // Decrypt - //memdump(stdout,"Key: ",key,16); - CryptNCCHSection(dest,size,src_pos,ncch_ctx,key,section); - //printf("no cigar\n"); - } - - return 0; -} - -int GetCXIStruct(ncch_struct *ctx, ncch_hdr *header) -{ - memcpy(ctx->titleID,header->title_id,8); - memcpy(ctx->programID,header->program_id,8); - - - u32 media_unit = GetNCCH_MediaUnitSize(header); - - ctx->titleVersion = u8_to_u16(header->titleVersion,LE); - if(!IsCfa(header)){ - ctx->exheader_offset = 0x200; - ctx->exheader_size = u8_to_u32(header->extended_header_size,LE) + 0x400; - ctx->logo_offset = (u64)(u8_to_u32(header->logo_region_offset,LE)*media_unit); - ctx->logo_size = (u64)(u8_to_u32(header->logo_region_size,LE)*media_unit); - ctx->plain_region_offset = (u64)(u8_to_u32(header->plain_region_offset,LE)*media_unit); - ctx->plain_region_size = (u64)(u8_to_u32(header->plain_region_size,LE)*media_unit); - ctx->exefs_offset = (u64)(u8_to_u32(header->exefs_offset,LE)*media_unit); - ctx->exefs_size = (u64)(u8_to_u32(header->exefs_size,LE)*media_unit); - ctx->exefs_hash_src_size = (u64)(u8_to_u32(header->exefs_hash_size,LE)*media_unit); - } - ctx->romfs_offset = (u64) (u8_to_u32(header->romfs_offset,LE)*media_unit); - ctx->romfs_size = (u64) (u8_to_u32(header->romfs_size,LE)*media_unit); - ctx->romfs_hash_src_size = (u64)(u8_to_u32(header->romfs_hash_size,LE)*media_unit); - return 0; -} - -void CryptNCCHSection(u8 *buffer, u64 size, u64 src_pos, ncch_struct *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)); - ctr_init_counter(&aes_ctx, key, counter); - if(src_pos > 0){ - u32 carry = 0; - carry = align_value(src_pos,0x10); - carry = 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) -{ - u8 *titleID = ctx->titleID; - u32 i; - u32 x = 0; - - memset(counter, 0, 16); - - if (ctx->titleVersion == 2 || ctx->titleVersion == 0) - { - for(i=0; i<8; i++) - counter[i] = titleID[7-i]; - counter[8] = type; - } - else if (ctx->titleVersion == 1) - { - switch(type){ - case ncch_ExHeader : x = ctx->exheader_offset; break; - case ncch_exefs : x = ctx->exefs_offset; break; - case ncch_romfs : x = ctx->romfs_offset; break; - } - for(i=0; i<8; i++) - counter[i] = titleID[i]; - for(i=0; i<4; i++) - counter[12+i] = x>>((3-i)*8); - } - - //memdump(stdout,"CTR: ",counter,16); -} \ No newline at end of file diff --git a/ncsd.c b/ncsd.c index 479e44d..3132670 100644 --- a/ncsd.c +++ b/ncsd.c @@ -175,6 +175,7 @@ int BuildCardInfoHeader(cci_settings *cciset, user_settings *usrset) memcpy((u8*)ctx.cardinfo.initial_data,cciset->initialData,0x30); memcpy((u8*)ctx.cardinfo.ncch_0_header,cciset->ncchHdr,0x100); memcpy((u8*)ctx.devcardinfo.TitleKey,cciset->titleKey,0x10); + return 0; } @@ -183,7 +184,15 @@ int WriteCCI_HDR_ToFile(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); - WriteBuffer((u8*)&ctx.devcardinfo,sizeof(devcardinfo_hdr),0x1200,cciset->out); + if(memcmp(ctx.devcardinfo.TitleKey,ctx.keys->aes.normalKey,16) == 0){ + // Creating Buffer of Dummy Bytes + u64 len = cciset->contentOffset[0] - 0x1200; + u8 *dummy_bytes = malloc(len); + memset(dummy_bytes,0xff,len); + WriteBuffer(dummy_bytes,len,0x1200,cciset->out); + } + else + WriteBuffer((u8*)&ctx.devcardinfo,sizeof(devcardinfo_hdr),0x1200,cciset->out); return 0; } @@ -213,7 +222,7 @@ int WriteCCI_Content_ToFile(cci_settings *cciset,user_settings *usrset) int WriteCCI_DummyBytes(cci_settings *cciset) { // Seeking end of CCI Data - fseek_64(cciset->out,cciset->cciTotalSize,SEEK_SET); + fseek_64(cciset->out,cciset->cciTotalSize); // Determining Size of Dummy Bytes u64 len = cciset->mediaSize - cciset->cciTotalSize; @@ -223,9 +232,8 @@ int WriteCCI_DummyBytes(cci_settings *cciset) memset(dummy_bytes,0xff,cciset->mediaUnit); // Writing Dummy Bytes to file - for(u64 i = 0; i < len; i += cciset->mediaUnit){ - fwrite(&dummy_bytes,cciset->mediaUnit,1,cciset->out); - } + for(u64 i = 0; i < len; i += cciset->mediaUnit) + fwrite(dummy_bytes,cciset->mediaUnit,1,cciset->out); return 0; } @@ -324,7 +332,9 @@ int GetDataFromContent0(cci_settings *cciset, user_settings *usrset) //memcpy(cciset->titleKey,(Hash+0x30),0x10); // Might Remove } - + /* FW6x SaveCrypto */ + cciset->flags[FW6x_SaveCryptoFlag] = usrset->cci.use6xSavedataCrypto; + cciset->flags[MediaUnitSize] = hdr->flags[ContentUnitSize]; cciset->mediaUnit = GetNCCH_MediaUnitSize(hdr); @@ -400,9 +410,6 @@ int GetNCSDFlags(cci_settings *cciset, rsf_settings *yaml) cciset->flags[FW6x_BackupWriteWaitTime] = (u8)WaitTime; } - /* FW6x SaveCrypto */ - cciset->flags[FW6x_SaveCryptoFlag] = 1; - /* MediaType */ if(!yaml->CardInfo.MediaType) cciset->flags[MediaTypeIndex] = CARD1; else{ @@ -467,12 +474,12 @@ int GetWriteableAddress(cci_settings *cciset, user_settings *usrset) if(cciset->writableAddress == -1){ // If not set manually or is max size if ((cciset->mediaSize / 2) < cciset->savedataSize){ // If SaveData size is greater than half the MediaSize u64 SavedataSize = cciset->savedataSize / KB; - fprintf(stderr,"[CCI ERROR] Too large SavedataSize %luK\n",SavedataSize); + fprintf(stderr,"[CCI ERROR] Too large SavedataSize %llK\n",SavedataSize); return SAVE_DATA_TOO_LARGE; } if (cciset->savedataSize > (u64)(2047*MB)){ // Limit set by Nintendo u64 SavedataSize = cciset->savedataSize / KB; - fprintf(stderr,"[CCI ERROR] Too large SavedataSize %luK\n",SavedataSize); + fprintf(stderr,"[CCI ERROR] Too large SavedataSize %llK\n",SavedataSize); return SAVE_DATA_TOO_LARGE; } u64 UnusedSize = GetUnusedSize(cciset->mediaSize,cciset->flags[MediaTypeIndex]); // Need to look into this diff --git a/ncsd.h b/ncsd.h index 9f089f5..9f03733 100644 --- a/ncsd.h +++ b/ncsd.h @@ -1,6 +1,4 @@ -#ifndef _NCSD_H_ -#define _NCSD_H_ - +#pragma once // Enums typedef enum @@ -162,11 +160,7 @@ static const u8 stock_title_key[0x10] = 0x97, 0x11, 0x92, 0xBA }; -#endif - // Public Prototypes - - // Build Functions int build_CCI(user_settings *usrset); diff --git a/ppki.h b/ppki.h index de1ea8f..3ead64c 100644 --- a/ppki.h +++ b/ppki.h @@ -1,5 +1,4 @@ -#ifndef _PPKI_H_ -#define _PPKI_H_ +#pragma once #ifdef PKI_LEGACY #include "ppki_legacy.h" @@ -752,6 +751,4 @@ static const unsigned char cpB_ppki_cert[0x300] = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/ppki_legacy.h b/ppki_legacy.h index e0eea7e..ddd9b7b 100644 --- a/ppki_legacy.h +++ b/ppki_legacy.h @@ -1,5 +1,4 @@ -#ifndef _PPKI_LEGACY_H_ -#define _PPKI_LEGACY_H_ +#pragma once // AES Keys static const unsigned char rvl_common_etd_key_ppki[2][16] = @@ -15,6 +14,4 @@ static const unsigned char twl_common_etd_key_ppki[1][16] = // RSA Keys -// Certificates - -#endif \ No newline at end of file +// Certificates \ No newline at end of file diff --git a/romfs.c b/romfs.c index 4081a05..c11cbbe 100644 --- a/romfs.c +++ b/romfs.c @@ -1,39 +1,50 @@ #include "lib.h" #include "ncch.h" #include "romfs.h" +#include "romfs_binary.h" +#include "romfs_import.h" // RomFs Build Functions - -int ImportRomFsBinaryFromFile(ncch_settings *ncchset); - -int BuildRomFs(ncch_settings *ncchset) +int SetupRomFs(ncch_settings *ncchset, romfs_buildctx *ctx) { - int result = 0; + ctx->output = NULL; + ctx->romfsSize = 0; // If Not Using RomFS Return - if(!ncchset->options.UseRomFS) return result; + if(!ncchset->options.UseRomFS) + return 0; - if(ncchset->componentFilePtrs.romfs){ // The user has specified a pre-built RomFs Binary - result = ImportRomFsBinaryFromFile(ncchset); - return result; - } + int result = 0; + + if(ncchset->componentFilePtrs.romfs)// The user has specified a pre-built RomFs Binary + result = PrepareImportRomFsBinaryFromFile(ncchset,ctx); - // Need to implement RomFs generation + else // Otherwise build ROMFS + result = PrepareBuildRomFsBinary(ncchset,ctx); return result; } -int ImportRomFsBinaryFromFile(ncch_settings *ncchset) +int BuildRomFs(romfs_buildctx *ctx) { - ncchset->sections.romFs.size = ncchset->componentFilePtrs.romfsSize; - ncchset->sections.romFs.buffer = malloc(ncchset->sections.romFs.size); - if(!ncchset->sections.romFs.buffer) {fprintf(stderr,"[ROMFS ERROR] MEM ERROR\n"); return MEM_ERROR;} - ReadFile_64(ncchset->sections.romFs.buffer,ncchset->sections.romFs.size,0,ncchset->componentFilePtrs.romfs); - if(memcmp(ncchset->sections.romFs.buffer,"IVFC",4) != 0){ - fprintf(stderr,"[ROMFS ERROR] Invalid RomFS Binary.\n"); - return INVALID_ROMFS_FILE; - } - return 0; + // If Not Using RomFS Return + if(!ctx->romfsSize) + return 0; + + int result = 0; + + if(ctx->ImportRomfsBinary) // The user has specified a pre-built RomFs Binary + result = ImportRomFsBinaryFromFile(ctx); + else // Otherwise build ROMFS + result = BuildRomFsBinary(ctx); + + FreeRomFsCtx(ctx); + + return result; } -// RomFs Read Functions \ No newline at end of file +void FreeRomFsCtx(romfs_buildctx *ctx) +{ + if(ctx->romfsBinary) + fclose(ctx->romfsBinary); +} \ No newline at end of file diff --git a/romfs.h b/romfs.h index 34dcc1a..ec9ff3c 100644 --- a/romfs.h +++ b/romfs.h @@ -1,15 +1,77 @@ -#ifndef _ROMFS_H_ -#define _ROMFS_H_ +#pragma once typedef enum { INVALID_ROMFS_FILE = -10, } romfs_errors; -#endif -// RomFs Build Functions +// IVFC Structs +typedef struct +{ + u8 logicalOffset[8]; + u8 hashDataSize[8]; + u8 blockSize[4]; + u8 reserved[4]; +} ivfc_levelheader; -int BuildRomFs(ncch_settings *ncchset); +typedef struct +{ + u8 magic[4]; + u8 id[4]; + u8 masterHashSize[4]; + ivfc_levelheader level1; + ivfc_levelheader level2; + ivfc_levelheader level3; + u8 reserved[4]; + u8 optionalSize[4]; +} ivfc_hdr; + +// ROMFS FS Structs +typedef struct +{ + u8 offset[4]; + u8 size[4]; +} romfs_sectionheader; + +typedef struct +{ + u8 headersize[4]; + romfs_sectionheader section[4]; + u8 dataoffset[4]; +} romfs_infoheader; + + +typedef struct +{ + u8 parentoffset[4]; + u8 siblingoffset[4]; + u8 childoffset[4]; + u8 fileoffset[4]; + u8 weirdoffset[4]; // this one is weird. it always points to a dir entry, but seems unrelated to the romfs structure. + u8 namesize[4]; + //u8 name[ROMFS_MAXNAMESIZE]; +} romfs_direntry; //sizeof(romfs_direntry) = 0x18 + +typedef struct +{ + u8 parentdiroffset[4]; + u8 siblingoffset[4]; + u8 dataoffset[8]; + u8 datasize[8]; + u8 weirdoffset[4]; // this one is also weird. it always points to a file entry, but seems unrelated to the romfs structure. + u8 namesize[4]; + //u8 name[ROMFS_MAXNAMESIZE]; +} romfs_fileentry; //sizeof(romfs_fileentry) = 0x20 + + +typedef struct +{ + u8 *output; + u64 romfsSize; + + + bool ImportRomfsBinary; + FILE *romfsBinary; +} romfs_buildctx; -// RomFs Read Functions \ No newline at end of file diff --git a/romfs_binary.c b/romfs_binary.c new file mode 100644 index 0000000..e50eee5 --- /dev/null +++ b/romfs_binary.c @@ -0,0 +1,13 @@ +#include "lib.h" +#include "ncch.h" +#include "romfs.h" + +int PrepareBuildRomFsBinary(ncch_settings *ncchset, romfs_buildctx *ctx) +{ + return 0; +} + +int BuildRomFsBinary(romfs_buildctx *ctx) +{ + return 0; +} \ No newline at end of file diff --git a/romfs_binary.h b/romfs_binary.h new file mode 100644 index 0000000..d06f5d3 --- /dev/null +++ b/romfs_binary.h @@ -0,0 +1,4 @@ +#pragma once + +int PrepareBuildRomFsBinary(ncch_settings *ncchset, romfs_buildctx *ctx); +int BuildRomFsBinary(romfs_buildctx *ctx); \ No newline at end of file diff --git a/romfs_import.c b/romfs_import.c new file mode 100644 index 0000000..a446212 --- /dev/null +++ b/romfs_import.c @@ -0,0 +1,22 @@ +#include "lib.h" +#include "ncch.h" +#include "romfs.h" + +int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx) +{ + ctx->ImportRomfsBinary = true; + ctx->romfsSize = ncchset->componentFilePtrs.romfsSize; + ctx->romfsBinary = ncchset->componentFilePtrs.romfs; + + return 0; +} + +int ImportRomFsBinaryFromFile(romfs_buildctx *ctx) +{ + ReadFile_64(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; + } + return 0; +} \ No newline at end of file diff --git a/romfs_import.h b/romfs_import.h new file mode 100644 index 0000000..0716e9a --- /dev/null +++ b/romfs_import.h @@ -0,0 +1,4 @@ +#pragma once + +int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx); +int ImportRomFsBinaryFromFile(romfs_buildctx *ctx); \ No newline at end of file diff --git a/romfs_spec.h b/romfs_spec.h new file mode 100644 index 0000000..77e8145 --- /dev/null +++ b/romfs_spec.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/srl.h b/srl.h index 0037441..209dba0 100644 --- a/srl.h +++ b/srl.h @@ -1,96 +1,93 @@ -#ifndef _SRL_H_ -#define _SRL_H_ +#pragma once typedef struct { - u8 game_title[0xC]; - u8 game_code[4]; - u8 maker_code[2]; - u8 unit_code; - u8 encryption_seed_select; - u8 device_capacity; - u8 reserved_0[9]; - u8 rom_version; - u8 internal_flag; - u8 arm9_rom_offset[4]; - u8 arm9_entry_address[4]; - u8 arm9_ram_address[4]; - u8 arm9_size[4]; - u8 arm7_rom_offset[4]; - u8 arm7_entry_address[4]; - u8 arm7_ram_address[4]; - u8 arm7_size[4]; - u8 fnt_offset[4]; - u8 fnt_size[4]; - u8 fat_offset[4]; - u8 fat_size[4]; - u8 arm9_overlay_offset[4]; - u8 arm9_overlay_size[4]; - u8 arm7_overlay_offset[4]; - u8 arm7_overlay_size[4]; - u8 normal_card_control_reg_settings[4]; - u8 secure_card_control_reg_settings[4]; - u8 icon_banner_offset[4]; - u8 secure_area_crc[2]; + u8 gameTitle[0xC]; + u8 gameCode[4]; + u8 makerCode[2]; + u8 unitCode; + u8 encryptionSeedSelect; + u8 deviceCapacity; + u8 reserved0[9]; + u8 romVersion; + u8 internalFlag; + u8 arm9RomOffset[4]; + u8 arm9EntryAddress[4]; + u8 arm9RamAddress[4]; + u8 arm9Size[4]; + u8 arm7RomOffset[4]; + u8 arm7EntryAddress[4]; + u8 arm7RamAddress[4]; + u8 arm7Size[4]; + u8 fntOffset[4]; + u8 fntSize[4]; + u8 fatOffset[4]; + u8 fatSize[4]; + u8 arm9OverlayOffset[4]; + u8 arm9OverlaySize[4]; + u8 arm7OverlayOffset[4]; + u8 arm7OverlaySize[4]; + u8 normalCardControlRegSettings[4]; + u8 secureCardControlRegSettings[4]; + u8 icon_bannerOffset[4]; + u8 secureAreaCrc[2]; u8 secure_transfer_timeout[2]; - u8 arm9_autoload[4]; - u8 arm7_autoload[4]; - u8 secure_disable[8]; - u8 ntr_rom_size[4]; - u8 header_size[4]; - u8 reserved_1[0x38]; - u8 nintendo_logo[0x9C]; - u8 nintendo_logo_crc[2]; - u8 header_crc[2]; - u8 debug_reserved[0x20]; + u8 arm9Autoload[4]; + u8 arm7Autoload[4]; + u8 secureDisable[8]; + u8 ntrRomSize[4]; + u8 headerSize[4]; + u8 reserved1[0x38]; + u8 nintendoLogo[0x9C]; + u8 nintendoLogoCrc[2]; + u8 headerCrc[2]; + u8 debugReserved[0x20]; //TWL Only Data - u8 config_settings[0x34]; - u8 access_control[4]; - u8 arm7_scfg_ext_mask[4]; + u8 configSettings[0x34]; + u8 accessControl[4]; + u8 arm7ScfgExtMask[4]; u8 reserved_flags[4]; - u8 arm9i_rom_offset[4]; - u8 reserved_2[4]; - u8 arm9i_load_address[4]; - u8 arm9i_size[4]; - u8 arm7i_rom_offset[4]; - u8 struct_param_base_address[4]; - u8 arm7i_load_address[4]; - u8 arm7i_size[4]; - u8 digest_ntr_region_offset[4]; - u8 digest_ntr_region_size[4]; - u8 digest_twl_region_offset[4]; - u8 digest_twl_region_size[4]; - u8 digest_sector_hashtable_offset[4]; - u8 digest_sector_hashtable_size[4]; - u8 digest_block_hashtable_offset[4]; - u8 digest_block_hashtable_size[4]; - u8 digest_sector_size[4]; - u8 digest_block_sectorcount[4]; - u8 reserved_3[8]; - u8 twl_rom_size[8]; + u8 arm9iRomOffset[4]; + u8 reserved2[4]; + u8 arm9iLoadAddress[4]; + u8 arm9iSize[4]; + u8 arm7iRomOffset[4]; + u8 struct_param_baseAddress[4]; + u8 arm7iLoadAddress[4]; + u8 arm7iSize[4]; + u8 digest_ntrRegionOffset[4]; + u8 digest_ntrRegionSize[4]; + u8 digest_twlRegionOffset[4]; + u8 digest_twlRegionSize[4]; + u8 digestSectorHashtableOffset[4]; + u8 digestSectorHashtableSize[4]; + u8 digest_blockHashtableOffset[4]; + u8 digest_blockHashtableSize[4]; + u8 digestSectorSize[4]; + u8 digest_blockSectorcount[4]; + u8 reserved3[8]; + u8 twlRomSize[8]; u8 unknown[8]; - u8 modcrypt_area_1_offset[4]; - u8 modcrypt_area_1_size[4]; - u8 modcrypt_area_2_offset[4]; - u8 modcrypt_area_2_size[4]; + u8 modcryptArea1Offset[4]; + u8 modcryptArea1Size[4]; + u8 modcryptArea2Offset[4]; + u8 modcryptArea2Size[4]; u8 title_id[8]; - u8 pub_save_data_size[4]; - u8 priv_save_data_size[4]; - u8 reserved_4[0xC0]; + u8 pubSaveDataSize[4]; + u8 privSaveDataSize[4]; + u8 reserved4[0xC0]; // TWL and Signed NTR - u8 arm9_with_sec_area_sha1_hmac[0x14]; - u8 arm7_sha1_hmac[0x14]; - u8 digest_master_sha1_hmac[0x14]; - u8 banner_sha1_hmac[0x14]; - u8 arm9i_sha1_hmac[0x14]; - u8 arm7i_sha1_hmac[0x14]; - u8 reserved_5[0x28]; - u8 arm9_sha1_hmac[0x14]; - u8 reserved_6[0xA4C]; - u8 reserved_7[0x180]; + u8 arm9WithSecAreaSha1Hmac[0x14]; + u8 arm7Sha1Hmac[0x14]; + u8 digestMasterSha1Hmac[0x14]; + u8 bannerSha1Hmac[0x14]; + u8 arm9iSha1Hmac[0x14]; + u8 arm7iSha1Hmac[0x14]; + u8 reserved5[0x28]; + u8 arm9Sha1Hmac[0x14]; + u8 reserved6[0xA4C]; + u8 reserved7[0x180]; u8 signature[0x80]; -} SRL_Header; - -#endif \ No newline at end of file +} srl_hdr; \ No newline at end of file diff --git a/tik.c b/tik.c index 44f71f6..c97112d 100644 --- a/tik.c +++ b/tik.c @@ -3,7 +3,7 @@ #include "tik.h" // Private Prototypes -int SetupTicketBuffer(COMPONENT_STRUCT *tik); +int SetupTicketBuffer(buffer_struct *tik); int SetupTicketHeader(tik_hdr *hdr, cia_settings *ciaset); int SignTicketHeader(tik_hdr *hdr, tik_signature *sig, keys_struct *keys); void SetLimits(tik_hdr *hdr, cia_settings *ciaset); @@ -26,7 +26,7 @@ int BuildTicket(cia_settings *ciaset) return 0; } -int SetupTicketBuffer(COMPONENT_STRUCT *tik) +int SetupTicketBuffer(buffer_struct *tik) { tik->size = sizeof(tik_signature) + sizeof(tik_hdr); tik->buffer = malloc(tik->size); diff --git a/tik.h b/tik.h index d6c04b2..d6d6b1e 100644 --- a/tik.h +++ b/tik.h @@ -1,5 +1,4 @@ -#ifndef _TIK_H_ -#define _TIK_H_ +#pragma once static const unsigned char default_contentIndex[0x30] = { @@ -64,8 +63,6 @@ typedef struct u8 contentIndex[0xAC]; } tik_hdr; -#endif - // 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/titleid.h b/titleid.h index c0a1228..4a247fa 100644 --- a/titleid.h +++ b/titleid.h @@ -1,5 +1,4 @@ -#ifndef _TITLEID_H_ -#define _TITLEID_H_ +#pragma once typedef enum { @@ -84,8 +83,6 @@ typedef enum } ProgramIdCategory; -#endif - u64 ConvertTwlIdToCtrId(u64 pgid); int GetProgramID(u64 *dest, rsf_settings *yaml, bool IsForExheader); diff --git a/tmd.c b/tmd.c index 3d8a8c8..5787032 100644 --- a/tmd.c +++ b/tmd.c @@ -3,7 +3,7 @@ #include "tmd.h" // Private Prototypes -int SetupTMDBuffer(COMPONENT_STRUCT *tik); +int SetupTMDBuffer(buffer_struct *tik); int SetupTMDHeader(tmd_hdr *hdr, tmd_content_info_record *info_record, cia_settings *ciaset); int SignTMDHeader(tmd_hdr *hdr, tmd_signature *sig, keys_struct *keys); int SetupTMDInfoRecord(tmd_content_info_record *info_record, u8 *content_record, u16 ContentCount); @@ -17,6 +17,7 @@ u32 PredictTMDSize(u16 ContentCount) int BuildTMD(cia_settings *ciaset) { int result = 0; + ciaset->ciaSections.tmd.size = PredictTMDSize(ciaset->content.contentCount); result = SetupTMDBuffer(&ciaset->ciaSections.tmd); if(result) return result; @@ -35,8 +36,9 @@ int BuildTMD(cia_settings *ciaset) return 0; } -int SetupTMDBuffer(COMPONENT_STRUCT *tmd) +int SetupTMDBuffer(buffer_struct *tmd) { + // Predict TMD Size tmd->buffer = malloc(tmd->size); // tmd->size is already set before if(!tmd->buffer) { fprintf(stderr,"[ERROR] MEM ERROR\n"); return MEM_ERROR; } memset(tmd->buffer,0,tmd->size); diff --git a/tmd.h b/tmd.h index ac3cd91..9854b3a 100644 --- a/tmd.h +++ b/tmd.h @@ -1,5 +1,4 @@ -#ifndef _TMD_H_ -#define _TMD_H_ +#pragma once typedef enum { @@ -61,8 +60,6 @@ typedef struct u8 infoRecordHash[0x20]; // SHA-256 } tmd_hdr; -#endif - // Prototypes u32 PredictTMDSize(u16 ContentCount); int BuildTMD(cia_settings *ciaset); \ No newline at end of file diff --git a/tpki.h b/tpki.h index 081078a..d22a639 100644 --- a/tpki.h +++ b/tpki.h @@ -1,5 +1,4 @@ -#ifndef _TPKI_H_ -#define _TPKI_H_ +#pragma once // AES KEYS static const unsigned char zeros_aesKey[16] = @@ -412,6 +411,4 @@ static const unsigned char cpB_tpki_cert[0x300] = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -#endif \ No newline at end of file +}; \ No newline at end of file diff --git a/usersettings.c b/usersettings.c index 65bfaa1..1110f32 100644 --- a/usersettings.c +++ b/usersettings.c @@ -174,19 +174,14 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) } if(strcasecmp(argv[i+1],"test") == 0 || strcasecmp(argv[i+1],"t") == 0) set->common.keys.keyset = pki_TEST; - else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0) - set->common.keys.keyset = pki_CUSTOM; - -#ifndef PUBLIC_BUILD + else if(strcasecmp(argv[i+1],"beta") == 0 || strcasecmp(argv[i+1],"b") == 0) + set->common.keys.keyset = pki_BETA; else if(strcasecmp(argv[i+1],"debug") == 0 || strcasecmp(argv[i+1],"development") == 0 || strcasecmp(argv[i+1],"d") == 0) 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],"beta") == 0 || strcasecmp(argv[i+1],"b") == 0) - set->common.keys.keyset = pki_BETA; - */ -#endif + else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0) + set->common.keys.keyset = pki_CUSTOM; else{ fprintf(stderr,"[SETTING ERROR] Unrecognised target '%s'\n",argv[i+1]); return USR_BAD_ARG; @@ -353,6 +348,15 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) return 1; } #endif + // + else if(strcmp(argv[i],"-6xcrypto") == 0){ + if(HasParam){ + PrintNoNeedParam("-6xcrypto"); + return USR_BAD_ARG; + } + set->cci.use6xSavedataCrypto = true; + return 1; + } // Cia Options #ifndef PUBLIC_BUILD else if(strcmp(argv[i],"-cci") == 0){ @@ -527,15 +531,16 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) if(set->dname.m_items == 0){ set->dname.m_items = 10; set->dname.u_items = 0; - set->dname.items = malloc(sizeof(dname_item)*set->dname.m_items); + set->dname.items = calloc(set->dname.m_items,sizeof(dname_item)); if(!set->dname.items){ fprintf(stderr,"[SETTING ERROR] Not enough memory\n"); return MEM_ERROR; } - memset(set->dname.items,0,sizeof(dname_item)*set->dname.m_items); + //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; + /* dname_item *tmp = malloc(sizeof(dname_item)*set->dname.m_items); if(!tmp){ fprintf(stderr,"[SETTING ERROR] Not enough memory\n"); @@ -545,6 +550,12 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) memcpy(tmp,set->dname.items,sizeof(dname_item)*set->dname.u_items); free(set->dname.items); set->dname.items = tmp; + */ + set->dname.items = realloc(set->dname.items,sizeof(dname_item)*set->dname.m_items); + if(!set->dname.items){ + fprintf(stderr,"[SETTING ERROR] Not enough memory\n"); + return MEM_ERROR; + } } char *name_pos = (char*)(argv[i]+2); @@ -633,6 +644,10 @@ int CheckArgumentCombination(user_settings *set) PrintNeedsArgument("-exheader"); return USR_BAD_ARG; } + if(set->common.keys.keyset == pki_CUSTOM && set->common.keys.keydir == NULL){ + PrintNeedsArgument("-keydir"); + return USR_BAD_ARG; + } // Reporting bad arguments if(!buildCXI && set->ncch.elfPath){ @@ -925,17 +940,13 @@ void DisplayHelp(char *app_name) //printf(" -v Verbose\n"); printf(" -DNAME=VALUE Substitute values in Spec files\n"); printf("KEY OPTIONS:\n"); -#ifdef PUBLIC_BUILD - printf(" -target Target for crypto, defaults to 't'\n"); - printf(" 't' Test(false) Keys & prod Certs\n"); - printf(" 'c' User provides Keys & Certs\n"); -#else 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(" 'b' Beta Keys & prod Certs\n"); printf(" 'd' Development Keys & Certs\n"); printf(" 'p' Production Keys & Certs\n"); - printf(" 'c' User provides Keys & Certs\n"); -#endif + printf(" 'c' Custom Keys & Certs\n"); printf(" -keydir Key Directory (for use with \"-target c\")\n"); printf(" -ckeyID Override the automatic commonKey selection\n"); printf(" -showkeys Display the loaded keychain\n"); @@ -956,6 +967,7 @@ void DisplayHelp(char *app_name) #ifndef PUBLIC_BUILD printf(" -devcardcci Use SDK CardInfo Method\n"); #endif + printf(" -6xcrypto Toggle FW6.X Save Crypto\n"); printf(" -content : Specify content files\n"); printf("CIA OPTIONS:\n"); #ifndef PUBLIC_BUILD diff --git a/usersettings.h b/usersettings.h index 63e15c7..c8254df 100644 --- a/usersettings.h +++ b/usersettings.h @@ -1,5 +1,4 @@ -#ifndef _USERSETTINGS_H_ -#define _USERSETTINGS_H_ +#pragma once #define CCI_MAX_CONTENT 8 #define CIA_MAX_CONTENT 65536 @@ -246,7 +245,7 @@ typedef struct char *workingFilePath; infile_type workingFileType; // Could Be ncch/ncsd/srl. This is mainly used for CIA gen - COMPONENT_STRUCT workingFile; + buffer_struct workingFile; } common; dname_struct dname; // For RSF value subsitution @@ -270,6 +269,7 @@ typedef struct struct{ bool useSDKStockData; // incase we want to use the SDK stock data, for whatever reason. + bool use6xSavedataCrypto; // 6.X Gamecard Save Crypto, because spec support. } cci; // CCI Settings struct{ @@ -287,7 +287,6 @@ typedef struct } user_settings; -#endif // Prototypes diff --git a/utf.c b/utf.c new file mode 100644 index 0000000..6ecadef --- /dev/null +++ b/utf.c @@ -0,0 +1,563 @@ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Source code file. + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Sept 2001: fixed const & error conditions per + mods suggested by S. Parent & A. Lillich. + June 2002: Tim Dodd added detection and handling of incomplete + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. + July 2003: slight mods to back out aggressive FFFE detection. + Jan 2004: updated switches in from-UTF8 conversions. + Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + + See the header file "utf.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "utf.h" +#ifdef CVTUTF_DEBUG +#include +#endif + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define false 0 +#define true 1 + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. + * Constants have been gathered. Loops & conditionals have been removed as + * much as possible for efficiency, in favor of drop-through switches. + * (See "Note A" at the bottom of the file for equivalent code.) + * If your compiler supports it, the "isLegalUTF8" call can be turned + * into an inline function. + */ + + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG +if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); +} +#endif + return result; +} +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (length > sourceEnd - source) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return the total number of bytes in a codepoint + * represented in UTF-8, given the value of the first byte. + */ +unsigned getNumBytesForUTF8(UTF8 first) { + return trailingBytesForUTF8[first] + 1; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 string is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd) { + while (*source != sourceEnd) { + int length = trailingBytesForUTF8[**source] + 1; + if (length > sourceEnd - *source || !isLegalUTF8(*source, length)) + return false; + *source += length; + } + return true; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (extraBytesToRead >= sourceEnd - source) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (extraBytesToRead >= sourceEnd - source) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + + Note A. + The fall-through switches in UTF-8 reading code save a + temp variable, some decrements & conditionals. The switches + are equivalent to the following loop: + { + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); + } + In UTF-8 writing code, the switches on "bytesToWrite" are + similarly unrolled loops. + + --------------------------------------------------------------------- */ diff --git a/utf.h b/utf.h new file mode 100644 index 0000000..215ad5a --- /dev/null +++ b/utf.h @@ -0,0 +1,151 @@ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Header file. + + Several funtions are included here, forming a complete set of + conversions between the three formats. UTF-7 is not included + here, but is handled in a separate source file. + + Each of these routines takes pointers to input buffers and output + buffers. The input buffers are const. + + Each routine converts the text between *sourceStart and sourceEnd, + putting the result into the buffer between *targetStart and + targetEnd. Note: the end pointers are *after* the last item: e.g. + *(sourceEnd - 1) is the last item. + + The return result indicates whether the conversion was successful, + and if not, whether the problem was in the source or target buffers. + (Only the first encountered problem is indicated.) + + After the conversion, *sourceStart and *targetStart are both + updated to point to the end of last text successfully converted in + the respective buffers. + + Input parameters: + sourceStart - pointer to a pointer to the source buffer. + The contents of this are modified on return so that + it points at the next thing to be converted. + targetStart - similarly, pointer to pointer to the target buffer. + sourceEnd, targetEnd - respectively pointers to the ends of the + two buffers, for overflow checking only. + + These conversion functions take a ConversionFlags argument. When this + flag is set to strict, both irregular sequences and isolated surrogates + will cause an error. When the flag is set to lenient, both irregular + sequences and isolated surrogates are converted. + + Whether the flag is strict or lenient, all illegal sequences will cause + an error return. This includes sequences such as: , , + or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code + must check for illegal sequences. + + When the flag is set to lenient, characters over 0x10FFFF are converted + to the replacement character; otherwise (when the flag is set to strict) + they constitute an error. + + Output parameters: + The value "sourceIllegal" is returned from some routines if the input + sequence is malformed. When "sourceIllegal" is returned, the source + value will point to the illegal value that caused the problem. E.g., + in UTF-8 when a sequence is malformed, it points to the start of the + malformed sequence. + + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +#pragma once + +/* --------------------------------------------------------------------- + The following 4 definitions are compiler-specific. + The C standard does not guarantee that wchar_t has at least + 16 bits, so wchar_t is no less portable than unsigned short! + All should be unsigned values to avoid sign extension during + bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef unsigned int UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +#define UNI_MAX_UTF8_BYTES_PER_CODE_POINT 4 + +#define UNI_UTF16_BYTE_ORDER_MARK_NATIVE 0xFEFF +#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED 0xFFFE + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +static Boolean isLegalUTF8(const UTF8 *source, int length); + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +unsigned getNumBytesForUTF8(UTF8 first); + +Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd); + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); \ No newline at end of file diff --git a/utils.c b/utils.c index de274d8..1b86067 100644 --- a/utils.c +++ b/utils.c @@ -1,6 +1,7 @@ #include "lib.h" +#include "utf.h" -//MISC +// Memory void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base) { char tmp[size][2]; @@ -33,52 +34,38 @@ void endian_memcpy(u8 *destination, u8 *source, u32 size, int endianness) } } -void u8_hex_print_be(u8 *array, int len) +int CopyData(u8 **dest, u8 *source, u64 size) { - for(int i = 0; i < len; i++) - printf("%02x",array[i]); -} - -void u8_hex_print_le(u8 *array, int len) -{ - for(int i = 0; i < len; i++) - printf("%02x",array[len - i - 1]); -} - -u64 align_value(u64 value, u64 alignment) -{ - u64 tmp = value; - while(tmp > alignment) - tmp -= alignment; - return (value + (alignment - tmp)); -} - -void resolve_flag(unsigned char flag, unsigned char *flag_bool) -{ - unsigned char bit_mask[8] = {0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1}; - for(int i = 0; i < 8; i++){ - if (flag >= bit_mask[i]){ - flag_bool[7-i] = true; - flag -= bit_mask[i]; - } - else - flag_bool[7-i] = false; + if(!*dest){ + *dest = malloc(size); + if(!*dest) return -1; } + memcpy(*dest,source,size); + return 0; } -void resolve_flag_u16(u16 flag, unsigned char *flag_bool) +// Misc +u64 align(u64 value, u64 alignment) { - u16 bit_mask[16] = {0x8000,0x4000,0x2000,0x1000,0x800,0x400,0x200,0x100,0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1}; - for(int i = 0; i < 16; i++){ - if (flag >= bit_mask[i]){ - flag_bool[15-i] = true; - flag -= bit_mask[i]; - } + if(value % alignment != 0) + return value + alignment - value % alignment; else - flag_bool[15-i] = false; - } + return value; } +u64 min_u64(u64 a, u64 b) +{ + if(a < b) return a; + return b; +} + +u64 max_u64(u64 a, u64 b) +{ + if(a > b) return a; + return b; +} + +// Strings int append_filextention(char *output, u16 max_outlen, char *input, char extention[]) { if(output == NULL || input == NULL){ @@ -102,111 +89,118 @@ int append_filextention(char *output, u16 max_outlen, char *input, char extentio return 0; } -int CopyData(u8 **dest, u8 *source, u64 size) +void memdump(FILE* fout, const char* prefix, const u8* data, u32 size) { - if(!*dest){ - *dest = malloc(size); - if(!*dest) return -1; + u32 i; + u32 prefixlen = strlen(prefix); + u32 offs = 0; + u32 line = 0; + while(size) + { + u32 max = 32; + + if (max > size) + max = size; + + if (line==0) + fprintf(fout, "%s", prefix); + else + fprintf(fout, "%*s", prefixlen, ""); + + + for(i=0; i b) return a; - return b; + *dst_len = src_len*sizeof(u16); + *dst = malloc((*dst_len)+sizeof(u16)); + if(*dst == NULL) + return -1; + memset(*dst,0,(*dst_len)+sizeof(u16)); + u16 *tmp = *dst; + for(int i=0; i 0){ + if(size != fsize){ + fprintf(stderr,"[!] %s has an invalid size (0x%llx)\n",fsize); + return NULL; + } + } + + u8 *data = (u8*)calloc(1,fsize); + if(!data){ + fprintf(stderr,"[!] Not enough memory\n"); + return NULL; + } + FILE *fp = fopen(file,"rb"); + fread(data,fsize,1,fp); + fclose(fp); + + return data; +} + +void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output) +{ + fseek_64(output,offset); + fwrite(buffer,size,1,output); +} + +void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file) +{ + fseek_64(file,offset); + fread(outbuff,size,1,file); +} + +int fseek_64(FILE *fp, u64 file_pos) +{ +#ifdef _WIN32 + fpos_t pos = file_pos; + return fsetpos(fp,&pos); +#else + return fseeko(fp,file_pos,SEEK_SET); +#endif +} + +//Data Size conversion u16 u8_to_u16(u8 *value, u8 endianness) { u16 new_value; @@ -341,33 +417,4 @@ int u64_to_u8(u8 *out_value, u64 in_value, u8 endianness) return 0; } -//Copied from ctrtool -void memdump(FILE* fout, const char* prefix, const u8* data, u32 size) -{ - u32 i; - u32 prefixlen = strlen(prefix); - u32 offs = 0; - u32 line = 0; - while(size) - { - u32 max = 32; - - if (max > size) - max = size; - - if (line==0) - fprintf(fout, "%s", prefix); - else - fprintf(fout, "%*s", prefixlen, ""); - - - for(i=0; i= SlotCount){ // if Exceeding Ptr capacity, expand buffer SlotCount = SlotCount*2; + /* char **tmp1 = malloc((SlotCount+1)*sizeof(char*)); // allocate new buffer if(!tmp1){ ctx->error = YAML_MEM_ERROR; @@ -357,6 +358,12 @@ u32 SetYAMLSequence(char ***dest, char *key, ctr_yaml_context *ctx) for(u32 i = 0; i < ActualCount; i++) tmp1[i] = tmp[i]; // Transfer ptrs free(tmp); // free original buffer tmp = tmp1; // transfer main ptr + */ + tmp = realloc(tmp,(SlotCount+1)*sizeof(char*)); + if(!tmp){ + ctx->error = true; + return 0; + } } FinishEvent(ctx); GetEvent(ctx); diff --git a/yaml_ctr.h b/yaml_ctr.h index 5f4d452..cb70195 100644 --- a/yaml_ctr.h +++ b/yaml_ctr.h @@ -1,5 +1,4 @@ -#ifndef _YAML_H_ -#define _YAML_H_ +#pragma once typedef enum { @@ -27,8 +26,6 @@ typedef struct } ctr_yaml_context; -#endif - // Public Prototypes int GetYamlSettings(user_settings *set); diff --git a/yamlsettings.h b/yamlsettings.h index 2958c95..d193fe5 100644 --- a/yamlsettings.h +++ b/yamlsettings.h @@ -1,3 +1,4 @@ +#pragma once int MergeSpecData(rsf_settings *out, rsf_settings *desc, rsf_settings *rsf); void EvaluateRSF(rsf_settings *rsf, ctr_yaml_context *ctx);