makerom v0.6

This commit is contained in:
3DSGuy
2014-04-08 13:09:00 +08:00
parent 26772b49c8
commit 9cb89cbe8b
59 changed files with 2935 additions and 2662 deletions
+7 -25
View File
@@ -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
+407
View File
@@ -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);
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
int set_AccessDesc(exheader_settings *exhdrset, ncch_settings *ncchset);
+2 -5
View File
@@ -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);
+1 -3
View File
@@ -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);
+179 -158
View File
@@ -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)
{
+9 -10
View File
@@ -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;
+25
View File
@@ -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;
+4 -4
View File
@@ -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)
+3 -6
View File
@@ -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
+2 -4
View File
@@ -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
};
+2 -5
View File
@@ -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
};
+1 -3
View File
@@ -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
+327
View File
@@ -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,&currentdir,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]);
}
+64
View File
@@ -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);
+6 -9
View File
@@ -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
};
+2 -5
View File
@@ -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
};
+5 -5
View File
@@ -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);
+1 -4
View File
@@ -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);
+2 -4
View File
@@ -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
} elf_64_phdr;
+54 -54
View File
@@ -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;
+18 -21
View File
@@ -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);
+12 -359
View File
@@ -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)
+15 -16
View File
@@ -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);
+122 -150
View File
@@ -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;
+6 -9
View File
@@ -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);
+5 -4
View File
@@ -11,15 +11,16 @@
#include <time.h>
#include <unistd.h>
#include <math.h>
#include <dirent.h>
#include <wchar.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef _WIN32
#include <io.h>
#include <direct.h>
#include <windows.h>
//#include <wchar.h>
#else
#include <sys/stat.h>
#include <sys/types.h>
#endif
+2 -5
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -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);
+378 -301
View File
@@ -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);
}
+18 -22
View File
@@ -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);
-1104
View File
File diff suppressed because it is too large Load Diff
+18 -11
View File
@@ -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
+1 -7
View File
@@ -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);
+2 -5
View File
@@ -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
};
+2 -5
View File
@@ -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
// Certificates
+33 -22
View File
@@ -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
void FreeRomFsCtx(romfs_buildctx *ctx)
{
if(ctx->romfsBinary)
fclose(ctx->romfsBinary);
}
+68 -6
View File
@@ -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
+13
View File
@@ -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;
}
+4
View File
@@ -0,0 +1,4 @@
#pragma once
int PrepareBuildRomFsBinary(ncch_settings *ncchset, romfs_buildctx *ctx);
int BuildRomFsBinary(romfs_buildctx *ctx);
+22
View File
@@ -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;
}
+4
View File
@@ -0,0 +1,4 @@
#pragma once
int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx);
int ImportRomFsBinaryFromFile(romfs_buildctx *ctx);
+2
View File
@@ -0,0 +1,2 @@
#pragma once
+81 -84
View File
@@ -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
} srl_hdr;
+2 -2
View File
@@ -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);
+1 -4
View File
@@ -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);
+1 -4
View File
@@ -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);
+4 -2
View File
@@ -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);
+1 -4
View File
@@ -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);
+2 -5
View File
@@ -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
};
+30 -18
View File
@@ -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 <t|c> 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 <t|d|p|c> Target for crypto, defaults to 't'\n");
//printf(" -target <t|b|d|p|c> 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 <dir> Key Directory (for use with \"-target c\")\n");
printf(" -ckeyID <u8 value> 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 <filepath>:<index> Specify content files\n");
printf("CIA OPTIONS:\n");
#ifndef PUBLIC_BUILD
+3 -4
View File
@@ -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
+563
View File
@@ -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 <stdio.h>
#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.
--------------------------------------------------------------------- */
+151
View File
@@ -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: <F4 90 80 80>, <C0 80>,
or <A0> 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);
+201 -154
View File
@@ -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<max; i++)
fprintf(fout, "%02X", data[offs+i]);
fprintf(fout, "\n");
line++;
size -= max;
offs += max;
}
memcpy(*dest,source,size);
}
int str_u8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len)
{
*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<src_len; i++)
tmp[i] = (u16)src[i];
return 0;
}
u64 min_u64(u64 a, u64 b)
int str_u16_to_u16(u16 **dst, u32 *dst_len, u16 *src, u32 src_len)
{
if(a < 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<src_len; i++)
tmp[i] = src[i];
return 0;
}
u64 max_u64(u64 a, u64 b)
int str_u32_to_u16(u16 **dst, u32 *dst_len, u32 *src, u32 src_len)
{
if(a > 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<src_len; i++)
tmp[i] = (u16)src[i];
return 0;
}
//IO Related
void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output)
#ifndef _WIN32
int str_utf8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len)
{
fseek_64(output,offset,SEEK_SET);
fwrite(buffer,size,1,output);
}
*dst_len = src_len*sizeof(u16);
*dst = malloc((*dst_len)+sizeof(u16));
if(*dst == NULL)
return -1;
memset(*dst,0,(*dst_len)+sizeof(u16));
UTF16 *target_start = *dst;
UTF16 *target_end = (target_start + *dst_len);
UTF8 *src_start = (UTF8*)src;
UTF8 *src_end = (UTF8*)(src+src_len*sizeof(u8));
return ConvertUTF8toUTF16 (&src_start, src_end, &target_start, target_end, strictConversion);
}
#endif
void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file)
//Char IO
bool DoesFileExist(char *filename)
{
fseek_64(file,offset,SEEK_SET);
fread(outbuff,size,1,file);
#ifdef _WIN32
struct _stat64 st;
return _stat64(filename, &st) == 0;
#else
struct stat st;
return stat(filename, &st) == 0;
#endif
}
u64 GetFileSize_u64(char *filename)
{
u64 size;
#ifdef _WIN32
/* Making sure file exists */
FILE *tmp = fopen(filename,"rb");
if(!tmp) return 0;
fclose(tmp);
int fh;
u64 n;
fh = _open( filename, 0 );
n = _lseeki64(fh, 0, SEEK_END);
_close(fh);
size = (n / sizeof(short))*2;
struct _stat64 st;
if( _stat64(filename, &st) != 0)
return 0;
else
return st.st_size;
#else
FILE *file = fopen(filename,"rb");
fseeko(file, 0L, SEEK_END);
size = ftello(file);
fclose(file);
#endif
return size;
}
u32 GetFileSize_u32(FILE *file)
{
u32 size = 0;
fseek(file, 0L, SEEK_END);
size = ftell(file);
fseek(file, 0L, SEEK_SET);
return size;
}
int TruncateFile_u64(char *filename, u64 filelen)
{
#ifdef _WIN32
HANDLE fh;
LARGE_INTEGER fp;
fp.QuadPart = filelen;
fh = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE) {
printf("[!] Invalid File handle\n");
return 1;
}
if (SetFilePointerEx(fh, fp, NULL, FILE_BEGIN) == 0 ||
SetEndOfFile(fh) == 0) {
printf("[!] truncate failed\n");
CloseHandle(fh);
return 1;
}
CloseHandle(fh);
return 0;
#else
return truncate(filename,filelen);
#endif
}
int fseek_64(FILE *fp, u64 file_pos, int whence)
{
#ifdef _WIN32
if(whence != SEEK_SET)
printf("[!] fseek_64, whence has been overided to SEEK_SET\n");
fpos_t pos = file_pos;
return fsetpos(fp,&pos); //I can't believe the 2gb problem with Windows & MINGW, maybe I have a bad installation :/
#else
return fseeko(fp,file_pos,whence);
struct stat st;
if( stat(filename, &st) != 0)
return 0;
else
return st.st_size;
#endif
}
@@ -228,7 +222,89 @@ char *getcwdir(char *buffer,int maxlen)
#endif
}
//Data Size contitleVersion
int TruncateFile_u64(char *filename, u64 filelen)
{
#ifdef _WIN32
HANDLE fh;
LARGE_INTEGER fp;
fp.QuadPart = filelen;
fh = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE) {
printf("[!] Invalid File handle\n");
return 1;
}
if (SetFilePointerEx(fh, fp, NULL, FILE_BEGIN) == 0 || SetEndOfFile(fh) == 0) {
printf("[!] Truncate failed\n");
CloseHandle(fh);
return 1;
}
CloseHandle(fh);
return 0;
#else
return truncate(filename,filelen);
#endif
}
// Wide Char IO
#ifdef _WIN32
u64 wGetFileSize_u64(u16 *filename)
{
struct _stat64 st;
_wstat64((wchar_t*)filename, &st);
return st.st_size;
}
#endif
//IO Misc
u8* ImportFile(char *file, u64 size)
{
u64 fsize = GetFileSize_u64(file);
if(size > 0){
if(size != fsize){
fprintf(stderr,"[!] %s has an invalid size (0x%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<max; i++)
fprintf(fout, "%02X", data[offs+i]);
fprintf(fout, "\n");
line++;
size -= max;
offs += max;
}
}
+34 -25
View File
@@ -1,46 +1,55 @@
#ifndef _UTILS_H_
#define _UTILS_H_
typedef struct
{
char *argument;
u16 arg_len;
} OPTION_CTX;
#pragma once
typedef struct
{
u64 size;
u8 *buffer;
} COMPONENT_STRUCT;
#endif
} buffer_struct;
//MISC
// Memory
void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base);
void endian_memcpy(u8 *destination, u8 *source, u32 size, int endianness);
void u8_hex_print_be(u8 *array, int len);
void u8_hex_print_le(u8 *array, int len);
u64 align_value(u64 value, u64 alignment);
void resolve_flag(unsigned char flag, unsigned char *flag_bool);
void resolve_flag_u16(u16 flag, unsigned char *flag_bool);
int append_filextention(char *output, u16 max_outlen, char *input, char extention[]);
int CopyData(u8 **dest, u8 *source, u64 size);
// MISC
u64 align(u64 value, u64 alignment);
u64 min_u64(u64 a, u64 b);
u64 max_u64(u64 a, u64 b);
//IO Related
void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output);
void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file);
// Strings
void memdump(FILE* fout, const char* prefix, const u8* data, u32 size);
int append_filextention(char *output, u16 max_outlen, char *input, char extention[]);
int str_u8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len);
int str_u16_to_u16(u16 **dst, u32 *dst_len, u16 *src, u32 src_len);
int str_u32_to_u16(u16 **dst, u32 *dst_len, u32 *src, u32 src_len);
#ifndef _WIN32
int str_utf8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len);
#endif
//Char IO
bool DoesFileExist(char *filename);
u64 GetFileSize_u64(char *filename);
u32 GetFileSize_u32(FILE *file);
int TruncateFile_u64(char *filename, u64 filelen);
int fseek_64(FILE *fp, u64 file_pos, int whence);
int makedir(const char* dir);
char *getcwdir(char *buffer,int maxlen);
//Data Size contitleVersion
int TruncateFile_u64(char *filename, u64 filelen);
//Wide Char IO
#ifdef _WIN32
u64 wGetFileSize_u64(u16 *filename);
#endif
//IO Misc
u8* ImportFile(char *file, u64 size);
void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output);
void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file);
int fseek_64(FILE *fp, u64 file_pos);
//Data Size conversion
u16 u8_to_u16(u8 *value, u8 endianness);
u32 u8_to_u32(u8 *value, u8 endianness);
u64 u8_to_u64(u8 *value, u8 endianness);
int u16_to_u8(u8 *out_value, u16 in_value, u8 endianness);
int u32_to_u8(u8 *out_value, u32 in_value, u8 endianness);
int u64_to_u8(u8 *out_value, u64 in_value, u8 endianness);
//from ctrtool
void memdump(FILE* fout, const char* prefix, const u8* data, u32 size);
+7
View File
@@ -348,6 +348,7 @@ u32 SetYAMLSequence(char ***dest, char *key, ctr_yaml_context *ctx)
ActualCount++;
if(ActualCount >= 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);
+1 -4
View File
@@ -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);
+1
View File
@@ -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);