mirror of
https://github.com/DarkStore-3DS/Project_CTR.git
synced 2026-07-03 00:39:14 +00:00
makerom v0.6
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# Makerom Sources
|
# 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
|
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
|
NCSD_OBJS = ncsd.o
|
||||||
SETTINGS_OBJS = usersettings.o yamlsettings.o
|
SETTINGS_OBJS = usersettings.o yamlsettings.o
|
||||||
LIB_API_OBJS = crypto.o yaml_ctr.o blz.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
|
# Compiler Settings
|
||||||
LIBS = -static-libgcc -static-libstdc++
|
LIBS = -static-libgcc -static-libstdc++
|
||||||
CXXFLAGS = -I.
|
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
|
CC = gcc
|
||||||
|
|
||||||
# MAKEROM Build Settings
|
# MAKEROM Build Settings
|
||||||
MAKEROM_BUILD_FLAGS = #-DDEBUG #-DPUBLIC_BUILD
|
MAKEROM_BUILD_FLAGS = #-DDEBUG #-DPUBLIC_BUILD
|
||||||
VER_MAJOR = 0
|
VER_MAJOR = 0
|
||||||
VER_MINOR = 5
|
VER_MINOR = 6
|
||||||
OUTPUT = makerom
|
OUTPUT = makerom
|
||||||
|
|
||||||
main: build
|
main: build
|
||||||
@@ -29,30 +29,12 @@ main: build
|
|||||||
rebuild: clean build
|
rebuild: clean build
|
||||||
|
|
||||||
build: $(OBJS) $(POLAR_OBJS) $(YAML_OBJS)
|
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:
|
clean:
|
||||||
rm -rf $(OUTPUT) $(OBJS) $(POLAR_OBJS) $(YAML_OBJS) *.cci *.cia *.cxi *.cfa
|
rm -rf $(OUTPUT) $(OBJS) $(POLAR_OBJS) $(YAML_OBJS) *.cci *.cia *.cxi *.cfa
|
||||||
|
|
||||||
# Winfail compatibility
|
# Windows compatibility
|
||||||
rebuildwin: cleanwin build
|
rebuildwin: cleanwin build
|
||||||
cleanwin:
|
cleanwin:
|
||||||
del /Q objs $(OUTPUT).exe *.o polarssl\*.o libyaml\*.o *.cci *.cia *.cxi *.cfa
|
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
|
|
||||||
+407
@@ -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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int set_AccessDesc(exheader_settings *exhdrset, ncch_settings *ncchset);
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
#ifndef _BLZ_H_
|
#pragma once
|
||||||
#define _BLZ_H_
|
|
||||||
|
|
||||||
#define BLZ_NORMAL 0 // normal mode
|
#define BLZ_NORMAL 0 // normal mode
|
||||||
#define BLZ_BEST 1 // best mode
|
#define BLZ_BEST 1 // best mode
|
||||||
|
|
||||||
u8 *BLZ_Code(u8 *raw_buffer, int raw_len, u32 *new_len, int best);
|
u8 *BLZ_Code(u8 *raw_buffer, int raw_len, u32 *new_len, int best);
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _CERTS_H_
|
#pragma once
|
||||||
#define _CERTS_H_
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -29,7 +28,6 @@ typedef struct
|
|||||||
u8 Padding[0x3C];
|
u8 Padding[0x3C];
|
||||||
} ecc_pubk_struct;
|
} ecc_pubk_struct;
|
||||||
|
|
||||||
#endif
|
|
||||||
// Cert Sizes
|
// Cert Sizes
|
||||||
u32 GetCertSize(u8 *cert);
|
u32 GetCertSize(u8 *cert);
|
||||||
void GetCertSigSectionSizes(u32 *SigSize, u32 *SigPadding, u8 *cert);
|
void GetCertSigSectionSizes(u32 *SigSize, u32 *SigPadding, u8 *cert);
|
||||||
|
|||||||
@@ -18,20 +18,22 @@ int get_CIASettings(cia_settings *ciaset, user_settings *usrset);
|
|||||||
|
|
||||||
int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset);
|
int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset);
|
||||||
int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset);
|
int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset);
|
||||||
int GetCIADataFromNcch(cia_settings *ciaset, ncch_hdr *NcchHdr, extended_hdr *ExHeader);
|
int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key);
|
||||||
int GetMetaRegion(cia_settings *ciaset, extended_hdr *ExHeader, u8 *ExeFs);
|
int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key);
|
||||||
int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset);
|
int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset);
|
||||||
|
int ImportNcchContent(cia_settings *ciaset);
|
||||||
int GetSettingsFromSrl(cia_settings *ciaset);
|
int GetSettingsFromSrl(cia_settings *ciaset);
|
||||||
int GetSettingsFromCci(cia_settings *ciaset);
|
int GetSettingsFromCci(cia_settings *ciaset);
|
||||||
|
|
||||||
u16 SetupVersion(u16 Major, u16 Minor, u16 Micro);
|
u16 SetupVersion(u16 Major, u16 Minor, u16 Micro);
|
||||||
|
|
||||||
|
void GetContentHashes(cia_settings *ciaset);
|
||||||
|
void EncryptContent(cia_settings *ciaset);
|
||||||
|
|
||||||
int BuildCIA_CertChain(cia_settings *ciaset);
|
int BuildCIA_CertChain(cia_settings *ciaset);
|
||||||
int BuildCIA_Header(cia_settings *ciaset);
|
int BuildCIA_Header(cia_settings *ciaset);
|
||||||
|
|
||||||
int WriteCurrentSectionstoFile(cia_settings *ciaset);
|
int WriteCIAtoFile(cia_settings *ciaset);
|
||||||
int WriteContentsToFile(cia_settings *ciaset, user_settings *usrset);
|
|
||||||
int WriteTMDToFile(cia_settings *ciaset);
|
|
||||||
|
|
||||||
int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, u8 mode);
|
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;
|
int result = 0;
|
||||||
|
|
||||||
// Init Settings
|
// Init Settings
|
||||||
cia_settings *ciaset = malloc(sizeof(cia_settings));
|
cia_settings *ciaset = calloc(1,sizeof(cia_settings));
|
||||||
if(!ciaset) {fprintf(stderr,"[CIA ERROR] MEM ERROR\n"); return MEM_ERROR;}
|
if(!ciaset) {
|
||||||
init_CIASettings(ciaset);
|
fprintf(stderr,"[CIA ERROR] MEM ERROR\n");
|
||||||
|
return MEM_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
// Get Settings
|
// Get Settings
|
||||||
|
init_CIASettings(ciaset);
|
||||||
result = get_CIASettings(ciaset,usrset);
|
result = get_CIASettings(ciaset,usrset);
|
||||||
if(result) goto finish;
|
if(result) goto finish;
|
||||||
|
|
||||||
@@ -58,6 +63,7 @@ int build_CIA(user_settings *usrset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create CIA Sections
|
// Create CIA Sections
|
||||||
|
|
||||||
/* Certificate Chain */
|
/* Certificate Chain */
|
||||||
result = BuildCIA_CertChain(ciaset);
|
result = BuildCIA_CertChain(ciaset);
|
||||||
if(result) goto finish;
|
if(result) goto finish;
|
||||||
@@ -66,25 +72,17 @@ int build_CIA(user_settings *usrset)
|
|||||||
result = BuildTicket(ciaset);
|
result = BuildTicket(ciaset);
|
||||||
if(result) goto finish;
|
if(result) goto finish;
|
||||||
|
|
||||||
/* CIA Header */
|
/* Title Metadata */
|
||||||
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;
|
|
||||||
|
|
||||||
result = BuildTMD(ciaset);
|
result = BuildTMD(ciaset);
|
||||||
if(result) goto finish;
|
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:
|
finish:
|
||||||
if(result != FAILED_TO_CREATE_OUTFILE && ciaset->out) fclose(ciaset->out);
|
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){
|
if(usrset->common.workingFileType == infile_ncch){
|
||||||
result = GetSettingsFromNcch0(ciaset,0);
|
result = GetSettingsFromNcch0(ciaset,0);
|
||||||
if(result) return result;
|
if(result)
|
||||||
|
return result;
|
||||||
result = GetContentFilePtrs(ciaset,usrset);
|
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){
|
else if(usrset->common.workingFileType == infile_srl){
|
||||||
result = GetSettingsFromSrl(ciaset);
|
result = GetSettingsFromSrl(ciaset);
|
||||||
if(result) return result;
|
if(result)
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(usrset->common.workingFileType == infile_ncsd){
|
else if(usrset->common.workingFileType == infile_ncsd){
|
||||||
result = GetSettingsFromCci(ciaset);
|
result = GetSettingsFromCci(ciaset);
|
||||||
if(result) return result;
|
if(result)
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetContentHashes(ciaset);
|
||||||
|
|
||||||
|
if(ciaset->content.encryptCia)
|
||||||
|
EncryptContent(ciaset);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -147,8 +156,8 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset)
|
|||||||
{
|
{
|
||||||
// General Stuff
|
// General Stuff
|
||||||
ciaset->keys = &usrset->common.keys;
|
ciaset->keys = &usrset->common.keys;
|
||||||
ciaset->inFile = usrset->common.workingFile.buffer;
|
ciaset->ciaSections.content.buffer = usrset->common.workingFile.buffer;
|
||||||
ciaset->inFileSize = usrset->common.workingFile.size;
|
ciaset->ciaSections.content.size = usrset->common.workingFile.size;
|
||||||
u32_to_u8(ciaset->tmd.titleType,TYPE_CTR,BE);
|
u32_to_u8(ciaset->tmd.titleType,TYPE_CTR,BE);
|
||||||
ciaset->content.encryptCia = usrset->cia.encryptCia;
|
ciaset->content.encryptCia = usrset->cia.encryptCia;
|
||||||
ciaset->content.IsDlc = usrset->cia.DlcContent;
|
ciaset->content.IsDlc = usrset->cia.DlcContent;
|
||||||
@@ -171,7 +180,7 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset)
|
|||||||
if(usrset->common.rsfPath)
|
if(usrset->common.rsfPath)
|
||||||
ctr_sha(usrset->common.rsfPath,strlen(usrset->common.rsfPath),hash,CTR_SHA_256);
|
ctr_sha(usrset->common.rsfPath,strlen(usrset->common.rsfPath),hash,CTR_SHA_256);
|
||||||
else
|
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
|
// Ticket Data
|
||||||
memcpy(ciaset->tik.ticketId,(hash+0x8),8);
|
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)
|
int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset)
|
||||||
{
|
{
|
||||||
/* Sanity Checks */
|
/* Sanity Checks */
|
||||||
if(!ciaset->inFile)
|
if(!ciaset->ciaSections.content.buffer)
|
||||||
return CIA_NO_NCCH0;
|
return CIA_NO_NCCH0;
|
||||||
|
|
||||||
u8 *ncch0 = (u8*)(ciaset->inFile+ncch0_offset);
|
u8 *ncch0 = (u8*)(ciaset->ciaSections.content.buffer+ncch0_offset);
|
||||||
|
|
||||||
if(!IsNCCH(NULL,ncch0)){
|
if(!IsNCCH(NULL,ncch0)){
|
||||||
fprintf(stderr,"[CIA ERROR] Content0 is not NCCH\n");
|
fprintf(stderr,"[CIA ERROR] Content0 is not NCCH\n");
|
||||||
@@ -227,10 +236,10 @@ int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset)
|
|||||||
return MEM_ERROR;
|
return MEM_ERROR;
|
||||||
}
|
}
|
||||||
memset(ncch_ctx,0x0,sizeof(ncch_struct));
|
memset(ncch_ctx,0x0,sizeof(ncch_struct));
|
||||||
GetCXIStruct(ncch_ctx,hdr);
|
GetNCCHStruct(ncch_ctx,hdr);
|
||||||
|
|
||||||
/* Verify Ncch0 (Sig&Hash Checks) */
|
/* 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){
|
if(result == UNABLE_TO_LOAD_NCCH_KEY){
|
||||||
ciaset->content.keyNotFound = true;
|
ciaset->content.keyNotFound = true;
|
||||||
if(!ciaset->content.IsCfa){
|
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);
|
endian_memcpy(ciaset->common.titleId,hdr->titleId,8,LE);
|
||||||
|
|
||||||
|
|
||||||
/* Getting ExeFs/ExHeader */
|
/* Getting ncch key */
|
||||||
u8 *ExeFs = malloc(ncch_ctx->exefsSize);
|
ncch_key_type keyType = GetNCCHKeyType(hdr);
|
||||||
if(!ExeFs){ fprintf(stderr,"[CIA ERROR] MEM ERROR\n"); return MEM_ERROR; }
|
u8 *ncchkey = NULL;
|
||||||
extended_hdr *ExHeader = malloc(ncch_ctx->exhdrSize);
|
if(!ciaset->content.keyNotFound){
|
||||||
if(!ExHeader){ fprintf(stderr,"[CIA ERROR] MEM ERROR\n"); free(ExeFs); return MEM_ERROR; }
|
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);
|
/* Get TMD Data from ncch */
|
||||||
if(!(ciaset->content.IsCfa||ciaset->content.keyNotFound)) GetNCCHSection((u8*)ExHeader, ncch_ctx->exhdrSize, 0, ncch0, ncch_ctx, ciaset->keys, ncch_exhdr);
|
result = GetCIADataFromNcch(ciaset,ncch0,ncch_ctx,ncchkey); // Data For TMD
|
||||||
|
|
||||||
result = GetCIADataFromNcch(ciaset,hdr,ExHeader); // Data For TMD
|
|
||||||
if(result) goto finish;
|
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 */
|
||||||
finish:
|
finish:
|
||||||
free(ExeFs);
|
|
||||||
free(ExHeader);
|
|
||||||
|
|
||||||
/* Return */
|
/* Return */
|
||||||
free(ncch_ctx);
|
free(ncch_ctx);
|
||||||
return result;
|
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);
|
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);
|
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){
|
if(ciaset->content.overrideSaveDataSize){
|
||||||
u64 size = 0;
|
u64 size = 0;
|
||||||
GetSaveDataSizeFromString(&size,ciaset->content.overrideSaveDataSize);
|
GetSaveDataSizeFromString(&size,ciaset->content.overrideSaveDataSize);
|
||||||
@@ -296,19 +310,42 @@ int GetCIADataFromNcch(cia_settings *ciaset, ncch_hdr *NcchHdr, extended_hdr *Ex
|
|||||||
return CIA_BAD_VERSION;
|
return CIA_BAD_VERSION;
|
||||||
}
|
}
|
||||||
// Setting remaster ver
|
// 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]);
|
u16 version = SetupVersion(ciaset->common.titleVersion[0],ciaset->common.titleVersion[1],ciaset->common.titleVersion[2]);
|
||||||
ciaset->tik.version = version;
|
ciaset->tik.version = version;
|
||||||
ciaset->tmd.version = version;
|
ciaset->tmd.version = version;
|
||||||
|
|
||||||
|
free(exhdr);
|
||||||
return 0;
|
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;
|
if(ciaset->content.IsCfa || ciaset->content.keyNotFound)
|
||||||
ciaset->ciaSections.meta.size = sizeof(cia_metadata) + GetExeFsSectionSize("icon",ExeFs);
|
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);
|
ciaset->ciaSections.meta.buffer = malloc(ciaset->ciaSections.meta.size);
|
||||||
if(!ciaset->ciaSections.meta.buffer){
|
if(!ciaset->ciaSections.meta.buffer){
|
||||||
fprintf(stderr,"[CIA ERROR] Not enough memory\n");
|
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;
|
cia_metadata *hdr = (cia_metadata*)ciaset->ciaSections.meta.buffer;
|
||||||
memset(hdr,0,sizeof(cia_metadata));
|
memset(hdr,0,sizeof(cia_metadata));
|
||||||
GetDependencyList_frm_exhdr(hdr->dependencyList,ExHeader);
|
GetDependencyList_frm_exhdr(hdr->dependencyList,exhdr);
|
||||||
GetCoreVersion_frm_exhdr(hdr->coreVersion,ExHeader);
|
GetCoreVersion_frm_exhdr(hdr->coreVersion,exhdr);
|
||||||
if(DoesExeFsSectionExist("icon",ExeFs)){
|
if(icon_size > 0){
|
||||||
u8 *IconDestPos = (ciaset->ciaSections.meta.buffer + sizeof(cia_metadata));
|
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);
|
//memdump(stdout,"Icon: ",IconDestPos,0x10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(exefsHdr);
|
||||||
|
free(exhdr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,9 +396,6 @@ int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset)
|
|||||||
|
|
||||||
// Get Data from ncch HDR
|
// Get Data from ncch HDR
|
||||||
GetNCCH_CommonHDR(hdr,ciaset->content.contentFilePtrs[j],NULL);
|
GetNCCH_CommonHDR(hdr,ciaset->content.contentFilePtrs[j],NULL);
|
||||||
|
|
||||||
// Get TitleID
|
|
||||||
memcpy(ciaset->content.contentTitleId[j],hdr->titleId,8);
|
|
||||||
|
|
||||||
// Get Size
|
// Get Size
|
||||||
ciaset->content.contentSize[j] = GetNCCH_MediaSize(hdr)*GetNCCH_MediaUnitSize(hdr);
|
ciaset->content.contentSize[j] = GetNCCH_MediaSize(hdr)*GetNCCH_MediaUnitSize(hdr);
|
||||||
@@ -384,10 +423,35 @@ int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset)
|
|||||||
return 0;
|
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)
|
int GetSettingsFromSrl(cia_settings *ciaset)
|
||||||
{
|
{
|
||||||
SRL_Header *hdr = (SRL_Header*)ciaset->inFile;
|
srl_hdr *hdr = (srl_hdr*)ciaset->ciaSections.content.buffer;
|
||||||
if(!hdr || ciaset->inFileSize < sizeof(SRL_Header)) {
|
if(!hdr || ciaset->ciaSections.content.size < sizeof(srl_hdr)) {
|
||||||
fprintf(stderr,"[CIA ERROR] Invalid TWL SRL File\n");
|
fprintf(stderr,"[CIA ERROR] Invalid TWL SRL File\n");
|
||||||
return FAILED_TO_IMPORT_FILE;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
}
|
}
|
||||||
@@ -406,35 +470,33 @@ int GetSettingsFromSrl(cia_settings *ciaset)
|
|||||||
ciaset->tmd.twlFlag = ((hdr->reserved_flags[3] & 6) >> 1);
|
ciaset->tmd.twlFlag = ((hdr->reserved_flags[3] & 6) >> 1);
|
||||||
|
|
||||||
// Get Remaster Version
|
// 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->tik.version = version;
|
||||||
ciaset->tmd.version = version;
|
ciaset->tmd.version = version;
|
||||||
|
|
||||||
// Get SaveDataSize (Public and Private)
|
// Get SaveDataSize (Public and Private)
|
||||||
memcpy(ciaset->tmd.savedataSize,hdr->pub_save_data_size,4);
|
memcpy(ciaset->tmd.savedataSize,hdr->pubSaveDataSize,4);
|
||||||
memcpy(ciaset->tmd.privSavedataSize,hdr->priv_save_data_size,4);
|
memcpy(ciaset->tmd.privSavedataSize,hdr->privSaveDataSize,4);
|
||||||
|
|
||||||
// Setting CIA Content Settings
|
// Setting CIA Content Settings
|
||||||
ciaset->content.contentCount = 1;
|
ciaset->content.contentCount = 1;
|
||||||
ciaset->content.contentOffset[0] = 0;
|
ciaset->content.contentOffset[0] = 0;
|
||||||
ciaset->content.contentSize[0] = ciaset->inFileSize;
|
ciaset->content.contentSize[0] = ciaset->ciaSections.content.size;
|
||||||
ciaset->content.totalContentSize = ciaset->inFileSize;
|
ciaset->content.totalContentSize = ciaset->ciaSections.content.size;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int GetSettingsFromCci(cia_settings *ciaset)
|
int GetSettingsFromCci(cia_settings *ciaset)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if(!IsCci(ciaset->inFile)){
|
if(!IsCci(ciaset->ciaSections.content.buffer)){
|
||||||
fprintf(stderr,"[CIA ERROR] Invalid CCI file\n");
|
fprintf(stderr,"[CIA ERROR] Invalid CCI file\n");
|
||||||
return FAILED_TO_IMPORT_FILE;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ncch0_offset = GetPartitionOffset(ciaset->inFile,0);
|
u32 ncch0_offset = GetPartitionOffset(ciaset->ciaSections.content.buffer,0);
|
||||||
if(!ncch0_offset){
|
if(!ncch0_offset){
|
||||||
fprintf(stderr,"[CIA ERROR] Invalid CCI file (invalid ncch0)\n");
|
fprintf(stderr,"[CIA ERROR] Invalid CCI file (invalid ncch0)\n");
|
||||||
return FAILED_TO_IMPORT_FILE;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
@@ -445,36 +507,45 @@ int GetSettingsFromCci(cia_settings *ciaset)
|
|||||||
fprintf(stderr,"Import of Ncch 0 failed(%d)\n",result);
|
fprintf(stderr,"Import of Ncch 0 failed(%d)\n",result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
ciaset->content.contentCount = 1;
|
int j = 1;
|
||||||
ciaset->content.cciContentOffsets[0] = ncch0_offset;
|
|
||||||
ncch_hdr *hdr = malloc(sizeof(ncch_hdr));
|
u64 cciContentOffsets[CCI_MAX_CONTENT];
|
||||||
|
cciContentOffsets[0] = ncch0_offset;
|
||||||
|
ncch_hdr *hdr;
|
||||||
for(int i = 1; i < 8; i++){
|
for(int i = 1; i < 8; i++){
|
||||||
if(GetPartitionSize(ciaset->inFile,i)){
|
if(GetPartitionSize(ciaset->ciaSections.content.buffer,i)){
|
||||||
ciaset->content.cciContentOffsets[ciaset->content.contentCount] = GetPartitionOffset(ciaset->inFile,i);
|
cciContentOffsets[j] = GetPartitionOffset(ciaset->ciaSections.content.buffer,i);
|
||||||
|
|
||||||
// Get Data from ncch HDR
|
// 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
|
// Get Size
|
||||||
ciaset->content.contentSize[ciaset->content.contentCount] = GetPartitionSize(ciaset->inFile,i);
|
ciaset->content.contentSize[j] = GetPartitionSize(ciaset->ciaSections.content.buffer,i);
|
||||||
ciaset->content.contentOffset[ciaset->content.contentCount] = ciaset->content.totalContentSize;
|
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
|
// Get ID
|
||||||
u8 hash[0x20];
|
u8 hash[0x20];
|
||||||
ctr_sha((u8*)hdr,0x200,hash,CTR_SHA_256);
|
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
|
// Get Index
|
||||||
ciaset->content.contentIndex[ciaset->content.contentCount] = i;
|
ciaset->content.contentIndex[j] = i;
|
||||||
|
|
||||||
// Increment Content Count
|
// 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,6 +554,21 @@ u16 SetupVersion(u16 Major, u16 Minor, u16 Micro)
|
|||||||
return (((Major << 10) & 0xFC00) | ((Minor << 4) & 0x3F0) | (Micro & 0xf));
|
return (((Major << 10) & 0xFC00) | ((Minor << 4) & 0x3F0) | (Micro & 0xf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetContentHashes(cia_settings *ciaset)
|
||||||
|
{
|
||||||
|
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)
|
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);
|
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
|
// Clearing
|
||||||
memset(hdr,0,sizeof(cia_hdr));
|
memset(hdr,0,sizeof(cia_hdr));
|
||||||
|
|
||||||
// Predict TMD Size
|
|
||||||
ciaset->ciaSections.tmd.size = PredictTMDSize(ciaset->content.contentCount);
|
|
||||||
|
|
||||||
// Setting Data
|
// Setting Data
|
||||||
u32_to_u8(hdr->hdrSize,sizeof(cia_hdr),LE);
|
u32_to_u8(hdr->hdrSize,sizeof(cia_hdr),LE);
|
||||||
u16_to_u8(hdr->type,0x0,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);
|
u64_to_u8(hdr->contentSize,ciaset->content.totalContentSize,LE);
|
||||||
|
|
||||||
// Recording Offsets
|
// Recording Offsets
|
||||||
ciaset->ciaSections.certChainOffset = align_value(sizeof(cia_hdr),0x40);
|
ciaset->ciaSections.certChainOffset = align(sizeof(cia_hdr),0x40);
|
||||||
ciaset->ciaSections.tikOffset = align_value(ciaset->ciaSections.certChainOffset+ciaset->ciaSections.certChain.size,0x40);
|
ciaset->ciaSections.tikOffset = align(ciaset->ciaSections.certChainOffset+ciaset->ciaSections.certChain.size,0x40);
|
||||||
ciaset->ciaSections.tmdOffset = align_value(ciaset->ciaSections.tikOffset+ciaset->ciaSections.tik.size,0x40);
|
ciaset->ciaSections.tmdOffset = align(ciaset->ciaSections.tikOffset+ciaset->ciaSections.tik.size,0x40);
|
||||||
ciaset->ciaSections.contentOffset = align_value(ciaset->ciaSections.tmdOffset+ciaset->ciaSections.tmd.size,0x40);
|
ciaset->ciaSections.contentOffset = align(ciaset->ciaSections.tmdOffset+ciaset->ciaSections.tmd.size,0x40);
|
||||||
ciaset->ciaSections.metaOffset = align_value(ciaset->ciaSections.contentOffset+ciaset->content.totalContentSize,0x40);
|
ciaset->ciaSections.metaOffset = align(ciaset->ciaSections.contentOffset+ciaset->content.totalContentSize,0x40);
|
||||||
|
|
||||||
for(int i = 0; i < ciaset->content.contentCount; i++){
|
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
|
// 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;
|
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.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.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.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);
|
WriteBuffer(ciaset->ciaSections.meta.buffer,ciaset->ciaSections.meta.size,ciaset->ciaSections.metaOffset,ciaset->out);
|
||||||
return 0;
|
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)
|
int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, u8 mode)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
// Enums
|
// Enums
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -84,7 +86,6 @@ typedef struct
|
|||||||
bool keyNotFound;
|
bool keyNotFound;
|
||||||
|
|
||||||
FILE **contentFilePtrs;
|
FILE **contentFilePtrs;
|
||||||
u64 cciContentOffsets[CCI_MAX_CONTENT];
|
|
||||||
|
|
||||||
/* Misc Records */
|
/* Misc Records */
|
||||||
u16 contentCount;
|
u16 contentCount;
|
||||||
@@ -96,28 +97,26 @@ typedef struct
|
|||||||
u16 contentIndex[CIA_MAX_CONTENT];
|
u16 contentIndex[CIA_MAX_CONTENT];
|
||||||
u16 contentFlags[CIA_MAX_CONTENT];
|
u16 contentFlags[CIA_MAX_CONTENT];
|
||||||
u32 contentId[CIA_MAX_CONTENT];
|
u32 contentId[CIA_MAX_CONTENT];
|
||||||
u8 contentHash[CIA_MAX_CONTENT][0x20];
|
u8 contentHash[CIA_MAX_CONTENT][0x20];
|
||||||
|
|
||||||
u8 contentTitleId[CIA_MAX_CONTENT][8];
|
|
||||||
|
|
||||||
} content;
|
} content;
|
||||||
|
|
||||||
struct{
|
struct{
|
||||||
COMPONENT_STRUCT ciaHdr;
|
buffer_struct ciaHdr;
|
||||||
|
|
||||||
u32 certChainOffset;
|
u32 certChainOffset;
|
||||||
COMPONENT_STRUCT certChain;
|
buffer_struct certChain;
|
||||||
|
|
||||||
u32 tikOffset;
|
u32 tikOffset;
|
||||||
COMPONENT_STRUCT tik;
|
buffer_struct tik;
|
||||||
|
|
||||||
u32 tmdOffset;
|
u32 tmdOffset;
|
||||||
COMPONENT_STRUCT tmd;
|
buffer_struct tmd;
|
||||||
|
|
||||||
u32 metaOffset;
|
u32 metaOffset;
|
||||||
COMPONENT_STRUCT meta;
|
buffer_struct meta;
|
||||||
|
|
||||||
u64 contentOffset;
|
u64 contentOffset;
|
||||||
|
buffer_struct content;
|
||||||
} ciaSections;
|
} ciaSections;
|
||||||
} cia_settings;
|
} cia_settings;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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 *KeyX_u32 = (u32*) KeyX;
|
||||||
u32 *KeyY_u32 = (u32*) KeyY;
|
u32 *KeyY_u32 = (u32*) KeyY;
|
||||||
u32 *Key = malloc(16);
|
u32 *Key_u32 = (u32*) Key;
|
||||||
|
|
||||||
for(int i = 0,j; i < 4; i++)
|
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
|
// Done Stuff
|
||||||
return (u8*)Key;
|
return (u8*)Key_u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctr_add_counter(ctr_aes_context* ctx, u32 carry)
|
void ctr_add_counter(ctr_aes_context* ctx, u32 carry)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _CTR_CRYPTO_H_
|
#pragma once
|
||||||
#define _CTR_CRYPTO_H_
|
|
||||||
|
|
||||||
#include "polarssl/config.h"
|
#include "polarssl/config.h"
|
||||||
#include "polarssl/aes.h"
|
#include "polarssl/aes.h"
|
||||||
@@ -74,7 +73,7 @@ extern "C" {
|
|||||||
// SHA
|
// SHA
|
||||||
void ctr_sha(void *data, u64 size, u8 *hash, int mode);
|
void ctr_sha(void *data, u64 size, u8 *hash, int mode);
|
||||||
// AES
|
// 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_add_counter(ctr_aes_context* ctx, u32 carry);
|
||||||
void ctr_init_counter(ctr_aes_context* ctx, u8 key[16],u8 ctr[16]);
|
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]);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
+2
-4
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _DESC_DEV_SIGDATA_H_
|
#pragma once
|
||||||
#define _DESC_DEV_SIGDATA_H_
|
|
||||||
|
|
||||||
/* CTR_SDK 1 (1.2.0) */
|
/* CTR_SDK 1 (1.2.0) */
|
||||||
// APP
|
// APP
|
||||||
@@ -114,5 +113,4 @@ static const unsigned char dlp_4_dev_hdrpvt[0x100] =
|
|||||||
static const unsigned char dlp_4_dev_acexsig[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
|
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
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _DESC_PRESETS_H_
|
#pragma once
|
||||||
#define _DESC_PRESETS_H_
|
|
||||||
|
|
||||||
/* CTR_SDK 1 (1.2.0) */
|
/* CTR_SDK 1 (1.2.0) */
|
||||||
// DependencyList
|
// DependencyList
|
||||||
@@ -80,6 +79,4 @@ static const unsigned char sdk7_dep_list[0x180] =
|
|||||||
static const unsigned char app_7_acex_data[0x200] =
|
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
|
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
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _DESC_PROD_SIGDATA_H_
|
#pragma once
|
||||||
#define _DESC_PROD_SIGDATA_H_
|
|
||||||
|
|
||||||
/* CTR_SDK 4/5 (4.2.8) */
|
/* CTR_SDK 4/5 (4.2.8) */
|
||||||
// APP
|
// 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
|
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
|
|
||||||
@@ -0,0 +1,327 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
#include "dir.h"
|
||||||
|
#include "utf.h"
|
||||||
|
|
||||||
|
/* This is mainly a FS interface for ROMFS generation */
|
||||||
|
|
||||||
|
|
||||||
|
int fs_InitDir(u16 *path, u32 pathlen, fs_dir *dir);
|
||||||
|
int fs_ManageDirSlot(fs_dir *dir);
|
||||||
|
int fs_ManageFileSlot(fs_dir *dir);
|
||||||
|
void fs_chdirUp(void);
|
||||||
|
fs_entry* fs_GetEntry(fs_DIR *dp);
|
||||||
|
void fs_FreeEntry(fs_entry *entry);
|
||||||
|
bool fs_EntryIsDirNav(fs_entry *entry);
|
||||||
|
int fs_AddDir(fs_entry *entry, fs_dir *dir);
|
||||||
|
int fs_AddFile(fs_entry *entry, fs_dir *dir);
|
||||||
|
|
||||||
|
int fs_InitDir(u16 *path, u32 pathlen, fs_dir *dir)
|
||||||
|
{
|
||||||
|
dir->name_len = pathlen;
|
||||||
|
dir->name = calloc(dir->name_len+2,1);
|
||||||
|
memcpy(dir->name,path,dir->name_len);
|
||||||
|
|
||||||
|
|
||||||
|
dir->m_dir = 10;
|
||||||
|
dir->u_dir = 0;
|
||||||
|
dir->dir = calloc(dir->m_dir,sizeof(fs_dir));
|
||||||
|
|
||||||
|
dir->m_file = 10;
|
||||||
|
dir->u_file = 0;
|
||||||
|
dir->file = calloc(dir->m_file,sizeof(fs_file));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_ManageDirSlot(fs_dir *dir)
|
||||||
|
{
|
||||||
|
if(dir->u_dir >= dir->m_dir)
|
||||||
|
{
|
||||||
|
dir->m_dir *= 2;
|
||||||
|
fs_dir *tmp = calloc(dir->m_dir,sizeof(fs_dir));
|
||||||
|
memcpy(tmp,dir->dir,sizeof(fs_dir)*dir->u_dir);
|
||||||
|
free(dir->dir);
|
||||||
|
dir->dir = tmp;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_ManageFileSlot(fs_dir *dir)
|
||||||
|
{
|
||||||
|
if(dir->u_file >= dir->m_file)
|
||||||
|
{
|
||||||
|
dir->m_file *= 2;
|
||||||
|
fs_file *tmp = calloc(dir->m_file,sizeof(fs_file));
|
||||||
|
memcpy(tmp,dir->file,sizeof(fs_file)*dir->u_file);
|
||||||
|
free(dir->file);
|
||||||
|
dir->file = tmp;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_chdirUp(void)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
fs_chdir(L"..");
|
||||||
|
#else
|
||||||
|
fs_chdir("..");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_entry* fs_GetEntry(fs_DIR *dp)
|
||||||
|
{
|
||||||
|
// Directory structs
|
||||||
|
struct fs_dirent *tmp_entry;
|
||||||
|
fs_DIR *tmp_dptr;
|
||||||
|
u32 namlen = 0;
|
||||||
|
|
||||||
|
//printf("get api dir entry from dir ptr\n");
|
||||||
|
tmp_entry = fs_readdir(dp);
|
||||||
|
|
||||||
|
//printf("if null, return\n");
|
||||||
|
if(!tmp_entry)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
namlen = tmp_entry->d_namlen;
|
||||||
|
#else
|
||||||
|
namlen = strlen(tmp_entry->d_name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//printf("allocate memory for entry\n");
|
||||||
|
fs_entry *entry = malloc(sizeof(fs_entry));
|
||||||
|
memset(entry,0,sizeof(fs_entry));
|
||||||
|
|
||||||
|
//Copy FS compatible Entry name
|
||||||
|
entry->fs_name = malloc(sizeof(fs_char)*(namlen+1));
|
||||||
|
memset(entry->fs_name,0,sizeof(fs_char)*(namlen+1));
|
||||||
|
memcpy(entry->fs_name,tmp_entry->d_name,sizeof(fs_char)*namlen);
|
||||||
|
|
||||||
|
// Convert Entry name into RomFS u16 char (windows wchar_t, thanks Nintendo)
|
||||||
|
#if _WIN32
|
||||||
|
str_u16_to_u16(&entry->name,&entry->name_len,tmp_entry->d_name,namlen);
|
||||||
|
#else
|
||||||
|
str_utf8_to_u16(&entry->name,&entry->name_len,(u8*)tmp_entry->d_name,namlen);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//printf("get dir entry from dir ptr to check if dir\n");
|
||||||
|
tmp_dptr = fs_opendir(entry->fs_name);
|
||||||
|
if(tmp_dptr)
|
||||||
|
{
|
||||||
|
//printf("is dir\n");
|
||||||
|
fs_closedir(tmp_dptr);
|
||||||
|
entry->IsDir = true;
|
||||||
|
entry->size = 0;
|
||||||
|
entry->fp = NULL;
|
||||||
|
}
|
||||||
|
else // Open file if it is a file
|
||||||
|
{
|
||||||
|
entry->IsDir = false;
|
||||||
|
#ifdef _WIN32
|
||||||
|
entry->size = wGetFileSize_u64(entry->fs_name);
|
||||||
|
entry->fp = _wfopen(entry->fs_name,L"rb");
|
||||||
|
#else
|
||||||
|
entry->size = GetFileSize_u64(entry->fs_name);
|
||||||
|
entry->fp = fopen(entry->fs_name,"rb");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
//printf("fs_GetEntry() return\n");
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_FreeEntry(fs_entry *entry)
|
||||||
|
{
|
||||||
|
free(entry->fs_name);
|
||||||
|
free(entry->name);
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fs_EntryIsDirNav(fs_entry *entry)
|
||||||
|
{
|
||||||
|
//memdump(stdout,"Entry RomFS Name: ",(u8*)entry->name,entry->name_len);
|
||||||
|
const fs_romfs_char currentdir = 0x2E;
|
||||||
|
const fs_romfs_char upperdir[2] = {0x2E,0x2E};
|
||||||
|
if(entry->name_len == sizeof(fs_romfs_char)*1 && memcmp(entry->name,¤tdir,sizeof(fs_romfs_char)*1) == 0)
|
||||||
|
return true;
|
||||||
|
if(entry->name_len == sizeof(fs_romfs_char)*2 && memcmp(entry->name,upperdir,sizeof(fs_romfs_char)*2) == 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_AddDir(fs_entry *entry, fs_dir *dir)
|
||||||
|
{
|
||||||
|
fs_ManageDirSlot(dir);
|
||||||
|
u32 current_slot = dir->u_dir;
|
||||||
|
dir->u_dir++;
|
||||||
|
fs_dir *tmp = (fs_dir*)dir->dir;
|
||||||
|
return fs_OpenDir(entry->fs_name,entry->name,entry->name_len,&tmp[current_slot]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_AddFile(fs_entry *entry, fs_dir *dir)
|
||||||
|
{
|
||||||
|
fs_ManageFileSlot(dir);
|
||||||
|
dir->file[dir->u_file].name_len = entry->name_len;
|
||||||
|
dir->file[dir->u_file].name = malloc(entry->name_len+2);
|
||||||
|
memset(dir->file[dir->u_file].name,0,entry->name_len+2);
|
||||||
|
memcpy(dir->file[dir->u_file].name,entry->name,entry->name_len);
|
||||||
|
|
||||||
|
dir->file[dir->u_file].size = entry->size;
|
||||||
|
dir->file[dir->u_file].fp = entry->fp;
|
||||||
|
|
||||||
|
dir->u_file++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fs_OpenDir(fs_char *fs_path, fs_romfs_char *path, u32 pathlen, fs_dir *dir)
|
||||||
|
{
|
||||||
|
//printf("init open dir\n");
|
||||||
|
int ret = 0;
|
||||||
|
fs_DIR *dp;
|
||||||
|
fs_entry *entry;
|
||||||
|
|
||||||
|
//printf("check if path exists\n");
|
||||||
|
dp = fs_opendir(fs_path);
|
||||||
|
if(!dp)
|
||||||
|
{
|
||||||
|
//wprintf(L"[!] Failed to open directory: \"%s\"\n",path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("do some more init\n");
|
||||||
|
fs_InitDir(path,pathlen,dir);
|
||||||
|
//wprintf(L" rec: \"%s\" (%d)\n",dir->name,dir->name_len);
|
||||||
|
|
||||||
|
//printf("chdir\n");
|
||||||
|
fs_chdir(fs_path);
|
||||||
|
|
||||||
|
//printf("read entries\n");
|
||||||
|
while((entry = fs_GetEntry(dp)))
|
||||||
|
{
|
||||||
|
if(!entry)
|
||||||
|
{
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(entry->IsDir)
|
||||||
|
{
|
||||||
|
//printf("Found Dir ");
|
||||||
|
if(!fs_EntryIsDirNav(entry))
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
//wprintf(L"is a dir: \"%s\" (%d)\n",entry->fs_name,entry->name_len);
|
||||||
|
#else
|
||||||
|
//printf("is a dir: \"%s\" (%d)\n",entry->fs_name,entry->name_len);
|
||||||
|
#endif
|
||||||
|
ret = fs_AddDir(entry,dir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//printf("Not wanted dir\n");
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
//wprintf(L"is a file: \"%s\" (%d)\n",entry->fs_name,entry->name_len);
|
||||||
|
#else
|
||||||
|
//printf("is a file: \"%s\" (%d)\n",entry->fs_name,entry->name_len);
|
||||||
|
#endif
|
||||||
|
ret = fs_AddFile(entry,dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("free entry\n");
|
||||||
|
fs_FreeEntry(entry);
|
||||||
|
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
//printf("error parsing entry\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//printf("close dir ptr\n");
|
||||||
|
fs_closedir(dp);
|
||||||
|
//printf("return up dir\n");
|
||||||
|
fs_chdirUp();
|
||||||
|
//printf("return from fs_OpenDir();\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fs_PrintDir(fs_dir *dir, u32 depth) // This is just for simple debugging, please don't shoot me
|
||||||
|
{
|
||||||
|
for(u32 i = 0; i < depth; i++)
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
wprintf(L"%s\n",dir->name);
|
||||||
|
#else
|
||||||
|
char *name = (char*)dir->name;
|
||||||
|
for(u32 i = 0; i < dir->name_len; i+=2)
|
||||||
|
putchar(name[i]);
|
||||||
|
putchar('\n');
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(dir->u_file)
|
||||||
|
{
|
||||||
|
for(u32 i = 0; i < dir->u_file; i++)
|
||||||
|
{
|
||||||
|
for(u32 j = 0; j < depth+1; j++)
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
wprintf(L"%s (0x%lx)\n",dir->file[i].name,dir->file[i].size);
|
||||||
|
#else
|
||||||
|
name = (char*)dir->file[i].name;
|
||||||
|
for(u32 j = 0; j < dir->file[i].name_len; j+=2)
|
||||||
|
putchar(name[j]);
|
||||||
|
printf(" (0x%lx)\n",dir->file[i].size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(dir->u_dir)
|
||||||
|
{
|
||||||
|
fs_dir *tmp = (fs_dir*)dir->dir;
|
||||||
|
for(u32 i = 0; i < dir->u_dir; i++)
|
||||||
|
fs_PrintDir(&tmp[i],depth+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_FreeDir(fs_dir *dir)
|
||||||
|
{
|
||||||
|
//printf("DIR!! free file names\n");
|
||||||
|
for(u32 i = 0; i < dir->u_file; i++)
|
||||||
|
{
|
||||||
|
free(dir->file[i].name);
|
||||||
|
}
|
||||||
|
//printf("free file struct\n");
|
||||||
|
free(dir->file);
|
||||||
|
|
||||||
|
|
||||||
|
fs_dir *tmp = (fs_dir*)dir->dir;
|
||||||
|
//printf("free dir names\n");
|
||||||
|
for(u32 i = 0; i < dir->u_dir; i++)
|
||||||
|
{
|
||||||
|
//wprintf(L"freeing: %s\n",tmp[i].name);
|
||||||
|
free(tmp[i].name);
|
||||||
|
fs_FreeDir(&tmp[i]);
|
||||||
|
}
|
||||||
|
//printf("free dir struct\n");
|
||||||
|
free(dir->dir);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_FreeFiles(fs_dir *dir)
|
||||||
|
{
|
||||||
|
for(u32 i = 0; i < dir->u_file; i++)
|
||||||
|
{
|
||||||
|
if(dir->file[i].fp)
|
||||||
|
fclose(dir->file[i].fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_dir *tmp = (fs_dir*)dir->dir;
|
||||||
|
for(u32 i = 0; i < dir->u_dir; i++)
|
||||||
|
fs_FreeFiles(&tmp[i]);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _DPKI_H_
|
#pragma once
|
||||||
#define _DPKI_H_
|
|
||||||
|
|
||||||
#ifdef PKI_LEGACY
|
#ifdef PKI_LEGACY
|
||||||
#include "dpki_legacy.h"
|
#include "dpki_legacy.h"
|
||||||
@@ -381,7 +380,7 @@ static const unsigned char dev_acex_pub[0x100] =
|
|||||||
0x29, 0x78, 0xBF, 0x2A, 0x3C, 0x3B, 0xB6, 0xB1
|
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,
|
0xC5, 0xF7, 0x09, 0x80, 0x5F, 0xDA, 0xDC, 0xBD,
|
||||||
0x46, 0x07, 0x52, 0xAA, 0x6D, 0xCD, 0x72, 0xB2,
|
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
|
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,
|
0x96, 0x5C, 0xBE, 0x5E, 0xEF, 0x08, 0x0B, 0x29,
|
||||||
0xEF, 0x95, 0x12, 0xA4, 0x80, 0x36, 0x47, 0xD5,
|
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
|
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,
|
0x8D, 0x27, 0x29, 0x6B, 0xC7, 0xA7, 0xED, 0xCD,
|
||||||
0x94, 0x2D, 0x36, 0x5E, 0x86, 0xA8, 0x26, 0xE7,
|
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
|
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,
|
0xE2, 0xAD, 0xA6, 0xEA, 0xCA, 0xA3, 0xE8, 0xCC,
|
||||||
0xA9, 0x70, 0x1D, 0x2E, 0x23, 0x4B, 0xC6, 0x55,
|
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,
|
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
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _DPKI_LEGACY_H_
|
#pragma once
|
||||||
#define _DPKI_LEGACY_H_
|
|
||||||
|
|
||||||
// AES Keys
|
// AES Keys
|
||||||
static const unsigned char rvl_twl_common_etd_key_dpki[1][16] =
|
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] =
|
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
|
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
|
|
||||||
@@ -147,7 +147,7 @@ finish:
|
|||||||
|
|
||||||
int ImportPlainRegionFromFile(ncch_settings *ncchset)
|
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);
|
ncchset->sections.plainRegion.buffer = malloc(ncchset->sections.plainRegion.size);
|
||||||
if(!ncchset->sections.plainRegion.buffer) {fprintf(stderr,"[ELF ERROR] MEM ERROR\n"); return MEM_ERROR;}
|
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);
|
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)
|
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 */
|
/* 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);
|
ncchset->sections.plainRegion.buffer = malloc(ncchset->sections.plainRegion.size);
|
||||||
if(!ncchset->sections.plainRegion.buffer) {fprintf(stderr,"[ELF ERROR] MEM ERROR\n"); return MEM_ERROR;}
|
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);
|
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;
|
u32 vAddr = Segments[0]->vAddr + Segments[0]->header->sizeInMemory;
|
||||||
for (int i = 1; i < SegmentNum; i++){
|
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);
|
fprintf(stderr,"[ELF ERROR] %s segment and %s segment are not continuous\n", Segments[i]->name, Segments[i - 1]->name);
|
||||||
free(Segments);
|
free(Segments);
|
||||||
*ContinuousSegmentNum = 0xffff; // Signify to function that an error occured
|
*ContinuousSegmentNum = 0xffff; // Signify to function that an error occured
|
||||||
@@ -938,7 +938,7 @@ int CreateElfSegments(ElfContext *elf, u8 *ElfFile)
|
|||||||
if(size == 0)
|
if(size == 0)
|
||||||
size = elf->sections[j].size;
|
size = elf->sections[j].size;
|
||||||
else
|
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("Section Name: %s",elf->sections[j].name);
|
||||||
//printf(" 0x%lx",elf->sections[j].size);
|
//printf(" 0x%lx",elf->sections[j].size);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _ELF_H_
|
#pragma once
|
||||||
#define _ELF_H_
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -82,6 +81,4 @@ typedef struct
|
|||||||
|
|
||||||
} ElfContext;
|
} ElfContext;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int BuildExeFsCode(ncch_settings *ncchset);
|
int BuildExeFsCode(ncch_settings *ncchset);
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _ELF_HDR_H_
|
#pragma once
|
||||||
#define _ELF_HDR_H_
|
|
||||||
|
|
||||||
static const u32 ELF_MAGIC = 0x7f454c46;
|
static const u32 ELF_MAGIC = 0x7f454c46;
|
||||||
|
|
||||||
@@ -174,5 +173,4 @@ typedef struct
|
|||||||
u8 p_filesz[8]; /* Segment size in file */
|
u8 p_filesz[8]; /* Segment size in file */
|
||||||
u8 p_memsz[8]; /* Segment size in memory */
|
u8 p_memsz[8]; /* Segment size in memory */
|
||||||
u8 p_align[8]; /* Segment alignment */
|
u8 p_align[8]; /* Segment alignment */
|
||||||
} elf_64_phdr;
|
} elf_64_phdr;
|
||||||
#endif
|
|
||||||
@@ -3,21 +3,21 @@
|
|||||||
#include "exefs.h"
|
#include "exefs.h"
|
||||||
|
|
||||||
// Private Prototypes
|
// Private Prototypes
|
||||||
u32 PredictExeFS_Size(ExeFs_BuildContext *ctx);
|
u32 PredictExeFS_Size(exefs_buildctx *ctx);
|
||||||
int GenerateExeFS_Header(ExeFs_BuildContext *ctx, u8 *outbuff);
|
int GenerateExeFS_Header(exefs_buildctx *ctx, u8 *outbuff);
|
||||||
void InitialiseExeFSContext(ExeFs_BuildContext *ctx);
|
void InitialiseExeFSContext(exefs_buildctx *ctx);
|
||||||
void FreeExeFSContext(ExeFs_BuildContext *ctx);
|
void FreeExeFSContext(exefs_buildctx *ctx);
|
||||||
int ImportDatatoExeFS(ExeFs_BuildContext *ctx, u8 *outbuff);
|
int ImportDatatoExeFS(exefs_buildctx *ctx, u8 *outbuff);
|
||||||
int ImportToExeFSContext(ExeFs_BuildContext *ctx, char *lable, u8 *buffer, u32 size);
|
int ImportToExeFSContext(exefs_buildctx *ctx, char *name, u8 *buffer, u32 size);
|
||||||
|
|
||||||
// ExeFs Build Functions
|
// ExeFs Build Functions
|
||||||
int BuildExeFs(ncch_settings *ncchset)
|
int BuildExeFs(ncch_settings *ncchset)
|
||||||
{
|
{
|
||||||
/* Intialising ExeFs Build Context */
|
/* 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;}
|
if(!ctx) {fprintf(stderr,"[EXEFS ERROR] MEM ERROR\n"); return MEM_ERROR;}
|
||||||
InitialiseExeFSContext(ctx);
|
InitialiseExeFSContext(ctx);
|
||||||
ctx->media_unit = ncchset->options.mediaSize;
|
ctx->mediaUnit = ncchset->options.mediaSize;
|
||||||
|
|
||||||
/* Importing ExeFs */
|
/* Importing ExeFs */
|
||||||
if(ncchset->exefsSections.code.size)
|
if(ncchset->exefsSections.code.size)
|
||||||
@@ -47,98 +47,98 @@ int BuildExeFs(ncch_settings *ncchset)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 PredictExeFS_Size(ExeFs_BuildContext *ctx)
|
u32 PredictExeFS_Size(exefs_buildctx *ctx)
|
||||||
{
|
{
|
||||||
u32 exefs_size = 0x200; // Size of header
|
u32 exefs_size = 0x200; // Size of header
|
||||||
for(int i = 0; i < ctx->section_count; i++){
|
for(int i = 0; i < ctx->fileCount; i++){
|
||||||
exefs_size += align_value(ctx->section_size[i],ctx->media_unit);
|
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;
|
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)
|
if(i == 0)
|
||||||
ctx->section_offset[i] = 0;
|
ctx->fileOffset[i] = 0;
|
||||||
else
|
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);
|
memcpy(ctx->fileHdr[i].name,ctx->fileName[i],8);
|
||||||
u32_to_u8(ctx->file_header[i].offset,ctx->section_offset[i],LE);
|
u32_to_u8(ctx->fileHdr[i].offset,ctx->fileOffset[i],LE);
|
||||||
u32_to_u8(ctx->file_header[i].size,ctx->section_size[i],LE);
|
u32_to_u8(ctx->fileHdr[i].size,ctx->fileSize[i],LE);
|
||||||
ctr_sha(ctx->section[i],ctx->section_size[i],ctx->file_hashes[9-i],CTR_SHA_256);
|
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,ctx->fileHdr,sizeof(exefs_filehdr)*10);
|
||||||
memcpy(outbuff+0xc0,ctx->file_hashes,0x20*10);
|
memcpy(outbuff+0xc0,ctx->fileHashes,0x20*10);
|
||||||
return 0;
|
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)
|
if(ctx->outbuff != NULL)
|
||||||
free(ctx->outbuff);
|
free(ctx->outbuff);
|
||||||
for(int i = 0; i < 10; i++){
|
for(int i = 0; i < 10; i++){
|
||||||
if(ctx->section[i] != NULL)
|
if(ctx->file[i] != NULL)
|
||||||
free(ctx->section[i]);
|
free(ctx->file[i]);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
memset(ctx,0,sizeof(ExeFs_BuildContext));
|
memset(ctx,0,sizeof(exefs_buildctx));
|
||||||
free(ctx);
|
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++){
|
for(int i = 0; i < ctx->fileCount; i++){
|
||||||
memcpy(outbuff+ctx->section_offset[i]+0x200,ctx->section[i],ctx->section_size[i]);
|
memcpy(outbuff+ctx->fileOffset[i]+0x200,ctx->file[i],ctx->fileSize[i]);
|
||||||
}
|
}
|
||||||
return 0;
|
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");
|
printf("[!] PTR ERROR\n");
|
||||||
return PTR_ERROR;
|
return PTR_ERROR;
|
||||||
}
|
}
|
||||||
if(ctx->section_count >= 10){
|
if(ctx->fileCount >= MAX_EXEFS_SECTIONS){
|
||||||
printf("[!] Maximum ExeFS Capacity Reached\n");
|
printf("[!] Maximum ExeFS Capacity Reached\n");
|
||||||
return EXEFS_MAX_REACHED;
|
return EXEFS_MAX_REACHED;
|
||||||
}
|
}
|
||||||
if(strlen(lable) > 8){
|
if(strlen(name) > 8){
|
||||||
printf("[!] ExeFS Section Name: '%s' is too large\n",lable);
|
printf("[!] ExeFS File Name: '%s' is too large\n",name);
|
||||||
return EXEFS_SECTION_NAME_ERROR;
|
return EXEFS_SECTION_NAME_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->section_count++;
|
ctx->fileCount++;
|
||||||
ctx->section[ctx->section_count - 1] = buffer;
|
ctx->file[ctx->fileCount - 1] = buffer;
|
||||||
ctx->section_size[ctx->section_count - 1] = size;
|
ctx->fileSize[ctx->fileCount - 1] = size;
|
||||||
strcpy(ctx->lable[ctx->section_count - 1],lable);
|
strcpy(ctx->fileName[ctx->fileCount - 1],name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExeFs Read Functions
|
// ExeFs Read Functions
|
||||||
bool DoesExeFsSectionExist(char *section, u8 *ExeFs)
|
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++){
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
u8* GetExeFsSection(char *section, u8 *ExeFs)
|
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++){
|
for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){
|
||||||
if(strncmp(hdr->SectionHdr[i].name,section,8) == 0){
|
if(strncmp(hdr->fileHdr[i].name,section,8) == 0){
|
||||||
u32 offset = u8_to_u32(hdr->SectionHdr[i].offset,LE) + sizeof(ExeFs_Header);
|
u32 offset = u8_to_u32(hdr->fileHdr[i].offset,LE) + sizeof(exefs_hdr);
|
||||||
return (u8*)(ExeFs+offset);
|
return (u8*)(ExeFs+offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,10 +147,10 @@ u8* GetExeFsSection(char *section, u8 *ExeFs)
|
|||||||
|
|
||||||
u8* GetExeFsSectionHash(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++){
|
for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){
|
||||||
if(strncmp(hdr->SectionHdr[i].name,section,8) == 0){
|
if(strncmp(hdr->fileHdr[i].name,section,8) == 0){
|
||||||
return (u8*)(hdr->SectionHashes[MAX_EXEFS_SECTIONS-1-i]);
|
return (u8*)(hdr->fileHashes[MAX_EXEFS_SECTIONS-1-i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -158,10 +158,10 @@ u8* GetExeFsSectionHash(char *section, u8 *ExeFs)
|
|||||||
|
|
||||||
u32 GetExeFsSectionSize(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++){
|
for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){
|
||||||
if(strncmp(hdr->SectionHdr[i].name,section,8) == 0){
|
if(strncmp(hdr->fileHdr[i].name,section,8) == 0){
|
||||||
return u8_to_u32(hdr->SectionHdr[i].size,LE);
|
return u8_to_u32(hdr->fileHdr[i].size,LE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -169,10 +169,10 @@ u32 GetExeFsSectionSize(char *section, u8 *ExeFs)
|
|||||||
|
|
||||||
u32 GetExeFsSectionOffset(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++){
|
for(int i = 0; i < MAX_EXEFS_SECTIONS; i++){
|
||||||
if(strncmp(hdr->SectionHdr[i].name,section,8) == 0){
|
if(strncmp(hdr->fileHdr[i].name,section,8) == 0){
|
||||||
return u8_to_u32(hdr->SectionHdr[i].offset,LE) + sizeof(ExeFs_Header);
|
return u8_to_u32(hdr->fileHdr[i].offset,LE) + sizeof(exefs_hdr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _EXEFS_H_
|
#pragma once
|
||||||
#define _EXEFS_H_
|
|
||||||
|
|
||||||
#define MAX_EXEFS_SECTIONS 10 // DO NOT CHANGE
|
#define MAX_EXEFS_SECTIONS 10 // DO NOT CHANGE
|
||||||
|
|
||||||
@@ -16,32 +15,30 @@ typedef struct
|
|||||||
char name[8];
|
char name[8];
|
||||||
u8 offset[4];
|
u8 offset[4];
|
||||||
u8 size[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
|
typedef struct
|
||||||
{
|
{
|
||||||
//Input
|
//Input
|
||||||
int section_count;
|
int fileCount;
|
||||||
u8 *section[10];
|
u8 *file[MAX_EXEFS_SECTIONS];
|
||||||
u32 section_size[10];
|
u32 fileSize[MAX_EXEFS_SECTIONS];
|
||||||
u32 section_offset[10];
|
u32 fileOffset[MAX_EXEFS_SECTIONS];
|
||||||
char lable[10][8];
|
char fileName[MAX_EXEFS_SECTIONS][8];
|
||||||
u32 media_unit;
|
u32 mediaUnit;
|
||||||
|
|
||||||
//Working Data
|
//Working Data
|
||||||
ExeFs_FileHeader file_header[10];
|
exefs_filehdr fileHdr[MAX_EXEFS_SECTIONS];
|
||||||
u8 file_hashes[10][0x20];
|
u8 fileHashes[MAX_EXEFS_SECTIONS][0x20];
|
||||||
|
|
||||||
} ExeFs_BuildContext;
|
} exefs_buildctx;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
ExeFs_FileHeader SectionHdr[MAX_EXEFS_SECTIONS];
|
|
||||||
u8 Reserved[0x20];
|
|
||||||
u8 SectionHashes[MAX_EXEFS_SECTIONS][0x20];
|
|
||||||
} ExeFs_Header;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ExeFs Build Functions */
|
/* ExeFs Build Functions */
|
||||||
int BuildExeFs(ncch_settings *ncchset);
|
int BuildExeFs(ncch_settings *ncchset);
|
||||||
|
|||||||
+12
-359
@@ -1,15 +1,9 @@
|
|||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "ncch.h"
|
#include "ncch.h"
|
||||||
#include "exheader.h"
|
#include "exheader.h"
|
||||||
|
#include "accessdesc.h"
|
||||||
#include "titleid.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 */
|
/* Prototypes */
|
||||||
void init_ExHeaderSettings(exheader_settings *exhdrset);
|
void init_ExHeaderSettings(exheader_settings *exhdrset);
|
||||||
@@ -56,16 +50,6 @@ void AllocateARM11KernelDescMemory(ARM11KernelCapabilityDescriptor *desc, u16 Nu
|
|||||||
u32 GetDescPrefixMask(int numPrefixBits);
|
u32 GetDescPrefixMask(int numPrefixBits);
|
||||||
u32 GetDescPrefixBits(int numPrefixBits, u32 PrefixVal);
|
u32 GetDescPrefixBits(int numPrefixBits, u32 PrefixVal);
|
||||||
int get_ExHeaderARM9AccessControlInfo(exhdr_ARM9AccessControlInfo *arm9, rsf_settings *rsf);
|
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 */
|
/* ExHeader Signature Functions */
|
||||||
int SignAccessDesc(extended_hdr *exHdr, keys_struct *keys)
|
int SignAccessDesc(extended_hdr *exHdr, keys_struct *keys)
|
||||||
@@ -104,8 +88,6 @@ int BuildExHeader(ncch_settings *ncchset)
|
|||||||
result = set_AccessDesc(exhdrset,ncchset);
|
result = set_AccessDesc(exhdrset,ncchset);
|
||||||
if(result) goto finish;
|
if(result) goto finish;
|
||||||
|
|
||||||
exhdrset->exHdr->accessDescriptor.arm11SystemLocalCapabilities.flags[6] = 5;
|
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
if(result) fprintf(stderr,"[EXHEADER ERROR] Failed to create ExHeader\n");
|
if(result) fprintf(stderr,"[EXHEADER ERROR] Failed to create ExHeader\n");
|
||||||
free_ExHeaderSettings(exhdrset);
|
free_ExHeaderSettings(exhdrset);
|
||||||
@@ -169,9 +151,9 @@ int get_ExHeaderSettingsFromNcchset(exheader_settings *exhdrset, ncch_settings *
|
|||||||
|
|
||||||
/* Set Simple Flags */
|
/* Set Simple Flags */
|
||||||
if(ncchset->options.CompressCode)
|
if(ncchset->options.CompressCode)
|
||||||
exhdrset->exHdr->codeSetInfo.flags.flag |= Compress;
|
exhdrset->exHdr->codeSetInfo.flag |= Compress;
|
||||||
if(ncchset->options.UseOnSD)
|
if(ncchset->options.UseOnSD)
|
||||||
exhdrset->exHdr->codeSetInfo.flags.flag |= RetailSDAppFlag;
|
exhdrset->exHdr->codeSetInfo.flag |= RetailSDAppFlag;
|
||||||
if(!ncchset->options.UseRomFS) // Move this later
|
if(!ncchset->options.UseRomFS) // Move this later
|
||||||
exhdrset->exHdr->arm11SystemLocalCapabilities.storageInfo.otherAttributes |= attribute_NOT_USE_ROMFS;
|
exhdrset->exHdr->arm11SystemLocalCapabilities.storageInfo.otherAttributes |= attribute_NOT_USE_ROMFS;
|
||||||
|
|
||||||
@@ -233,10 +215,10 @@ int get_ExHeaderCodeSetInfo(exhdr_CodeSetInfo *CodeSetInfo, rsf_settings *rsf)
|
|||||||
/* Remaster Version */
|
/* Remaster Version */
|
||||||
if(rsf->SystemControlInfo.RemasterVersion){
|
if(rsf->SystemControlInfo.RemasterVersion){
|
||||||
u16 RemasterVersion = strtol(rsf->SystemControlInfo.RemasterVersion,NULL,0);
|
u16 RemasterVersion = strtol(rsf->SystemControlInfo.RemasterVersion,NULL,0);
|
||||||
u16_to_u8(CodeSetInfo->flags.remasterVersion,RemasterVersion,LE);
|
u16_to_u8(CodeSetInfo->remasterVersion,RemasterVersion,LE);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
u16_to_u8(CodeSetInfo->flags.remasterVersion,0,LE);
|
u16_to_u8(CodeSetInfo->remasterVersion,0,LE);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -325,14 +307,14 @@ int SetARM11SystemLocalInfoFlags(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_
|
|||||||
/* Core Version */
|
/* Core Version */
|
||||||
if(rsf->AccessControlInfo.CoreVersion){
|
if(rsf->AccessControlInfo.CoreVersion){
|
||||||
u32 Version = strtoul(rsf->AccessControlInfo.CoreVersion,NULL,0);
|
u32 Version = strtoul(rsf->AccessControlInfo.CoreVersion,NULL,0);
|
||||||
u32_to_u8(&arm11->flags[0],Version,LE);
|
u32_to_u8(arm11->coreVersion,Version,LE);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
ErrorParamNotFound("AccessControlInfo/CoreVersion");
|
ErrorParamNotFound("AccessControlInfo/CoreVersion");
|
||||||
return EXHDR_BAD_YAML_OPT;
|
return EXHDR_BAD_YAML_OPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Byte[6] */
|
/* Flag */
|
||||||
u8 AffinityMask = 0;
|
u8 AffinityMask = 0;
|
||||||
u8 IdealProcessor = 0;
|
u8 IdealProcessor = 0;
|
||||||
u8 SystemMode = 0;
|
u8 SystemMode = 0;
|
||||||
@@ -357,7 +339,7 @@ int SetARM11SystemLocalInfoFlags(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_
|
|||||||
return EXHDR_BAD_YAML_OPT;
|
return EXHDR_BAD_YAML_OPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arm11->flags[6] = (u8)(SystemMode << 4 | AffinityMask << 2 | IdealProcessor);
|
arm11->flag = (u8)(SystemMode << 4 | AffinityMask << 2 | IdealProcessor);
|
||||||
|
|
||||||
/* Thread Priority */
|
/* Thread Priority */
|
||||||
if(rsf->AccessControlInfo.Priority){
|
if(rsf->AccessControlInfo.Priority){
|
||||||
@@ -371,7 +353,7 @@ int SetARM11SystemLocalInfoFlags(exhdr_ARM11SystemLocalCapabilities *arm11, rsf_
|
|||||||
fprintf(stderr,"[EXHEADER ERROR] Invalid Priority: %d\n",Priority);
|
fprintf(stderr,"[EXHEADER ERROR] Invalid Priority: %d\n",Priority);
|
||||||
return EXHDR_BAD_YAML_OPT;
|
return EXHDR_BAD_YAML_OPT;
|
||||||
}
|
}
|
||||||
arm11->flags[7] = Priority;
|
arm11->priority = Priority;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
ErrorParamNotFound("AccessControlInfo/Priority");
|
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 */
|
/* Generic Exheader Errors */
|
||||||
void ErrorParamNotFound(char *string)
|
void ErrorParamNotFound(char *string)
|
||||||
@@ -1531,7 +1184,7 @@ u8* GetAccessDesc_frm_exhdr(extended_hdr *hdr)
|
|||||||
|
|
||||||
u16 GetRemasterVersion_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)
|
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);
|
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)
|
int GetDependencyList_frm_exhdr(u8 *Dest, extended_hdr *hdr)
|
||||||
|
|||||||
+15
-16
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _EXHEADER_H_
|
#pragma once
|
||||||
#define _EXHEADER_H_
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -94,13 +93,6 @@ typedef enum
|
|||||||
arm9cap_USE_DIRECT_SDMC = (1 << 9),
|
arm9cap_USE_DIRECT_SDMC = (1 << 9),
|
||||||
} arm9_capability;
|
} arm9_capability;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
u8 reserved[5];
|
|
||||||
u8 flag;
|
|
||||||
u8 remasterVersion[2]; // le u16
|
|
||||||
} exhdr_SystemInfoFlags;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
u8 address[4]; // le u32
|
u8 address[4]; // le u32
|
||||||
@@ -111,11 +103,13 @@ typedef struct
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
u8 name[8];
|
u8 name[8];
|
||||||
exhdr_SystemInfoFlags flags;
|
u8 padding0[5];
|
||||||
|
u8 flag;
|
||||||
|
u8 remasterVersion[2]; // le u16
|
||||||
exhdr_CodeSegmentInfo textSectionInfo;
|
exhdr_CodeSegmentInfo textSectionInfo;
|
||||||
u8 stackSize[4]; // le u32
|
u8 stackSize[4]; // le u32
|
||||||
exhdr_CodeSegmentInfo readOnlySectionInfo;
|
exhdr_CodeSegmentInfo readOnlySectionInfo;
|
||||||
u8 padding0[4];
|
u8 padding1[4];
|
||||||
exhdr_CodeSegmentInfo dataSectionInfo;
|
exhdr_CodeSegmentInfo dataSectionInfo;
|
||||||
u8 bssSize[4]; // le u32
|
u8 bssSize[4]; // le u32
|
||||||
} exhdr_CodeSetInfo;
|
} exhdr_CodeSetInfo;
|
||||||
@@ -139,11 +133,14 @@ typedef struct
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
u8 programId[8];
|
u8 programId[8];
|
||||||
u8 flags[8];
|
u8 coreVersion[4];
|
||||||
|
u8 padding0[2];
|
||||||
|
u8 flag;
|
||||||
|
u8 priority;
|
||||||
u8 resourceLimitDescriptor[16][2];
|
u8 resourceLimitDescriptor[16][2];
|
||||||
exhdr_StorageInfo storageInfo;
|
exhdr_StorageInfo storageInfo;
|
||||||
u8 serviceAccessControl[32][8]; // Those char[8] svc handles
|
u8 serviceAccessControl[32][8]; // Those char[8] server names
|
||||||
u8 padding0[0x1f];
|
u8 padding1[0x1f];
|
||||||
u8 resourceLimitCategory;
|
u8 resourceLimitCategory;
|
||||||
} exhdr_ARM11SystemLocalCapabilities;
|
} exhdr_ARM11SystemLocalCapabilities;
|
||||||
|
|
||||||
@@ -208,7 +205,7 @@ typedef struct
|
|||||||
extended_hdr *exHdr; // is the exheader output buffer ptr(in ncchset) cast as exheader struct ptr;
|
extended_hdr *exHdr; // is the exheader output buffer ptr(in ncchset) cast as exheader struct ptr;
|
||||||
} exheader_settings;
|
} exheader_settings;
|
||||||
|
|
||||||
#endif
|
|
||||||
/* ExHeader Signature Functions */
|
/* ExHeader Signature Functions */
|
||||||
int SignAccessDesc(extended_hdr *ExHdr, keys_struct *keys);
|
int SignAccessDesc(extended_hdr *ExHdr, keys_struct *keys);
|
||||||
int CheckaccessDescSignature(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);
|
u16 GetRemasterVersion_frm_exhdr(extended_hdr *hdr);
|
||||||
u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr);
|
u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr);
|
||||||
int GetDependencyList_frm_exhdr(u8 *Dest,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 */
|
/* ExHeader Settings Read from Yaml */
|
||||||
int GetSaveDataSize_rsf(u64 *SaveDataSize, user_settings *usrset);
|
int GetSaveDataSize_rsf(u64 *SaveDataSize, user_settings *usrset);
|
||||||
int GetSaveDataSizeFromString(u64 *out, char *string);
|
int GetSaveDataSizeFromString(u64 *out, char *string);
|
||||||
int GetRemasterVersion_rsf(u16 *RemasterVersion, user_settings *usrset);
|
int GetRemasterVersion_rsf(u16 *RemasterVersion, user_settings *usrset);
|
||||||
|
|
||||||
|
void ErrorParamNotFound(char *string);
|
||||||
@@ -13,6 +13,7 @@ int SetunFixedKey(keys_struct *keys, u8 *unFixedKey);
|
|||||||
void InitcommonKeySlots(keys_struct *keys);
|
void InitcommonKeySlots(keys_struct *keys);
|
||||||
|
|
||||||
FILE* keyset_OpenFile(char *dir, char *name, bool FileRequired);
|
FILE* keyset_OpenFile(char *dir, char *name, bool FileRequired);
|
||||||
|
void keysetOpenError(char *file);
|
||||||
|
|
||||||
int SetTIK_RsaKey(keys_struct *keys, u8 *PrivateExp, u8 *PublicMod);
|
int SetTIK_RsaKey(keys_struct *keys, u8 *PrivateExp, u8 *PublicMod);
|
||||||
int SetTMD_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);
|
InitcommonKeySlots(keys);
|
||||||
keys->rsa.cxiHdrPub = malloc(RSA_2048_KEY_SIZE);
|
keys->rsa.cxiHdrPub = malloc(RSA_2048_KEY_SIZE);
|
||||||
keys->rsa.cxiHdrPvt = malloc(RSA_2048_KEY_SIZE);
|
keys->rsa.cxiHdrPvt = malloc(RSA_2048_KEY_SIZE);
|
||||||
keys->aes.supportUnFixedKeys = false;
|
|
||||||
keys->aes.unFixedKey0 = malloc(16);
|
keys->aes.unFixedKey0 = malloc(16);
|
||||||
keys->aes.unFixedKey1 = malloc(16);
|
keys->aes.unFixedKey1 = malloc(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintBadKeySize(char *path, u32 size)
|
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)
|
int SetKeys(keys_struct *keys)
|
||||||
@@ -47,12 +47,14 @@ int SetKeys(keys_struct *keys)
|
|||||||
if(keys->keyset == pki_TEST){ // Ergo False Sign
|
if(keys->keyset == pki_TEST){ // Ergo False Sign
|
||||||
/* AES Keys */
|
/* AES Keys */
|
||||||
// CIA
|
// CIA
|
||||||
//SetcommonKey(keys,(u8*)zeros_aesKey,1);
|
//SetCommonKey(keys,(u8*)zeros_aesKey,1);
|
||||||
if(keys->aes.currentCommonKey > 0xff)
|
if(keys->aes.currentCommonKey > 0xff)
|
||||||
SetcurrentCommonKey(keys,0);
|
SetCurrentCommonKey(keys,0);
|
||||||
|
|
||||||
// NCCH
|
// NCCH
|
||||||
keys->aes.normalKey = (u8*)zeros_aesKey;
|
keys->aes.normalKey = (u8*)zeros_aesKey;
|
||||||
|
keys->aes.systemFixedKey = NULL;
|
||||||
|
//SetSystemFixedKey(keys,(u8*)zeros_aesKey);
|
||||||
|
|
||||||
/* RSA Keys */
|
/* RSA Keys */
|
||||||
keys->rsa.isFalseSign = true;
|
keys->rsa.isFalseSign = true;
|
||||||
@@ -70,33 +72,17 @@ int SetKeys(keys_struct *keys)
|
|||||||
SetTmdCert(keys,(u8*)cpB_tpki_cert);
|
SetTmdCert(keys,(u8*)cpB_tpki_cert);
|
||||||
}
|
}
|
||||||
else if(keys->keyset == pki_CUSTOM){
|
else if(keys->keyset == pki_CUSTOM){
|
||||||
int keydir_pathlen = strlen(keys->keydir);
|
char *cwd = calloc(100,sizeof(char));
|
||||||
char *path = NULL;
|
getcwdir(cwd,100);
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *fp = NULL;
|
chdir(keys->keydir);
|
||||||
|
|
||||||
// NCCH
|
// NCCH
|
||||||
keys->aes.normalKey = (u8*)zeros_aesKey;
|
keys->aes.normalKey = (u8*)zeros_aesKey;
|
||||||
fp = keyset_OpenFile(path,"systemfixed.aesKey",false);
|
if(DoesFileExist("systemfixed.aesKey")){
|
||||||
if(fp){
|
keys->aes.systemFixedKey = ImportFile("systemfixed.aesKey",16);
|
||||||
keys->aes.systemFixedKey = malloc(16);
|
if(!keys->aes.systemFixedKey)
|
||||||
fread(keys->aes.systemFixedKey,16,1,fp);
|
return FAILED_TO_IMPORT_FILE;
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// commonKeys
|
// commonKeys
|
||||||
@@ -104,165 +90,129 @@ int SetKeys(keys_struct *keys)
|
|||||||
for(int i = 0; i < 256; i++){
|
for(int i = 0; i < 256; i++){
|
||||||
memset(common_key_name,0,sizeof(char)*30);
|
memset(common_key_name,0,sizeof(char)*30);
|
||||||
sprintf(common_key_name,"common_etd_%d.aesKey",i);
|
sprintf(common_key_name,"common_etd_%d.aesKey",i);
|
||||||
fp = keyset_OpenFile(path,common_key_name,false);
|
if(DoesFileExist(common_key_name)){
|
||||||
if(fp){
|
keys->aes.commonKey[i] = ImportFile(common_key_name,16);
|
||||||
keys->aes.commonKey[i] = malloc(16);
|
if(!keys->aes.commonKey[i])
|
||||||
fread(keys->aes.commonKey[i],16,1,fp);
|
return FAILED_TO_IMPORT_FILE;
|
||||||
if(keys->aes.currentCommonKey > 0xff)
|
if(keys->aes.currentCommonKey > 0xff)
|
||||||
SetcurrentCommonKey(keys,i);
|
SetCurrentCommonKey(keys,i);
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certs
|
// Certs
|
||||||
fp = keyset_OpenFile(path,"ca_cpki.cert",true);
|
if(DoesFileExist("ca_cpki.cert")){
|
||||||
if(fp){
|
keys->certs.caCert = ImportFile("ca_cpki.cert",0);
|
||||||
u32 size = GetFileSize_u32(fp);
|
if(!keys->certs.caCert)
|
||||||
keys->certs.caCert = malloc(size);
|
return FAILED_TO_IMPORT_FILE;
|
||||||
fread(keys->certs.caCert,size,1,fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
else
|
else{
|
||||||
|
keysetOpenError("ca_cpki.cert");
|
||||||
return FAILED_TO_IMPORT_FILE;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
fp = keyset_OpenFile(path,"xs_cpki.cert",true);
|
if(DoesFileExist("xs_cpki.cert")){
|
||||||
if(fp){
|
keys->certs.xsCert = ImportFile("xs_cpki.cert",0);
|
||||||
u32 size = GetFileSize_u32(fp);
|
if(!keys->certs.xsCert)
|
||||||
keys->certs.xsCert = malloc(size);
|
return FAILED_TO_IMPORT_FILE;
|
||||||
fread(keys->certs.xsCert,size,1,fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
else
|
else{
|
||||||
|
keysetOpenError("xs_cpki.cert");
|
||||||
return FAILED_TO_IMPORT_FILE;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
fp = keyset_OpenFile(path,"cp_cpki.cert",true);
|
if(DoesFileExist("cp_cpki.cert")){
|
||||||
if(fp){
|
keys->certs.cpCert = ImportFile("cp_cpki.cert",0);
|
||||||
u32 size = GetFileSize_u32(fp);
|
if(!keys->certs.cpCert)
|
||||||
keys->certs.cpCert = malloc(size);
|
return FAILED_TO_IMPORT_FILE;
|
||||||
fread(keys->certs.cpCert,size,1,fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
else
|
else{
|
||||||
|
keysetOpenError("cp_cpki.cert");
|
||||||
return FAILED_TO_IMPORT_FILE;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
// RSA Keys
|
// RSA Keys
|
||||||
fp = keyset_OpenFile(path,"cp_cpki.rsaPubKey",true);
|
if(DoesFileExist("cp_cpki.rsaPubKey")){
|
||||||
if(fp){
|
keys->rsa.cpPub = ImportFile("cp_cpki.rsaPubKey",RSA_2048_KEY_SIZE);
|
||||||
u32 size = GetFileSize_u32(fp);
|
if(!keys->rsa.cpPub)
|
||||||
if(size != RSA_2048_KEY_SIZE){
|
|
||||||
PrintBadKeySize("cp_cpki.rsaPubKey",size);
|
|
||||||
return FAILED_TO_IMPORT_FILE;
|
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;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
fp = keyset_OpenFile(path,"cp_cpki.rsaPvtKey",true);
|
if(DoesFileExist("cp_cpki.rsaPvtKey")){
|
||||||
if(fp){
|
keys->rsa.cpPvt = ImportFile("cp_cpki.rsaPvtKey",RSA_2048_KEY_SIZE);
|
||||||
u32 size = GetFileSize_u32(fp);
|
if(!keys->rsa.cpPvt)
|
||||||
if(size != RSA_2048_KEY_SIZE){
|
|
||||||
PrintBadKeySize("cp_cpki.rsaPvtKey",size);
|
|
||||||
return FAILED_TO_IMPORT_FILE;
|
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;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
fp = keyset_OpenFile(path,"xs_cpki.rsaPubKey",true);
|
if(DoesFileExist("xs_cpki.rsaPubKey")){
|
||||||
if(fp){
|
keys->rsa.xsPub = ImportFile("xs_cpki.rsaPubKey",RSA_2048_KEY_SIZE);
|
||||||
u32 size = GetFileSize_u32(fp);
|
if(!keys->rsa.xsPub)
|
||||||
if(size != RSA_2048_KEY_SIZE){
|
|
||||||
PrintBadKeySize("xs_cpki.rsaPubKey",size);
|
|
||||||
return FAILED_TO_IMPORT_FILE;
|
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;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
fp = keyset_OpenFile(path,"xs_cpki.rsaPvtKey",true);
|
if(DoesFileExist("xs_cpki.rsaPvtKey")){
|
||||||
if(fp){
|
keys->rsa.xsPvt = ImportFile("xs_cpki.rsaPvtKey",RSA_2048_KEY_SIZE);
|
||||||
u32 size = GetFileSize_u32(fp);
|
if(!keys->rsa.xsPvt)
|
||||||
if(size != RSA_2048_KEY_SIZE){
|
|
||||||
PrintBadKeySize("xs_cpki.rsaPvtKey",size);
|
|
||||||
return FAILED_TO_IMPORT_FILE;
|
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;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
fp = keyset_OpenFile(path,"ncsd_cfa.rsaPubKey",true);
|
if(DoesFileExist("ncsd_cfa.rsaPubKey")){
|
||||||
if(fp){
|
keys->rsa.cciCfaPub = ImportFile("ncsd_cfa.rsaPubKey",RSA_2048_KEY_SIZE);
|
||||||
u32 size = GetFileSize_u32(fp);
|
if(!keys->rsa.cciCfaPub)
|
||||||
if(size != RSA_2048_KEY_SIZE){
|
|
||||||
PrintBadKeySize("ncsd_cfa.rsaPubKey",size);
|
|
||||||
return FAILED_TO_IMPORT_FILE;
|
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;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
fp = keyset_OpenFile(path,"ncsd_cfa.rsaPvtKey",true);
|
if(DoesFileExist("ncsd_cfa.rsaPvtKey")){
|
||||||
if(fp){
|
keys->rsa.cciCfaPvt = ImportFile("ncsd_cfa.rsaPvtKey",RSA_2048_KEY_SIZE);
|
||||||
u32 size = GetFileSize_u32(fp);
|
if(!keys->rsa.cciCfaPvt)
|
||||||
if(size != RSA_2048_KEY_SIZE){
|
|
||||||
PrintBadKeySize("ncsd_cfa.rsaPvtKey",size);
|
|
||||||
return FAILED_TO_IMPORT_FILE;
|
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;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
fp = keyset_OpenFile(path,"acex.rsaPubKey",true);
|
|
||||||
if(fp){
|
if(DoesFileExist("acex.rsaPubKey")){
|
||||||
u32 size = GetFileSize_u32(fp);
|
keys->rsa.acexPub = ImportFile("acex.rsaPubKey",RSA_2048_KEY_SIZE);
|
||||||
if(size != RSA_2048_KEY_SIZE){
|
if(!keys->rsa.acexPub)
|
||||||
PrintBadKeySize("acex.rsaPubKey",size);
|
|
||||||
return FAILED_TO_IMPORT_FILE;
|
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;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
fp = keyset_OpenFile(path,"acex.rsaPvtKey",true);
|
if(DoesFileExist("acex.rsaPvtKey")){
|
||||||
if(fp){
|
keys->rsa.acexPvt = ImportFile("acex.rsaPvtKey",RSA_2048_KEY_SIZE);
|
||||||
u32 size = GetFileSize_u32(fp);
|
if(!keys->rsa.acexPvt)
|
||||||
if(size != RSA_2048_KEY_SIZE){
|
|
||||||
PrintBadKeySize("acex.rsaPvtKey",size);
|
|
||||||
return FAILED_TO_IMPORT_FILE;
|
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;
|
return FAILED_TO_IMPORT_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
chdir(cwd);
|
||||||
fprintf(stdout,"[DEBUG] Set Keys, free path now\n");
|
free(cwd);
|
||||||
#endif
|
|
||||||
|
|
||||||
free(path);
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stdout,"[DEBUG] freed path\n");
|
fprintf(stdout,"[DEBUG] freed path\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -272,17 +222,18 @@ int SetKeys(keys_struct *keys)
|
|||||||
/* AES Keys */
|
/* AES Keys */
|
||||||
// CIA
|
// CIA
|
||||||
for(int i = 0; i < 2; i++){
|
for(int i = 0; i < 2; i++){
|
||||||
SetcommonKey(keys,(u8*)ctr_common_etd_key_dpki[i],i);
|
SetCommonKey(keys,(u8*)ctr_common_etd_key_dpki[i],i);
|
||||||
}
|
}
|
||||||
if(keys->aes.currentCommonKey > 0xff)
|
if(keys->aes.currentCommonKey > 0xff)
|
||||||
SetcurrentCommonKey(keys,0);
|
SetCurrentCommonKey(keys,0);
|
||||||
|
|
||||||
// NCCH
|
// NCCH
|
||||||
keys->aes.normalKey = (u8*)ctr_fixed_ncch_key_dpki[0];
|
keys->aes.normalKey = (u8*)ctr_fixed_ncch_key_dpki[0];
|
||||||
SetsystemFixedKey(keys,(u8*)ctr_fixed_ncch_key_dpki[1]);
|
SetSystemFixedKey(keys,(u8*)ctr_fixed_ncch_key_dpki[1]);
|
||||||
keys->aes.supportUnFixedKeys = true;
|
/*
|
||||||
keys->aes.ncchKeyX0 = (u8*)ctr_unfixed_ncch_keyX_dpki[0];
|
keys->aes.ncchKeyX0 = (u8*)ctr_unfixed_ncch_keyX_dpki[0];
|
||||||
keys->aes.ncchKeyX1 = (u8*)ctr_unfixed_ncch_keyX_dpki[1];
|
keys->aes.ncchKeyX1 = (u8*)ctr_unfixed_ncch_keyX_dpki[1];
|
||||||
|
*/
|
||||||
|
|
||||||
/* RSA Keys */
|
/* RSA Keys */
|
||||||
// CIA
|
// CIA
|
||||||
@@ -302,14 +253,14 @@ int SetKeys(keys_struct *keys)
|
|||||||
/* AES Keys */
|
/* AES Keys */
|
||||||
// CIA
|
// CIA
|
||||||
for(int i = 0; i < 6; i++){
|
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
|
// NCCH
|
||||||
keys->aes.normalKey = (u8*)zeros_aesKey;
|
keys->aes.normalKey = (u8*)zeros_aesKey;
|
||||||
/*
|
/*
|
||||||
keys->aes.supportUnFixedKeys = true;
|
|
||||||
keys->aes.ncchKeyX0 = (u8*)ctr_unfixed_ncch_keyX_ppki[0];
|
keys->aes.ncchKeyX0 = (u8*)ctr_unfixed_ncch_keyX_ppki[0];
|
||||||
keys->aes.ncchKeyX1 = (u8*)ctr_unfixed_ncch_keyX_ppki[1];
|
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;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void keysetOpenError(char *file)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"[KEYSET ERROR] Failed to open: %s\n",file);
|
||||||
|
}
|
||||||
|
|
||||||
void FreeKeys(keys_struct *keys)
|
void FreeKeys(keys_struct *keys)
|
||||||
{
|
{
|
||||||
// AES
|
// AES
|
||||||
@@ -447,7 +403,7 @@ int SetRsaKeySet(u8 **PrivDest, u8 *PrivSource, u8 **PubDest, u8 *PubSource)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SetcommonKey(keys_struct *keys, u8 *commonKey, u8 Index)
|
int SetCommonKey(keys_struct *keys, u8 *commonKey, u8 Index)
|
||||||
{
|
{
|
||||||
if(!keys) return -1;
|
if(!keys) return -1;
|
||||||
return CopyData(&keys->aes.commonKey[Index],commonKey,16);
|
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;
|
if(!keys) return -1;
|
||||||
keys->aes.currentCommonKey = Index;
|
keys->aes.currentCommonKey = Index;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SetsystemFixedKey(keys_struct *keys, u8 *systemFixedKey)
|
int SetSystemFixedKey(keys_struct *keys, u8 *systemFixedKey)
|
||||||
{
|
{
|
||||||
if(!keys) return -1;
|
if(!keys) return -1;
|
||||||
return CopyData(&keys->aes.systemFixedKey,systemFixedKey,16);
|
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)
|
int SetTIK_RsaKey(keys_struct *keys, u8 *PrivateExp, u8 *PublicMod)
|
||||||
{
|
{
|
||||||
if(!keys) return -1;
|
if(!keys) return -1;
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#ifndef _KEYSET_H_
|
#pragma once
|
||||||
#define _KEYSET_H_
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
RSA_1024_KEY_SIZE = 0x80,
|
RSA_1024_KEY_SIZE = 0x80,
|
||||||
@@ -51,7 +49,6 @@ typedef struct
|
|||||||
u8 *normalKey;
|
u8 *normalKey;
|
||||||
u8 *systemFixedKey;
|
u8 *systemFixedKey;
|
||||||
|
|
||||||
bool supportUnFixedKeys;
|
|
||||||
u8 *ncchKeyX0;
|
u8 *ncchKeyX0;
|
||||||
u8 *ncchKeyX1;
|
u8 *ncchKeyX1;
|
||||||
u8 *unFixedKey0;
|
u8 *unFixedKey0;
|
||||||
@@ -88,13 +85,13 @@ typedef struct
|
|||||||
} certs;
|
} certs;
|
||||||
} keys_struct;
|
} keys_struct;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Public Prototypes
|
// Public Prototypes
|
||||||
void InitKeys(keys_struct *keys);
|
void InitKeys(keys_struct *keys);
|
||||||
int SetKeys(keys_struct *keys);
|
int SetKeys(keys_struct *keys);
|
||||||
void FreeKeys(keys_struct *keys);
|
void FreeKeys(keys_struct *keys);
|
||||||
|
|
||||||
int SetcommonKey(keys_struct *keys, u8 *commonKey, u8 Index);
|
int SetCommonKey(keys_struct *keys, u8 *commonKey, u8 Index);
|
||||||
int SetcurrentCommonKey(keys_struct *keys, u8 Index);
|
int SetCurrentCommonKey(keys_struct *keys, u8 Index);
|
||||||
int SetsystemFixedKey(keys_struct *keys, u8 *systemFixedKey);
|
int SetSystemFixedKey(keys_struct *keys, u8 *systemFixedKey);
|
||||||
|
|
||||||
|
int SetNcchUnfixedKeys(keys_struct *keys, u8 *ncchSig);
|
||||||
@@ -11,15 +11,16 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
//#include <wchar.h>
|
|
||||||
#else
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-5
File diff suppressed because one or more lines are too long
@@ -48,7 +48,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
u64 size = GetFileSize_u64(usrset->common.workingFilePath);
|
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);
|
usrset->common.workingFile.buffer = malloc(usrset->common.workingFile.size);
|
||||||
fp = fopen(usrset->common.workingFilePath,"rb");
|
fp = fopen(usrset->common.workingFilePath,"rb");
|
||||||
ReadFile_64(usrset->common.workingFile.buffer,size,0,fp);
|
ReadFile_64(usrset->common.workingFile.buffer,size,0,fp);
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ int CreateInputFilePtrs(ncch_settings *ncchset, user_settings *usrset);
|
|||||||
int ImportNonCodeExeFsSections(ncch_settings *ncchset);
|
int ImportNonCodeExeFsSections(ncch_settings *ncchset);
|
||||||
int ImportLogo(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 SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr);
|
||||||
int SetCommonHeaderSectionData(ncch_settings *ncchset, ncch_hdr *hdr);
|
|
||||||
bool IsValidProductCode(char *ProductCode, bool FreeProductCode);
|
bool IsValidProductCode(char *ProductCode, bool FreeProductCode);
|
||||||
|
|
||||||
int BuildCommonHeader(ncch_settings *ncchset);
|
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 build_NCCH(user_settings *usrset)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
#ifdef DEBUG
|
|
||||||
printf("[DEBUG] Init Settings\n");
|
// Init Settings\n");
|
||||||
#endif
|
|
||||||
// Init Settings
|
|
||||||
ncch_settings *ncchset = malloc(sizeof(ncch_settings));
|
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);
|
init_NCCHSettings(ncchset);
|
||||||
|
|
||||||
#ifdef DEBUG
|
// Get Settings\n");
|
||||||
printf("[DEBUG] Get Settings\n");
|
|
||||||
#endif
|
|
||||||
// Get Settings
|
|
||||||
result = get_NCCHSettings(ncchset,usrset);
|
result = get_NCCHSettings(ncchset,usrset);
|
||||||
if(result) goto finish;
|
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
|
if(!ncchset->options.IsCfa){ // CXI Specfic Sections
|
||||||
printf("[DEBUG] Exefs\n");
|
// Build ExeFs Code Section\n");
|
||||||
#endif
|
result = BuildExeFsCode(ncchset);
|
||||||
// Build ExeFs/RomFs
|
if(result) goto finish;
|
||||||
|
|
||||||
|
// Build ExHeader\n");
|
||||||
|
result = BuildExHeader(ncchset);
|
||||||
|
if(result) goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Build ExeFs\n");
|
||||||
result = BuildExeFs(ncchset);
|
result = BuildExeFs(ncchset);
|
||||||
if(result) goto finish;
|
if(result) goto finish;
|
||||||
#ifdef DEBUG
|
|
||||||
printf("[DEBUG] Build Romfs\n");
|
|
||||||
#endif
|
// Prepare for RomFs\n");
|
||||||
result = BuildRomFs(ncchset);
|
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;
|
if(result) goto finish;
|
||||||
|
|
||||||
// Final Steps
|
// Finalise NCCH (Hashes/Signatures and crypto)\n");
|
||||||
#ifdef DEBUG
|
result = FinaliseNcch(ncchset);
|
||||||
printf("[DEBUG] Build common header\n");
|
|
||||||
#endif
|
|
||||||
result = BuildCommonHeader(ncchset);
|
|
||||||
if(result) goto finish;
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("[DEBUG] Encrypt Sections\n");
|
|
||||||
#endif
|
|
||||||
result = EncryptNCCHSections(ncchset);
|
|
||||||
if(result) goto finish;
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("[DEBUG] Write Sections\n");
|
|
||||||
#endif
|
|
||||||
result = WriteNCCHSectionsToBuffer(ncchset);
|
|
||||||
if(result) goto finish;
|
if(result) goto finish;
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
#ifdef DEBUG
|
if(result)
|
||||||
printf("[DEBUG] Finish Building\n");
|
fprintf(stderr,"[NCCH ERROR] NCCH Build Process Failed\n");
|
||||||
#endif
|
|
||||||
if(result) fprintf(stderr,"[NCCH ERROR] NCCH Build Process Failed\n");
|
|
||||||
free_NCCHSettings(ncchset);
|
free_NCCHSettings(ncchset);
|
||||||
return result;
|
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.banner.size) free(set->exefsSections.banner.buffer);
|
||||||
if(set->exefsSections.icon.size) free(set->exefsSections.icon.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.exhdr.size) free(set->sections.exhdr.buffer);
|
||||||
if(set->sections.logo.size) free(set->sections.logo.buffer);
|
if(set->sections.logo.size) free(set->sections.logo.buffer);
|
||||||
if(set->sections.plainRegion.size) free(set->sections.plainRegion.buffer);
|
if(set->sections.plainRegion.size) free(set->sections.plainRegion.buffer);
|
||||||
if(set->sections.exeFs.size) free(set->sections.exeFs.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));
|
memset(set,0,sizeof(ncch_settings));
|
||||||
|
|
||||||
@@ -171,6 +150,7 @@ int get_NCCHSettings(ncch_settings *ncchset, user_settings *usrset)
|
|||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
ncchset->out = &usrset->common.workingFile;
|
ncchset->out = &usrset->common.workingFile;
|
||||||
|
|
||||||
ncchset->rsfSet = &usrset->common.rsfSet;
|
ncchset->rsfSet = &usrset->common.rsfSet;
|
||||||
ncchset->keys = &usrset->common.keys;
|
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);
|
ncchset->options.UseRomFS = ((ncchset->rsfSet->Rom.HostRoot && strlen(ncchset->rsfSet->Rom.HostRoot) > 0) || usrset->ncch.romfsPath);
|
||||||
|
|
||||||
if(ncchset->options.IsCfa && !ncchset->options.UseRomFS){
|
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;
|
return NCCH_BAD_YAML_SET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,15 +298,15 @@ int ImportNonCodeExeFsSections(ncch_settings *ncchset)
|
|||||||
|
|
||||||
int ImportLogo(ncch_settings *ncchset)
|
int ImportLogo(ncch_settings *ncchset)
|
||||||
{
|
{
|
||||||
if(ncchset->options.IsCfa) return 0;
|
|
||||||
if(ncchset->componentFilePtrs.logo){
|
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);
|
ncchset->sections.logo.buffer = malloc(ncchset->sections.logo.size);
|
||||||
if(!ncchset->sections.logo.buffer) {
|
if(!ncchset->sections.logo.buffer) {
|
||||||
fprintf(stderr,"[NCCH ERROR] MEM ERROR\n");
|
fprintf(stderr,"[NCCH ERROR] MEM ERROR\n");
|
||||||
return MEM_ERROR;
|
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){
|
else if(ncchset->rsfSet->BasicInfo.Logo){
|
||||||
if(strcasecmp(ncchset->rsfSet->BasicInfo.Logo,"nintendo") == 0){
|
if(strcasecmp(ncchset->rsfSet->BasicInfo.Logo,"nintendo") == 0){
|
||||||
@@ -382,8 +362,224 @@ int ImportLogo(ncch_settings *ncchset)
|
|||||||
return 0;
|
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)
|
int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr)
|
||||||
{
|
{
|
||||||
|
/* NCCH Magic */
|
||||||
|
memcpy(hdr->magic,"NCCH",4);
|
||||||
|
|
||||||
/* NCCH Format titleVersion */
|
/* NCCH Format titleVersion */
|
||||||
u16_to_u8(hdr->formatVersion,0x2,LE);
|
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);
|
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 */
|
/* Set ContentUnitSize */
|
||||||
hdr->flags[ContentUnitSize] = 0; // 0x200
|
hdr->flags[ContentUnitSize] = 0; // 0x200
|
||||||
|
|
||||||
@@ -421,14 +628,13 @@ int SetCommonHeaderBasicData(ncch_settings *ncchset, ncch_hdr *hdr)
|
|||||||
hdr->flags[ContentPlatform] = 1; // CTR
|
hdr->flags[ContentPlatform] = 1; // CTR
|
||||||
|
|
||||||
/* Setting OtherFlag */
|
/* Setting OtherFlag */
|
||||||
hdr->flags[OtherFlag] = FixedCryptoKey;
|
if(!ncchset->options.UseRomFS)
|
||||||
if(!ncchset->options.Encrypt) hdr->flags[OtherFlag] |= NoCrypto;
|
hdr->flags[OtherFlag] |= NoMountRomFs;
|
||||||
if(!ncchset->sections.romFs.size) hdr->flags[OtherFlag] |= NoMountRomFs;
|
|
||||||
|
|
||||||
|
|
||||||
/* Setting ContentType */
|
/* Setting ContentType */
|
||||||
hdr->flags[ContentType] = 0;
|
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->options.IsCfa) hdr->flags[ContentType] |= content_Executable;
|
||||||
if(ncchset->rsfSet->BasicInfo.ContentType){
|
if(ncchset->rsfSet->BasicInfo.ContentType){
|
||||||
if(strcmp(ncchset->rsfSet->BasicInfo.ContentType,"Application") == 0) hdr->flags[ContentType] |= 0;
|
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;
|
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)
|
bool IsValidProductCode(char *ProductCode, bool FreeProductCode)
|
||||||
{
|
{
|
||||||
if(strlen(ProductCode) > 16) return false;
|
if(strlen(ProductCode) > 16) return false;
|
||||||
@@ -531,104 +669,9 @@ bool IsValidProductCode(char *ProductCode, bool FreeProductCode)
|
|||||||
return true;
|
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
|
// NCCH Read Functions
|
||||||
|
|
||||||
int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput)
|
int VerifyNCCH(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput)
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
u8 Hash[0x20];
|
u8 Hash[0x20];
|
||||||
@@ -638,16 +681,38 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput)
|
|||||||
ncch_struct *ncch_ctx = malloc(sizeof(ncch_struct));
|
ncch_struct *ncch_ctx = malloc(sizeof(ncch_struct));
|
||||||
if(!ncch_ctx){ fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR; }
|
if(!ncch_ctx){ fprintf(stderr,"[NCCH ERROR] MEM ERROR\n"); return MEM_ERROR; }
|
||||||
memset(ncch_ctx,0x0,sizeof(ncch_struct));
|
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(IsCfa(hdr)){
|
||||||
if(CheckCFASignature(hdr_sig,(u8*)hdr,keys) != Good && !keys->rsa.isFalseSign){
|
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);
|
free(ncch_ctx);
|
||||||
return NCCH_HDR_SIG_BAD;
|
return NCCH_HDR_SIG_BAD;
|
||||||
}
|
}
|
||||||
if(!ncch_ctx->romfsSize){
|
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);
|
free(ncch_ctx);
|
||||||
return NO_ROMFS_IN_CFA;
|
return NO_ROMFS_IN_CFA;
|
||||||
}
|
}
|
||||||
@@ -655,12 +720,14 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput)
|
|||||||
else{ // IsCxi
|
else{ // IsCxi
|
||||||
// Checking for necessary sections
|
// Checking for necessary sections
|
||||||
if(!ncch_ctx->exhdrSize){
|
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);
|
free(ncch_ctx);
|
||||||
return NO_EXHEADER_IN_CXI;
|
return NO_EXHEADER_IN_CXI;
|
||||||
}
|
}
|
||||||
if(!ncch_ctx->exefsSize){
|
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);
|
free(ncch_ctx);
|
||||||
return NO_EXEFS_IN_CXI;
|
return NO_EXEFS_IN_CXI;
|
||||||
}
|
}
|
||||||
@@ -671,19 +738,9 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput)
|
|||||||
free(ncch_ctx);
|
free(ncch_ctx);
|
||||||
return MEM_ERROR;
|
return MEM_ERROR;
|
||||||
}
|
}
|
||||||
int ret = GetNCCHSection((u8*)ExHeader,ncch_ctx->exhdrSize,0,ncch,ncch_ctx,keys,ncch_exhdr);
|
memcpy(ExHeader,ncch+ncch_ctx->exhdrOffset,ncch_ctx->exhdrSize);
|
||||||
if(ret != 0 && ret != UNABLE_TO_LOAD_NCCH_KEY){
|
if(key0 != NULL)
|
||||||
if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] CXI is corrupt\n");
|
CryptNCCHSection((u8*)ExHeader,ncch_ctx->exhdrSize,0,ncch_ctx,key0,ncch_exhdr);
|
||||||
free(ncch_ctx);
|
|
||||||
free(ExHeader);
|
|
||||||
return CXI_CORRUPT;
|
|
||||||
}
|
|
||||||
else if(ret == UNABLE_TO_LOAD_NCCH_KEY){
|
|
||||||
if(!SuppressOutput) fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key.\n");
|
|
||||||
free(ncch_ctx);
|
|
||||||
free(ExHeader);
|
|
||||||
return UNABLE_TO_LOAD_NCCH_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checking Exheader Hash to see if decryption was sucessful
|
// Checking Exheader Hash to see if decryption was sucessful
|
||||||
ctr_sha(ExHeader,0x400,Hash,CTR_SHA_256);
|
ctr_sha(ExHeader,0x400,Hash,CTR_SHA_256);
|
||||||
@@ -717,6 +774,10 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput)
|
|||||||
}
|
}
|
||||||
free(ExHeader);
|
free(ExHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!CheckHash)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Checking ExeFs Hash, if present */
|
/* Checking ExeFs Hash, if present */
|
||||||
if(ncch_ctx->exefsSize)
|
if(ncch_ctx->exefsSize)
|
||||||
{
|
{
|
||||||
@@ -726,7 +787,9 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput)
|
|||||||
free(ncch_ctx);
|
free(ncch_ctx);
|
||||||
return MEM_ERROR;
|
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);
|
ctr_sha(ExeFs,ncch_ctx->exefsHashDataSize,Hash,CTR_SHA_256);
|
||||||
free(ExeFs);
|
free(ExeFs);
|
||||||
if(memcmp(Hash,hdr->exefsHash,0x20) != 0){
|
if(memcmp(Hash,hdr->exefsHash,0x20) != 0){
|
||||||
@@ -744,7 +807,9 @@ int VerifyNCCH(u8 *ncch, keys_struct *keys, bool SuppressOutput)
|
|||||||
free(ncch_ctx);
|
free(ncch_ctx);
|
||||||
return MEM_ERROR;
|
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);
|
ctr_sha(RomFs,ncch_ctx->romfsHashDataSize,Hash,CTR_SHA_256);
|
||||||
free(RomFs);
|
free(RomFs);
|
||||||
if(memcmp(Hash,hdr->romfsHash,0x20) != 0){
|
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
|
ReadFile_64(ncch,size,0,fp); // Importing
|
||||||
|
|
||||||
if(!IsNCCH(NULL,ncch)){
|
if(ModifyNcchIds(ncch,TitleId, ProgramId, keys) != 0){
|
||||||
free(ncch);
|
free(ncch);
|
||||||
return NULL;
|
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;
|
ncch_hdr *hdr = NULL;
|
||||||
hdr = GetNCCH_CommonHDR(NULL,NULL,ncch);
|
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)){
|
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
|
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);
|
free(ncch);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((memcmp(TitleId,hdr->titleId,8) == 0) && (memcmp(ProgramId,hdr->programId,8) == 0))
|
bool titleIdMatches = titleId == NULL? true : memcmp(titleId,hdr->titleId,8) == 0;
|
||||||
return ncch;// if no modification is required don't do anything
|
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.
|
if(titleIdMatches && programIdMatches)
|
||||||
memcpy(hdr->programId,ProgramId,8);
|
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);
|
SignCFA(ncch,(u8*)hdr,keys);
|
||||||
return ncch;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ncch_key_type keytype = GetNCCHKeyType(hdr);
|
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;
|
ncch_struct ncch_struct;
|
||||||
if(keytype != NoKey){ //Decrypting if necessary
|
u8 *key = NULL;
|
||||||
GetCXIStruct(&ncch_struct,hdr);
|
u8 *romfs = NULL;
|
||||||
u8 *romfs = (ncch+ncch_struct.romfsOffset);
|
|
||||||
key = GetNCCHKey(hdr,keys);
|
//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){
|
if(key == NULL){
|
||||||
fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n");
|
fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n");
|
||||||
free(ncch);
|
free(ncch);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
CryptNCCHSection(romfs,ncch_struct.romfsSize,0,&ncch_struct,key,ncch_romfs);
|
CryptNCCHSection(romfs,ncch_struct.romfsSize,0,&ncch_struct,key,ncch_romfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Editing data and resigning
|
||||||
memcpy(hdr->titleId,TitleId,8);
|
if(titleId)
|
||||||
memcpy(hdr->programId,ProgramId,8);
|
memcpy(hdr->titleId,titleId,8);
|
||||||
|
if(programId)
|
||||||
//Checking New Fixed Key Type
|
memcpy(hdr->programId,programId,8);
|
||||||
|
SignCFA(ncch,(u8*)hdr,keys);
|
||||||
|
|
||||||
|
//Checking New Key Type
|
||||||
keytype = GetNCCHKeyType(hdr);
|
keytype = GetNCCHKeyType(hdr);
|
||||||
|
|
||||||
if(keytype != NoKey){ // Re-encrypting if necessary
|
// Re-encrypting if necessary
|
||||||
GetCXIStruct(&ncch_struct,hdr);
|
if(keytype != NoKey){
|
||||||
u8 *romfs = (ncch+ncch_struct.romfsOffset);
|
GetNCCHStruct(&ncch_struct,hdr);
|
||||||
key = GetNCCHKey(hdr,keys);
|
romfs = (ncch+ncch_struct.romfsOffset);
|
||||||
|
SetNcchUnfixedKeys(keys, ncch); // For Secure Crypto
|
||||||
|
key = GetNCCHKey(keytype,keys);
|
||||||
if(key == NULL){
|
if(key == NULL){
|
||||||
fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n");
|
fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key\n");
|
||||||
free(ncch);
|
free(ncch);
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
CryptNCCHSection(romfs,ncch_struct.romfsSize,0,&ncch_struct,key,ncch_romfs);
|
CryptNCCHSection(romfs,ncch_struct.romfsSize,0,&ncch_struct,key,ncch_romfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
SignCFA(ncch,(u8*)hdr,keys);
|
return 0;
|
||||||
|
|
||||||
return ncch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -923,23 +1000,23 @@ ncch_key_type GetNCCHKeyType(ncch_hdr* hdr)
|
|||||||
return KeyIsUnFixed;
|
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){
|
switch(keytype){
|
||||||
case NoKey: return NULL;
|
case NoKey: return NULL;
|
||||||
case KeyIsNormalFixed: return keys->aes.normalKey;
|
case KeyIsNormalFixed: return keys->aes.normalKey;
|
||||||
case KeyIsSystemFixed:
|
case KeyIsSystemFixed:
|
||||||
if(!keys->aes.systemFixedKey) fprintf(stderr,"[NCCH WARNING] Unable to load SystemFixed Key\n");
|
|
||||||
return keys->aes.systemFixedKey;
|
return keys->aes.systemFixedKey;
|
||||||
case KeyIsUnFixed:
|
case KeyIsUnFixed:
|
||||||
fprintf(stderr,"[NCCH WARNING] Unable to load UnFixed Key\n");
|
if(keys->aes.ncchKeyX0)
|
||||||
return NULL;
|
return keys->aes.unFixedKey0;
|
||||||
//if(!keys->aes.unFixedKey0) fprintf(stderr,"[NCCH WARNING] Unable to load UnFixed Key\n");
|
else
|
||||||
//return keys->aes.unFixedKey0;
|
return NULL;
|
||||||
case KeyIsUnFixed2:
|
case KeyIsUnFixed2:
|
||||||
fprintf(stderr,"[NCCH WARNING] Crypto method (Secure2) not supported yet\n");
|
if(keys->aes.ncchKeyX1)
|
||||||
return NULL;
|
return keys->aes.unFixedKey1;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
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);
|
ncch_key_type keytype = GetNCCHKeyType(hdr);
|
||||||
|
|
||||||
if(keytype != NoKey && (section == ncch_exhdr || section == ncch_exefs || section == ncch_romfs)){
|
if(keytype != NoKey && (section == ncch_exhdr || section == ncch_exefs || section == ncch_romfs)){
|
||||||
key = GetNCCHKey(hdr,keys);
|
key = GetNCCHKey(keytype,keys);
|
||||||
if(key == NULL){
|
if(key == NULL){
|
||||||
//fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key.\n");
|
//fprintf(stderr,"[NCCH ERROR] Failed to load ncch aes key.\n");
|
||||||
return UNABLE_TO_LOAD_NCCH_KEY;
|
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;
|
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->titleId,header->titleId,8);
|
||||||
memcpy(ctx->programId,header->programId,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);
|
ctr_init_counter(&aes_ctx, key, counter);
|
||||||
if(src_pos > 0){
|
if(src_pos > 0){
|
||||||
u32 carry = 0;
|
u32 carry = 0;
|
||||||
carry = align_value(src_pos,0x10);
|
carry = align(src_pos,0x10);
|
||||||
carry /= 0x10;
|
carry /= 0x10;
|
||||||
ctr_add_counter(&aes_ctx,carry);
|
ctr_add_counter(&aes_ctx,carry);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _NCCH_H_
|
#pragma once
|
||||||
#define _NCCH_H_
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -123,9 +122,10 @@ typedef struct
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
buffer_struct *out;
|
||||||
keys_struct *keys;
|
keys_struct *keys;
|
||||||
rsf_settings *rsfSet;
|
rsf_settings *rsfSet;
|
||||||
COMPONENT_STRUCT *out;
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@@ -169,9 +169,9 @@ typedef struct
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
COMPONENT_STRUCT code;
|
buffer_struct code;
|
||||||
COMPONENT_STRUCT banner;
|
buffer_struct banner;
|
||||||
COMPONENT_STRUCT icon;
|
buffer_struct icon;
|
||||||
} exefsSections;
|
} exefsSections;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
@@ -190,31 +190,27 @@ typedef struct
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
u64 totalNcchSize;
|
buffer_struct exhdr;
|
||||||
COMPONENT_STRUCT ncchHdr;
|
buffer_struct logo;
|
||||||
COMPONENT_STRUCT exhdr;
|
buffer_struct plainRegion;
|
||||||
u64 logoOffset;
|
buffer_struct exeFs;
|
||||||
COMPONENT_STRUCT logo;
|
|
||||||
u64 plainRegionOffset;
|
|
||||||
COMPONENT_STRUCT plainRegion;
|
|
||||||
u64 exeFsOffset;
|
|
||||||
COMPONENT_STRUCT exeFs;
|
|
||||||
u64 romFsOffset;
|
|
||||||
COMPONENT_STRUCT romFs;
|
|
||||||
} sections;
|
} sections;
|
||||||
|
|
||||||
|
ncch_struct cryptoDetails;
|
||||||
|
|
||||||
|
|
||||||
} ncch_settings;
|
} ncch_settings;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// NCCH Build Functions
|
// NCCH Build Functions
|
||||||
int build_NCCH(user_settings *usrset);
|
int build_NCCH(user_settings *usrset);
|
||||||
|
|
||||||
|
|
||||||
// NCCH Read Functions
|
// 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);
|
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);
|
ncch_hdr* GetNCCH_CommonHDR(void *out, FILE *fp, u8 *buf);
|
||||||
bool IsNCCH(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);
|
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);
|
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 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);
|
void CryptNCCHSection(u8 *buffer, u64 size, u64 src_pos, ncch_struct *ctx, u8 key[16], u8 type);
|
||||||
-1104
File diff suppressed because it is too large
Load Diff
@@ -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.initial_data,cciset->initialData,0x30);
|
||||||
memcpy((u8*)ctx.cardinfo.ncch_0_header,cciset->ncchHdr,0x100);
|
memcpy((u8*)ctx.cardinfo.ncch_0_header,cciset->ncchHdr,0x100);
|
||||||
memcpy((u8*)ctx.devcardinfo.TitleKey,cciset->titleKey,0x10);
|
memcpy((u8*)ctx.devcardinfo.TitleKey,cciset->titleKey,0x10);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +184,15 @@ int WriteCCI_HDR_ToFile(cci_settings *cciset)
|
|||||||
WriteBuffer(ctx.signature,0x100,0,cciset->out);
|
WriteBuffer(ctx.signature,0x100,0,cciset->out);
|
||||||
WriteBuffer((u8*)&ctx.cciHdr,sizeof(cci_hdr),0x100,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.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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +222,7 @@ int WriteCCI_Content_ToFile(cci_settings *cciset,user_settings *usrset)
|
|||||||
int WriteCCI_DummyBytes(cci_settings *cciset)
|
int WriteCCI_DummyBytes(cci_settings *cciset)
|
||||||
{
|
{
|
||||||
// Seeking end of CCI Data
|
// Seeking end of CCI Data
|
||||||
fseek_64(cciset->out,cciset->cciTotalSize,SEEK_SET);
|
fseek_64(cciset->out,cciset->cciTotalSize);
|
||||||
|
|
||||||
// Determining Size of Dummy Bytes
|
// Determining Size of Dummy Bytes
|
||||||
u64 len = cciset->mediaSize - cciset->cciTotalSize;
|
u64 len = cciset->mediaSize - cciset->cciTotalSize;
|
||||||
@@ -223,9 +232,8 @@ int WriteCCI_DummyBytes(cci_settings *cciset)
|
|||||||
memset(dummy_bytes,0xff,cciset->mediaUnit);
|
memset(dummy_bytes,0xff,cciset->mediaUnit);
|
||||||
|
|
||||||
// Writing Dummy Bytes to file
|
// Writing Dummy Bytes to file
|
||||||
for(u64 i = 0; i < len; i += cciset->mediaUnit){
|
for(u64 i = 0; i < len; i += cciset->mediaUnit)
|
||||||
fwrite(&dummy_bytes,cciset->mediaUnit,1,cciset->out);
|
fwrite(dummy_bytes,cciset->mediaUnit,1,cciset->out);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -324,7 +332,9 @@ int GetDataFromContent0(cci_settings *cciset, user_settings *usrset)
|
|||||||
//memcpy(cciset->titleKey,(Hash+0x30),0x10); // Might Remove
|
//memcpy(cciset->titleKey,(Hash+0x30),0x10); // Might Remove
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FW6x SaveCrypto */
|
||||||
|
cciset->flags[FW6x_SaveCryptoFlag] = usrset->cci.use6xSavedataCrypto;
|
||||||
|
|
||||||
cciset->flags[MediaUnitSize] = hdr->flags[ContentUnitSize];
|
cciset->flags[MediaUnitSize] = hdr->flags[ContentUnitSize];
|
||||||
cciset->mediaUnit = GetNCCH_MediaUnitSize(hdr);
|
cciset->mediaUnit = GetNCCH_MediaUnitSize(hdr);
|
||||||
|
|
||||||
@@ -400,9 +410,6 @@ int GetNCSDFlags(cci_settings *cciset, rsf_settings *yaml)
|
|||||||
cciset->flags[FW6x_BackupWriteWaitTime] = (u8)WaitTime;
|
cciset->flags[FW6x_BackupWriteWaitTime] = (u8)WaitTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FW6x SaveCrypto */
|
|
||||||
cciset->flags[FW6x_SaveCryptoFlag] = 1;
|
|
||||||
|
|
||||||
/* MediaType */
|
/* MediaType */
|
||||||
if(!yaml->CardInfo.MediaType) cciset->flags[MediaTypeIndex] = CARD1;
|
if(!yaml->CardInfo.MediaType) cciset->flags[MediaTypeIndex] = CARD1;
|
||||||
else{
|
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->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
|
if ((cciset->mediaSize / 2) < cciset->savedataSize){ // If SaveData size is greater than half the MediaSize
|
||||||
u64 SavedataSize = cciset->savedataSize / KB;
|
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;
|
return SAVE_DATA_TOO_LARGE;
|
||||||
}
|
}
|
||||||
if (cciset->savedataSize > (u64)(2047*MB)){ // Limit set by Nintendo
|
if (cciset->savedataSize > (u64)(2047*MB)){ // Limit set by Nintendo
|
||||||
u64 SavedataSize = cciset->savedataSize / KB;
|
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;
|
return SAVE_DATA_TOO_LARGE;
|
||||||
}
|
}
|
||||||
u64 UnusedSize = GetUnusedSize(cciset->mediaSize,cciset->flags[MediaTypeIndex]); // Need to look into this
|
u64 UnusedSize = GetUnusedSize(cciset->mediaSize,cciset->flags[MediaTypeIndex]); // Need to look into this
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#ifndef _NCSD_H_
|
#pragma once
|
||||||
#define _NCSD_H_
|
|
||||||
|
|
||||||
|
|
||||||
// Enums
|
// Enums
|
||||||
typedef enum
|
typedef enum
|
||||||
@@ -162,11 +160,7 @@ static const u8 stock_title_key[0x10] =
|
|||||||
0x97, 0x11, 0x92, 0xBA
|
0x97, 0x11, 0x92, 0xBA
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Public Prototypes
|
// Public Prototypes
|
||||||
|
|
||||||
|
|
||||||
// Build Functions
|
// Build Functions
|
||||||
int build_CCI(user_settings *usrset);
|
int build_CCI(user_settings *usrset);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _PPKI_H_
|
#pragma once
|
||||||
#define _PPKI_H_
|
|
||||||
|
|
||||||
#ifdef PKI_LEGACY
|
#ifdef PKI_LEGACY
|
||||||
#include "ppki_legacy.h"
|
#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,
|
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
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _PPKI_LEGACY_H_
|
#pragma once
|
||||||
#define _PPKI_LEGACY_H_
|
|
||||||
|
|
||||||
// AES Keys
|
// AES Keys
|
||||||
static const unsigned char rvl_common_etd_key_ppki[2][16] =
|
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
|
// RSA Keys
|
||||||
|
|
||||||
// Certificates
|
// Certificates
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,39 +1,50 @@
|
|||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "ncch.h"
|
#include "ncch.h"
|
||||||
#include "romfs.h"
|
#include "romfs.h"
|
||||||
|
#include "romfs_binary.h"
|
||||||
|
#include "romfs_import.h"
|
||||||
|
|
||||||
// RomFs Build Functions
|
// RomFs Build Functions
|
||||||
|
int SetupRomFs(ncch_settings *ncchset, romfs_buildctx *ctx)
|
||||||
int ImportRomFsBinaryFromFile(ncch_settings *ncchset);
|
|
||||||
|
|
||||||
int BuildRomFs(ncch_settings *ncchset)
|
|
||||||
{
|
{
|
||||||
int result = 0;
|
ctx->output = NULL;
|
||||||
|
ctx->romfsSize = 0;
|
||||||
|
|
||||||
// If Not Using RomFS Return
|
// 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
|
int result = 0;
|
||||||
result = ImportRomFsBinaryFromFile(ncchset);
|
|
||||||
return result;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ImportRomFsBinaryFromFile(ncch_settings *ncchset)
|
int BuildRomFs(romfs_buildctx *ctx)
|
||||||
{
|
{
|
||||||
ncchset->sections.romFs.size = ncchset->componentFilePtrs.romfsSize;
|
// If Not Using RomFS Return
|
||||||
ncchset->sections.romFs.buffer = malloc(ncchset->sections.romFs.size);
|
if(!ctx->romfsSize)
|
||||||
if(!ncchset->sections.romFs.buffer) {fprintf(stderr,"[ROMFS ERROR] MEM ERROR\n"); return MEM_ERROR;}
|
return 0;
|
||||||
ReadFile_64(ncchset->sections.romFs.buffer,ncchset->sections.romFs.size,0,ncchset->componentFilePtrs.romfs);
|
|
||||||
if(memcmp(ncchset->sections.romFs.buffer,"IVFC",4) != 0){
|
int result = 0;
|
||||||
fprintf(stderr,"[ROMFS ERROR] Invalid RomFS Binary.\n");
|
|
||||||
return INVALID_ROMFS_FILE;
|
if(ctx->ImportRomfsBinary) // The user has specified a pre-built RomFs Binary
|
||||||
}
|
result = ImportRomFsBinaryFromFile(ctx);
|
||||||
return 0;
|
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);
|
||||||
|
}
|
||||||
@@ -1,15 +1,77 @@
|
|||||||
#ifndef _ROMFS_H_
|
#pragma once
|
||||||
#define _ROMFS_H_
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
INVALID_ROMFS_FILE = -10,
|
INVALID_ROMFS_FILE = -10,
|
||||||
} romfs_errors;
|
} 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
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int PrepareBuildRomFsBinary(ncch_settings *ncchset, romfs_buildctx *ctx);
|
||||||
|
int BuildRomFsBinary(romfs_buildctx *ctx);
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx);
|
||||||
|
int ImportRomFsBinaryFromFile(romfs_buildctx *ctx);
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
@@ -1,96 +1,93 @@
|
|||||||
#ifndef _SRL_H_
|
#pragma once
|
||||||
#define _SRL_H_
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
u8 game_title[0xC];
|
u8 gameTitle[0xC];
|
||||||
u8 game_code[4];
|
u8 gameCode[4];
|
||||||
u8 maker_code[2];
|
u8 makerCode[2];
|
||||||
u8 unit_code;
|
u8 unitCode;
|
||||||
u8 encryption_seed_select;
|
u8 encryptionSeedSelect;
|
||||||
u8 device_capacity;
|
u8 deviceCapacity;
|
||||||
u8 reserved_0[9];
|
u8 reserved0[9];
|
||||||
u8 rom_version;
|
u8 romVersion;
|
||||||
u8 internal_flag;
|
u8 internalFlag;
|
||||||
u8 arm9_rom_offset[4];
|
u8 arm9RomOffset[4];
|
||||||
u8 arm9_entry_address[4];
|
u8 arm9EntryAddress[4];
|
||||||
u8 arm9_ram_address[4];
|
u8 arm9RamAddress[4];
|
||||||
u8 arm9_size[4];
|
u8 arm9Size[4];
|
||||||
u8 arm7_rom_offset[4];
|
u8 arm7RomOffset[4];
|
||||||
u8 arm7_entry_address[4];
|
u8 arm7EntryAddress[4];
|
||||||
u8 arm7_ram_address[4];
|
u8 arm7RamAddress[4];
|
||||||
u8 arm7_size[4];
|
u8 arm7Size[4];
|
||||||
u8 fnt_offset[4];
|
u8 fntOffset[4];
|
||||||
u8 fnt_size[4];
|
u8 fntSize[4];
|
||||||
u8 fat_offset[4];
|
u8 fatOffset[4];
|
||||||
u8 fat_size[4];
|
u8 fatSize[4];
|
||||||
u8 arm9_overlay_offset[4];
|
u8 arm9OverlayOffset[4];
|
||||||
u8 arm9_overlay_size[4];
|
u8 arm9OverlaySize[4];
|
||||||
u8 arm7_overlay_offset[4];
|
u8 arm7OverlayOffset[4];
|
||||||
u8 arm7_overlay_size[4];
|
u8 arm7OverlaySize[4];
|
||||||
u8 normal_card_control_reg_settings[4];
|
u8 normalCardControlRegSettings[4];
|
||||||
u8 secure_card_control_reg_settings[4];
|
u8 secureCardControlRegSettings[4];
|
||||||
u8 icon_banner_offset[4];
|
u8 icon_bannerOffset[4];
|
||||||
u8 secure_area_crc[2];
|
u8 secureAreaCrc[2];
|
||||||
u8 secure_transfer_timeout[2];
|
u8 secure_transfer_timeout[2];
|
||||||
u8 arm9_autoload[4];
|
u8 arm9Autoload[4];
|
||||||
u8 arm7_autoload[4];
|
u8 arm7Autoload[4];
|
||||||
u8 secure_disable[8];
|
u8 secureDisable[8];
|
||||||
u8 ntr_rom_size[4];
|
u8 ntrRomSize[4];
|
||||||
u8 header_size[4];
|
u8 headerSize[4];
|
||||||
u8 reserved_1[0x38];
|
u8 reserved1[0x38];
|
||||||
u8 nintendo_logo[0x9C];
|
u8 nintendoLogo[0x9C];
|
||||||
u8 nintendo_logo_crc[2];
|
u8 nintendoLogoCrc[2];
|
||||||
u8 header_crc[2];
|
u8 headerCrc[2];
|
||||||
u8 debug_reserved[0x20];
|
u8 debugReserved[0x20];
|
||||||
|
|
||||||
//TWL Only Data
|
//TWL Only Data
|
||||||
u8 config_settings[0x34];
|
u8 configSettings[0x34];
|
||||||
u8 access_control[4];
|
u8 accessControl[4];
|
||||||
u8 arm7_scfg_ext_mask[4];
|
u8 arm7ScfgExtMask[4];
|
||||||
u8 reserved_flags[4];
|
u8 reserved_flags[4];
|
||||||
u8 arm9i_rom_offset[4];
|
u8 arm9iRomOffset[4];
|
||||||
u8 reserved_2[4];
|
u8 reserved2[4];
|
||||||
u8 arm9i_load_address[4];
|
u8 arm9iLoadAddress[4];
|
||||||
u8 arm9i_size[4];
|
u8 arm9iSize[4];
|
||||||
u8 arm7i_rom_offset[4];
|
u8 arm7iRomOffset[4];
|
||||||
u8 struct_param_base_address[4];
|
u8 struct_param_baseAddress[4];
|
||||||
u8 arm7i_load_address[4];
|
u8 arm7iLoadAddress[4];
|
||||||
u8 arm7i_size[4];
|
u8 arm7iSize[4];
|
||||||
u8 digest_ntr_region_offset[4];
|
u8 digest_ntrRegionOffset[4];
|
||||||
u8 digest_ntr_region_size[4];
|
u8 digest_ntrRegionSize[4];
|
||||||
u8 digest_twl_region_offset[4];
|
u8 digest_twlRegionOffset[4];
|
||||||
u8 digest_twl_region_size[4];
|
u8 digest_twlRegionSize[4];
|
||||||
u8 digest_sector_hashtable_offset[4];
|
u8 digestSectorHashtableOffset[4];
|
||||||
u8 digest_sector_hashtable_size[4];
|
u8 digestSectorHashtableSize[4];
|
||||||
u8 digest_block_hashtable_offset[4];
|
u8 digest_blockHashtableOffset[4];
|
||||||
u8 digest_block_hashtable_size[4];
|
u8 digest_blockHashtableSize[4];
|
||||||
u8 digest_sector_size[4];
|
u8 digestSectorSize[4];
|
||||||
u8 digest_block_sectorcount[4];
|
u8 digest_blockSectorcount[4];
|
||||||
u8 reserved_3[8];
|
u8 reserved3[8];
|
||||||
u8 twl_rom_size[8];
|
u8 twlRomSize[8];
|
||||||
u8 unknown[8];
|
u8 unknown[8];
|
||||||
u8 modcrypt_area_1_offset[4];
|
u8 modcryptArea1Offset[4];
|
||||||
u8 modcrypt_area_1_size[4];
|
u8 modcryptArea1Size[4];
|
||||||
u8 modcrypt_area_2_offset[4];
|
u8 modcryptArea2Offset[4];
|
||||||
u8 modcrypt_area_2_size[4];
|
u8 modcryptArea2Size[4];
|
||||||
u8 title_id[8];
|
u8 title_id[8];
|
||||||
u8 pub_save_data_size[4];
|
u8 pubSaveDataSize[4];
|
||||||
u8 priv_save_data_size[4];
|
u8 privSaveDataSize[4];
|
||||||
u8 reserved_4[0xC0];
|
u8 reserved4[0xC0];
|
||||||
|
|
||||||
// TWL and Signed NTR
|
// TWL and Signed NTR
|
||||||
u8 arm9_with_sec_area_sha1_hmac[0x14];
|
u8 arm9WithSecAreaSha1Hmac[0x14];
|
||||||
u8 arm7_sha1_hmac[0x14];
|
u8 arm7Sha1Hmac[0x14];
|
||||||
u8 digest_master_sha1_hmac[0x14];
|
u8 digestMasterSha1Hmac[0x14];
|
||||||
u8 banner_sha1_hmac[0x14];
|
u8 bannerSha1Hmac[0x14];
|
||||||
u8 arm9i_sha1_hmac[0x14];
|
u8 arm9iSha1Hmac[0x14];
|
||||||
u8 arm7i_sha1_hmac[0x14];
|
u8 arm7iSha1Hmac[0x14];
|
||||||
u8 reserved_5[0x28];
|
u8 reserved5[0x28];
|
||||||
u8 arm9_sha1_hmac[0x14];
|
u8 arm9Sha1Hmac[0x14];
|
||||||
u8 reserved_6[0xA4C];
|
u8 reserved6[0xA4C];
|
||||||
u8 reserved_7[0x180];
|
u8 reserved7[0x180];
|
||||||
u8 signature[0x80];
|
u8 signature[0x80];
|
||||||
} SRL_Header;
|
} srl_hdr;
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "tik.h"
|
#include "tik.h"
|
||||||
|
|
||||||
// Private Prototypes
|
// Private Prototypes
|
||||||
int SetupTicketBuffer(COMPONENT_STRUCT *tik);
|
int SetupTicketBuffer(buffer_struct *tik);
|
||||||
int SetupTicketHeader(tik_hdr *hdr, cia_settings *ciaset);
|
int SetupTicketHeader(tik_hdr *hdr, cia_settings *ciaset);
|
||||||
int SignTicketHeader(tik_hdr *hdr, tik_signature *sig, keys_struct *keys);
|
int SignTicketHeader(tik_hdr *hdr, tik_signature *sig, keys_struct *keys);
|
||||||
void SetLimits(tik_hdr *hdr, cia_settings *ciaset);
|
void SetLimits(tik_hdr *hdr, cia_settings *ciaset);
|
||||||
@@ -26,7 +26,7 @@ int BuildTicket(cia_settings *ciaset)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SetupTicketBuffer(COMPONENT_STRUCT *tik)
|
int SetupTicketBuffer(buffer_struct *tik)
|
||||||
{
|
{
|
||||||
tik->size = sizeof(tik_signature) + sizeof(tik_hdr);
|
tik->size = sizeof(tik_signature) + sizeof(tik_hdr);
|
||||||
tik->buffer = malloc(tik->size);
|
tik->buffer = malloc(tik->size);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _TIK_H_
|
#pragma once
|
||||||
#define _TIK_H_
|
|
||||||
|
|
||||||
static const unsigned char default_contentIndex[0x30] =
|
static const unsigned char default_contentIndex[0x30] =
|
||||||
{
|
{
|
||||||
@@ -64,8 +63,6 @@ typedef struct
|
|||||||
u8 contentIndex[0xAC];
|
u8 contentIndex[0xAC];
|
||||||
} tik_hdr;
|
} tik_hdr;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Prototypes
|
// Prototypes
|
||||||
int BuildTicket(cia_settings *ciaset);
|
int BuildTicket(cia_settings *ciaset);
|
||||||
int CryptTitleKey(u8 *EncTitleKey, u8 *DecTitleKey, u8 *TitleID, keys_struct *keys, u8 mode);
|
int CryptTitleKey(u8 *EncTitleKey, u8 *DecTitleKey, u8 *TitleID, keys_struct *keys, u8 mode);
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _TITLEID_H_
|
#pragma once
|
||||||
#define _TITLEID_H_
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -84,8 +83,6 @@ typedef enum
|
|||||||
|
|
||||||
} ProgramIdCategory;
|
} ProgramIdCategory;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
u64 ConvertTwlIdToCtrId(u64 pgid);
|
u64 ConvertTwlIdToCtrId(u64 pgid);
|
||||||
|
|
||||||
int GetProgramID(u64 *dest, rsf_settings *yaml, bool IsForExheader);
|
int GetProgramID(u64 *dest, rsf_settings *yaml, bool IsForExheader);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
#include "tmd.h"
|
#include "tmd.h"
|
||||||
|
|
||||||
// Private Prototypes
|
// 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 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 SignTMDHeader(tmd_hdr *hdr, tmd_signature *sig, keys_struct *keys);
|
||||||
int SetupTMDInfoRecord(tmd_content_info_record *info_record, u8 *content_record, u16 ContentCount);
|
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 BuildTMD(cia_settings *ciaset)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
ciaset->ciaSections.tmd.size = PredictTMDSize(ciaset->content.contentCount);
|
||||||
result = SetupTMDBuffer(&ciaset->ciaSections.tmd);
|
result = SetupTMDBuffer(&ciaset->ciaSections.tmd);
|
||||||
if(result) return result;
|
if(result) return result;
|
||||||
|
|
||||||
@@ -35,8 +36,9 @@ int BuildTMD(cia_settings *ciaset)
|
|||||||
return 0;
|
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
|
tmd->buffer = malloc(tmd->size); // tmd->size is already set before
|
||||||
if(!tmd->buffer) { fprintf(stderr,"[ERROR] MEM ERROR\n"); return MEM_ERROR; }
|
if(!tmd->buffer) { fprintf(stderr,"[ERROR] MEM ERROR\n"); return MEM_ERROR; }
|
||||||
memset(tmd->buffer,0,tmd->size);
|
memset(tmd->buffer,0,tmd->size);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _TMD_H_
|
#pragma once
|
||||||
#define _TMD_H_
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -61,8 +60,6 @@ typedef struct
|
|||||||
u8 infoRecordHash[0x20]; // SHA-256
|
u8 infoRecordHash[0x20]; // SHA-256
|
||||||
} tmd_hdr;
|
} tmd_hdr;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Prototypes
|
// Prototypes
|
||||||
u32 PredictTMDSize(u16 ContentCount);
|
u32 PredictTMDSize(u16 ContentCount);
|
||||||
int BuildTMD(cia_settings *ciaset);
|
int BuildTMD(cia_settings *ciaset);
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _TPKI_H_
|
#pragma once
|
||||||
#define _TPKI_H_
|
|
||||||
|
|
||||||
// AES KEYS
|
// AES KEYS
|
||||||
static const unsigned char zeros_aesKey[16] =
|
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,
|
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
@@ -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)
|
if(strcasecmp(argv[i+1],"test") == 0 || strcasecmp(argv[i+1],"t") == 0)
|
||||||
set->common.keys.keyset = pki_TEST;
|
set->common.keys.keyset = pki_TEST;
|
||||||
else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0)
|
else if(strcasecmp(argv[i+1],"beta") == 0 || strcasecmp(argv[i+1],"b") == 0)
|
||||||
set->common.keys.keyset = pki_CUSTOM;
|
set->common.keys.keyset = pki_BETA;
|
||||||
|
|
||||||
#ifndef PUBLIC_BUILD
|
|
||||||
else if(strcasecmp(argv[i+1],"debug") == 0 || strcasecmp(argv[i+1],"development") == 0 || strcasecmp(argv[i+1],"d") == 0)
|
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;
|
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)
|
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;
|
set->common.keys.keyset = pki_PRODUCTION;
|
||||||
/*
|
else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0)
|
||||||
else if(strcasecmp(argv[i+1],"beta") == 0 || strcasecmp(argv[i+1],"b") == 0)
|
set->common.keys.keyset = pki_CUSTOM;
|
||||||
set->common.keys.keyset = pki_BETA;
|
|
||||||
*/
|
|
||||||
#endif
|
|
||||||
else{
|
else{
|
||||||
fprintf(stderr,"[SETTING ERROR] Unrecognised target '%s'\n",argv[i+1]);
|
fprintf(stderr,"[SETTING ERROR] Unrecognised target '%s'\n",argv[i+1]);
|
||||||
return USR_BAD_ARG;
|
return USR_BAD_ARG;
|
||||||
@@ -353,6 +348,15 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
//
|
||||||
|
else if(strcmp(argv[i],"-6xcrypto") == 0){
|
||||||
|
if(HasParam){
|
||||||
|
PrintNoNeedParam("-6xcrypto");
|
||||||
|
return USR_BAD_ARG;
|
||||||
|
}
|
||||||
|
set->cci.use6xSavedataCrypto = true;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
// Cia Options
|
// Cia Options
|
||||||
#ifndef PUBLIC_BUILD
|
#ifndef PUBLIC_BUILD
|
||||||
else if(strcmp(argv[i],"-cci") == 0){
|
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){
|
if(set->dname.m_items == 0){
|
||||||
set->dname.m_items = 10;
|
set->dname.m_items = 10;
|
||||||
set->dname.u_items = 0;
|
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){
|
if(!set->dname.items){
|
||||||
fprintf(stderr,"[SETTING ERROR] Not enough memory\n");
|
fprintf(stderr,"[SETTING ERROR] Not enough memory\n");
|
||||||
return MEM_ERROR;
|
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){
|
else if(set->dname.m_items == set->dname.u_items){
|
||||||
set->dname.m_items *= 2;
|
set->dname.m_items *= 2;
|
||||||
|
/*
|
||||||
dname_item *tmp = malloc(sizeof(dname_item)*set->dname.m_items);
|
dname_item *tmp = malloc(sizeof(dname_item)*set->dname.m_items);
|
||||||
if(!tmp){
|
if(!tmp){
|
||||||
fprintf(stderr,"[SETTING ERROR] Not enough memory\n");
|
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);
|
memcpy(tmp,set->dname.items,sizeof(dname_item)*set->dname.u_items);
|
||||||
free(set->dname.items);
|
free(set->dname.items);
|
||||||
set->dname.items = tmp;
|
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);
|
char *name_pos = (char*)(argv[i]+2);
|
||||||
@@ -633,6 +644,10 @@ int CheckArgumentCombination(user_settings *set)
|
|||||||
PrintNeedsArgument("-exheader");
|
PrintNeedsArgument("-exheader");
|
||||||
return USR_BAD_ARG;
|
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
|
// Reporting bad arguments
|
||||||
if(!buildCXI && set->ncch.elfPath){
|
if(!buildCXI && set->ncch.elfPath){
|
||||||
@@ -925,17 +940,13 @@ void DisplayHelp(char *app_name)
|
|||||||
//printf(" -v Verbose\n");
|
//printf(" -v Verbose\n");
|
||||||
printf(" -DNAME=VALUE Substitute values in Spec files\n");
|
printf(" -DNAME=VALUE Substitute values in Spec files\n");
|
||||||
printf("KEY OPTIONS:\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|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(" 't' Test(false) Keys & prod Certs\n");
|
||||||
|
//printf(" 'b' Beta Keys & prod Certs\n");
|
||||||
printf(" 'd' Development Keys & Certs\n");
|
printf(" 'd' Development Keys & Certs\n");
|
||||||
printf(" 'p' Production Keys & Certs\n");
|
printf(" 'p' Production Keys & Certs\n");
|
||||||
printf(" 'c' User provides Keys & Certs\n");
|
printf(" 'c' Custom Keys & Certs\n");
|
||||||
#endif
|
|
||||||
printf(" -keydir <dir> Key Directory (for use with \"-target c\")\n");
|
printf(" -keydir <dir> Key Directory (for use with \"-target c\")\n");
|
||||||
printf(" -ckeyID <u8 value> Override the automatic commonKey selection\n");
|
printf(" -ckeyID <u8 value> Override the automatic commonKey selection\n");
|
||||||
printf(" -showkeys Display the loaded keychain\n");
|
printf(" -showkeys Display the loaded keychain\n");
|
||||||
@@ -956,6 +967,7 @@ void DisplayHelp(char *app_name)
|
|||||||
#ifndef PUBLIC_BUILD
|
#ifndef PUBLIC_BUILD
|
||||||
printf(" -devcardcci Use SDK CardInfo Method\n");
|
printf(" -devcardcci Use SDK CardInfo Method\n");
|
||||||
#endif
|
#endif
|
||||||
|
printf(" -6xcrypto Toggle FW6.X Save Crypto\n");
|
||||||
printf(" -content <filepath>:<index> Specify content files\n");
|
printf(" -content <filepath>:<index> Specify content files\n");
|
||||||
printf("CIA OPTIONS:\n");
|
printf("CIA OPTIONS:\n");
|
||||||
#ifndef PUBLIC_BUILD
|
#ifndef PUBLIC_BUILD
|
||||||
|
|||||||
+3
-4
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _USERSETTINGS_H_
|
#pragma once
|
||||||
#define _USERSETTINGS_H_
|
|
||||||
|
|
||||||
#define CCI_MAX_CONTENT 8
|
#define CCI_MAX_CONTENT 8
|
||||||
#define CIA_MAX_CONTENT 65536
|
#define CIA_MAX_CONTENT 65536
|
||||||
@@ -246,7 +245,7 @@ typedef struct
|
|||||||
|
|
||||||
char *workingFilePath;
|
char *workingFilePath;
|
||||||
infile_type workingFileType; // Could Be ncch/ncsd/srl. This is mainly used for CIA gen
|
infile_type workingFileType; // Could Be ncch/ncsd/srl. This is mainly used for CIA gen
|
||||||
COMPONENT_STRUCT workingFile;
|
buffer_struct workingFile;
|
||||||
} common;
|
} common;
|
||||||
|
|
||||||
dname_struct dname; // For RSF value subsitution
|
dname_struct dname; // For RSF value subsitution
|
||||||
@@ -270,6 +269,7 @@ typedef struct
|
|||||||
|
|
||||||
struct{
|
struct{
|
||||||
bool useSDKStockData; // incase we want to use the SDK stock data, for whatever reason.
|
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
|
} cci; // CCI Settings
|
||||||
|
|
||||||
struct{
|
struct{
|
||||||
@@ -287,7 +287,6 @@ typedef struct
|
|||||||
|
|
||||||
|
|
||||||
} user_settings;
|
} user_settings;
|
||||||
#endif
|
|
||||||
|
|
||||||
// Prototypes
|
// Prototypes
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------- */
|
||||||
@@ -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);
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
|
#include "utf.h"
|
||||||
|
|
||||||
//MISC
|
// Memory
|
||||||
void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base)
|
void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base)
|
||||||
{
|
{
|
||||||
char tmp[size][2];
|
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++)
|
if(!*dest){
|
||||||
printf("%02x",array[i]);
|
*dest = malloc(size);
|
||||||
}
|
if(!*dest) return -1;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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};
|
if(value % alignment != 0)
|
||||||
for(int i = 0; i < 16; i++){
|
return value + alignment - value % alignment;
|
||||||
if (flag >= bit_mask[i]){
|
|
||||||
flag_bool[15-i] = true;
|
|
||||||
flag -= bit_mask[i];
|
|
||||||
}
|
|
||||||
else
|
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[])
|
int append_filextention(char *output, u16 max_outlen, char *input, char extention[])
|
||||||
{
|
{
|
||||||
if(output == NULL || input == NULL){
|
if(output == NULL || input == NULL){
|
||||||
@@ -102,111 +89,118 @@ int append_filextention(char *output, u16 max_outlen, char *input, char extentio
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CopyData(u8 **dest, u8 *source, u64 size)
|
void memdump(FILE* fout, const char* prefix, const u8* data, u32 size)
|
||||||
{
|
{
|
||||||
if(!*dest){
|
u32 i;
|
||||||
*dest = malloc(size);
|
u32 prefixlen = strlen(prefix);
|
||||||
if(!*dest) return -1;
|
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;
|
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;
|
*dst_len = src_len*sizeof(u16);
|
||||||
return b;
|
*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;
|
*dst_len = src_len*sizeof(u16);
|
||||||
return b;
|
*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
|
#ifndef _WIN32
|
||||||
void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output)
|
int str_utf8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len)
|
||||||
{
|
{
|
||||||
fseek_64(output,offset,SEEK_SET);
|
*dst_len = src_len*sizeof(u16);
|
||||||
fwrite(buffer,size,1,output);
|
*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);
|
#ifdef _WIN32
|
||||||
fread(outbuff,size,1,file);
|
struct _stat64 st;
|
||||||
|
return _stat64(filename, &st) == 0;
|
||||||
|
#else
|
||||||
|
struct stat st;
|
||||||
|
return stat(filename, &st) == 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetFileSize_u64(char *filename)
|
u64 GetFileSize_u64(char *filename)
|
||||||
{
|
{
|
||||||
u64 size;
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/* Making sure file exists */
|
struct _stat64 st;
|
||||||
FILE *tmp = fopen(filename,"rb");
|
if( _stat64(filename, &st) != 0)
|
||||||
if(!tmp) return 0;
|
return 0;
|
||||||
fclose(tmp);
|
else
|
||||||
|
return st.st_size;
|
||||||
int fh;
|
|
||||||
u64 n;
|
|
||||||
fh = _open( filename, 0 );
|
|
||||||
n = _lseeki64(fh, 0, SEEK_END);
|
|
||||||
_close(fh);
|
|
||||||
size = (n / sizeof(short))*2;
|
|
||||||
#else
|
#else
|
||||||
FILE *file = fopen(filename,"rb");
|
struct stat st;
|
||||||
fseeko(file, 0L, SEEK_END);
|
if( stat(filename, &st) != 0)
|
||||||
size = ftello(file);
|
return 0;
|
||||||
fclose(file);
|
else
|
||||||
#endif
|
return st.st_size;
|
||||||
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);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +222,89 @@ char *getcwdir(char *buffer,int maxlen)
|
|||||||
#endif
|
#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 u8_to_u16(u8 *value, u8 endianness)
|
||||||
{
|
{
|
||||||
u16 new_value;
|
u16 new_value;
|
||||||
@@ -341,33 +417,4 @@ int u64_to_u8(u8 *out_value, u64 in_value, u8 endianness)
|
|||||||
return 0;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +1,55 @@
|
|||||||
#ifndef _UTILS_H_
|
#pragma once
|
||||||
#define _UTILS_H_
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
char *argument;
|
|
||||||
u16 arg_len;
|
|
||||||
} OPTION_CTX;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
u64 size;
|
u64 size;
|
||||||
u8 *buffer;
|
u8 *buffer;
|
||||||
} COMPONENT_STRUCT;
|
} buffer_struct;
|
||||||
#endif
|
|
||||||
|
|
||||||
//MISC
|
// Memory
|
||||||
void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base);
|
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 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);
|
int CopyData(u8 **dest, u8 *source, u64 size);
|
||||||
|
|
||||||
|
// MISC
|
||||||
|
u64 align(u64 value, u64 alignment);
|
||||||
u64 min_u64(u64 a, u64 b);
|
u64 min_u64(u64 a, u64 b);
|
||||||
u64 max_u64(u64 a, u64 b);
|
u64 max_u64(u64 a, u64 b);
|
||||||
//IO Related
|
|
||||||
void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output);
|
// Strings
|
||||||
void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file);
|
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);
|
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);
|
int makedir(const char* dir);
|
||||||
char *getcwdir(char *buffer,int maxlen);
|
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);
|
u16 u8_to_u16(u8 *value, u8 endianness);
|
||||||
u32 u8_to_u32(u8 *value, u8 endianness);
|
u32 u8_to_u32(u8 *value, u8 endianness);
|
||||||
u64 u8_to_u64(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 u16_to_u8(u8 *out_value, u16 in_value, u8 endianness);
|
||||||
int u32_to_u8(u8 *out_value, u32 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);
|
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);
|
|
||||||
|
|
||||||
|
|||||||
@@ -348,6 +348,7 @@ u32 SetYAMLSequence(char ***dest, char *key, ctr_yaml_context *ctx)
|
|||||||
ActualCount++;
|
ActualCount++;
|
||||||
if(ActualCount >= SlotCount){ // if Exceeding Ptr capacity, expand buffer
|
if(ActualCount >= SlotCount){ // if Exceeding Ptr capacity, expand buffer
|
||||||
SlotCount = SlotCount*2;
|
SlotCount = SlotCount*2;
|
||||||
|
/*
|
||||||
char **tmp1 = malloc((SlotCount+1)*sizeof(char*)); // allocate new buffer
|
char **tmp1 = malloc((SlotCount+1)*sizeof(char*)); // allocate new buffer
|
||||||
if(!tmp1){
|
if(!tmp1){
|
||||||
ctx->error = YAML_MEM_ERROR;
|
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
|
for(u32 i = 0; i < ActualCount; i++) tmp1[i] = tmp[i]; // Transfer ptrs
|
||||||
free(tmp); // free original buffer
|
free(tmp); // free original buffer
|
||||||
tmp = tmp1; // transfer main ptr
|
tmp = tmp1; // transfer main ptr
|
||||||
|
*/
|
||||||
|
tmp = realloc(tmp,(SlotCount+1)*sizeof(char*));
|
||||||
|
if(!tmp){
|
||||||
|
ctx->error = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FinishEvent(ctx);
|
FinishEvent(ctx);
|
||||||
GetEvent(ctx);
|
GetEvent(ctx);
|
||||||
|
|||||||
+1
-4
@@ -1,5 +1,4 @@
|
|||||||
#ifndef _YAML_H_
|
#pragma once
|
||||||
#define _YAML_H_
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -27,8 +26,6 @@ typedef struct
|
|||||||
|
|
||||||
} ctr_yaml_context;
|
} ctr_yaml_context;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Public Prototypes
|
// Public Prototypes
|
||||||
int GetYamlSettings(user_settings *set);
|
int GetYamlSettings(user_settings *set);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
int MergeSpecData(rsf_settings *out, rsf_settings *desc, rsf_settings *rsf);
|
int MergeSpecData(rsf_settings *out, rsf_settings *desc, rsf_settings *rsf);
|
||||||
void EvaluateRSF(rsf_settings *rsf, ctr_yaml_context *ctx);
|
void EvaluateRSF(rsf_settings *rsf, ctr_yaml_context *ctx);
|
||||||
|
|||||||
Reference in New Issue
Block a user