mirror of
https://github.com/DarkStore-3DS/Project_CTR.git
synced 2026-07-03 00:39:14 +00:00
big update
lots cleaned, added cia to cci conv, it 's called a block, separated reading from building, improved ncch keyx stuff, and basic verbose for keys, elf checking and romfs
This commit is contained in:
+5
-5
@@ -1,8 +1,8 @@
|
||||
# Makerom Sources
|
||||
UTILS_OBJS = utils.o dir.o utf.o keyset.o titleid.o
|
||||
CIA_OBJS = cia.o cia_read.o certs.o tik.o tmd.o tmd_read.o
|
||||
NCCH_OBJS = ncch.o exheader.o accessdesc.o exefs.o elf.o romfs.o romfs_import.o romfs_binary.o
|
||||
NCSD_OBJS = ncsd.o
|
||||
UTILS_OBJS = utils.o ctr_utils.o dir.o utf.o keyset.o titleid.o
|
||||
CIA_OBJS = cia.o certs.o tik.o tmd.o
|
||||
NCCH_OBJS = ncch.o exheader.o accessdesc.o exefs.o elf.o romfs.o romfs_import.o romfs_gen.o
|
||||
NCSD_OBJS = ncsd.o cardinfo.o
|
||||
SETTINGS_OBJS = user_settings.o rsf_settings.o
|
||||
LIB_API_OBJS = crypto.o yaml_parser.o blz.o
|
||||
|
||||
@@ -21,7 +21,7 @@ CC = gcc
|
||||
# MAKEROM Build Settings
|
||||
MAKEROM_BUILD_FLAGS = #-DDEBUG
|
||||
VER_MAJOR = 0
|
||||
VER_MINOR = 10
|
||||
VER_MINOR = 11
|
||||
OUTPUT = makerom
|
||||
|
||||
main: build
|
||||
|
||||
+29
-82
@@ -1,13 +1,11 @@
|
||||
#include "lib.h"
|
||||
#include "ncch.h"
|
||||
#include "exheader.h"
|
||||
#include "ncch_build.h"
|
||||
#include "exheader_build.h"
|
||||
#include "accessdesc.h"
|
||||
|
||||
#include "polarssl/base64.h"
|
||||
|
||||
#include "desc_presets.h"
|
||||
#include "desc_dev_sigdata.h"
|
||||
#include "desc_prod_sigdata.h"
|
||||
#include "desc/presets.h"
|
||||
#include "desc/dev_sigdata.h"
|
||||
#include "desc/prod_sigdata.h"
|
||||
|
||||
const int RSF_RSA_DATA_LEN = 344;
|
||||
const int RSF_DESC_DATA_LEN = 684;
|
||||
@@ -19,20 +17,16 @@ int accessdesc_GetSignFromPreset(exheader_settings *exhdrset);
|
||||
void accessdesc_GetPresetData(u8 **desc, u8 **accessDesc, u8 **depList, keys_struct *keys);
|
||||
void accessdesc_GetPresetSigData(u8 **accessDescSig, u8 **cxiPubk, u8 **cxiPvtk, keys_struct *keys);
|
||||
|
||||
bool IsValidB64Char(char chr);
|
||||
u32 b64_strlen(char *str);
|
||||
void b64_strcpy(char *dst, char *src);
|
||||
|
||||
int set_AccessDesc(exheader_settings *exhdrset)
|
||||
{
|
||||
if(exhdrset->useAccessDescPreset)
|
||||
if(exhdrset->useAccessDescPreset) // Use AccessDesc Template
|
||||
return accessdesc_GetSignFromPreset(exhdrset);
|
||||
else if(exhdrset->rsf->CommonHeaderKey.Found) // Keydata exists in RSF
|
||||
return accessdesc_GetSignFromRsf(exhdrset);
|
||||
else if(!exhdrset->keys->rsa.requiresPresignedDesc) // Else if The AccessDesc can be signed with key
|
||||
return accessdesc_SignWithKey(exhdrset);
|
||||
else{ // No way the access desc signature can be 'obtained'
|
||||
fprintf(stderr,"[EXHEADER ERROR] Current keyset cannot sign AccessDesc, please appropriatly setup RSF, or specify a preset with -accessdesc\n");
|
||||
fprintf(stderr,"[ACEXDESC ERROR] Current keyset cannot sign AccessDesc, please appropriately set-up RSF, or specify a preset with \"-desc\"\n");
|
||||
return CANNOT_SIGN_ACCESSDESC;
|
||||
}
|
||||
}
|
||||
@@ -65,7 +59,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset)
|
||||
{
|
||||
/* Yaml Option Sanity Checks */
|
||||
if(!exhdrset->rsf->CommonHeaderKey.Found){
|
||||
fprintf(stderr,"[EXHEADER ERROR] RSF Section \"CommonHeaderKey\" not found\n");
|
||||
fprintf(stderr,"[ACEXDESC ERROR] RSF Section \"CommonHeaderKey\" not found\n");
|
||||
return COMMON_HEADER_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -74,7 +68,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset)
|
||||
return COMMON_HEADER_KEY_NOT_FOUND;
|
||||
}
|
||||
if(b64_strlen(exhdrset->rsf->CommonHeaderKey.D) != RSF_RSA_DATA_LEN){
|
||||
fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/D\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.D));
|
||||
fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/D\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.D));
|
||||
return COMMON_HEADER_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -83,7 +77,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset)
|
||||
return COMMON_HEADER_KEY_NOT_FOUND;
|
||||
}
|
||||
if(b64_strlen(exhdrset->rsf->CommonHeaderKey.Modulus) != RSF_RSA_DATA_LEN){
|
||||
fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Modulus\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.Modulus));
|
||||
fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/Modulus\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.Modulus));
|
||||
return COMMON_HEADER_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -92,7 +86,7 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset)
|
||||
return COMMON_HEADER_KEY_NOT_FOUND;
|
||||
}
|
||||
if(b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign) != RSF_RSA_DATA_LEN){
|
||||
fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Signature\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign));
|
||||
fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/Signature\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescSign));
|
||||
return COMMON_HEADER_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -101,41 +95,30 @@ int accessdesc_GetSignFromRsf(exheader_settings *exhdrset)
|
||||
return COMMON_HEADER_KEY_NOT_FOUND;
|
||||
}
|
||||
if(b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin) != RSF_DESC_DATA_LEN){
|
||||
fprintf(stderr,"[EXHEADER ERROR] \"CommonHeaderKey/Descriptor\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin));
|
||||
fprintf(stderr,"[ACEXDESC ERROR] \"CommonHeaderKey/Descriptor\" has invalid length (%d)\n",b64_strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin));
|
||||
return COMMON_HEADER_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Set RSA Keys */
|
||||
int result = 0;
|
||||
u32 out;
|
||||
|
||||
out = 0x100;
|
||||
result = base64_decode(exhdrset->keys->rsa.cxiHdrPub,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.Modulus,strlen(exhdrset->rsf->CommonHeaderKey.Modulus));
|
||||
if(out != 0x100)
|
||||
result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL;
|
||||
if(result) goto finish;
|
||||
|
||||
out = 0x100;
|
||||
result = base64_decode(exhdrset->keys->rsa.cxiHdrPvt,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.D,strlen(exhdrset->rsf->CommonHeaderKey.D));
|
||||
if(out != 0x100)
|
||||
result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL;
|
||||
if(result) goto finish;
|
||||
// NCCH Header pubk
|
||||
result = b64_decode(exhdrset->keys->rsa.cxiHdrPub,exhdrset->rsf->CommonHeaderKey.Modulus,0x100);
|
||||
if(result) return result;
|
||||
// NCCH Header privk
|
||||
result = b64_decode(exhdrset->keys->rsa.cxiHdrPvt,exhdrset->rsf->CommonHeaderKey.D,0x100);
|
||||
if(result) return result;
|
||||
|
||||
/* Set AccessDesc */
|
||||
out = 0x100;
|
||||
result = base64_decode(exhdrset->acexDesc->signature,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.AccCtlDescSign, strlen( exhdrset->rsf->CommonHeaderKey.AccCtlDescSign));
|
||||
if(out != 0x100)
|
||||
result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL;
|
||||
if(result) goto finish;
|
||||
// Signature
|
||||
result = b64_decode(exhdrset->acexDesc->signature,exhdrset->rsf->CommonHeaderKey.AccCtlDescSign,0x100);
|
||||
if(result) return result;
|
||||
// NCCH Header pubk
|
||||
memcpy(exhdrset->acexDesc->ncchRsaPubKey,exhdrset->keys->rsa.cxiHdrPub,0x100);
|
||||
|
||||
out = 0x200;
|
||||
result = base64_decode((u8*)&exhdrset->acexDesc->arm11SystemLocalCapabilities,(size_t *)&out,(const u8*)exhdrset->rsf->CommonHeaderKey.AccCtlDescBin,strlen(exhdrset->rsf->CommonHeaderKey.AccCtlDescBin));
|
||||
if(out != 0x200)
|
||||
result = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL;
|
||||
if(result) goto finish;
|
||||
finish:
|
||||
return result;
|
||||
// Access Control
|
||||
result = b64_decode((u8*)&exhdrset->acexDesc->arm11SystemLocalCapabilities,exhdrset->rsf->CommonHeaderKey.AccCtlDescBin,0x200);
|
||||
if(result) return result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int accessdesc_GetSignFromPreset(exheader_settings *exhdrset)
|
||||
@@ -153,12 +136,12 @@ int accessdesc_GetSignFromPreset(exheader_settings *exhdrset)
|
||||
|
||||
// Error Checking
|
||||
if(!desc || !depList){
|
||||
fprintf(stderr,"[EXHEADER ERROR] AccessDesc preset is unavailable, please configure RSF file\n");
|
||||
fprintf(stderr,"[ACEXDESC ERROR] AccessDesc template is unavailable, please configure RSF file\n");
|
||||
return CANNOT_SIGN_ACCESSDESC;
|
||||
}
|
||||
|
||||
if((!cxiPubk || !cxiPvtk || !accessDesc || !accessDescSig) && exhdrset->keys->rsa.requiresPresignedDesc){
|
||||
fprintf(stderr,"[EXHEADER ERROR] This AccessDesc preset needs to be signed, the current keyset is incapable of doing so. Please configure RSF file with the appropriate signature data.\n");
|
||||
fprintf(stderr,"[ACEXDESC ERROR] This AccessDesc template needs to be signed, the current keyset is incapable of doing so. Please configure RSF file with the appropriate signature data.\n");
|
||||
return CANNOT_SIGN_ACCESSDESC;
|
||||
}
|
||||
|
||||
@@ -451,40 +434,4 @@ void accessdesc_GetPresetSigData(u8 **accessDescSig, u8 **cxiPubk, u8 **cxiPvtk,
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsValidB64Char(char chr)
|
||||
{
|
||||
return (isalnum(chr) || chr == '+' || chr == '/' || chr == '=');
|
||||
}
|
||||
|
||||
u32 b64_strlen(char *str)
|
||||
{
|
||||
u32 count = 0;
|
||||
u32 i = 0;
|
||||
while(str[i] != 0x0){
|
||||
if(IsValidB64Char(str[i])) {
|
||||
//printf("Is Valid: %c\n",str[i]);
|
||||
count++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void b64_strcpy(char *dst, char *src)
|
||||
{
|
||||
u32 src_len = strlen(src);
|
||||
u32 j = 0;
|
||||
for(u32 i = 0; i < src_len; i++){
|
||||
if(IsValidB64Char(src[i])){
|
||||
dst[j] = src[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
dst[j] = 0;
|
||||
|
||||
//memdump(stdout,"src: ",(u8*)src,src_len+1);
|
||||
//memdump(stdout,"dst: ",(u8*)dst,j+1);
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
#include "lib.h"
|
||||
#include "ncch_read.h"
|
||||
#include "ncsd_build.h"
|
||||
#include "cardinfo.h"
|
||||
|
||||
void InitCardInfoHdr(cardinfo_hdr **cihdr, devcardinfo_hdr **dcihdr, cci_settings *set);
|
||||
int SetWriteableAddress(cardinfo_hdr *hdr, cci_settings *set);
|
||||
int SetCardInfoBitmask(cardinfo_hdr *hdr, cci_settings *set);
|
||||
int SetCardInfoNotes(cardinfo_hdr *hdr, cci_settings *set);
|
||||
void ImportNcch0Data(cardinfo_hdr *hdr, cci_settings *set);
|
||||
void SetInitialData(cardinfo_hdr *hdr, cci_settings *set);
|
||||
void SetDevCardInfo(devcardinfo_hdr *hdr, cci_settings *set);
|
||||
|
||||
|
||||
int GenCardInfoHdr(cci_settings *set)
|
||||
{
|
||||
cardinfo_hdr *cihdr;
|
||||
devcardinfo_hdr *dcihdr;
|
||||
|
||||
InitCardInfoHdr(&cihdr,&dcihdr,set);
|
||||
|
||||
if(SetWriteableAddress(cihdr,set))
|
||||
return GEN_HDR_FAIL;
|
||||
if(SetCardInfoBitmask(cihdr,set))
|
||||
return GEN_HDR_FAIL;
|
||||
if(SetCardInfoNotes(cihdr,set))
|
||||
return GEN_HDR_FAIL;
|
||||
ImportNcch0Data(cihdr,set);
|
||||
SetInitialData(cihdr,set);
|
||||
|
||||
if(dcihdr)
|
||||
SetDevCardInfo(dcihdr,set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InitCardInfoHdr(cardinfo_hdr **cihdr, devcardinfo_hdr **dcihdr, cci_settings *set)
|
||||
{
|
||||
set->headers.cardinfohdr.size = sizeof(cardinfo_hdr);
|
||||
if(set->options.useExternalSdkCardInfo)
|
||||
set->headers.cardinfohdr.size += sizeof(devcardinfo_hdr);
|
||||
|
||||
set->headers.cardinfohdr.buffer = calloc(1,set->headers.cardinfohdr.size);
|
||||
|
||||
*cihdr = (cardinfo_hdr*)set->headers.cardinfohdr.buffer;
|
||||
|
||||
if(set->headers.cardinfohdr.size > sizeof(cardinfo_hdr))
|
||||
*dcihdr = (devcardinfo_hdr*)(set->headers.cardinfohdr.buffer+sizeof(cardinfo_hdr));
|
||||
else
|
||||
*dcihdr = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
u64 GetCciUnusedSize(u64 mediaSize, u8 cardType)
|
||||
{
|
||||
if(cardType == mediatype_CARD1){
|
||||
switch(mediaSize){
|
||||
case (u64)MB*128: return (u64)2621440;
|
||||
case (u64)MB*256: return (u64)5242880;
|
||||
case (u64)MB*512: return (u64)10485760;
|
||||
case (u64)GB*1: return (u64)73924608;
|
||||
case (u64)GB*2: return (u64)147324928;
|
||||
case (u64)GB*4: return (u64)294649856;
|
||||
case (u64)GB*8: return (u64)587202560;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
else if(cardType == mediatype_CARD2){
|
||||
switch(mediaSize){
|
||||
case (u64)MB*512: return (u64)37224448;
|
||||
case (u64)GB*1: return (u64)73924608;
|
||||
case (u64)GB*2: return (u64)147324928;
|
||||
case (u64)GB*4: return (u64)294649856;
|
||||
case (u64)GB*8: return (u64)587202560;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetWriteableAddress(cardinfo_hdr *hdr, cci_settings *set)
|
||||
{
|
||||
if(set->romInfo.mediaType != mediatype_CARD2){ // Can only be set for Card2 Media
|
||||
u32_to_u8(hdr->writableAddress,(u32)-1,LE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *str = set->rsf->CardInfo.WritableAddress;
|
||||
set->romInfo.card2SaveOffset = -1;
|
||||
|
||||
if(str){
|
||||
if(strncmp(str,"0x",2) != 0){
|
||||
fprintf(stderr,"[CCI ERROR] WritableAddress requires a Hexadecimal value\n");
|
||||
return INVALID_RSF_OPT;
|
||||
}
|
||||
set->romInfo.card2SaveOffset = strtoull(str,NULL,16);
|
||||
}
|
||||
else{
|
||||
if ((set->romInfo.mediaSize / 2) < set->romInfo.saveSize || set->romInfo.saveSize > (u64)(2047*MB)){
|
||||
u64 saveDataSize = set->romInfo.saveSize / KB;
|
||||
fprintf(stderr,"[CCI ERROR] Too large SavedataSize %"PRIu64"K\n",saveDataSize);
|
||||
return SAVE_DATA_TOO_LARGE;
|
||||
}
|
||||
if(set->options.closeAlignWR)
|
||||
set->romInfo.card2SaveOffset = align(set->romInfo.usedSize, set->romInfo.blockSize); // invalid for "real" chips
|
||||
else{
|
||||
u64 unusedSize = GetCciUnusedSize(set->romInfo.mediaSize,set->romInfo.mediaType); // Some value related to the physical implementation of gamecards
|
||||
if(unusedSize > 0)
|
||||
set->romInfo.card2SaveOffset = set->romInfo.mediaSize - unusedSize - set->romInfo.saveSize; // Nintendo's method for calculating writable region offset
|
||||
else{
|
||||
fprintf(stderr,"[CCI WARNING] Nintendo does not support CARD2 for the current MediaSize, aligning save offset after last NCCH\n");
|
||||
set->romInfo.card2SaveOffset = align(set->romInfo.usedSize, set->romInfo.blockSize); // invalid for "real" chips
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32_to_u8(hdr->writableAddress,(u32)(set->romInfo.card2SaveOffset/set->romInfo.blockSize),LE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetCardInfoBitmask(cardinfo_hdr *hdr, cci_settings *set)
|
||||
{
|
||||
u32 bitmask = 0;
|
||||
|
||||
char *str = set->rsf->CardInfo.CardType;
|
||||
if(!str)
|
||||
bitmask |= 0;
|
||||
else{
|
||||
if(strcasecmp(str,"s1") == 0)
|
||||
bitmask |= 0;
|
||||
else if(strcasecmp(str,"s2") == 0)
|
||||
bitmask |= 0x20;
|
||||
else {
|
||||
fprintf(stderr,"[CCI ERROR] Invalid CardType: %s\n",str);
|
||||
return INVALID_RSF_OPT;
|
||||
}
|
||||
}
|
||||
|
||||
str = set->rsf->CardInfo.CryptoType;
|
||||
if(!str)
|
||||
bitmask |= 0;//(3*0x40);
|
||||
else{
|
||||
int val = strtol(str,NULL,10);
|
||||
if(val < 0 || val > 3) {
|
||||
fprintf(stderr,"[CCI ERROR] Invalid CryptoType: %s\n",str);
|
||||
return INVALID_RSF_OPT;
|
||||
}
|
||||
if(val != 3)
|
||||
fprintf(stderr,"[CCI WARNING] Card crypto type = '%d'\n",val);
|
||||
bitmask |= val * 0x40;
|
||||
}
|
||||
|
||||
u32_to_u8(hdr->cardInfoBitmask,bitmask,BE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetCardInfoNotes(cardinfo_hdr *hdr, cci_settings *set)
|
||||
{
|
||||
u64_to_u8(hdr->notes.mediaSizeUsed,set->romInfo.usedSize,LE);
|
||||
u32_to_u8(hdr->notes.unknown,0,LE);
|
||||
|
||||
if(set->options.tmdHdr){
|
||||
u64_to_u8(hdr->notes.cverTitleId,GetTmdTitleId(set->options.tmdHdr),LE);
|
||||
u16_to_u8(hdr->notes.cverTitleId,GetTmdVersion(set->options.tmdHdr),LE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ImportNcch0Data(cardinfo_hdr *hdr, cci_settings *set)
|
||||
{
|
||||
u8 *ncch;
|
||||
ncch_hdr *ncchHdr;
|
||||
|
||||
ncch = set->content.data + set->content.dOffset[0];
|
||||
ncchHdr = (ncch_hdr*)ncch;
|
||||
|
||||
memcpy(hdr->ncch0TitleId,ncchHdr->titleId,8);
|
||||
memcpy(hdr->ncch0Hdr,GetNcchHdrData(ncchHdr),GetNcchHdrDataLen(ncchHdr));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void SetInitialData(cardinfo_hdr *hdr, cci_settings *set)
|
||||
{
|
||||
clrmem(hdr->initialData,0x30);
|
||||
if(set->options.useExternalSdkCardInfo)
|
||||
memcpy(hdr->initialData,(u8*)stock_initial_data,0x30);
|
||||
else
|
||||
rndset(hdr->initialData,0x2c);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void SetDevCardInfo(devcardinfo_hdr *hdr, cci_settings *set)
|
||||
{
|
||||
clrmem(hdr,sizeof(devcardinfo_hdr));
|
||||
if(set->options.useExternalSdkCardInfo)
|
||||
memcpy(hdr->titleKey,(u8*)stock_title_key,0x10);
|
||||
else
|
||||
rndset(hdr->titleKey,0x10);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 reserved0[0xf8];
|
||||
u8 mediaSizeUsed[8];
|
||||
u8 reserved1[0x8];
|
||||
u8 unknown[0x4];
|
||||
u8 reserved2[0xc];
|
||||
u8 cverTitleId[8];
|
||||
u8 cverTitleVersion[2];
|
||||
u8 reserved3[0xcd6];
|
||||
} cardinfo_notes; // reserved[0xDF8];
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 writableAddress[4];
|
||||
u8 cardInfoBitmask[4];
|
||||
cardinfo_notes notes;
|
||||
u8 ncch0TitleId[8];
|
||||
u8 reserved0[8];
|
||||
u8 initialData[0x30];
|
||||
u8 reserved1[0xc0];
|
||||
u8 ncch0Hdr[0x100];
|
||||
} cardinfo_hdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 cardDeviceReserved1[0x200];
|
||||
u8 titleKey[0x10];
|
||||
u8 cardDeviceReserved2[0xf0];
|
||||
} devcardinfo_hdr;
|
||||
|
||||
static const u8 stock_initial_data[0x30] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xAD, 0x88,
|
||||
0xAC, 0x41, 0xA2, 0xB1, 0x5E, 0x8F,
|
||||
0x66, 0x9C, 0x97, 0xE5, 0xE1, 0x5E,
|
||||
0xA3, 0xEB, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const u8 stock_title_key[0x10] =
|
||||
{
|
||||
0x6E, 0xC7, 0x5F, 0xB2, 0xE2, 0xB4,
|
||||
0x87, 0x46, 0x1E, 0xDD, 0xCB, 0xB8,
|
||||
0x97, 0x11, 0x92, 0xBA
|
||||
};
|
||||
|
||||
int GenCardInfoHdr(cci_settings *set);
|
||||
+198
-89
@@ -1,41 +1,44 @@
|
||||
#include "lib.h"
|
||||
#include "ncch.h"
|
||||
#include "exheader.h"
|
||||
#include "exefs.h"
|
||||
#include "certs.h"
|
||||
#include "cia.h"
|
||||
#include "tik.h"
|
||||
#include "tmd.h"
|
||||
#include "titleid.h"
|
||||
|
||||
#include "srl.h"
|
||||
#include "ncsd.h"
|
||||
#include "ncsd_read.h"
|
||||
#include "ncch_read.h"
|
||||
#include "exheader_read.h"
|
||||
#include "exefs_read.h"
|
||||
|
||||
#include "cia_build.h"
|
||||
#include "cia_read.h"
|
||||
#include "tik_build.h"
|
||||
#include "tmd_build.h"
|
||||
#include "titleid.h"
|
||||
#include "certs.h"
|
||||
|
||||
const int CIA_ALIGN_SIZE = 0x40;
|
||||
const int CIA_CONTENT_ALIGN = 0x10;
|
||||
|
||||
// Private Prototypes
|
||||
/* cia_settings tools */
|
||||
void init_CIASettings(cia_settings *set);
|
||||
void free_CIASettings(cia_settings *set);
|
||||
int get_CIASettings(cia_settings *ciaset, user_settings *usrset);
|
||||
void InitCiaSettings(cia_settings *set);
|
||||
void FreeCiaSettings(cia_settings *set);
|
||||
int GetCiaSettings(cia_settings *ciaset, user_settings *usrset);
|
||||
|
||||
int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset);
|
||||
int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset);
|
||||
int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key);
|
||||
int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key);
|
||||
int GetTmdDataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *key);
|
||||
int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *key);
|
||||
int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset);
|
||||
int ImportNcchContent(cia_settings *ciaset);
|
||||
int GetSettingsFromSrl(cia_settings *ciaset);
|
||||
int GetSettingsFromCci(cia_settings *ciaset);
|
||||
|
||||
u16 SetupVersion(u16 Major, u16 Minor, u16 Micro);
|
||||
u16 SetupVersion(u16 major, u16 minor, u16 micro);
|
||||
|
||||
void GetContentHashes(cia_settings *ciaset);
|
||||
void EncryptContent(cia_settings *ciaset);
|
||||
|
||||
int BuildCIA_CertChain(cia_settings *ciaset);
|
||||
int BuildCIA_Header(cia_settings *ciaset);
|
||||
int BuildCiaCertChain(cia_settings *ciaset);
|
||||
int BuildCiaHdr(cia_settings *ciaset);
|
||||
|
||||
int WriteCIAtoFile(cia_settings *ciaset);
|
||||
|
||||
int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, u8 mode);
|
||||
int WriteCiaToFile(cia_settings *ciaset);
|
||||
|
||||
|
||||
int build_CIA(user_settings *usrset)
|
||||
@@ -50,8 +53,8 @@ int build_CIA(user_settings *usrset)
|
||||
}
|
||||
|
||||
// Get Settings
|
||||
init_CIASettings(ciaset);
|
||||
result = get_CIASettings(ciaset,usrset);
|
||||
InitCiaSettings(ciaset);
|
||||
result = GetCiaSettings(ciaset,usrset);
|
||||
if(result) goto finish;
|
||||
|
||||
// Create Output File
|
||||
@@ -65,7 +68,7 @@ int build_CIA(user_settings *usrset)
|
||||
// Create CIA Sections
|
||||
|
||||
/* Certificate Chain */
|
||||
result = BuildCIA_CertChain(ciaset);
|
||||
result = BuildCiaCertChain(ciaset);
|
||||
if(result) goto finish;
|
||||
|
||||
/* Ticket */
|
||||
@@ -77,28 +80,28 @@ int build_CIA(user_settings *usrset)
|
||||
if(result) goto finish;
|
||||
|
||||
/* CIA Header */
|
||||
result = BuildCIA_Header(ciaset);
|
||||
result = BuildCiaHdr(ciaset);
|
||||
if(result) goto finish;
|
||||
|
||||
/* Write To File */
|
||||
result = WriteCIAtoFile(ciaset);
|
||||
result = WriteCiaToFile(ciaset);
|
||||
if(result) goto finish;
|
||||
|
||||
finish:
|
||||
if(result != FAILED_TO_CREATE_OUTFILE && ciaset->out)
|
||||
fclose(ciaset->out);
|
||||
|
||||
free_CIASettings(ciaset);
|
||||
FreeCiaSettings(ciaset);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void init_CIASettings(cia_settings *set)
|
||||
void InitCiaSettings(cia_settings *set)
|
||||
{
|
||||
memset(set,0,sizeof(cia_settings));
|
||||
}
|
||||
|
||||
void free_CIASettings(cia_settings *set)
|
||||
void FreeCiaSettings(cia_settings *set)
|
||||
{
|
||||
if(set->content.filePtrs){
|
||||
for(u32 i = 1; i < set->content.count; i++){
|
||||
@@ -117,7 +120,7 @@ void free_CIASettings(cia_settings *set)
|
||||
free(set);
|
||||
}
|
||||
|
||||
int get_CIASettings(cia_settings *ciaset, user_settings *usrset)
|
||||
int GetCiaSettings(cia_settings *ciaset, user_settings *usrset)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
@@ -125,26 +128,21 @@ int get_CIASettings(cia_settings *ciaset, user_settings *usrset)
|
||||
result = GetSettingsFromUsrset(ciaset,usrset);
|
||||
|
||||
if(usrset->common.workingFileType == infile_ncch){
|
||||
result = GetSettingsFromNcch0(ciaset,0);
|
||||
if(result)
|
||||
if((result = GetSettingsFromNcch0(ciaset,0)) != 0)
|
||||
return result;
|
||||
result = GetContentFilePtrs(ciaset,usrset);
|
||||
if(result)
|
||||
if((result = GetContentFilePtrs(ciaset,usrset)) != 0)
|
||||
return result;
|
||||
result = ImportNcchContent(ciaset);
|
||||
if(result)
|
||||
if((result = ImportNcchContent(ciaset)) != 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
else if(usrset->common.workingFileType == infile_srl){
|
||||
result = GetSettingsFromSrl(ciaset);
|
||||
if(result)
|
||||
if((result = GetSettingsFromSrl(ciaset)) != 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
else if(usrset->common.workingFileType == infile_ncsd){
|
||||
result = GetSettingsFromCci(ciaset);
|
||||
if(result)
|
||||
if((result = GetSettingsFromCci(ciaset)) != 0)
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -165,7 +163,9 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset)
|
||||
ciaset->ciaSections.content.size = usrset->common.workingFile.size;
|
||||
usrset->common.workingFile.buffer = NULL;
|
||||
ciaset->ciaSections.content.size = 0;
|
||||
|
||||
ciaset->content.includeUpdateNcch = usrset->cia.includeUpdateNcch;
|
||||
ciaset->verbose = usrset->common.verbose;
|
||||
|
||||
u32_to_u8(ciaset->tmd.titleType,TYPE_CTR,BE);
|
||||
ciaset->content.encryptCia = usrset->common.rsfSet.Option.EnableCrypt;
|
||||
ciaset->content.IsDlc = usrset->cia.DlcContent;
|
||||
@@ -183,16 +183,19 @@ int GetSettingsFromUsrset(cia_settings *ciaset, user_settings *usrset)
|
||||
|
||||
// Ticket Data
|
||||
rndset(ciaset->tik.ticketId,8);
|
||||
clrmem(ciaset->tik.deviceId,4);
|
||||
clrmem(ciaset->tik.eshopAccId,4);
|
||||
u32_to_u8(ciaset->tik.deviceId,usrset->cia.deviceId,BE);
|
||||
u32_to_u8(ciaset->tik.eshopAccId,usrset->cia.eshopAccId,BE);
|
||||
ciaset->tik.licenceType = 0;
|
||||
ciaset->tik.audit = 0;
|
||||
|
||||
if(usrset->cia.randomTitleKey)
|
||||
rndset(ciaset->common.titleKey,16);
|
||||
rndset(ciaset->common.titleKey,AES_128_KEY_SIZE);
|
||||
else
|
||||
clrmem(ciaset->common.titleKey,16);
|
||||
clrmem(ciaset->common.titleKey,AES_128_KEY_SIZE);
|
||||
|
||||
if(ciaset->verbose)
|
||||
memdump(stdout,"[CIA] CIA title key: ",ciaset->common.titleKey,AES_128_KEY_SIZE);
|
||||
|
||||
ciaset->tik.formatVersion = 1;
|
||||
|
||||
int result = GenCertChildIssuer(ciaset->tik.issuer,ciaset->keys->certs.xsCert);
|
||||
@@ -217,33 +220,29 @@ int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset)
|
||||
|
||||
u8 *ncch0 = (u8*)(ciaset->ciaSections.content.buffer+ncch0_offset);
|
||||
|
||||
if(!IsNCCH(NULL,ncch0)){
|
||||
if(!IsNcch(NULL,ncch0)){
|
||||
fprintf(stderr,"[CIA ERROR] Content0 is not NCCH\n");
|
||||
return CIA_INVALID_NCCH0;
|
||||
}
|
||||
|
||||
/* Get Ncch0 Header */
|
||||
ncch_hdr *hdr = NULL;
|
||||
hdr = GetNCCH_CommonHDR(hdr,NULL,ncch0);
|
||||
if(IsCfa(hdr)){
|
||||
ciaset->content.IsCfa = true;
|
||||
}
|
||||
ncch_hdr *hdr = (ncch_hdr*)ncch0;
|
||||
ciaset->content.IsCfa = IsCfa(hdr);
|
||||
|
||||
ciaset->content.offset[0] = 0;
|
||||
ciaset->content.size[0] = align(GetNCCH_MediaSize(hdr)*GetNCCH_MediaUnitSize(hdr),0x10);
|
||||
ciaset->content.size[0] = align(GetNcchSize(hdr),0x10);
|
||||
ciaset->content.totalSize = ciaset->content.size[0];
|
||||
|
||||
/* Get Ncch0 Import Context */
|
||||
ncch_struct *ncch_ctx = malloc(sizeof(ncch_struct));
|
||||
if(!ncch_ctx){
|
||||
ncch_info *info = calloc(1,sizeof(ncch_info));
|
||||
if(!info){
|
||||
fprintf(stderr,"[CIA ERROR] Not enough memory\n");
|
||||
return MEM_ERROR;
|
||||
}
|
||||
memset(ncch_ctx,0x0,sizeof(ncch_struct));
|
||||
GetNCCHStruct(ncch_ctx,hdr);
|
||||
GetNcchInfo(info,hdr);
|
||||
|
||||
/* Verify Ncch0 (Sig&Hash Checks) */
|
||||
int result = VerifyNCCH(ncch0,ciaset->keys,false,true);
|
||||
int result = VerifyNcch(ncch0,ciaset->keys,false,true);
|
||||
if(result == UNABLE_TO_LOAD_NCCH_KEY){
|
||||
ciaset->content.keyNotFound = true;
|
||||
if(!ciaset->content.IsCfa){
|
||||
@@ -261,31 +260,35 @@ int GetSettingsFromNcch0(cia_settings *ciaset, u32 ncch0_offset)
|
||||
|
||||
|
||||
/* Getting ncch key */
|
||||
ncch_key_type keyType = GetNCCHKeyType(hdr);
|
||||
u8 *ncchkey = NULL;
|
||||
if(!ciaset->content.keyNotFound){
|
||||
SetNcchUnfixedKeys(ciaset->keys,ncch0);
|
||||
ncchkey = GetNCCHKey0(keyType,ciaset->keys);
|
||||
if(!ciaset->content.keyNotFound || IsNcchEncrypted(hdr)){
|
||||
SetNcchKeys(ciaset->keys,hdr);
|
||||
ncchkey = ciaset->keys->aes.ncchKey0;
|
||||
if(ciaset->verbose){
|
||||
printf("[CIA] NCCH AES keys:\n");
|
||||
memdump(stdout," > key0: ",ciaset->keys->aes.ncchKey0,AES_128_KEY_SIZE);
|
||||
memdump(stdout," > key1: ",ciaset->keys->aes.ncchKey1,AES_128_KEY_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get TMD Data from ncch */
|
||||
result = GetCIADataFromNcch(ciaset,ncch0,ncch_ctx,ncchkey); // Data For TMD
|
||||
result = GetTmdDataFromNcch(ciaset,ncch0,info,ncchkey); // Data For TMD
|
||||
if(result) goto finish;
|
||||
/* Get META Region from ncch */
|
||||
result = GetMetaRegion(ciaset,ncch0,ncch_ctx,ncchkey); // Meta Region
|
||||
result = GetMetaRegion(ciaset,ncch0,info,ncchkey); // Meta Region
|
||||
/* Finish */
|
||||
finish:
|
||||
/* Return */
|
||||
free(ncch_ctx);
|
||||
free(info);
|
||||
return result;
|
||||
}
|
||||
|
||||
int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key)
|
||||
int GetTmdDataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_info *ncch_ctx, u8 *key)
|
||||
{
|
||||
extended_hdr *exhdr = malloc(sizeof(extended_hdr));
|
||||
memcpy(exhdr,ncch+ncch_ctx->exhdrOffset,sizeof(extended_hdr));
|
||||
if(key != NULL)
|
||||
CryptNCCHSection((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx,key,ncch_exhdr);
|
||||
CryptNcchRegion((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx,key,ncch_exhdr);
|
||||
|
||||
u16 Category = u8_to_u16((ciaset->common.titleId+2),BE);
|
||||
if(IsPatch(Category)||ciaset->content.IsCfa||ciaset->content.keyNotFound)
|
||||
@@ -318,28 +321,26 @@ int GetCIADataFromNcch(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8
|
||||
ciaset->common.titleVersion[VER_MAJOR] = GetRemasterVersion_frm_exhdr(exhdr);
|
||||
}
|
||||
|
||||
u16 version = SetupVersion(ciaset->common.titleVersion[VER_MAJOR],ciaset->common.titleVersion[VER_MINOR],ciaset->common.titleVersion[VER_MICRO]);
|
||||
ciaset->tik.version = version;
|
||||
ciaset->tmd.version = version;
|
||||
ciaset->tmd.version = ciaset->tik.version = SetupVersion(ciaset->common.titleVersion[VER_MAJOR],ciaset->common.titleVersion[VER_MINOR],ciaset->common.titleVersion[VER_MICRO]);
|
||||
|
||||
free(exhdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key)
|
||||
int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_info *info, u8 *key)
|
||||
{
|
||||
if(ciaset->content.IsCfa || ciaset->content.keyNotFound)
|
||||
return 0;
|
||||
|
||||
extended_hdr *exhdr = malloc(sizeof(extended_hdr));
|
||||
memcpy(exhdr,ncch+ncch_ctx->exhdrOffset,sizeof(extended_hdr));
|
||||
memcpy(exhdr,ncch+info->exhdrOffset,sizeof(extended_hdr));
|
||||
if(key != NULL)
|
||||
CryptNCCHSection((u8*)exhdr,sizeof(extended_hdr),0,ncch_ctx,key,ncch_exhdr);
|
||||
CryptNcchRegion((u8*)exhdr,sizeof(extended_hdr),0,info,key,ncch_exhdr);
|
||||
|
||||
exefs_hdr *exefsHdr = malloc(sizeof(exefs_hdr));
|
||||
memcpy(exefsHdr,ncch+ncch_ctx->exefsOffset,sizeof(exefs_hdr));
|
||||
memcpy(exefsHdr,ncch+info->exefsOffset,sizeof(exefs_hdr));
|
||||
if(key != NULL)
|
||||
CryptNCCHSection((u8*)exefsHdr,sizeof(exefs_hdr),0,ncch_ctx,key,ncch_exefs);
|
||||
CryptNcchRegion((u8*)exefsHdr,sizeof(exefs_hdr),0,info,key,ncch_exefs);
|
||||
|
||||
u32 icon_size = 0;
|
||||
u32 icon_offset = 0;
|
||||
@@ -349,7 +350,7 @@ int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key
|
||||
icon_offset = u8_to_u32(exefsHdr->fileHdr[i].offset,LE) + sizeof(exefs_hdr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ciaset->ciaSections.meta.size = sizeof(cia_metadata) + icon_size;
|
||||
ciaset->ciaSections.meta.buffer = malloc(ciaset->ciaSections.meta.size);
|
||||
if(!ciaset->ciaSections.meta.buffer){
|
||||
@@ -362,9 +363,9 @@ int GetMetaRegion(cia_settings *ciaset, u8 *ncch, ncch_struct *ncch_ctx, u8 *key
|
||||
GetCoreVersion_frm_exhdr(hdr->coreVersion,exhdr);
|
||||
if(icon_size > 0){
|
||||
u8 *IconDestPos = (ciaset->ciaSections.meta.buffer + sizeof(cia_metadata));
|
||||
memcpy(IconDestPos,ncch+ncch_ctx->exefsOffset+icon_offset,icon_size);
|
||||
memcpy(IconDestPos,ncch+info->exefsOffset+icon_offset,icon_size);
|
||||
if(key != NULL)
|
||||
CryptNCCHSection(IconDestPos,icon_size,icon_offset,ncch_ctx,key,ncch_exefs);
|
||||
CryptNcchRegion(IconDestPos,icon_size,icon_offset,info,key,ncch_exefs);
|
||||
//memdump(stdout,"Icon: ",IconDestPos,0x10);
|
||||
}
|
||||
|
||||
@@ -389,7 +390,7 @@ int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset)
|
||||
fprintf(stderr,"[CIA ERROR] Failed to open \"%s\"\n",usrset->common.contentPath[i]);
|
||||
return FAILED_TO_OPEN_FILE;
|
||||
}
|
||||
ciaset->content.fileSize[j] = GetFileSize_u64(usrset->common.contentPath[i]);
|
||||
ciaset->content.fileSize[j] = GetFileSize64(usrset->common.contentPath[i]);
|
||||
ciaset->content.filePtrs[j] = fopen(usrset->common.contentPath[i],"rb");
|
||||
|
||||
if(usrset->cia.contentId[i] > MAX_U32)
|
||||
@@ -400,10 +401,10 @@ int GetContentFilePtrs(cia_settings *ciaset, user_settings *usrset)
|
||||
ciaset->content.index[j] = (u16)i;
|
||||
|
||||
// Get Data from ncch HDR
|
||||
GetNCCH_CommonHDR(hdr,ciaset->content.filePtrs[j],NULL);
|
||||
ReadNcchHdr(hdr,ciaset->content.filePtrs[j]);
|
||||
|
||||
// Get Size
|
||||
u64 calcSize = (u64)GetNCCH_MediaSize(hdr) * (u64)GetNCCH_MediaUnitSize(hdr);
|
||||
u64 calcSize = GetNcchSize(hdr);
|
||||
if(calcSize != ciaset->content.fileSize[j]){
|
||||
fprintf(stderr,"[CIA ERROR] \"%s\" is corrupt\n",usrset->common.contentPath[i]);
|
||||
return FAILED_TO_OPEN_FILE;
|
||||
@@ -447,7 +448,7 @@ int ImportNcchContent(cia_settings *ciaset)
|
||||
// Import
|
||||
u8 *ncchpos = (u8*)(ciaset->ciaSections.content.buffer+ciaset->content.offset[i]);
|
||||
|
||||
ReadFile_64(ncchpos, ciaset->content.fileSize[i], 0, ciaset->content.filePtrs[i]);
|
||||
ReadFile64(ncchpos, ciaset->content.fileSize[i], 0, ciaset->content.filePtrs[i]);
|
||||
if(ModifyNcchIds(ncchpos, NULL, ncch0hdr->programId, ciaset->keys) != 0)
|
||||
return -1;
|
||||
|
||||
@@ -528,6 +529,11 @@ int GetSettingsFromCci(cia_settings *ciaset)
|
||||
cciContentOffsets[0] = ncch0_offset;
|
||||
for(int i = 1; i < 8; i++){
|
||||
if(GetPartitionSize(ciaset->ciaSections.content.buffer,i)){
|
||||
ncch_hdr *ncchHdr = (ncch_hdr*)GetPartition(ciaset->ciaSections.content.buffer, i);
|
||||
|
||||
if(IsUpdateCfa(ncchHdr) && !ciaset->content.includeUpdateNcch)
|
||||
continue;
|
||||
|
||||
cciContentOffsets[j] = GetPartitionOffset(ciaset->ciaSections.content.buffer,i);
|
||||
|
||||
// Get Size
|
||||
@@ -557,9 +563,9 @@ int GetSettingsFromCci(cia_settings *ciaset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 SetupVersion(u16 Major, u16 Minor, u16 Micro)
|
||||
u16 SetupVersion(u16 major, u16 minor, u16 micro)
|
||||
{
|
||||
return (((Major << 10) & 0xFC00) | ((Minor << 4) & 0x3F0) | (Micro & 0xf));
|
||||
return (((major << 10) & 0xFC00) | ((minor << 4) & 0x3F0) | (micro & 0xf));
|
||||
}
|
||||
|
||||
void GetContentHashes(cia_settings *ciaset)
|
||||
@@ -577,7 +583,7 @@ void EncryptContent(cia_settings *ciaset)
|
||||
}
|
||||
}
|
||||
|
||||
int BuildCIA_CertChain(cia_settings *ciaset)
|
||||
int BuildCiaCertChain(cia_settings *ciaset)
|
||||
{
|
||||
ciaset->ciaSections.certChain.size = GetCertSize(ciaset->keys->certs.caCert) + GetCertSize(ciaset->keys->certs.xsCert) + GetCertSize(ciaset->keys->certs.cpCert);
|
||||
ciaset->ciaSections.certChain.buffer = malloc(ciaset->ciaSections.certChain.size);
|
||||
@@ -591,7 +597,7 @@ int BuildCIA_CertChain(cia_settings *ciaset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BuildCIA_Header(cia_settings *ciaset)
|
||||
int BuildCiaHdr(cia_settings *ciaset)
|
||||
{
|
||||
// Allocating memory for header
|
||||
ciaset->ciaSections.ciaHdr.size = sizeof(cia_hdr);
|
||||
@@ -644,7 +650,7 @@ int BuildCIA_Header(cia_settings *ciaset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WriteCIAtoFile(cia_settings *ciaset)
|
||||
int WriteCiaToFile(cia_settings *ciaset)
|
||||
{
|
||||
WriteBuffer(ciaset->ciaSections.ciaHdr.buffer,ciaset->ciaSections.ciaHdr.size,0,ciaset->out);
|
||||
WriteBuffer(ciaset->ciaSections.certChain.buffer,ciaset->ciaSections.certChain.size,ciaset->ciaSections.certChainOffset,ciaset->out);
|
||||
@@ -656,7 +662,7 @@ int WriteCIAtoFile(cia_settings *ciaset)
|
||||
}
|
||||
|
||||
|
||||
int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index, u8 mode)
|
||||
int CryptContent(u8 *enc, u8 *dec, u64 size, u8 *title_key, u16 index, u8 mode)
|
||||
{
|
||||
//generating IV
|
||||
u8 iv[16];
|
||||
@@ -667,7 +673,110 @@ int CryptContent(u8 *EncBuffer,u8 *DecBuffer,u64 size,u8 *title_key, u16 index,
|
||||
ctr_aes_context ctx;
|
||||
memset(&ctx,0x0,sizeof(ctr_aes_context));
|
||||
ctr_init_aes_cbc(&ctx,title_key,iv,mode);
|
||||
if(mode == ENC) ctr_aes_cbc(&ctx,DecBuffer,EncBuffer,size,ENC);
|
||||
else ctr_aes_cbc(&ctx,EncBuffer,DecBuffer,size,DEC);
|
||||
if(mode == ENC) ctr_aes_cbc(&ctx,dec,enc,size,ENC);
|
||||
else ctr_aes_cbc(&ctx,enc,dec,size,DEC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool IsCia(u8 *cia)
|
||||
{
|
||||
if(!cia)
|
||||
return false;
|
||||
|
||||
cia_hdr *hdr = (cia_hdr*)cia;
|
||||
|
||||
if(u8_to_u32(hdr->hdrSize,LE) != sizeof(cia_hdr) || u8_to_u16(hdr->type,LE) != 0 || u8_to_u16(hdr->version,LE) != 0)
|
||||
return false;
|
||||
|
||||
if(!GetCiaCertSize(hdr) || !GetCiaTikSize(hdr) || !GetCiaTmdSize(hdr) || !GetCiaContentSize(hdr))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 GetCiaCertOffset(cia_hdr *hdr)
|
||||
{
|
||||
u64 hdrSize = u8_to_u32(hdr->hdrSize,LE);
|
||||
return align(hdrSize,CIA_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
u64 GetCiaCertSize(cia_hdr *hdr)
|
||||
{
|
||||
return u8_to_u32(hdr->certChainSize,LE);
|
||||
}
|
||||
|
||||
u64 GetCiaTikOffset(cia_hdr *hdr)
|
||||
{
|
||||
u64 certOffset = GetCiaCertOffset(hdr);
|
||||
u64 certSize = GetCiaCertSize(hdr);
|
||||
return align(certOffset + certSize,CIA_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
u64 GetCiaTikSize(cia_hdr *hdr)
|
||||
{
|
||||
return u8_to_u32(hdr->tikSize,LE);
|
||||
}
|
||||
|
||||
u64 GetCiaTmdOffset(cia_hdr *hdr)
|
||||
{
|
||||
u64 tikOffset = GetCiaTikOffset(hdr);
|
||||
u64 tikSize = GetCiaTikSize(hdr);
|
||||
return align(tikOffset + tikSize,CIA_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
u64 GetCiaTmdSize(cia_hdr *hdr)
|
||||
{
|
||||
return u8_to_u32(hdr->tmdSize,LE);
|
||||
}
|
||||
|
||||
u64 GetCiaContentOffset(cia_hdr *hdr)
|
||||
{
|
||||
u64 tmdOffset = GetCiaTmdOffset(hdr);
|
||||
u64 tmdSize = GetCiaTmdSize(hdr);
|
||||
return align(tmdOffset + tmdSize,CIA_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
u64 GetCiaContentSize(cia_hdr *hdr)
|
||||
{
|
||||
return u8_to_u64(hdr->contentSize,LE);
|
||||
}
|
||||
|
||||
u64 GetCiaMetaOffset(cia_hdr *hdr)
|
||||
{
|
||||
u64 contentOffset = GetCiaContentOffset(hdr);
|
||||
u64 contentSize = GetCiaContentSize(hdr);
|
||||
return align(contentOffset + contentSize,CIA_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
u64 GetCiaMetaSize(cia_hdr *hdr)
|
||||
{
|
||||
return u8_to_u32(hdr->metaSize,LE);
|
||||
}
|
||||
|
||||
u8* GetCiaCert(u8 *cia)
|
||||
{
|
||||
return cia + GetCiaCertOffset((cia_hdr*)cia);
|
||||
}
|
||||
|
||||
u8* GetCiaTik(u8 *cia)
|
||||
{
|
||||
return cia + GetCiaTikOffset((cia_hdr*)cia);
|
||||
}
|
||||
|
||||
u8* GetCiaTmd(u8 *cia)
|
||||
{
|
||||
return cia + GetCiaTmdOffset((cia_hdr*)cia);
|
||||
}
|
||||
|
||||
u8* GetCiaContent(u8 *cia)
|
||||
{
|
||||
return cia + GetCiaContentOffset((cia_hdr*)cia);
|
||||
}
|
||||
|
||||
u8* GetCiaMeta(u8 *cia)
|
||||
{
|
||||
if(GetCiaMetaSize((cia_hdr*)cia))
|
||||
return cia + GetCiaMetaOffset((cia_hdr*)cia);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
+1
-115
@@ -1,17 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
static const int CIA_ALIGN_SIZE = 0x40;
|
||||
static const int CIA_CONTENT_ALIGN = 0x10;
|
||||
|
||||
// Enums
|
||||
typedef enum
|
||||
{
|
||||
CIA_NO_NCCH0 = -1,
|
||||
CIA_INVALID_NCCH0 = -2,
|
||||
CIA_CONFILCTING_CONTENT_IDS = -3,
|
||||
CIA_BAD_VERSION = -4,
|
||||
} cia_errors;
|
||||
|
||||
// Structs
|
||||
typedef struct
|
||||
{
|
||||
@@ -34,107 +22,5 @@ typedef struct
|
||||
u8 padding1[0xfc];
|
||||
} cia_metadata;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 *inFile;
|
||||
u64 inFileSize;
|
||||
int CryptContent(u8 *enc, u8 *dec, u64 size, u8 *title_key, u16 index, u8 mode);
|
||||
|
||||
FILE *out;
|
||||
|
||||
rsf_settings *rsf;
|
||||
keys_struct *keys;
|
||||
|
||||
struct{
|
||||
u8 titleId[8];
|
||||
u16 titleVersion[4];
|
||||
u8 titleKey[16];
|
||||
} common;
|
||||
|
||||
|
||||
struct{
|
||||
u8 caCrlVersion;
|
||||
u8 signerCrlVersion;
|
||||
} cert;
|
||||
|
||||
struct{
|
||||
u8 issuer[0x40];
|
||||
u8 formatVersion;
|
||||
|
||||
u16 version;
|
||||
|
||||
u8 ticketId[8];
|
||||
u8 deviceId[4];
|
||||
u8 licenceType;
|
||||
u8 audit;
|
||||
u8 eshopAccId[4];
|
||||
} tik;
|
||||
|
||||
struct{
|
||||
u8 issuer[0x40];
|
||||
u8 formatVersion;
|
||||
|
||||
u16 version;
|
||||
|
||||
u8 titleType[4];
|
||||
u8 savedataSize[4];
|
||||
u8 privSavedataSize[4];
|
||||
u8 twlFlag;
|
||||
} tmd;
|
||||
|
||||
struct{
|
||||
bool IsCfa;
|
||||
bool IsDlc;
|
||||
bool encryptCia;
|
||||
|
||||
bool keyNotFound;
|
||||
|
||||
FILE **filePtrs;
|
||||
u64 fileSize[CIA_MAX_CONTENT];
|
||||
|
||||
/* Misc Records */
|
||||
u16 count;
|
||||
u64 offset[CIA_MAX_CONTENT];
|
||||
u64 totalSize;
|
||||
|
||||
/* Content Chunk Records */
|
||||
u64 size[CIA_MAX_CONTENT];
|
||||
u16 index[CIA_MAX_CONTENT];
|
||||
u16 flags[CIA_MAX_CONTENT];
|
||||
u32 id[CIA_MAX_CONTENT];
|
||||
u8 hash[CIA_MAX_CONTENT][0x20];
|
||||
} content;
|
||||
|
||||
struct{
|
||||
buffer_struct ciaHdr;
|
||||
|
||||
u32 certChainOffset;
|
||||
buffer_struct certChain;
|
||||
|
||||
u32 tikOffset;
|
||||
buffer_struct tik;
|
||||
|
||||
u32 tmdOffset;
|
||||
buffer_struct tmd;
|
||||
|
||||
u32 metaOffset;
|
||||
buffer_struct meta;
|
||||
|
||||
u64 contentOffset;
|
||||
buffer_struct content;
|
||||
} ciaSections;
|
||||
} cia_settings;
|
||||
|
||||
// Public Prototypes
|
||||
int build_CIA(user_settings *usrset);
|
||||
|
||||
// Cia Read Functions
|
||||
u64 GetCiaCertOffset(cia_hdr *hdr);
|
||||
u64 GetCiaCertSize(cia_hdr *hdr);
|
||||
u64 GetTikOffset(cia_hdr *hdr);
|
||||
u64 GetTikSize(cia_hdr *hdr);
|
||||
u64 GetTmdOffset(cia_hdr *hdr);
|
||||
u64 GetTmdSize(cia_hdr *hdr);
|
||||
u64 GetContentOffset(cia_hdr *hdr);
|
||||
u64 GetContentSize(cia_hdr *hdr);
|
||||
u64 GetMetaOffset(cia_hdr *hdr);
|
||||
u64 GetMetaSize(cia_hdr *hdr);
|
||||
@@ -0,0 +1,107 @@
|
||||
#pragma once
|
||||
#include "cia.h"
|
||||
|
||||
// Enums
|
||||
typedef enum
|
||||
{
|
||||
CIA_NO_NCCH0 = -1,
|
||||
CIA_INVALID_NCCH0 = -2,
|
||||
CIA_CONFILCTING_CONTENT_IDS = -3,
|
||||
CIA_BAD_VERSION = -4,
|
||||
} cia_errors;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 *inFile;
|
||||
u64 inFileSize;
|
||||
|
||||
FILE *out;
|
||||
|
||||
rsf_settings *rsf;
|
||||
keys_struct *keys;
|
||||
|
||||
bool verbose;
|
||||
|
||||
struct{
|
||||
u8 titleId[8];
|
||||
u16 titleVersion[4];
|
||||
u8 titleKey[16];
|
||||
} common;
|
||||
|
||||
|
||||
struct{
|
||||
u8 caCrlVersion;
|
||||
u8 signerCrlVersion;
|
||||
} cert;
|
||||
|
||||
struct{
|
||||
u8 issuer[0x40];
|
||||
u8 formatVersion;
|
||||
|
||||
u16 version;
|
||||
|
||||
u8 ticketId[8];
|
||||
u8 deviceId[4];
|
||||
u8 licenceType;
|
||||
u8 audit;
|
||||
u8 eshopAccId[4];
|
||||
} tik;
|
||||
|
||||
struct{
|
||||
u8 issuer[0x40];
|
||||
u8 formatVersion;
|
||||
|
||||
u16 version;
|
||||
|
||||
u8 titleType[4];
|
||||
u8 savedataSize[4];
|
||||
u8 privSavedataSize[4];
|
||||
u8 twlFlag;
|
||||
} tmd;
|
||||
|
||||
struct{
|
||||
bool IsCfa;
|
||||
bool IsDlc;
|
||||
bool encryptCia;
|
||||
bool includeUpdateNcch; // for cci -> cia conversions
|
||||
|
||||
bool keyNotFound;
|
||||
|
||||
FILE **filePtrs;
|
||||
u64 fileSize[CIA_MAX_CONTENT];
|
||||
|
||||
/* Misc Records */
|
||||
u16 count;
|
||||
u64 offset[CIA_MAX_CONTENT];
|
||||
u64 totalSize;
|
||||
|
||||
/* Content Chunk Records */
|
||||
u64 size[CIA_MAX_CONTENT];
|
||||
u16 index[CIA_MAX_CONTENT];
|
||||
u16 flags[CIA_MAX_CONTENT];
|
||||
u32 id[CIA_MAX_CONTENT];
|
||||
u8 hash[CIA_MAX_CONTENT][0x20];
|
||||
} content;
|
||||
|
||||
struct{
|
||||
buffer_struct ciaHdr;
|
||||
|
||||
u32 certChainOffset;
|
||||
buffer_struct certChain;
|
||||
|
||||
u32 tikOffset;
|
||||
buffer_struct tik;
|
||||
|
||||
u32 tmdOffset;
|
||||
buffer_struct tmd;
|
||||
|
||||
u32 metaOffset;
|
||||
buffer_struct meta;
|
||||
|
||||
u64 contentOffset;
|
||||
buffer_struct content;
|
||||
} ciaSections;
|
||||
} cia_settings;
|
||||
|
||||
// Public Prototypes
|
||||
int build_CIA(user_settings *usrset);
|
||||
@@ -1,61 +0,0 @@
|
||||
#include "lib.h"
|
||||
#include "cia.h"
|
||||
|
||||
u64 GetCiaCertOffset(cia_hdr *hdr)
|
||||
{
|
||||
u64 hdrSize = u8_to_u32(hdr->hdrSize,LE);
|
||||
return align(hdrSize,CIA_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
u64 GetCiaCertSize(cia_hdr *hdr)
|
||||
{
|
||||
return u8_to_u32(hdr->certChainSize,LE);
|
||||
}
|
||||
|
||||
u64 GetTikOffset(cia_hdr *hdr)
|
||||
{
|
||||
u64 certOffset = GetCiaCertOffset(hdr);
|
||||
u64 certSize = GetCiaCertSize(hdr);
|
||||
return align(certOffset + certSize,CIA_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
u64 GetTikSize(cia_hdr *hdr)
|
||||
{
|
||||
return u8_to_u32(hdr->tikSize,LE);
|
||||
}
|
||||
|
||||
u64 GetTmdOffset(cia_hdr *hdr)
|
||||
{
|
||||
u64 tikOffset = GetTikOffset(hdr);
|
||||
u64 tikSize = GetTikSize(hdr);
|
||||
return align(tikOffset + tikSize,CIA_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
u64 GetTmdSize(cia_hdr *hdr)
|
||||
{
|
||||
return u8_to_u32(hdr->tmdSize,LE);
|
||||
}
|
||||
|
||||
u64 GetContentOffset(cia_hdr *hdr)
|
||||
{
|
||||
u64 tmdOffset = GetTmdOffset(hdr);
|
||||
u64 tmdSize = GetTmdSize(hdr);
|
||||
return align(tmdOffset + tmdSize,CIA_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
u64 GetContentSize(cia_hdr *hdr)
|
||||
{
|
||||
return u8_to_u64(hdr->contentSize,LE);
|
||||
}
|
||||
|
||||
u64 GetMetaOffset(cia_hdr *hdr)
|
||||
{
|
||||
u64 contentOffset = GetContentOffset(hdr);
|
||||
u64 contentSize = GetContentSize(hdr);
|
||||
return align(contentOffset + contentSize,CIA_ALIGN_SIZE);
|
||||
}
|
||||
|
||||
u64 GetMetaSize(cia_hdr *hdr)
|
||||
{
|
||||
return u8_to_u32(hdr->metaSize,LE);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "cia.h"
|
||||
|
||||
// Cia Read Functions
|
||||
bool IsCia(u8 *cia);
|
||||
u64 GetCiaCertOffset(cia_hdr *hdr);
|
||||
u64 GetCiaCertSize(cia_hdr *hdr);
|
||||
u64 GetCiaTikOffset(cia_hdr *hdr);
|
||||
u64 GetCiaTikSize(cia_hdr *hdr);
|
||||
u64 GetCiaTmdOffset(cia_hdr *hdr);
|
||||
u64 GetCiaTmdSize(cia_hdr *hdr);
|
||||
u64 GetCiaContentOffset(cia_hdr *hdr);
|
||||
u64 GetCiaContentSize(cia_hdr *hdr);
|
||||
u64 GetCiaMetaOffset(cia_hdr *hdr);
|
||||
u64 GetCiaMetaSize(cia_hdr *hdr);
|
||||
|
||||
u8* GetCiaCert(u8 *cia);
|
||||
u8* GetCiaTik(u8 *cia);
|
||||
u8* GetCiaTmd(u8 *cia);
|
||||
u8* GetCiaContent(u8 *cia);
|
||||
u8* GetCiaMeta(u8 *cia);
|
||||
+7
-15
@@ -1,6 +1,13 @@
|
||||
#include "lib.h"
|
||||
#include "crypto.h"
|
||||
|
||||
bool VerifySha256(void *data, u64 size, u8 hash[32])
|
||||
{
|
||||
u8 calchash[32];
|
||||
ctr_sha(data, size, calchash, CTR_SHA_256);
|
||||
return memcmp(hash,calchash,32) == 0;
|
||||
}
|
||||
|
||||
void ctr_sha(void *data, u64 size, u8 *hash, int mode)
|
||||
{
|
||||
switch(mode){
|
||||
@@ -9,21 +16,6 @@ void ctr_sha(void *data, u64 size, u8 *hash, int mode)
|
||||
}
|
||||
}
|
||||
|
||||
u8* AesKeyScrambler(u8 *Key, u8 *KeyX, u8 *KeyY)
|
||||
{
|
||||
// Process KeyX/KeyY to get raw normal key
|
||||
for(int i = 0; i < 16; i++)
|
||||
Key[i] = KeyX[i] ^ ((KeyY[i] >> 2) | ((KeyY[i < 15 ? i+1 : 0] & 3) << 6));
|
||||
|
||||
const u8 SCRAMBLE_SECRET[16] = {0x51, 0xD7, 0x5D, 0xBE, 0xFD, 0x07, 0x57, 0x6A, 0x1C, 0xFC, 0x2A, 0xF0, 0x94, 0x4B, 0xD5, 0x6C};
|
||||
|
||||
// Apply Secret to get final normal key
|
||||
for(int i = 0; i < 16; i++)
|
||||
Key[i] = Key[i] ^ SCRAMBLE_SECRET[i];
|
||||
|
||||
return Key;
|
||||
}
|
||||
|
||||
void ctr_add_counter(ctr_aes_context* ctx, u32 carry)
|
||||
{
|
||||
u32 counter[4];
|
||||
|
||||
+1
-1
@@ -71,9 +71,9 @@ typedef struct
|
||||
extern "C" {
|
||||
#endif
|
||||
// SHA
|
||||
bool VerifySha256(void *data, u64 size, u8 hash[32]);
|
||||
void ctr_sha(void *data, u64 size, u8 *hash, int mode);
|
||||
// AES
|
||||
u8* AesKeyScrambler(u8 *Key, u8 *KeyX, u8 *KeyY);
|
||||
void ctr_add_counter(ctr_aes_context* ctx, u32 carry);
|
||||
void ctr_init_counter(ctr_aes_context* ctx, u8 key[16],u8 ctr[16]);
|
||||
void ctr_crypt_counter_block(ctr_aes_context* ctx, u8 input[16], u8 output[16]);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "lib.h"
|
||||
|
||||
u32 GetCtrBlockSize(u8 flag)
|
||||
{
|
||||
return 1 << (flag + 9);
|
||||
}
|
||||
|
||||
u8 GetCtrBlockSizeFlag(u32 size)
|
||||
{
|
||||
u8 ret = 0;
|
||||
for(u32 tmp = size; tmp > 0x200; tmp = tmp >> 1)
|
||||
ret++;
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
u32 GetCtrBlockSize(u8 flag);
|
||||
u8 GetCtrBlockSizeFlag(u32 size);
|
||||
+2
-2
@@ -118,10 +118,10 @@ fs_entry* fs_GetEntry(fs_DIR *dp)
|
||||
{
|
||||
entry->IsDir = false;
|
||||
#ifdef _WIN32
|
||||
entry->size = wGetFileSize_u64(entry->fs_name);
|
||||
entry->size = wGetFileSize64(entry->fs_name);
|
||||
entry->fp = _wfopen(entry->fs_name,L"rb");
|
||||
#else
|
||||
entry->size = GetFileSize_u64(entry->fs_name);
|
||||
entry->size = GetFileSize64(entry->fs_name);
|
||||
entry->fp = fopen(entry->fs_name,"rb");
|
||||
#endif
|
||||
}
|
||||
|
||||
+295
-322
File diff suppressed because it is too large
Load Diff
+10
-11
@@ -23,7 +23,7 @@ typedef struct
|
||||
u64 size;
|
||||
u64 address;
|
||||
u64 alignment;
|
||||
} ElfSectionEntry;
|
||||
} elf_section_entry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -36,18 +36,17 @@ typedef struct
|
||||
u64 physicalAddress;
|
||||
u64 sizeInMemory;
|
||||
u64 alignment;
|
||||
|
||||
} ElfProgramEntry;
|
||||
} elf_program_entry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
u64 vAddr;
|
||||
|
||||
ElfProgramEntry *header;
|
||||
elf_program_entry *header;
|
||||
u32 sectionNum;
|
||||
ElfSectionEntry *sections;
|
||||
} ElfSegment;
|
||||
elf_section_entry *sections;
|
||||
} elf_segment;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -55,7 +54,7 @@ typedef struct
|
||||
u32 size;
|
||||
u32 maxPageNum;
|
||||
u8 *data;
|
||||
} CodeSegment;
|
||||
} code_segment;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -73,12 +72,12 @@ typedef struct
|
||||
|
||||
u16 sectionHeaderNameEntryIndex;
|
||||
|
||||
ElfSectionEntry *sections;
|
||||
ElfProgramEntry *programHeaders;
|
||||
elf_section_entry *sections;
|
||||
elf_program_entry *programHeaders;
|
||||
|
||||
u16 activeSegments;
|
||||
ElfSegment *segments;
|
||||
elf_segment *segments;
|
||||
|
||||
} ElfContext;
|
||||
} elf_context;
|
||||
|
||||
int BuildExeFsCode(ncch_settings *ncchset);
|
||||
+7
-8
@@ -1,6 +1,6 @@
|
||||
#include "lib.h"
|
||||
#include "ncch.h"
|
||||
#include "exefs.h"
|
||||
#include "ncch_build.h"
|
||||
#include "exefs_build.h"
|
||||
|
||||
// Private Prototypes
|
||||
u32 PredictExeFS_Size(exefs_buildctx *ctx);
|
||||
@@ -18,7 +18,7 @@ int BuildExeFs(ncch_settings *ncchset)
|
||||
fprintf(stderr,"[EXEFS ERROR] Not enough memory\n");
|
||||
return MEM_ERROR;
|
||||
}
|
||||
ctx->mediaUnit = ncchset->options.mediaSize;
|
||||
ctx->blockSize = ncchset->options.blockSize;
|
||||
|
||||
/* Importing ExeFs */
|
||||
if(ncchset->exefsSections.code.size)
|
||||
@@ -56,10 +56,9 @@ int BuildExeFs(ncch_settings *ncchset)
|
||||
|
||||
u32 PredictExeFS_Size(exefs_buildctx *ctx)
|
||||
{
|
||||
u32 exefs_size = 0x200; // Size of header
|
||||
for(int i = 0; i < ctx->fileCount; i++){
|
||||
exefs_size += align(ctx->fileSize[i],ctx->mediaUnit);
|
||||
}
|
||||
u32 exefs_size = sizeof(exefs_hdr); // Size of header
|
||||
for(int i = 0; i < ctx->fileCount; i++)
|
||||
exefs_size += align(ctx->fileSize[i],ctx->blockSize);
|
||||
//exefs_size = align(ctx->exefs_size,ctx->mediaUnit);
|
||||
return exefs_size;
|
||||
}
|
||||
@@ -70,7 +69,7 @@ int GenerateExeFS_Header(exefs_buildctx *ctx, u8 *outbuff)
|
||||
if(i == 0)
|
||||
ctx->fileOffset[i] = 0;
|
||||
else
|
||||
ctx->fileOffset[i] = align((ctx->fileOffset[i-1]+ctx->fileSize[i-1]),ctx->mediaUnit);
|
||||
ctx->fileOffset[i] = align((ctx->fileOffset[i-1]+ctx->fileSize[i-1]),ctx->blockSize);
|
||||
|
||||
memcpy(ctx->fileHdr[i].name,ctx->fileName[i],8);
|
||||
u32_to_u8(ctx->fileHdr[i].offset,ctx->fileOffset[i],LE);
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
|
||||
#define MAX_EXEFS_SECTIONS 10 // DO NOT CHANGE
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PTR_ERROR = -10,
|
||||
EXEFS_MAX_REACHED = -11,
|
||||
EXEFS_SECTION_NAME_ERROR = -12,
|
||||
|
||||
} exefs_errors;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[8];
|
||||
@@ -23,29 +15,3 @@ typedef struct
|
||||
u8 reserved[0x20];
|
||||
u8 fileHashes[MAX_EXEFS_SECTIONS][0x20];
|
||||
} exefs_hdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
//Input
|
||||
int fileCount;
|
||||
u8 *file[MAX_EXEFS_SECTIONS];
|
||||
u32 fileSize[MAX_EXEFS_SECTIONS];
|
||||
u32 fileOffset[MAX_EXEFS_SECTIONS];
|
||||
char fileName[MAX_EXEFS_SECTIONS][8];
|
||||
u32 mediaUnit;
|
||||
|
||||
//Working Data
|
||||
exefs_filehdr fileHdr[MAX_EXEFS_SECTIONS];
|
||||
u8 fileHashes[MAX_EXEFS_SECTIONS][0x20];
|
||||
|
||||
} exefs_buildctx;
|
||||
|
||||
/* ExeFs Build Functions */
|
||||
int BuildExeFs(ncch_settings *ncchset);
|
||||
|
||||
/* ExeFs Read Functions */
|
||||
bool DoesExeFsSectionExist(char *section, u8 *ExeFs);
|
||||
u8* GetExeFsSection(char *section, u8 *ExeFs);
|
||||
u8* GetExeFsSectionHash(char *section, u8 *ExeFs);
|
||||
u32 GetExeFsSectionSize(char *section, u8 *ExeFs);
|
||||
u32 GetExeFsSectionOffset(char *section, u8 *ExeFs);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "exefs.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PTR_ERROR = -10,
|
||||
EXEFS_MAX_REACHED = -11,
|
||||
EXEFS_SECTION_NAME_ERROR = -12,
|
||||
} exefs_errors;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
//Input
|
||||
int fileCount;
|
||||
u8 *file[MAX_EXEFS_SECTIONS];
|
||||
u32 fileSize[MAX_EXEFS_SECTIONS];
|
||||
u32 fileOffset[MAX_EXEFS_SECTIONS];
|
||||
char fileName[MAX_EXEFS_SECTIONS][8];
|
||||
u32 blockSize;
|
||||
|
||||
//Working Data
|
||||
exefs_filehdr fileHdr[MAX_EXEFS_SECTIONS];
|
||||
u8 fileHashes[MAX_EXEFS_SECTIONS][0x20];
|
||||
|
||||
} exefs_buildctx;
|
||||
|
||||
/* ExeFs Build Functions */
|
||||
int BuildExeFs(ncch_settings *ncchset);
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "exefs.h"
|
||||
|
||||
/* ExeFs Read Functions */
|
||||
bool DoesExeFsSectionExist(char *section, u8 *ExeFs);
|
||||
u8* GetExeFsSection(char *section, u8 *ExeFs);
|
||||
u8* GetExeFsSectionHash(char *section, u8 *ExeFs);
|
||||
u32 GetExeFsSectionSize(char *section, u8 *ExeFs);
|
||||
u32 GetExeFsSectionOffset(char *section, u8 *ExeFs);
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
#include "lib.h"
|
||||
#include "ncch.h"
|
||||
#include "exheader.h"
|
||||
#include "ncch_build.h"
|
||||
#include "exheader_build.h"
|
||||
#include "accessdesc.h"
|
||||
#include "titleid.h"
|
||||
|
||||
@@ -124,13 +124,13 @@ int get_ExHeaderSettingsFromNcchset(exheader_settings *exhdrset, ncch_settings *
|
||||
|
||||
/* Import ExHeader Code Section template */
|
||||
if(ncchset->componentFilePtrs.exhdrSize){
|
||||
u32 import_size = 0x30; //min_u64(0x30,ncchset->componentFilePtrs.exhdrSize);
|
||||
u32 import_size = 0x30; //min64(0x30,ncchset->componentFilePtrs.exhdrSize);
|
||||
u32 import_offset = 0x10;
|
||||
if((import_size+import_offset) > ncchset->componentFilePtrs.exhdrSize){
|
||||
fprintf(stderr,"[EXHEADER ERROR] Exheader Template is too small\n");
|
||||
return FAILED_TO_IMPORT_FILE;
|
||||
}
|
||||
ReadFile_64((ncchset->sections.exhdr.buffer+import_offset),import_size,import_offset,ncchset->componentFilePtrs.exhdr);
|
||||
ReadFile64((ncchset->sections.exhdr.buffer+import_offset),import_size,import_offset,ncchset->componentFilePtrs.exhdr);
|
||||
}
|
||||
|
||||
/* Create ExHeader Struct for output */
|
||||
|
||||
+1
-34
@@ -1,12 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COMMON_HEADER_KEY_NOT_FOUND = -10,
|
||||
EXHDR_BAD_YAML_OPT = -11,
|
||||
CANNOT_SIGN_ACCESSDESC = -12
|
||||
} exheader_errors;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
infoflag_COMPRESS_EXEFS_0 = 1,
|
||||
@@ -197,37 +190,11 @@ typedef struct
|
||||
exhdr_ARM9AccessControlInfo arm9AccessControlInfo;
|
||||
} access_descriptor;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
keys_struct *keys;
|
||||
rsf_settings *rsf;
|
||||
bool useAccessDescPreset;
|
||||
|
||||
/* Output */
|
||||
extended_hdr *exHdr; // is the exheader output buffer ptr(in ncchset) cast as exheader struct ptr;
|
||||
access_descriptor *acexDesc;
|
||||
} exheader_settings;
|
||||
|
||||
|
||||
/* ExHeader Signature Functions */
|
||||
int SignAccessDesc(access_descriptor *acexDesc, keys_struct *keys);
|
||||
int CheckAccessDescSignature(access_descriptor *acexDesc, keys_struct *keys);
|
||||
|
||||
/* ExHeader Build Functions */
|
||||
int BuildExHeader(ncch_settings *ncchset);
|
||||
|
||||
/* ExHeader Binary Print Functions */
|
||||
void exhdr_Print_ServiceAccessControl(extended_hdr *hdr);
|
||||
|
||||
/* ExHeader Binary Read Functions */
|
||||
u8* GetAcexRsaSig(access_descriptor *acexDesc);
|
||||
u8* GetAcexNcchPubKey(access_descriptor *acexDesc);
|
||||
u16 GetRemasterVersion_frm_exhdr(extended_hdr *hdr);
|
||||
u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr);
|
||||
int GetDependencyList_frm_exhdr(u8 *Dest,extended_hdr *hdr);
|
||||
void GetCoreVersion_frm_exhdr(u8 *Dest, extended_hdr *hdr);
|
||||
|
||||
/* ExHeader Settings Read from Yaml */
|
||||
/* ExHeader Settings Read from Rsf */
|
||||
int GetSaveDataSizeFromString(u64 *out, char *string, char *moduleName);
|
||||
int GetRemasterVersion_rsf(u16 *RemasterVersion, user_settings *usrset);
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "exheader.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COMMON_HEADER_KEY_NOT_FOUND = -10,
|
||||
EXHDR_BAD_YAML_OPT = -11,
|
||||
CANNOT_SIGN_ACCESSDESC = -12
|
||||
} exheader_errors;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
keys_struct *keys;
|
||||
rsf_settings *rsf;
|
||||
bool useAccessDescPreset;
|
||||
|
||||
/* Output, these ptrs where created originally in ncchset */
|
||||
extended_hdr *exHdr;
|
||||
access_descriptor *acexDesc;
|
||||
} exheader_settings;
|
||||
|
||||
/* ExHeader Build Functions */
|
||||
int BuildExHeader(ncch_settings *ncchset);
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "exheader.h"
|
||||
|
||||
/* ExHeader Binary Print Functions */
|
||||
void exhdr_Print_ServiceAccessControl(extended_hdr *hdr);
|
||||
|
||||
/* ExHeader Binary Read Functions */
|
||||
u8* GetAcexRsaSig(access_descriptor *acexDesc);
|
||||
u8* GetAcexNcchPubKey(access_descriptor *acexDesc);
|
||||
u16 GetRemasterVersion_frm_exhdr(extended_hdr *hdr);
|
||||
u64 GetSaveDataSize_frm_exhdr(extended_hdr *hdr);
|
||||
int GetDependencyList_frm_exhdr(u8 *Dest,extended_hdr *hdr);
|
||||
void GetCoreVersion_frm_exhdr(u8 *Dest, extended_hdr *hdr);
|
||||
+63
-47
@@ -1,14 +1,16 @@
|
||||
#include "lib.h"
|
||||
|
||||
// KeyData
|
||||
#include "tpki.h" // Test PKI
|
||||
#include "ppki.h" // Production PKI
|
||||
#include "dpki.h" // Development PKI
|
||||
#include "pki/test.h" // Test PKI
|
||||
#include "pki/prod.h" // Production PKI
|
||||
#include "pki/dev.h" // Development PKI
|
||||
|
||||
// Private Prototypes
|
||||
int SetRsaKeySet(u8 **PrivDest, u8 *PrivSource, u8 **PubDest, u8 *PubSource);
|
||||
int SetunFixedKey(keys_struct *keys, u8 *unFixedKey);
|
||||
void InitcommonKeySlots(keys_struct *keys);
|
||||
void InitCommonKeySlots(keys_struct *keys);
|
||||
void InitNcchKeyXSlots(keys_struct *keys);
|
||||
int SetNcchKeyX(keys_struct *keys, u8 *keyX, u8 index);
|
||||
|
||||
FILE* keyset_OpenFile(char *dir, char *name, bool FileRequired);
|
||||
void keysetOpenError(char *file);
|
||||
@@ -33,11 +35,12 @@ void DumpKeyset(keys_struct *keys);
|
||||
void InitKeys(keys_struct *keys)
|
||||
{
|
||||
memset(keys,0,sizeof(keys_struct));
|
||||
InitcommonKeySlots(keys);
|
||||
InitCommonKeySlots(keys);
|
||||
InitNcchKeyXSlots(keys);
|
||||
keys->rsa.cxiHdrPub = malloc(RSA_2048_KEY_SIZE);
|
||||
keys->rsa.cxiHdrPvt = malloc(RSA_2048_KEY_SIZE);
|
||||
keys->aes.unFixedKey0 = malloc(16);
|
||||
keys->aes.unFixedKey1 = malloc(16);
|
||||
keys->aes.ncchKey0 = malloc(AES_128_KEY_SIZE);
|
||||
keys->aes.ncchKey1 = malloc(AES_128_KEY_SIZE);
|
||||
}
|
||||
|
||||
void PrintBadKeySize(char *path, u32 size)
|
||||
@@ -45,6 +48,21 @@ void PrintBadKeySize(char *path, u32 size)
|
||||
fprintf(stderr,"[KEYSET ERROR] %s has invalid size (0x%x)\n",path,size);
|
||||
}
|
||||
|
||||
u8* AesKeyScrambler(u8 *key, u8 *keyX, u8 *keyY)
|
||||
{
|
||||
// Process keyX/keyY to get raw normal key
|
||||
for(int i = 0; i < 16; i++)
|
||||
key[i] = keyX[i] ^ ((keyY[i] >> 2) | ((keyY[i < 15 ? i+1 : 0] & 3) << 6)); // keyX[i] ^
|
||||
|
||||
const u8 SCRAMBLE_SECRET[16] = {0x51, 0xD7, 0x5D, 0xBE, 0xFD, 0x07, 0x57, 0x6A, 0x1C, 0xFC, 0x2A, 0xF0, 0x94, 0x4B, 0xD5, 0x6C};
|
||||
|
||||
// Apply Secret to get final normal key
|
||||
for(int i = 0; i < 16; i++)
|
||||
key[i] = key[i] ^ SCRAMBLE_SECRET[i];
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
int SetKeys(keys_struct *keys)
|
||||
{
|
||||
int result = 0;
|
||||
@@ -90,9 +108,9 @@ int LoadKeysFromResources(keys_struct *keys)
|
||||
keys->keysetLoaded = true;
|
||||
/* AES Keys */
|
||||
// CIA
|
||||
for(int i = 0; i < 2; i++){
|
||||
for(int i = 0; i < 2; i++)
|
||||
SetCommonKey(keys,(u8*)ctr_common_etd_key_dpki[i],i);
|
||||
}
|
||||
|
||||
if(keys->aes.currentCommonKey > 0xff)
|
||||
SetCurrentCommonKey(keys,0);
|
||||
|
||||
@@ -100,10 +118,9 @@ int LoadKeysFromResources(keys_struct *keys)
|
||||
SetNormalKey(keys,(u8*)dev_fixed_ncch_key[0]);
|
||||
SetSystemFixedKey(keys,(u8*)dev_fixed_ncch_key[1]);
|
||||
|
||||
/*
|
||||
keys->aes.ncchKeyX0 = (u8*)dev_unfixed_ncch_keyX[0];
|
||||
keys->aes.ncchKeyX1 = (u8*)dev_unfixed_ncch_keyX[1];
|
||||
*/
|
||||
for(int i = 0; i < 2; i++)
|
||||
SetNcchKeyX(keys,(u8*)dev_unfixed_ncch_keyX[i],i);
|
||||
|
||||
|
||||
/* RSA Keys */
|
||||
// CIA
|
||||
@@ -123,18 +140,19 @@ int LoadKeysFromResources(keys_struct *keys)
|
||||
keys->keysetLoaded = true;
|
||||
/* AES Keys */
|
||||
// CIA
|
||||
for(int i = 0; i < 6; i++){
|
||||
keys->aes.commonKey[i] = malloc(16);
|
||||
AesKeyScrambler(keys->aes.commonKey[i],(u8*)ctr_common_etd_keyX_ppki,(u8*)ctr_common_etd_keyY_ppki[i]);
|
||||
}
|
||||
SetCurrentCommonKey(keys,1);
|
||||
//for(int i = 0; i < 6; i++){
|
||||
// keys->aes.commonKey[i] = malloc(16);
|
||||
// AesKeyScrambler(keys->aes.commonKey[i],(u8*)ctr_common_etd_keyX_ppki,(u8*)ctr_common_etd_keyY_ppki[i]);
|
||||
//}
|
||||
if(keys->aes.currentCommonKey > 0xff)
|
||||
SetCurrentCommonKey(keys,0);
|
||||
|
||||
// NCCH
|
||||
keys->aes.normalKey = NULL;
|
||||
keys->aes.systemFixedKey = NULL;
|
||||
/*
|
||||
keys->aes.ncchKeyX0 = (u8*)prod_unfixed_ncch_keyX[0];
|
||||
keys->aes.ncchKeyX1 = (u8*)prod_unfixed_ncch_keyX[1];
|
||||
for(int i = 0; i < 2; i++)
|
||||
SetNcchKeyX(keys,(u8*)prod_unfixed_ncch_keyX[i],i);
|
||||
*/
|
||||
|
||||
/* RSA Keys */
|
||||
@@ -264,15 +282,19 @@ void FreeKeys(keys_struct *keys)
|
||||
{
|
||||
// AES
|
||||
if(keys->aes.commonKey){
|
||||
for(int i = 0; i < 256; i++){
|
||||
for(int i = 0; i <= MAX_CMN_KEY; i++)
|
||||
free(keys->aes.commonKey[i]);
|
||||
}
|
||||
}
|
||||
free(keys->aes.commonKey);
|
||||
free(keys->aes.normalKey);
|
||||
free(keys->aes.systemFixedKey);
|
||||
free(keys->aes.unFixedKey0);
|
||||
free(keys->aes.unFixedKey1);
|
||||
if(keys->aes.ncchKeyX){
|
||||
for(int i = 0; i <= MAX_NCCH_KEYX; i++)
|
||||
free(keys->aes.ncchKeyX[i]);
|
||||
}
|
||||
free(keys->aes.ncchKeyX);
|
||||
free(keys->aes.ncchKey0);
|
||||
free(keys->aes.ncchKey1);
|
||||
|
||||
// RSA
|
||||
free(keys->rsa.xsPvt);
|
||||
@@ -309,18 +331,28 @@ int SetRsaKeySet(u8 **PrivDest, u8 *PrivSource, u8 **PubDest, u8 *PubSource)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetCommonKey(keys_struct *keys, u8 *commonKey, u8 Index)
|
||||
int SetCommonKey(keys_struct *keys, u8 *commonKey, u8 index)
|
||||
{
|
||||
if(!keys) return -1;
|
||||
return CopyData(&keys->aes.commonKey[Index],commonKey,16);
|
||||
return CopyData(&keys->aes.commonKey[index],commonKey,AES_128_KEY_SIZE);
|
||||
}
|
||||
|
||||
void InitcommonKeySlots(keys_struct *keys)
|
||||
void InitCommonKeySlots(keys_struct *keys)
|
||||
{
|
||||
if(!keys->aes.commonKey){
|
||||
keys->aes.commonKey = malloc(sizeof(u8*)*256);
|
||||
memset(keys->aes.commonKey,0,sizeof(u8*)*256);
|
||||
}
|
||||
if(!keys->aes.commonKey)
|
||||
keys->aes.commonKey = calloc(MAX_CMN_KEY+1,sizeof(u8*));
|
||||
}
|
||||
|
||||
int SetNcchKeyX(keys_struct *keys, u8 *keyX, u8 index)
|
||||
{
|
||||
if(!keys) return -1;
|
||||
return CopyData(&keys->aes.ncchKeyX[index],keyX,AES_128_KEY_SIZE);
|
||||
}
|
||||
|
||||
void InitNcchKeyXSlots(keys_struct *keys)
|
||||
{
|
||||
if(!keys->aes.ncchKeyX)
|
||||
keys->aes.ncchKeyX = calloc(MAX_NCCH_KEYX+1,sizeof(u8*));
|
||||
}
|
||||
|
||||
int SetCurrentCommonKey(keys_struct *keys, u8 Index)
|
||||
@@ -342,22 +374,6 @@ int SetSystemFixedKey(keys_struct *keys, u8 *systemFixedKey)
|
||||
return CopyData(&keys->aes.systemFixedKey,systemFixedKey,16);
|
||||
}
|
||||
|
||||
int SetNcchUnfixedKeys(keys_struct *keys, u8 *ncchSig)
|
||||
{
|
||||
if(!keys) return -1;
|
||||
|
||||
//memdump(stdout,"keyY: ",ncchSig,16);
|
||||
//memdump(stdout,"keyX0: ",keys->aes.ncchKeyX0,16);
|
||||
//memdump(stdout,"keyX1: ",keys->aes.ncchKeyX1,16);
|
||||
|
||||
if(keys->aes.ncchKeyX0)
|
||||
AesKeyScrambler(keys->aes.unFixedKey0,keys->aes.ncchKeyX0,ncchSig);
|
||||
if(keys->aes.ncchKeyX1)
|
||||
AesKeyScrambler(keys->aes.unFixedKey1,keys->aes.ncchKeyX1,ncchSig);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SetTIK_RsaKey(keys_struct *keys, u8 *PrivateExp, u8 *PublicMod)
|
||||
{
|
||||
if(!keys) return -1;
|
||||
|
||||
+12
-7
@@ -1,5 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AES_128_KEY_SIZE = 16,
|
||||
MAX_CMN_KEY = MAX_U8,
|
||||
MAX_NCCH_KEYX = MAX_U8
|
||||
} keydata_limits;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
KEYSET_ERROR = -10,
|
||||
@@ -54,11 +61,10 @@ typedef struct
|
||||
// NCCH Keys
|
||||
u8 *normalKey;
|
||||
u8 *systemFixedKey;
|
||||
|
||||
u8 *ncchKeyX0;
|
||||
u8 *ncchKeyX1;
|
||||
u8 *unFixedKey0;
|
||||
u8 *unFixedKey1;
|
||||
u8 **ncchKeyX;
|
||||
|
||||
u8 *ncchKey0;
|
||||
u8 *ncchKey1;
|
||||
} aes;
|
||||
|
||||
struct
|
||||
@@ -101,5 +107,4 @@ int SetCurrentCommonKey(keys_struct *keys, u8 Index);
|
||||
int SetNormalKey(keys_struct *keys, u8 *systemFixedKey);
|
||||
int SetSystemFixedKey(keys_struct *keys, u8 *systemFixedKey);
|
||||
|
||||
|
||||
int SetNcchUnfixedKeys(keys_struct *keys, u8 *ncchSig);
|
||||
u8* AesKeyScrambler(u8 *key, u8 *keyX, u8 *keyY);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "ctr_utils.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#include "keyset.h"
|
||||
|
||||
+41
-48
@@ -1,73 +1,66 @@
|
||||
#include "lib.h"
|
||||
#include "ncch.h"
|
||||
#include "ncsd.h"
|
||||
#include "cia.h"
|
||||
#include "ncch_build.h"
|
||||
#include "ncsd_build.h"
|
||||
#include "cia_build.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Setting up user settings
|
||||
user_settings *usrset = calloc(1,sizeof(user_settings));
|
||||
if(usrset == NULL) {
|
||||
user_settings *set = calloc(1,sizeof(user_settings));
|
||||
if(set == NULL) {
|
||||
fprintf(stderr,"[!] Not enough memory\n");
|
||||
return -1;
|
||||
}
|
||||
init_UserSettings(usrset);
|
||||
init_UserSettings(set);
|
||||
initRand();
|
||||
|
||||
int result;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[DEBUG] Parseing Args\n");
|
||||
#endif
|
||||
|
||||
// Parsing command args
|
||||
result = ParseArgs(argc,argv,usrset);
|
||||
if(result < 0) goto finish;
|
||||
if((result = ParseArgs(argc,argv,set)) < 0)
|
||||
goto finish;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[DEBUG] Importing Yaml Settings\n");
|
||||
#endif
|
||||
|
||||
// Import RSF Settings if present
|
||||
result = GetYamlSettings(usrset);
|
||||
if(result < 0) goto finish;
|
||||
if((result = GetRsfSettings(set)) < 0)
|
||||
goto finish;
|
||||
|
||||
// Setup Content 0
|
||||
if(!usrset->ncch.buildNcch0){ // Import Content
|
||||
if(usrset->common.workingFileType == infile_ncch){
|
||||
if(!AssertFile(usrset->common.contentPath[0])){
|
||||
fprintf(stderr,"[MAKEROM ERROR] Failed to open Content 0: %s\n",usrset->common.contentPath[0]);
|
||||
if(!set->ncch.buildNcch0){ // Import Content
|
||||
if(set->common.workingFileType == infile_ncch){
|
||||
if(!AssertFile(set->common.contentPath[0])){
|
||||
fprintf(stderr,"[MAKEROM ERROR] Failed to open Content 0: %s\n",set->common.contentPath[0]);
|
||||
goto finish;
|
||||
}
|
||||
u64 fileSize = GetFileSize_u64(usrset->common.contentPath[0]);
|
||||
u64 fileSize = GetFileSize64(set->common.contentPath[0]);
|
||||
u64 calcSize = 0;
|
||||
|
||||
FILE *ncch0 = fopen(usrset->common.contentPath[0],"rb");
|
||||
FILE *ncch0 = fopen(set->common.contentPath[0],"rb");
|
||||
|
||||
ncch_hdr hdr;
|
||||
GetNCCH_CommonHDR(&hdr,ncch0,NULL);
|
||||
calcSize = GetNCCH_MediaSize(&hdr) * GetNCCH_MediaUnitSize(&hdr);
|
||||
ReadNcchHdr(&hdr,ncch0);
|
||||
calcSize = GetNcchSize(&hdr);
|
||||
if(calcSize != fileSize){
|
||||
fprintf(stderr,"[MAKEROM ERROR] Content 0 is corrupt\n");
|
||||
fclose(ncch0);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
usrset->common.workingFile.size = fileSize;
|
||||
usrset->common.workingFile.buffer = malloc(fileSize);
|
||||
ReadFile_64(usrset->common.workingFile.buffer, usrset->common.workingFile.size,0,ncch0);
|
||||
set->common.workingFile.size = fileSize;
|
||||
set->common.workingFile.buffer = malloc(fileSize);
|
||||
ReadFile64(set->common.workingFile.buffer, set->common.workingFile.size,0,ncch0);
|
||||
fclose(ncch0);
|
||||
}
|
||||
else if(usrset->common.workingFileType == infile_srl || usrset->common.workingFileType == infile_ncsd){
|
||||
if(!AssertFile(usrset->common.workingFilePath)) {
|
||||
fprintf(stderr,"[MAKEROM ERROR] Failed to open %s: %s\n",usrset->common.workingFileType == infile_srl? "SRL":"CCI",usrset->common.workingFilePath);
|
||||
else{
|
||||
if(!AssertFile(set->common.workingFilePath)) {
|
||||
fprintf(stderr,"[MAKEROM ERROR] Failed to open: %s\n",set->common.workingFilePath);
|
||||
goto finish;
|
||||
}
|
||||
u64 size = GetFileSize_u64(usrset->common.workingFilePath);
|
||||
usrset->common.workingFile.size = align(size,0x10);
|
||||
usrset->common.workingFile.buffer = malloc(usrset->common.workingFile.size);
|
||||
FILE *fp = fopen(usrset->common.workingFilePath,"rb");
|
||||
ReadFile_64(usrset->common.workingFile.buffer,size,0,fp);
|
||||
u64 size = GetFileSize64(set->common.workingFilePath);
|
||||
set->common.workingFile.size = align(size,0x10);
|
||||
set->common.workingFile.buffer = malloc(set->common.workingFile.size);
|
||||
FILE *fp = fopen(set->common.workingFilePath,"rb");
|
||||
ReadFile64(set->common.workingFile.buffer,size,0,fp);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
@@ -75,48 +68,48 @@ int main(int argc, char *argv[])
|
||||
#ifdef DEBUG
|
||||
printf("[DEBUG] Build NCCH0\n");
|
||||
#endif
|
||||
result = build_NCCH(usrset);
|
||||
result = build_NCCH(set);
|
||||
if(result < 0) {
|
||||
//fprintf(stderr,"[ERROR] %s generation failed\n",usrset->build_ncch_type == CXI? "CXI" : "CFA");
|
||||
//fprintf(stderr,"[ERROR] %s generation failed\n",set->build_ncch_type == CXI? "CXI" : "CFA");
|
||||
fprintf(stderr,"[RESULT] Failed to build outfile\n");
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
// Make CCI
|
||||
if(usrset->common.outFormat == CCI){
|
||||
if(set->common.outFormat == CCI){
|
||||
#ifdef DEBUG
|
||||
printf("[DEBUG] Building CCI\n");
|
||||
#endif
|
||||
result = build_CCI(usrset);
|
||||
result = build_CCI(set);
|
||||
if(result < 0) {
|
||||
fprintf(stderr,"[RESULT] Failed to build CCI\n");
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
// Make CIA
|
||||
else if(usrset->common.outFormat == CIA){
|
||||
else if(set->common.outFormat == CIA){
|
||||
#ifdef DEBUG
|
||||
printf("[DEBUG] Building CIA\n");
|
||||
#endif
|
||||
result = build_CIA(usrset);
|
||||
result = build_CIA(set);
|
||||
if(result < 0) {
|
||||
fprintf(stderr,"[RESULT] Failed to build CIA\n");
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
// No Container Raw CXI/CFA
|
||||
else if(usrset->common.outFormat == CXI || usrset->common.outFormat == CFA){
|
||||
else if(set->common.outFormat == CXI || set->common.outFormat == CFA){
|
||||
#ifdef DEBUG
|
||||
printf("[DEBUG] Outputting NCCH, because No Container\n");
|
||||
#endif
|
||||
FILE *ncch_out = fopen(usrset->common.outFileName,"wb");
|
||||
FILE *ncch_out = fopen(set->common.outFileName,"wb");
|
||||
if(!ncch_out) {
|
||||
fprintf(stderr,"[MAKEROM ERROR] Failed to create '%s'\n",usrset->common.outFileName);
|
||||
fprintf(stderr,"[RESULT] Failed to build '%s'\n",usrset->common.outFormat == CXI? "CXI" : "CFA");
|
||||
fprintf(stderr,"[MAKEROM ERROR] Failed to create '%s'\n",set->common.outFileName);
|
||||
fprintf(stderr,"[RESULT] Failed to build '%s'\n",set->common.outFormat == CXI? "CXI" : "CFA");
|
||||
result = FAILED_TO_CREATE_OUTFILE;
|
||||
goto finish;
|
||||
}
|
||||
WriteBuffer(usrset->common.workingFile.buffer,usrset->common.workingFile.size,0,ncch_out);
|
||||
WriteBuffer(set->common.workingFile.buffer,set->common.workingFile.size,0,ncch_out);
|
||||
fclose(ncch_out);
|
||||
}
|
||||
|
||||
@@ -124,7 +117,7 @@ finish:
|
||||
#ifdef DEBUG
|
||||
printf("[DEBUG] Free Context\n");
|
||||
#endif
|
||||
free_UserSettings(usrset);
|
||||
free_UserSettings(set);
|
||||
#ifdef DEBUG
|
||||
printf("[DEBUG] Finished returning (result=%d)\n",result);
|
||||
#endif
|
||||
|
||||
+444
-491
File diff suppressed because it is too large
Load Diff
+31
-126
@@ -15,10 +15,10 @@ typedef enum
|
||||
ACCESSDESC_SIG_BAD = -10,
|
||||
NCCH_HDR_SIG_BAD = -11,
|
||||
// HashCheck Errors
|
||||
ExHeader_Hashfail = -12,
|
||||
Logo_Hashfail = -13,
|
||||
ExeFs_Hashfail = -14,
|
||||
RomFs_Hashfail = -15,
|
||||
EXHDR_CORRUPT = -12,
|
||||
LOGO_CORRUPT = -13,
|
||||
EXEFS_CORRUPT = -14,
|
||||
ROMFS_CORRUPT = -15,
|
||||
// Others
|
||||
NCCH_BAD_YAML_SET = -16,
|
||||
DATA_POS_DNE = -17,
|
||||
@@ -29,34 +29,23 @@ typedef enum
|
||||
ncch_exhdr = 1,
|
||||
ncch_exefs,
|
||||
ncch_romfs,
|
||||
ncch_Logo,
|
||||
ncch_PlainRegion,
|
||||
} ncch_section;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NoKey,
|
||||
KeyIsNormalFixed,
|
||||
KeyIsSystemFixed,
|
||||
KeyIsUnFixed,
|
||||
KeyIsUnFixed2,
|
||||
} ncch_key_type;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SecureCrypto2 = 3,
|
||||
ContentPlatform = 4,
|
||||
ContentType = 5,
|
||||
ContentUnitSize = 6,
|
||||
OtherFlag = 7
|
||||
ncchflag_CONTENT_KEYX = 3,
|
||||
ncchflag_CONTENT_PLATFORM = 4,
|
||||
ncchflag_CONTENT_TYPE = 5,
|
||||
ncchflag_CONTENT_BLOCK_SIZE = 6,
|
||||
ncchflag_OTHER_FLAG = 7
|
||||
} ncch_flags;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UnFixedCryptoKey = 0x0,
|
||||
FixedCryptoKey = 0x1,
|
||||
NoMountRomFs = 0x2,
|
||||
NoCrypto = 0x4,
|
||||
otherflag_Clear = 0,
|
||||
otherflag_FixedCryptoKey = (1 << 0),
|
||||
otherflag_NoMountRomFs = (1 << 1),
|
||||
otherflag_NoCrypto = (1 << 2),
|
||||
} ncch_otherflag_bitmask;
|
||||
|
||||
typedef enum
|
||||
@@ -88,10 +77,11 @@ typedef struct
|
||||
u64 romfsHashDataSize;
|
||||
u8 titleId[8];
|
||||
u8 programId[8];
|
||||
} ncch_struct;
|
||||
} ncch_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 signature[0x100];
|
||||
u8 magic[4];
|
||||
u8 ncchSize[4];
|
||||
u8 titleId[8];
|
||||
@@ -122,109 +112,24 @@ typedef struct
|
||||
u8 romfsHash[0x20];
|
||||
} ncch_hdr;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
buffer_struct *out;
|
||||
keys_struct *keys;
|
||||
rsf_settings *rsfSet;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 mediaSize;
|
||||
bool IncludeExeFsLogo;
|
||||
bool CompressCode;
|
||||
bool UseOnSD;
|
||||
bool Encrypt;
|
||||
bool FreeProductCode;
|
||||
bool IsCfa;
|
||||
bool IsBuildingCodeSection;
|
||||
bool UseRomFS;
|
||||
} options;
|
||||
|
||||
struct
|
||||
{
|
||||
FILE *elf;
|
||||
u64 elfSize;
|
||||
|
||||
FILE *banner;
|
||||
u64 bannerSize;
|
||||
|
||||
FILE *icon;
|
||||
u64 iconSize;
|
||||
|
||||
FILE *logo;
|
||||
u64 logoSize;
|
||||
|
||||
FILE *code;
|
||||
u64 codeSize;
|
||||
|
||||
FILE *exhdr;
|
||||
u64 exhdrSize;
|
||||
|
||||
FILE *romfs;
|
||||
u64 romfsSize;
|
||||
|
||||
FILE *plainregion;
|
||||
u64 plainregionSize;
|
||||
} componentFilePtrs;
|
||||
|
||||
struct
|
||||
{
|
||||
buffer_struct code;
|
||||
buffer_struct banner;
|
||||
buffer_struct icon;
|
||||
} exefsSections;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 textAddress;
|
||||
u32 textSize;
|
||||
u32 textMaxPages;
|
||||
u32 roAddress;
|
||||
u32 roSize;
|
||||
u32 roMaxPages;
|
||||
u32 rwAddress;
|
||||
u32 rwSize;
|
||||
u32 rwMaxPages;
|
||||
u32 bssSize;
|
||||
} codeDetails;
|
||||
|
||||
struct
|
||||
{
|
||||
buffer_struct exhdr;
|
||||
buffer_struct acexDesc;
|
||||
buffer_struct logo;
|
||||
buffer_struct plainRegion;
|
||||
buffer_struct exeFs;
|
||||
} sections;
|
||||
|
||||
ncch_struct cryptoDetails;
|
||||
|
||||
|
||||
} ncch_settings;
|
||||
|
||||
// NCCH Build Functions
|
||||
int build_NCCH(user_settings *usrset);
|
||||
|
||||
|
||||
// NCCH Read Functions
|
||||
int VerifyNCCH(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput);
|
||||
int VerifyNcch(u8 *ncch, keys_struct *keys, bool CheckHash, bool SuppressOutput);
|
||||
|
||||
u8* RetargetNCCH(FILE *fp, u64 size, u8 *TitleId, u8 *ProgramId, keys_struct *keys);
|
||||
int ModifyNcchIds(u8 *ncch, u8 *titleId, u8 *programId, keys_struct *keys);
|
||||
|
||||
|
||||
ncch_hdr* GetNCCH_CommonHDR(void *out, FILE *fp, u8 *buf);
|
||||
bool IsNCCH(FILE *fp, u8 *buf);
|
||||
void ReadNcchHdr(ncch_hdr *hdr, FILE *fp);
|
||||
u8* GetNcchHdrSig(ncch_hdr *hdr);
|
||||
u8* GetNcchHdrData(ncch_hdr *hdr);
|
||||
u32 GetNcchHdrSigLen(ncch_hdr *hdr);
|
||||
u32 GetNcchHdrDataLen(ncch_hdr *hdr);
|
||||
bool IsNcch(FILE *fp, u8 *buf);
|
||||
bool IsCfa(ncch_hdr* hdr);
|
||||
u32 GetNCCH_MediaUnitSize(ncch_hdr* hdr);
|
||||
u32 GetNCCH_MediaSize(ncch_hdr* hdr);
|
||||
ncch_key_type GetNCCHKeyType(ncch_hdr* hdr);
|
||||
|
||||
u8* GetNCCHKey0(ncch_key_type keytype, keys_struct *keys);
|
||||
u8* GetNCCHKey1(ncch_key_type keytype, keys_struct *keys);
|
||||
|
||||
int GetNCCHStruct(ncch_struct *ctx, ncch_hdr *header);
|
||||
void ncch_get_counter(ncch_struct *ctx, u8 counter[16], u8 type);
|
||||
void CryptNCCHSection(u8 *buffer, u64 size, u64 src_pos, ncch_struct *ctx, u8 key[16], u8 type);
|
||||
bool IsUpdateCfa(ncch_hdr* hdr);
|
||||
u32 GetNcchBlockSize(ncch_hdr* hdr);
|
||||
u8 GetBlockSizeFlag(u32 size);
|
||||
u64 GetNcchSize(ncch_hdr* hdr);
|
||||
bool IsNcchEncrypted(ncch_hdr *hdr);
|
||||
bool SetNcchKeys(keys_struct *keys, ncch_hdr *hdr);
|
||||
int GetNcchInfo(ncch_info *ctx, ncch_hdr *header);
|
||||
void GetNcchAesCounter(ncch_info *ctx, u8 counter[16], u8 type);
|
||||
void CryptNcchRegion(u8 *buffer, u64 size, u64 src_pos, ncch_info *ctx, u8 key[16], u8 type);
|
||||
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
#include "ncch.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
buffer_struct *out;
|
||||
keys_struct *keys;
|
||||
rsf_settings *rsfSet;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 blockSize;
|
||||
bool verbose;
|
||||
bool IncludeExeFsLogo;
|
||||
bool CompressCode;
|
||||
bool UseOnSD;
|
||||
bool Encrypt;
|
||||
bool FreeProductCode;
|
||||
bool IsCfa;
|
||||
bool IsBuildingCodeSection;
|
||||
bool UseRomFS;
|
||||
|
||||
bool useSecCrypto;
|
||||
u8 keyXID;
|
||||
} options;
|
||||
|
||||
struct
|
||||
{
|
||||
FILE *elf;
|
||||
u64 elfSize;
|
||||
|
||||
FILE *banner;
|
||||
u64 bannerSize;
|
||||
|
||||
FILE *icon;
|
||||
u64 iconSize;
|
||||
|
||||
FILE *logo;
|
||||
u64 logoSize;
|
||||
|
||||
FILE *code;
|
||||
u64 codeSize;
|
||||
|
||||
FILE *exhdr;
|
||||
u64 exhdrSize;
|
||||
|
||||
FILE *romfs;
|
||||
u64 romfsSize;
|
||||
|
||||
FILE *plainregion;
|
||||
u64 plainregionSize;
|
||||
} componentFilePtrs;
|
||||
|
||||
struct
|
||||
{
|
||||
buffer_struct code;
|
||||
buffer_struct banner;
|
||||
buffer_struct icon;
|
||||
} exefsSections;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 textAddress;
|
||||
u32 textSize;
|
||||
u32 textMaxPages;
|
||||
u32 roAddress;
|
||||
u32 roSize;
|
||||
u32 roMaxPages;
|
||||
u32 rwAddress;
|
||||
u32 rwSize;
|
||||
u32 rwMaxPages;
|
||||
u32 bssSize;
|
||||
} codeDetails;
|
||||
|
||||
struct
|
||||
{
|
||||
buffer_struct exhdr;
|
||||
buffer_struct acexDesc;
|
||||
buffer_struct logo;
|
||||
buffer_struct plainRegion;
|
||||
buffer_struct exeFs;
|
||||
} sections;
|
||||
|
||||
ncch_info cryptoDetails;
|
||||
} ncch_settings;
|
||||
|
||||
// NCCH Build Functions
|
||||
int build_NCCH(user_settings *usrset);
|
||||
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
#include "ncch.h"
|
||||
+595
-579
File diff suppressed because it is too large
Load Diff
+30
-175
@@ -1,199 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
// Enums
|
||||
typedef enum
|
||||
{
|
||||
NCSD_NO_NCCH0 = -1,
|
||||
NCSD_INVALID_NCCH0 = -2,
|
||||
NCSD_INVALID_NCCH = -3,
|
||||
INVALID_YAML_OPT = -4,
|
||||
CCI_SIG_FAIL = -5,
|
||||
|
||||
} ncsd_errors;
|
||||
cciflag_BACKUP_WRITE_WAIT_TIME = 0,
|
||||
cciflag_FW6_SAVE_CRYPTO = 1,
|
||||
cciflag_CARD_DEVICE = 3,
|
||||
cciflag_MEDIA_PLATFORM = 4,
|
||||
cciflag_MEDIA_TYPE = 5,
|
||||
cciflag_MEDIA_BLOCK_SIZE = 6,
|
||||
cciflag_CARD_DEVICE_OLD = 7
|
||||
} cci_flagindex;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FW6x_BackupWriteWaitTime = 0,
|
||||
FW6x_SaveCryptoFlag = 1,
|
||||
CardDeviceFlag = 3,
|
||||
MediaPlatformIndex = 4,
|
||||
MediaTypeIndex = 5,
|
||||
MediaUnitSize = 6,
|
||||
OldCardDeviceFlag = 7
|
||||
} FlagIndex;
|
||||
carddevice_NOR_FLASH = 1,
|
||||
carddevice_NONE = 2,
|
||||
carddevice_BT = 3
|
||||
} cci_carddevice;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CARD_DEVICE_NOR_FLASH = 1,
|
||||
CARD_DEVICE_NONE = 2,
|
||||
CARD_DEVICE_BT = 3
|
||||
} _CardDevice;
|
||||
cciplatform_CTR = 1,
|
||||
} cci_platform;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CTR = 1,
|
||||
} _PlatformIndex;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
INNER_DEVICE,
|
||||
CARD1,
|
||||
CARD2,
|
||||
EXTENDED_DEVICE
|
||||
} _TypeIndex;
|
||||
mediatype_INNER_DEVICE, // NAND
|
||||
mediatype_CARD1,
|
||||
mediatype_CARD2,
|
||||
mediatype_EXTENDED_DEVICE
|
||||
} cci_mediatype;
|
||||
|
||||
// Structs
|
||||
typedef struct
|
||||
{
|
||||
u8 offset[4];
|
||||
u8 size[4];
|
||||
} partition_offsetsize;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 magic[4];
|
||||
u8 mediaSize[4];
|
||||
u8 titleId[8];
|
||||
u8 partitionsFsType[8];
|
||||
u8 partitionsCryptoType[8];
|
||||
partition_offsetsize offset_sizeTable[8];
|
||||
u8 exhdrHash[0x20];
|
||||
u8 additionalHdrSize[0x4];
|
||||
u8 sectorZeroOffset[0x4];
|
||||
u8 partitionFlags[8];
|
||||
u8 partitionIdTable[8][8];
|
||||
u8 padding[0x30];
|
||||
} ncsd_hdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 magic[4];
|
||||
u8 mediaSize[4];
|
||||
u8 titleId[8];
|
||||
u8 contentFsType[8];
|
||||
u8 contentCryptoType[8];
|
||||
partition_offsetsize offset_sizeTable[8];
|
||||
u8 padding0[0x28];
|
||||
u8 flags[8];
|
||||
u8 contentIdTable[8][8];
|
||||
u8 padding1[0x30];
|
||||
} cci_hdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 writableAddress[4];
|
||||
u8 cardInfoBitmask[4];
|
||||
// Notes: reserved[0xDF8];
|
||||
u8 reserved0[0xf8];
|
||||
u8 mediaSizeUsed[8];
|
||||
u8 reserved1[0x8];
|
||||
u8 unknown[0x4];
|
||||
u8 reserved2[0xc];
|
||||
u8 cverTitleId[8];
|
||||
u8 cverTitleVersion[2];
|
||||
u8 reserved3[0xcd6];
|
||||
//
|
||||
u8 ncch0TitleId[8];
|
||||
u8 reserved4[8];
|
||||
u8 initialData[0x30];
|
||||
u8 reserved5[0xc0];
|
||||
u8 ncch0Hdr[0x100];
|
||||
} cardinfo_hdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 cardDeviceReserved1[0x200];
|
||||
u8 titleKey[0x10];
|
||||
u8 cardDeviceReserved2[0xf0];
|
||||
} devcardinfo_hdr;
|
||||
} ncch_offsetsize;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 signature[0x100];
|
||||
cci_hdr cciHdr;
|
||||
cardinfo_hdr cardinfo;
|
||||
devcardinfo_hdr devcardinfo;
|
||||
} InternalCCI_Context;
|
||||
u8 magic[4];
|
||||
u8 mediaSize[4];
|
||||
u8 titleId[8];
|
||||
u8 padding0[0x10];
|
||||
ncch_offsetsize offset_sizeTable[8];
|
||||
u8 padding1[0x28];
|
||||
u8 flags[8];
|
||||
u8 ncchIdTable[8][8];
|
||||
u8 padding2[0x30];
|
||||
} cci_hdr;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FILE *out;
|
||||
keys_struct *keys;
|
||||
|
||||
struct{
|
||||
bool fillOutCci;
|
||||
bool useDevCardInfo;
|
||||
u32 mediaUnit;
|
||||
|
||||
u64 savedataSize;
|
||||
} option;
|
||||
|
||||
struct{
|
||||
/* Data */
|
||||
buffer_struct *data;
|
||||
|
||||
/* Misc Records */
|
||||
FILE **filePtrs;
|
||||
u64 fileSize[CCI_MAX_CONTENT];
|
||||
u16 count;
|
||||
|
||||
/* Details for NCSD header */
|
||||
u8 fsType[CCI_MAX_CONTENT];
|
||||
u8 cryptoType[CCI_MAX_CONTENT];
|
||||
u64 offset[CCI_MAX_CONTENT];
|
||||
u64 size[CCI_MAX_CONTENT];
|
||||
u8 titleId[CCI_MAX_CONTENT][8];
|
||||
} content;
|
||||
|
||||
struct{
|
||||
u64 mediaSize;
|
||||
u8 mediaId[8];
|
||||
u8 flags[8];
|
||||
} header;
|
||||
|
||||
struct{
|
||||
u64 writableAddress;
|
||||
u32 cardInfoBitmask;
|
||||
|
||||
u64 cciTotalSize;
|
||||
|
||||
// cver details
|
||||
u8 cverTitleId[8];
|
||||
u8 cverTitleVersion[2];
|
||||
|
||||
u8 initialData[0x30];
|
||||
ncch_hdr ncchHdr;
|
||||
u8 titleKey[0x10];
|
||||
} cardinfo;
|
||||
} cci_settings;
|
||||
|
||||
#ifndef PUBLIC_BUILD
|
||||
static const u8 stock_initial_data[0x30] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xAD, 0x88,
|
||||
0xAC, 0x41, 0xA2, 0xB1, 0x5E, 0x8F,
|
||||
0x66, 0x9C, 0x97, 0xE5, 0xE1, 0x5E,
|
||||
0xA3, 0xEB, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const u8 stock_title_key[0x10] =
|
||||
{
|
||||
0x6E, 0xC7, 0x5F, 0xB2, 0xE2, 0xB4,
|
||||
0x87, 0x46, 0x1E, 0xDD, 0xCB, 0xB8,
|
||||
0x97, 0x11, 0x92, 0xBA
|
||||
};
|
||||
#endif
|
||||
|
||||
// Public Prototypes
|
||||
// Build Functions
|
||||
int build_CCI(user_settings *usrset);
|
||||
|
||||
// Read Functions
|
||||
bool IsCci(u8 *ncsd);
|
||||
u8* GetPartition(u8 *ncsd, u8 index);
|
||||
u64 GetPartitionOffset(u8 *ncsd, u8 index);
|
||||
u64 GetPartitionSize(u8 *ncsd, u8 index);
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
#include "ncsd.h"
|
||||
#include "tmd_read.h"
|
||||
|
||||
|
||||
// Enums
|
||||
typedef enum
|
||||
{
|
||||
NCSD_NO_NCCH0 = -1,
|
||||
NCSD_INVALID_NCCH0 = -2,
|
||||
NCSD_INVALID_NCCH = -3,
|
||||
INVALID_RSF_OPT = -4,
|
||||
GEN_HDR_FAIL = -5,
|
||||
INCOMPAT_CIA = -6,
|
||||
CCI_CONFIG_FAIL = -7,
|
||||
} ncsd_errors;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rsf_settings *rsf;
|
||||
keys_struct *keys;
|
||||
|
||||
FILE *out;
|
||||
|
||||
struct{
|
||||
bool verbose;
|
||||
bool padCci;
|
||||
bool noModTid;
|
||||
bool useExternalSdkCardInfo;
|
||||
bool closeAlignWR;
|
||||
|
||||
u8 cverDataType;
|
||||
char *cverDataPath;
|
||||
tmd_hdr *tmdHdr;
|
||||
} options;
|
||||
|
||||
struct{
|
||||
u32 blockSize;
|
||||
|
||||
u64 mediaSize;
|
||||
u64 usedSize;
|
||||
|
||||
u8 mediaType;
|
||||
u8 cardDevice;
|
||||
u64 saveSize;
|
||||
u64 card2SaveOffset;
|
||||
} romInfo;
|
||||
|
||||
struct{
|
||||
u8 *data;
|
||||
u64 dataLen;
|
||||
infile_type dataType;
|
||||
|
||||
char **path;
|
||||
|
||||
bool active[CCI_MAX_CONTENT];
|
||||
u64 dOffset[CCI_MAX_CONTENT];
|
||||
u64 *dSize;
|
||||
u64 titleId[CCI_MAX_CONTENT];
|
||||
|
||||
u64 cOffset[CCI_MAX_CONTENT];
|
||||
} content;
|
||||
|
||||
struct{
|
||||
buffer_struct ccihdr;
|
||||
buffer_struct cardinfohdr;
|
||||
} headers;
|
||||
} cci_settings;
|
||||
|
||||
// Public Prototypes
|
||||
// Build Functions
|
||||
int build_CCI(user_settings *usrset);
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "ncsd.h"
|
||||
|
||||
// Read Functions
|
||||
bool IsCci(u8 *ncsd);
|
||||
u8* GetPartition(u8 *ncsd, u8 index);
|
||||
u64 GetPartitionOffset(u8 *ncsd, u8 index);
|
||||
u64 GetPartitionSize(u8 *ncsd, u8 index);
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef PKI_LEGACY
|
||||
#include "dpki_legacy.h"
|
||||
#include "pki/dev_legacy.h"
|
||||
#endif
|
||||
|
||||
// AES KEYS
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef PKI_LEGACY
|
||||
#include "ppki_legacy.h"
|
||||
#include "pki/prod_legacy.h"
|
||||
#endif
|
||||
|
||||
// AES KEYS
|
||||
@@ -13,8 +13,7 @@ static const unsigned char prod_unfixed_ncch_keyX[2][16] = // Dummy
|
||||
|
||||
static const unsigned char ctr_common_etd_keyX_ppki[16] = // Dummy
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const unsigned char ctr_common_etd_keyY_ppki[6][16] =
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
#include "lib.h"
|
||||
#include "dir.h"
|
||||
#include "ncch.h"
|
||||
#include "ncch_build.h"
|
||||
#include "romfs.h"
|
||||
#include "romfs_binary.h"
|
||||
#include "romfs_gen.h"
|
||||
#include "romfs_import.h"
|
||||
|
||||
void FreeRomFsCtx(romfs_buildctx *ctx);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "lib.h"
|
||||
#include "dir.h"
|
||||
#include "ncch.h"
|
||||
#include "ncch_build.h"
|
||||
#include "romfs.h"
|
||||
|
||||
const int ROMFS_BLOCK_SIZE = 0x1000;
|
||||
@@ -75,7 +75,10 @@ int PrepareBuildRomFsBinary(ncch_settings *ncchset, romfs_buildctx *ctx)
|
||||
|
||||
// Print Filtered FS
|
||||
//printf("print filtered FS\n");
|
||||
//fs_PrintDir(ctx->fs,0);
|
||||
if(ncchset->options.verbose){
|
||||
printf("[ROMFS] File System:\n");
|
||||
fs_PrintDir(ctx->fs,0);
|
||||
}
|
||||
|
||||
//printf("predict romfs size\n");
|
||||
CalcRomfsSize(ctx);
|
||||
@@ -349,7 +352,7 @@ int AddFileToRomfs(romfs_buildctx *ctx, fs_file *file, u32 parent, u32 sibling)
|
||||
u64_to_u8(entry->dataoffset,ctx->u_dataLen,LE);
|
||||
u64_to_u8(entry->datasize,file->size,LE);
|
||||
u8 *data_pos = (ctx->data + ctx->u_dataLen);
|
||||
ReadFile_64(data_pos,file->size,0,file->fp);
|
||||
ReadFile64(data_pos,file->size,0,file->fp);
|
||||
ctx->u_dataLen += file->size; // adding file size
|
||||
}
|
||||
else
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "lib.h"
|
||||
#include "dir.h"
|
||||
#include "ncch.h"
|
||||
#include "ncch_build.h"
|
||||
#include "romfs.h"
|
||||
|
||||
int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx)
|
||||
@@ -11,7 +11,7 @@ int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx
|
||||
|
||||
ivfc_hdr *hdr = calloc(1,sizeof(ivfc_hdr));
|
||||
|
||||
ReadFile_64(hdr,sizeof(ivfc_hdr),0,ctx->romfsBinary);
|
||||
ReadFile64(hdr,sizeof(ivfc_hdr),0,ctx->romfsBinary);
|
||||
if(memcmp(hdr->magic,"IVFC",4) != 0){
|
||||
fprintf(stderr,"[ROMFS ERROR] Invalid RomFS Binary.\n");
|
||||
return INVALID_ROMFS_FILE;
|
||||
@@ -24,7 +24,7 @@ int PrepareImportRomFsBinaryFromFile(ncch_settings *ncchset, romfs_buildctx *ctx
|
||||
|
||||
int ImportRomFsBinaryFromFile(romfs_buildctx *ctx)
|
||||
{
|
||||
ReadFile_64(ctx->output,ctx->romfsSize,0,ctx->romfsBinary);
|
||||
ReadFile64(ctx->output,ctx->romfsSize,0,ctx->romfsBinary);
|
||||
if(memcmp(ctx->output,"IVFC",4) != 0){
|
||||
fprintf(stderr,"[ROMFS ERROR] Invalid RomFS Binary.\n");
|
||||
return INVALID_ROMFS_FILE;
|
||||
|
||||
@@ -56,7 +56,7 @@ void GET_Option(ctr_yaml_context *ctx, rsf_settings *rsf)
|
||||
//else if(cmpYamlValue("NoPadding",ctx)) SetBoolYAMLValue(&rsf->Option.NoPadding,"NoPadding",ctx);
|
||||
else if(cmpYamlValue("EnableCrypt",ctx)) SetBoolYAMLValue(&rsf->Option.EnableCrypt,"EnableCrypt",ctx);
|
||||
else if(cmpYamlValue("EnableCompress",ctx)) SetBoolYAMLValue(&rsf->Option.EnableCompress,"EnableCompress",ctx);
|
||||
else if(cmpYamlValue("FreeProductCode",ctx)) SetBoolYAMLValue(&rsf->Option.EnableCompress,"FreeProductCode",ctx);
|
||||
else if(cmpYamlValue("FreeProductCode",ctx)) SetBoolYAMLValue(&rsf->Option.FreeProductCode,"FreeProductCode",ctx);
|
||||
else if(cmpYamlValue("UseOnSD",ctx)) SetBoolYAMLValue(&rsf->Option.UseOnSD,"UseOnSD",ctx);
|
||||
else if(cmpYamlValue("PageSize",ctx)) SetSimpleYAMLValue(&rsf->Option.PageSize,"PageSize",ctx,0);
|
||||
//else if(cmpYamlValue("AppendSystemCall",ctx)) rsf->Option.AppendSystemCallNum = SetYAMLSequence(&rsf->Option.AppendSystemCall,"AppendSystemCall",ctx);
|
||||
|
||||
+33
-2
@@ -1,6 +1,6 @@
|
||||
#include "lib.h"
|
||||
#include "cia.h"
|
||||
#include "tik.h"
|
||||
#include "cia_build.h"
|
||||
#include "tik_build.h"
|
||||
|
||||
// Private Prototypes
|
||||
int SetupTicketBuffer(buffer_struct *tik);
|
||||
@@ -99,3 +99,34 @@ void SetContentIndexData(tik_hdr *hdr, cia_settings *ciaset) // TODO?
|
||||
memset(hdr->contentIndex,0,0xAC);
|
||||
memcpy(hdr->contentIndex,default_contentIndex,0x30);
|
||||
}
|
||||
|
||||
tik_hdr *GetTikHdr(u8 *tik)
|
||||
{
|
||||
u32 sigType = u8_to_u32(tik,BE);
|
||||
|
||||
switch(sigType){
|
||||
case(RSA_4096_SHA1):
|
||||
case(RSA_4096_SHA256):
|
||||
return (tik_hdr*)(tik+0x240);
|
||||
case(RSA_2048_SHA1):
|
||||
case(RSA_2048_SHA256):
|
||||
return (tik_hdr*)(tik+0x140);
|
||||
case(ECC_SHA1):
|
||||
case(ECC_SHA256):
|
||||
return (tik_hdr*)(tik+0x7C);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool GetTikTitleKey(u8 *titleKey, tik_hdr *hdr, keys_struct *keys)
|
||||
{
|
||||
if(keys->aes.commonKey[hdr->keyId] == NULL)
|
||||
return false;
|
||||
|
||||
keys->aes.currentCommonKey = hdr->keyId;
|
||||
|
||||
CryptTitleKey(hdr->encryptedTitleKey, titleKey, hdr->titleId, keys, DEC);
|
||||
|
||||
return true;
|
||||
}
|
||||
+2
-13
@@ -1,15 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
static const unsigned char default_contentIndex[0x30] =
|
||||
{
|
||||
0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC,
|
||||
0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84,
|
||||
0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
lic_Permanent = 0,
|
||||
@@ -63,6 +53,5 @@ typedef struct
|
||||
u8 contentIndex[0xAC];
|
||||
} tik_hdr;
|
||||
|
||||
// Prototypes
|
||||
int BuildTicket(cia_settings *ciaset);
|
||||
int CryptTitleKey(u8 *EncTitleKey, u8 *DecTitleKey, u8 *TitleID, keys_struct *keys, u8 mode);
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "tik.h"
|
||||
|
||||
static const unsigned char default_contentIndex[0x30] =
|
||||
{
|
||||
0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC,
|
||||
0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84,
|
||||
0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// Prototypes
|
||||
int BuildTicket(cia_settings *ciaset);
|
||||
int CryptTitleKey(u8 *EncTitleKey, u8 *DecTitleKey, u8 *TitleID, keys_struct *keys, u8 mode);
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
#include "tik.h"
|
||||
|
||||
tik_hdr *GetTikHdr(u8 *tik);
|
||||
bool GetTikTitleKey(u8 *titleKey, tik_hdr *hdr, keys_struct *keys);
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
#include "lib.h"
|
||||
#include "ncch.h"
|
||||
#include "ncch_read.h"
|
||||
#include "titleid.h"
|
||||
|
||||
void SetPIDType(u16 *type);
|
||||
@@ -22,7 +22,7 @@ int GetProgramID(u64 *dest, rsf_settings *rsf, bool IsForExheader)
|
||||
u8 variation;
|
||||
|
||||
if(rsf->TitleInfo.Category && rsf->TitleInfo.CategoryFlags){
|
||||
fprintf(stderr,"[ID ERROR] Can not set \"Cateory\" and \"CategoryFlags\" at the same time.\n");
|
||||
fprintf(stderr,"[ID ERROR] Can not set \"Category\" and \"CategoryFlags\" at the same time.\n");
|
||||
return PID_BAD_RSF_SET;
|
||||
}
|
||||
|
||||
|
||||
+92
-7
@@ -1,6 +1,6 @@
|
||||
#include "lib.h"
|
||||
#include "cia.h"
|
||||
#include "tmd.h"
|
||||
#include "cia_build.h"
|
||||
#include "tmd_build.h"
|
||||
|
||||
// Private Prototypes
|
||||
int SetupTMDBuffer(buffer_struct *tik);
|
||||
@@ -85,11 +85,96 @@ int SetupTMDContentRecord(u8 *content_record, cia_settings *ciaset)
|
||||
{
|
||||
for(int i = 0; i < ciaset->content.count; i++){
|
||||
tmd_content_chunk *ptr = (tmd_content_chunk*)(content_record+sizeof(tmd_content_chunk)*i);
|
||||
u32_to_u8(ptr->contentID,ciaset->content.id[i],BE);
|
||||
u16_to_u8(ptr->contentIndex,ciaset->content.index[i],BE);
|
||||
u16_to_u8(ptr->contentFlags,ciaset->content.flags[i],BE);
|
||||
u64_to_u8(ptr->contentSize,ciaset->content.size[i],BE);
|
||||
memcpy(ptr->contentHash,ciaset->content.hash[i],0x20);
|
||||
u32_to_u8(ptr->id,ciaset->content.id[i],BE);
|
||||
u16_to_u8(ptr->index,ciaset->content.index[i],BE);
|
||||
u16_to_u8(ptr->flags,ciaset->content.flags[i],BE);
|
||||
u64_to_u8(ptr->size,ciaset->content.size[i],BE);
|
||||
memcpy(ptr->hash,ciaset->content.hash[i],0x20);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmd_hdr *GetTmdHdr(u8 *tmd)
|
||||
{
|
||||
u32 sigType = u8_to_u32(tmd,BE);
|
||||
|
||||
switch(sigType){
|
||||
case(RSA_4096_SHA1):
|
||||
case(RSA_4096_SHA256):
|
||||
return (tmd_hdr*)(tmd+0x240);
|
||||
case(RSA_2048_SHA1):
|
||||
case(RSA_2048_SHA256):
|
||||
return (tmd_hdr*)(tmd+0x140);
|
||||
case(ECC_SHA1):
|
||||
case(ECC_SHA256):
|
||||
return (tmd_hdr*)(tmd+0x7C);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmd_content_chunk* GetTmdContentInfo(u8 *tmd)
|
||||
{
|
||||
tmd_hdr *hdr = GetTmdHdr(tmd);
|
||||
if(!hdr)
|
||||
return NULL;
|
||||
|
||||
return (tmd_content_chunk*)((u8*)hdr + sizeof(tmd_hdr) + (sizeof(tmd_content_info_record)*64));
|
||||
}
|
||||
|
||||
u64 GetTmdTitleId(tmd_hdr *hdr)
|
||||
{
|
||||
return u8_to_u64(hdr->titleID,BE);
|
||||
}
|
||||
|
||||
u32 GetTmdSaveSize(tmd_hdr *hdr)
|
||||
{
|
||||
return u8_to_u32(hdr->savedataSize,BE);
|
||||
}
|
||||
|
||||
u16 GetTmdContentCount(tmd_hdr *hdr)
|
||||
{
|
||||
return u8_to_u16(hdr->contentCount,BE);
|
||||
}
|
||||
|
||||
u16 GetTmdVersion(tmd_hdr *hdr)
|
||||
{
|
||||
return u8_to_u16(hdr->titleVersion,BE);
|
||||
}
|
||||
|
||||
u32 GetTmdContentId(tmd_content_chunk info)
|
||||
{
|
||||
return u8_to_u32(info.id,BE);
|
||||
}
|
||||
|
||||
u16 GetTmdContentIndex(tmd_content_chunk info)
|
||||
{
|
||||
return u8_to_u16(info.index,BE);
|
||||
}
|
||||
|
||||
u16 GetTmdContentFlags(tmd_content_chunk info)
|
||||
{
|
||||
return u8_to_u16(info.flags,BE);
|
||||
}
|
||||
|
||||
u64 GetTmdContentSize(tmd_content_chunk info)
|
||||
{
|
||||
return u8_to_u64(info.size,BE);
|
||||
}
|
||||
|
||||
u8* GetTmdContentHash(tmd_content_chunk *info)
|
||||
{
|
||||
return (u8*)info->hash;
|
||||
}
|
||||
|
||||
bool IsTmdContentEncrypted(tmd_content_chunk info)
|
||||
{
|
||||
return (GetTmdContentFlags(info) & content_Encrypted) == content_Encrypted;
|
||||
}
|
||||
|
||||
bool ValidateTmdContent(u8 *data, tmd_content_chunk info)
|
||||
{
|
||||
u8 hash[32];
|
||||
ctr_sha(data,GetTmdContentSize(info),hash,CTR_SHA_256);
|
||||
return memcmp(hash,GetTmdContentHash(&info),32) == 0;
|
||||
}
|
||||
+6
-13
@@ -15,11 +15,11 @@ typedef enum
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 contentID[4];
|
||||
u8 contentIndex[2];
|
||||
u8 contentFlags[2];
|
||||
u8 contentSize[8];
|
||||
u8 contentHash[0x20]; // SHA 256
|
||||
u8 id[4];
|
||||
u8 index[2];
|
||||
u8 flags[2];
|
||||
u8 size[8];
|
||||
u8 hash[0x20]; // SHA 256
|
||||
} tmd_content_chunk;
|
||||
|
||||
typedef struct
|
||||
@@ -58,11 +58,4 @@ typedef struct
|
||||
u8 bootContent[2];
|
||||
u8 padding3[2];
|
||||
u8 infoRecordHash[0x20]; // SHA-256
|
||||
} tmd_hdr;
|
||||
|
||||
// Prototypes
|
||||
u32 PredictTMDSize(u16 ContentCount);
|
||||
int BuildTMD(cia_settings *ciaset);
|
||||
|
||||
// Read TMD
|
||||
tmd_hdr *GetTmdHdr(u8 *tmd);
|
||||
} tmd_hdr;
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "tmd.h"
|
||||
|
||||
// Prototypes
|
||||
u32 PredictTMDSize(u16 ContentCount);
|
||||
int BuildTMD(cia_settings *ciaset);
|
||||
@@ -1,22 +0,0 @@
|
||||
#include "lib.h"
|
||||
#include "cia.h"
|
||||
#include "tmd.h"
|
||||
|
||||
tmd_hdr *GetTmdHdr(u8 *tmd)
|
||||
{
|
||||
u32 sigType = u8_to_u32(tmd,BE);
|
||||
|
||||
switch(sigType){
|
||||
case(RSA_4096_SHA1):
|
||||
case(RSA_4096_SHA256):
|
||||
return (tmd_hdr*)(tmd+0x240);
|
||||
case(RSA_2048_SHA1):
|
||||
case(RSA_2048_SHA256):
|
||||
return (tmd_hdr*)(tmd+0x140);
|
||||
case(ECC_SHA1):
|
||||
case(ECC_SHA256):
|
||||
return (tmd_hdr*)(tmd+0x7C);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include "tmd.h"
|
||||
|
||||
// Read TMD
|
||||
tmd_hdr *GetTmdHdr(u8 *tmd);
|
||||
tmd_content_chunk* GetTmdContentInfo(u8 *tmd);
|
||||
u64 GetTmdTitleId(tmd_hdr *hdr);
|
||||
u32 GetTmdSaveSize(tmd_hdr *hdr);
|
||||
u16 GetTmdContentCount(tmd_hdr *hdr);
|
||||
u16 GetTmdVersion(tmd_hdr *hdr);
|
||||
|
||||
u32 GetTmdContentId(tmd_content_chunk info);
|
||||
u16 GetTmdContentIndex(tmd_content_chunk info);
|
||||
u16 GetTmdContentFlags(tmd_content_chunk info);
|
||||
u64 GetTmdContentSize(tmd_content_chunk info);
|
||||
u8* GetTmdContentHash(tmd_content_chunk info);
|
||||
|
||||
bool IsTmdContentEncrypted(tmd_content_chunk info);
|
||||
bool ValidateTmdContent(u8 *data, tmd_content_chunk info);
|
||||
+229
-157
@@ -10,9 +10,9 @@ void PrintArgInvalid(char *arg);
|
||||
void PrintArgReqParam(char *arg, u32 paramNum);
|
||||
void PrintNoNeedParam(char *arg);
|
||||
|
||||
int ParseArgs(int argc, char *argv[], user_settings *usr_settings)
|
||||
int ParseArgs(int argc, char *argv[], user_settings *set)
|
||||
{
|
||||
if(argv == NULL || usr_settings == NULL)
|
||||
if(argv == NULL || set == NULL)
|
||||
return USR_PTR_PASS_FAIL;
|
||||
|
||||
if(argc < 2){
|
||||
@@ -29,26 +29,23 @@ int ParseArgs(int argc, char *argv[], user_settings *usr_settings)
|
||||
}
|
||||
|
||||
// Allocating Memory for Content Path Ptrs
|
||||
usr_settings->common.contentPath = calloc(CIA_MAX_CONTENT,sizeof(char*));
|
||||
if(usr_settings->common.contentPath == NULL){
|
||||
set->common.contentPath = calloc(CIA_MAX_CONTENT,sizeof(char*));
|
||||
if(set->common.contentPath == NULL){
|
||||
fprintf(stderr,"[SETTING ERROR] Not Enough Memory\n");
|
||||
return USR_MEM_ERROR;
|
||||
}
|
||||
|
||||
// Initialise Keys
|
||||
InitKeys(&usr_settings->common.keys);
|
||||
InitKeys(&set->common.keys);
|
||||
|
||||
// Setting Defaults
|
||||
SetDefaults(usr_settings);
|
||||
SetDefaults(set);
|
||||
|
||||
// Parsing Arguments
|
||||
#ifdef DEBUG
|
||||
fprintf(stdout,"[DEBUG] Parsing Args\n");
|
||||
#endif
|
||||
int set_result;
|
||||
int i = 1;
|
||||
while(i < argc){
|
||||
set_result = SetArgument(argc,i,argv,usr_settings);
|
||||
set_result = SetArgument(argc,i,argv,set);
|
||||
if(set_result < 1){
|
||||
fprintf(stderr,"[RESULT] Invalid arguments, see '%s -help'\n",argv[0]);
|
||||
return set_result;
|
||||
@@ -57,39 +54,30 @@ int ParseArgs(int argc, char *argv[], user_settings *usr_settings)
|
||||
}
|
||||
|
||||
// Checking arguments
|
||||
#ifdef DEBUG
|
||||
fprintf(stdout,"[DEBUG] Checking Args\n");
|
||||
#endif
|
||||
set_result = CheckArgumentCombination(usr_settings);
|
||||
if(set_result) return set_result;
|
||||
if((set_result = CheckArgumentCombination(set)) != 0)
|
||||
return set_result;
|
||||
|
||||
// Setting Keys
|
||||
#ifdef DEBUG
|
||||
fprintf(stdout,"[DEBUG] Setting Keys\n");
|
||||
#endif
|
||||
set_result = SetKeys(&usr_settings->common.keys);
|
||||
if(set_result) return set_result;
|
||||
if((set_result = SetKeys(&set->common.keys)) != 0)
|
||||
return set_result;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stdout,"[DEBUG] Generating output path name if required\n");
|
||||
#endif
|
||||
|
||||
if(!usr_settings->common.outFileName){
|
||||
// Generating outpath if required
|
||||
if(!set->common.outFileName){
|
||||
char *source_path = NULL;
|
||||
if(usr_settings->ncch.buildNcch0)
|
||||
source_path = usr_settings->common.rsfPath;
|
||||
else if(usr_settings->common.workingFileType == infile_ncsd || usr_settings->common.workingFileType == infile_srl)
|
||||
source_path = usr_settings->common.workingFilePath;
|
||||
if(set->ncch.buildNcch0)
|
||||
source_path = set->common.rsfPath;
|
||||
else if(set->common.workingFileType == infile_ncsd || set->common.workingFileType == infile_cia || set->common.workingFileType == infile_srl)
|
||||
source_path = set->common.workingFilePath;
|
||||
else
|
||||
source_path = usr_settings->common.contentPath[0];
|
||||
u16 outfile_len = strlen(source_path) + 3;
|
||||
usr_settings->common.outFileName = calloc(outfile_len,sizeof(char));
|
||||
if(!usr_settings->common.outFileName){
|
||||
source_path = set->common.contentPath[0];
|
||||
u16 outfile_len = strlen(source_path) + 0x10;
|
||||
set->common.outFileName = calloc(outfile_len,sizeof(char));
|
||||
if(!set->common.outFileName){
|
||||
fprintf(stderr,"[SETTING ERROR] Not Enough Memory\n");
|
||||
return USR_MEM_ERROR;
|
||||
}
|
||||
usr_settings->common.outFileName_mallocd = true;
|
||||
append_filextention(usr_settings->common.outFileName,outfile_len,source_path,(char*)&output_extention[usr_settings->common.outFormat-1]);
|
||||
set->common.outFileName_mallocd = true;
|
||||
append_filextention(set->common.outFileName,outfile_len,source_path,(char*)&output_extention[set->common.outFormat-1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -101,12 +89,14 @@ void SetDefaults(user_settings *set)
|
||||
set->common.keys.accessDescSign.presetType = desc_preset_NONE;
|
||||
|
||||
// Build NCCH Info
|
||||
set->ncch.useSecCrypto = false;
|
||||
set->ncch.buildNcch0 = false;
|
||||
set->ncch.includeExefsLogo = false;
|
||||
set->common.outFormat = NCCH;
|
||||
set->ncch.ncchType = format_not_set;
|
||||
|
||||
// RSF Settings
|
||||
clrmem(&set->common.rsfSet,sizeof(rsf_settings));
|
||||
set->common.rsfSet.Option.EnableCompress = true;
|
||||
set->common.rsfSet.Option.EnableCrypt = true;
|
||||
set->common.rsfSet.Option.UseOnSD = false;
|
||||
@@ -119,13 +109,15 @@ void SetDefaults(user_settings *set)
|
||||
set->cci.useSDKStockData = false;
|
||||
|
||||
// CIA Info
|
||||
set->cia.includeUpdateNcch = false;
|
||||
set->cia.deviceId = 0;
|
||||
set->cia.eshopAccId = 0;
|
||||
set->cia.useDataTitleVer = false;
|
||||
set->cia.titleVersion[VER_MAJOR] = MAX_U16; // invalid so changes can be detected
|
||||
set->cia.randomTitleKey = false;
|
||||
set->common.keys.aes.currentCommonKey = MAX_U8 + 1; // invalid so changes can be detected
|
||||
for(int i = 0; i < CIA_MAX_CONTENT; i++){
|
||||
for(int i = 0; i < CIA_MAX_CONTENT; i++)
|
||||
set->cia.contentId[i] = MAX_U32 + 1; // invalid so changes can be detected
|
||||
}
|
||||
}
|
||||
|
||||
int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
@@ -137,7 +129,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
// Global Settings
|
||||
if(strcmp(argv[i],"-rsf") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-rsf",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->common.rsfPath = argv[i+1];
|
||||
@@ -145,7 +137,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-f") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-f",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
if(strcasecmp(argv[i+1],"ncch") == 0)
|
||||
@@ -162,17 +154,25 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-o") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-o",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->common.outFileName = argv[i+1];
|
||||
set->common.outFileName_mallocd = false;
|
||||
return 2;
|
||||
}
|
||||
else if(strcmp(argv[i],"-v") == 0){
|
||||
if(ParamNum){
|
||||
PrintNoNeedParam(argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->common.verbose = true;
|
||||
return 1;
|
||||
}
|
||||
// Key Options
|
||||
else if(strcmp(argv[i],"-target") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-target",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
if(strcasecmp(argv[i+1],"test") == 0 || strcasecmp(argv[i+1],"t") == 0)
|
||||
@@ -181,7 +181,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
set->common.keys.keyset = pki_DEVELOPMENT;
|
||||
else if(strcasecmp(argv[i+1],"retail") == 0 || strcasecmp(argv[i+1],"production") == 0 || strcasecmp(argv[i+1],"p") == 0)
|
||||
set->common.keys.keyset = pki_PRODUCTION;
|
||||
//else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0)
|
||||
//else if(strcasecmp(argv[i+1],"custom") == 0 || strcasecmp(argv[i+1],"c") == 0) // given all known keys are here, this isn't needed
|
||||
// set->common.keys.keyset = pki_CUSTOM;
|
||||
else{
|
||||
fprintf(stderr,"[SETTING ERROR] Unrecognised target '%s'\n",argv[i+1]);
|
||||
@@ -189,22 +189,36 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
else if(strcmp(argv[i],"-ckeyID") == 0){
|
||||
else if(strcmp(argv[i],"-ckeyid") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-ckeyID",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->common.keys.aes.currentCommonKey = strtol(argv[i+1],NULL,0);
|
||||
if(set->common.keys.aes.currentCommonKey > 0xff)
|
||||
if(set->common.keys.aes.currentCommonKey > MAX_CMN_KEY)
|
||||
{
|
||||
fprintf(stderr,"[SETTING ERROR] Invalid Common Key ID: 0x%x\n",set->common.keys.aes.currentCommonKey);
|
||||
fprintf(stderr,"[SETTING ERROR] Invalid Common Key Index: 0x%x\n",set->common.keys.aes.currentCommonKey);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
else if(strcmp(argv[i],"-ncchseckey") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.useSecCrypto = true;
|
||||
set->ncch.keyXID = strtol(argv[i+1],NULL,0);
|
||||
if(set->ncch.keyXID > MAX_NCCH_KEYX)
|
||||
{
|
||||
fprintf(stderr,"[SETTING ERROR] Invalid NCCH KeyX Index: 0x%x\n",set->ncch.keyXID);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
else if(strcmp(argv[i],"-showkeys") == 0){
|
||||
if(ParamNum){
|
||||
PrintNoNeedParam("-showkeys");
|
||||
PrintNoNeedParam(argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->common.keys.dumpkeys = true;
|
||||
@@ -212,7 +226,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-fsign") == 0){
|
||||
if(ParamNum){
|
||||
PrintNoNeedParam("-fsign");
|
||||
PrintNoNeedParam(argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->common.keys.rsa.isFalseSign = true;
|
||||
@@ -222,7 +236,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
// Ncch Options
|
||||
else if(strcmp(argv[i],"-elf") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-elf",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.elfPath = argv[i+1];
|
||||
@@ -232,7 +246,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
|
||||
else if(strcmp(argv[i],"-icon") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-icon",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.iconPath = argv[i+1];
|
||||
@@ -241,7 +255,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-banner") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-banner",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.bannerPath = argv[i+1];
|
||||
@@ -250,7 +264,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-logo") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-logo",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.logoPath = argv[i+1];
|
||||
@@ -259,7 +273,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-desc") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-desc",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
char *tmp = argv[i+1];
|
||||
@@ -281,7 +295,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
else if(strcasecmp(app_type,"ECApp") == 0) set->common.keys.accessDescSign.presetType = desc_preset_EC_APP;
|
||||
else if(strcasecmp(app_type,"Demo") == 0) set->common.keys.accessDescSign.presetType = desc_preset_DEMO;
|
||||
else if(strcasecmp(app_type,"DlpChild") == 0 || strcasecmp(app_type,"Dlp") == 0) set->common.keys.accessDescSign.presetType = desc_preset_DLP;
|
||||
//else if(strcasecmp(app_type,"FIRM") == 0) set->common.keys.accessDescSign.presetType = desc_preset_FIRM;
|
||||
else if(strcasecmp(app_type,"FIRM") == 0) set->common.keys.accessDescSign.presetType = desc_preset_FIRM;
|
||||
else{
|
||||
fprintf(stderr,"[SETTING ERROR] Accessdesc AppType preset '%s' not valid, please manually configure RSF\n",app_type);
|
||||
return USR_BAD_ARG;
|
||||
@@ -324,7 +338,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-exefslogo") == 0){
|
||||
if(ParamNum){
|
||||
PrintNoNeedParam("-exefslogo");
|
||||
PrintNoNeedParam(argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->ncch.includeExefsLogo = true;
|
||||
@@ -335,7 +349,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
// Ncch Rebuild Options
|
||||
else if(strcmp(argv[i],"-code") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-code",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.codePath = argv[i+1];
|
||||
@@ -344,16 +358,16 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-exheader") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-exheader",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.exheaderPath = argv[i+1];
|
||||
set->ncch.ncchType |= CXI;
|
||||
return 2;
|
||||
}
|
||||
else if(strcmp(argv[i],"-plain-region") == 0){
|
||||
else if(strcmp(argv[i],"-plainrgn") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-plain-region",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.plainRegionPath = argv[i+1];
|
||||
@@ -362,7 +376,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-romfs") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-romfs",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.romfsPath = argv[i+1];
|
||||
@@ -370,9 +384,9 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
return 2;
|
||||
}
|
||||
// Cci Options
|
||||
else if(strcmp(argv[i],"-devcardcci") == 0){
|
||||
else if(strcmp(argv[i],"-devcci") == 0){
|
||||
if(ParamNum){
|
||||
PrintNoNeedParam("-devcardcci");
|
||||
PrintNoNeedParam(argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->cci.useSDKStockData = true;
|
||||
@@ -380,7 +394,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-nomodtid") == 0){
|
||||
if(ParamNum){
|
||||
PrintNoNeedParam("-nomodtid");
|
||||
PrintNoNeedParam(argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->cci.dontModifyNcchTitleID = true;
|
||||
@@ -388,7 +402,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-alignwr") == 0){
|
||||
if(ParamNum){
|
||||
PrintNoNeedParam("-alignwr");
|
||||
PrintNoNeedParam(argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->cci.closeAlignWritableRegion = true;
|
||||
@@ -396,17 +410,42 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-cverinfo") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-cverinfo",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->cci.cverCiaPath = argv[i+1];
|
||||
char *pos = strstr(argv[i+1],":");
|
||||
if(!pos || strlen(pos) < 2){
|
||||
fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]);
|
||||
fprintf(stderr," %s <DATA PATH>:<'cia'/'tmd'>\n",argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
|
||||
char *dtype = pos + 1;
|
||||
if(strcasecmp(dtype,"tmd") == 0)
|
||||
set->cci.cverDataType = CVER_DTYPE_TMD;
|
||||
else if(strcasecmp(dtype,"cia") == 0)
|
||||
set->cci.cverDataType = CVER_DTYPE_CIA;
|
||||
else{
|
||||
fprintf(stderr,"[SETTING ERROR] Unrecognised cver data type:\"%s\"\n",dtype);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
|
||||
u32 path_len = (pos-argv[i+1])+1;
|
||||
set->cci.cverDataPath = calloc(path_len,sizeof(char));
|
||||
strncpy(set->cci.cverDataPath,argv[i+1],path_len-1);
|
||||
|
||||
if(!AssertFile(set->cci.cverDataPath)){
|
||||
fprintf(stderr,"[SETTING ERROR] Failed to open '%s'\n",set->cci.cverDataPath);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Cia Options
|
||||
else if(strcmp(argv[i],"-major") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-major",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->cia.useNormTitleVer = true;
|
||||
@@ -420,7 +459,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-minor") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-minor",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->cia.useNormTitleVer = true;
|
||||
@@ -434,7 +473,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-micro") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-micro",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
u32 ver = strtoul(argv[i+1],NULL,10);
|
||||
@@ -447,7 +486,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
}
|
||||
else if(strcmp(argv[i],"-dver") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-dver",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->cia.useDataTitleVer = true;
|
||||
@@ -457,31 +496,44 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->cia.titleVersion[VER_MAJOR] = (ver >> 6) & VER_MAJOR_MAX;
|
||||
set->cia.titleVersion[VER_MINOR] = ver & VER_MAJOR_MAX;
|
||||
set->cia.titleVersion[VER_MINOR] = ver & VER_MINOR_MAX;
|
||||
return 2;
|
||||
}
|
||||
else if(strcmp(argv[i],"-deviceid") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->cia.deviceId = strtoul(argv[i+1],NULL,16);
|
||||
return 2;
|
||||
}
|
||||
else if(strcmp(argv[i],"-esaccid") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->cia.eshopAccId = strtoul(argv[i+1],NULL,16);
|
||||
return 2;
|
||||
}
|
||||
else if(strcmp(argv[i],"-rand") == 0){
|
||||
if(ParamNum){
|
||||
PrintNoNeedParam("-rand");
|
||||
PrintNoNeedParam(argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->cia.randomTitleKey = true;
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[i],"-cci") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-cci",1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
else if(strcmp(argv[i],"-dlc") == 0){
|
||||
if(ParamNum){
|
||||
PrintNoNeedParam(argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->ncch.buildNcch0 = false;
|
||||
set->common.workingFileType = infile_ncsd;
|
||||
set->common.workingFilePath = argv[i+1];
|
||||
set->common.outFormat = CIA;
|
||||
return 2;
|
||||
set->cia.DlcContent = true;
|
||||
return 1;
|
||||
}
|
||||
else if(strcmp(argv[i],"-srl") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-srl",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.buildNcch0 = false;
|
||||
@@ -491,36 +543,53 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
return 2;
|
||||
|
||||
}
|
||||
else if(strcmp(argv[i],"-dlc") == 0){
|
||||
|
||||
// Ncch Container Conversion
|
||||
else if(strcmp(argv[i],"-ccitocia") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.buildNcch0 = false;
|
||||
set->common.workingFileType = infile_ncsd;
|
||||
set->common.workingFilePath = argv[i+1];
|
||||
set->common.outFormat = CIA;
|
||||
return 2;
|
||||
}
|
||||
else if(strcmp(argv[i],"-ciatocci") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
set->ncch.buildNcch0 = false;
|
||||
set->common.workingFileType = infile_cia;
|
||||
set->common.workingFilePath = argv[i+1];
|
||||
set->common.outFormat = CCI;
|
||||
return 2;
|
||||
}
|
||||
else if(strcmp(argv[i],"-inclupd") == 0){
|
||||
if(ParamNum){
|
||||
PrintNoNeedParam("-dlc");
|
||||
PrintNoNeedParam(argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->cia.DlcContent = true;
|
||||
set->cia.includeUpdateNcch = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Other Setting
|
||||
else if(strcmp(argv[i],"-content") == 0){
|
||||
if(ParamNum != 1){
|
||||
PrintArgReqParam("-content",1);
|
||||
PrintArgReqParam(argv[i],1);
|
||||
return USR_ARG_REQ_PARAM;
|
||||
}
|
||||
char *pos = strstr(argv[i+1],":");
|
||||
if(!pos){
|
||||
if(!pos || strlen(pos) < 2){
|
||||
fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]);
|
||||
fprintf(stderr," -content <CONTENT PATH>:<INDEX>\n");
|
||||
fprintf(stderr," %s <CONTENT PATH>:<INDEX>\n",argv[i]);
|
||||
fprintf(stderr," If generating a CIA, then use the format:\n");
|
||||
fprintf(stderr," -content <CONTENT PATH>:<INDEX>:<ID>\n");
|
||||
fprintf(stderr," %s <CONTENT PATH>:<INDEX>:<ID>\n",argv[i]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
if(strlen(pos) < 2){
|
||||
fprintf(stderr,"[SETTING ERROR] Bad argument '%s %s', correct format:\n",argv[i],argv[i+1]);
|
||||
fprintf(stderr," -content <CONTENT PATH>:<INDEX>\n");
|
||||
fprintf(stderr," If generating a CIA, then use the format:\n");
|
||||
fprintf(stderr," -content <CONTENT PATH>:<INDEX>:<ID>\n");
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
|
||||
/* Getting Content Index */
|
||||
u16 content_index = strtol((char*)(pos+1),NULL,0);
|
||||
@@ -528,7 +597,6 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
/* Storing Content Filepath */
|
||||
u32 path_len = (u32)(pos-argv[i+1])+1;
|
||||
|
||||
if(content_index == 0) set->ncch.buildNcch0 = false;
|
||||
if(set->common.contentPath[content_index] != NULL){
|
||||
fprintf(stderr,"[SETTING ERROR] Content %d is already specified\n",content_index);
|
||||
return USR_BAD_ARG;
|
||||
@@ -539,12 +607,16 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
return USR_MEM_ERROR;
|
||||
}
|
||||
strncpy(set->common.contentPath[content_index],argv[i+1],path_len-1);
|
||||
|
||||
if(!AssertFile(set->common.contentPath[content_index])){
|
||||
fprintf(stderr,"[SETTING ERROR] '%s' could not be opened\n",set->common.contentPath[content_index]);
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
set->common.contentSize[content_index] = GetFileSize64(set->common.contentPath[content_index]);
|
||||
|
||||
/* Get ContentID for CIA gen */
|
||||
char *pos2 = strstr(pos+1,":");
|
||||
if(pos2) {
|
||||
if(pos2)
|
||||
set->cia.contentId[content_index] = strtoul((pos2+1),NULL,0);
|
||||
}
|
||||
|
||||
/* Return Next Arg Pos*/
|
||||
return 2;
|
||||
@@ -563,7 +635,6 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set)
|
||||
fprintf(stderr,"[SETTING ERROR] Not enough memory\n");
|
||||
return MEM_ERROR;
|
||||
}
|
||||
//memset(set->dname.items,0,sizeof(dname_item)*set->dname.m_items);
|
||||
}
|
||||
else if(set->dname.m_items == set->dname.u_items){
|
||||
set->dname.m_items *= 2;
|
||||
@@ -655,7 +726,7 @@ int CheckArgumentCombination(user_settings *set)
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
|
||||
if(set->common.outFormat == CIA && set->cci.cverCiaPath){
|
||||
if(set->common.outFormat == CIA && set->cci.cverDataPath){
|
||||
fprintf(stderr,"[SETTING ERROR] You cannot use argument \"-cverinfo\" when generating a CIA\n");
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
@@ -700,7 +771,7 @@ int CheckArgumentCombination(user_settings *set)
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
if(!buildCXI && set->ncch.plainRegionPath){
|
||||
PrintArgInvalid("-plain-region");
|
||||
PrintArgInvalid("-plainrgn");
|
||||
return USR_BAD_ARG;
|
||||
}
|
||||
if(!set->ncch.buildNcch0 && set->ncch.includeExefsLogo){
|
||||
@@ -715,45 +786,47 @@ int CheckArgumentCombination(user_settings *set)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void init_UserSettings(user_settings *usr_settings)
|
||||
void init_UserSettings(user_settings *set)
|
||||
{
|
||||
memset(usr_settings,0,sizeof(user_settings));
|
||||
memset(set,0,sizeof(user_settings));
|
||||
}
|
||||
|
||||
void free_UserSettings(user_settings *usr_settings)
|
||||
void free_UserSettings(user_settings *set)
|
||||
{
|
||||
// Free Content Paths
|
||||
if(usr_settings->common.contentPath){
|
||||
if(set->common.contentPath){
|
||||
for(int i = 0; i < CIA_MAX_CONTENT; i++)
|
||||
free(usr_settings->common.contentPath[i]);
|
||||
free(usr_settings->common.contentPath);
|
||||
free(set->common.contentPath[i]);
|
||||
free(set->common.contentPath);
|
||||
}
|
||||
|
||||
// free -DNAME=VALUE
|
||||
for(u32 i = 0; i < usr_settings->dname.u_items; i++){
|
||||
free(usr_settings->dname.items[i].name);
|
||||
free(usr_settings->dname.items[i].value);
|
||||
for(u32 i = 0; i < set->dname.u_items; i++){
|
||||
free(set->dname.items[i].name);
|
||||
free(set->dname.items[i].value);
|
||||
}
|
||||
free(usr_settings->dname.items);
|
||||
free(set->dname.items);
|
||||
|
||||
free(set->cci.cverDataPath);
|
||||
|
||||
// Free Spec File Setting
|
||||
free_RsfSettings(&usr_settings->common.rsfSet);
|
||||
free_RsfSettings(&set->common.rsfSet);
|
||||
|
||||
// Free Key Data
|
||||
FreeKeys(&usr_settings->common.keys);
|
||||
FreeKeys(&set->common.keys);
|
||||
|
||||
// Free Working File
|
||||
free(usr_settings->common.workingFile.buffer);
|
||||
free(set->common.workingFile.buffer);
|
||||
|
||||
// Free outfile path, if malloc'd
|
||||
if(usr_settings->common.outFileName_mallocd)
|
||||
free(usr_settings->common.outFileName);
|
||||
if(set->common.outFileName_mallocd)
|
||||
free(set->common.outFileName);
|
||||
|
||||
// Clear settings
|
||||
init_UserSettings(usr_settings);
|
||||
init_UserSettings(set);
|
||||
|
||||
// Free
|
||||
free(usr_settings);
|
||||
free(set);
|
||||
}
|
||||
|
||||
void PrintNeedsArg(char *arg)
|
||||
@@ -787,53 +860,52 @@ void DisplayHelp(char *app_name)
|
||||
printf("Option Parameter Explanation\n");
|
||||
printf("GLOBAL OPTIONS:\n");
|
||||
printf(" -help Display this text\n");
|
||||
printf(" -rsf <file> Rom Specification File (*.rsf)\n");
|
||||
printf(" -f <ncch|cci|cia> Output Format, defaults to 'ncch'\n");
|
||||
printf(" -o <file> Output File\n");
|
||||
//printf(" -v Verbose\n");
|
||||
printf(" -DNAME=VALUE Substitute values in Spec file\n");
|
||||
printf(" -rsf <file> ROM Spec File (*.rsf)\n");
|
||||
printf(" -f <ncch|cci|cia> Output format, defaults to 'ncch'\n");
|
||||
printf(" -o <file> Output file\n");
|
||||
printf(" -v Verbose output\n");
|
||||
printf(" -DNAME=VALUE Substitute values in RSF file\n");
|
||||
printf("KEY OPTIONS:\n");
|
||||
//printf(" -target <t|d|p|c> Target for crypto, defaults to 't'\n");
|
||||
printf(" -target <t|d|p> Target for crypto, defaults to 't'\n");
|
||||
printf(" 't' Test(false) Keys & prod Certs\n");
|
||||
printf(" 'd' Development Keys & Certs\n");
|
||||
printf(" 'p' Production Keys & Certs\n");
|
||||
//printf(" 'c' Custom Keys & Certs\n");
|
||||
printf(" -ckeyID <u8 value> Override the automatic commonKey selection\n");
|
||||
printf(" -showkeys Display the loaded keychain\n");
|
||||
printf(" -ckeyid <index> Override the automatic common key selection\n");
|
||||
printf(" -ncchseckey <index> Ncch keyX index ('0'=1.0+, '1'=7.0+)\n");
|
||||
printf(" -showkeys Display the loaded key chain\n");
|
||||
printf(" -fsign Ignore invalid signatures\n");
|
||||
printf("NCCH OPTIONS:\n");
|
||||
printf(" -elf <file> ELF File\n");
|
||||
printf(" -icon <file> Icon File\n");
|
||||
printf(" -banner <file> Banner File\n");
|
||||
printf(" -logo <file> Logo File (Overrides \"BasicInfo/Logo\" in RSF)\n");
|
||||
printf(" -desc <apptype>:<fw> Specify Access Descriptor Preset\n");
|
||||
//printf(" AppTypes:\n");
|
||||
//printf(" 'SDApp' Normal SD Application\n");
|
||||
//printf(" 'ECApp' SD Application with DLC Capability\n");
|
||||
//printf(" 'Demo' SD Demo Application\n");
|
||||
//printf(" 'Dlp' NAND DLP Child Application\n");
|
||||
//printf(" 'FIRM' FIRM CXI\n");
|
||||
printf(" -exefslogo Include Logo in ExeFs (Required for usage on <5.X Systems)\n");
|
||||
printf(" -elf <file> ELF file\n");
|
||||
printf(" -icon <file> Icon file\n");
|
||||
printf(" -banner <file> Banner file\n");
|
||||
printf(" -logo <file> Logo file (Overrides \"BasicInfo/Logo\" in RSF)\n");
|
||||
printf(" -desc <apptype>:<fw> Specify Access Descriptor template\n");
|
||||
printf(" -exefslogo Include Logo in ExeFS (Required for usage on <5.0 systems)\n");
|
||||
printf("NCCH REBUILD OPTIONS:\n");
|
||||
printf(" -code <code path> Specify ExeFs code File\n");
|
||||
printf(" -exheader <exhdr path> ExHeader Template File\n");
|
||||
printf(" -plain-region <pln region path> PlainRegion File\n");
|
||||
printf(" -romfs <romfs path> RomFS File\n");
|
||||
printf(" -code <file> Decompressed ExeFS \".code\"\n");
|
||||
printf(" -exheader <file> Exheader template\n");
|
||||
printf(" -plainrgn <file> Plain Region binary\n");
|
||||
printf(" -romfs <file> RomFS binary\n");
|
||||
printf("CCI OPTIONS:\n");
|
||||
printf(" -content <filepath>:<index> Specify content files\n");
|
||||
printf(" -devcardcci Use SDK CardInfo Method\n");
|
||||
printf(" -content <file>:<index> Specify content files\n");
|
||||
printf(" -devcci Use external CTRSDK \"CardInfo\" method\n");
|
||||
printf(" -nomodtid Don't Modify Content TitleIDs\n");
|
||||
printf(" -alignwr Align Writeable Region to the end of last NCCH\n");
|
||||
printf(" -cverinfo <cver cia path> Include CVer title info\n");
|
||||
printf(" -alignwr Align writeable region to the end of last NCCH\n");
|
||||
printf(" -cverinfo <file>:<cia|tmd> Include cver title info\n");
|
||||
printf("CIA OPTIONS:\n");
|
||||
printf(" -content <filepath>:<index>:<id> Specify content files\n");
|
||||
printf(" -major <major version> Specify Major Version\n");
|
||||
printf(" -minor <minor version> Specify Minor Version\n");
|
||||
printf(" -micro <micro version> Specify Micro Version\n");
|
||||
printf(" -dver <datatitle ver> Specify Data Title Version\n");
|
||||
printf(" -content <file>:<index>:<id> Specify content files\n");
|
||||
printf(" -major <version> Major version\n");
|
||||
printf(" -minor <version> Minor version\n");
|
||||
printf(" -micro <version> Micro version\n");
|
||||
printf(" -dver <version> Data-title version\n");
|
||||
printf(" -deviceid <hex id> 3DS unique device ID\n");
|
||||
printf(" -esaccid <hex id> e-Shop account ID\n");
|
||||
printf(" -rand Use a random title key\n");
|
||||
printf(" -cci <cci path> Convert CCI to CIA\n");
|
||||
printf(" -srl <srl path> Use TWL SRL as Content0\n");
|
||||
printf(" -dlc Create DLC CIA\n");
|
||||
printf(" -srl <srl file> Package a TWL SRL in a CIA\n");
|
||||
printf("NCCH CONTAINER CONVERSION:\n");
|
||||
printf(" -ccitocia <cci file> Convert CCI to CIA\n");
|
||||
printf(" -ciatocci <cia file> Convert CIA to CCI\n");
|
||||
printf(" -inclupd Include \"Update NCCH\" in CCI to CIA conversion\n");
|
||||
|
||||
}
|
||||
+24
-5
@@ -21,6 +21,12 @@ typedef enum
|
||||
VER_DVER_MAX = 4095,
|
||||
} title_ver_max;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CVER_DTYPE_TMD,
|
||||
CVER_DTYPE_CIA,
|
||||
} cver_data_type;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USR_PTR_PASS_FAIL = -1,
|
||||
@@ -37,6 +43,7 @@ typedef enum
|
||||
infile_ncch,
|
||||
infile_ncsd,
|
||||
infile_srl,
|
||||
infile_cia,
|
||||
} infile_type;
|
||||
|
||||
typedef enum
|
||||
@@ -49,7 +56,7 @@ typedef enum
|
||||
NCCH
|
||||
} output_format;
|
||||
|
||||
static const char output_extention[4][5] = {".cxi",".cfa",".cci",".cia"};
|
||||
static const char output_extention[5][5] = {".cxi",".cfa",".cci",".cia",".app"};
|
||||
|
||||
/* This does not follow style, so the rsf string names match the variables where they're stored */
|
||||
typedef struct
|
||||
@@ -246,6 +253,8 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
struct{
|
||||
bool verbose;
|
||||
|
||||
char *rsfPath;
|
||||
bool outFileName_mallocd;
|
||||
char *outFileName;
|
||||
@@ -259,9 +268,10 @@ typedef struct
|
||||
|
||||
// Content Details
|
||||
char **contentPath;
|
||||
u64 contentSize[CIA_MAX_CONTENT];
|
||||
|
||||
char *workingFilePath;
|
||||
infile_type workingFileType; // Could Be ncch/ncsd/srl. This is mainly used for CIA gen
|
||||
infile_type workingFileType; // Could Be ncch/ncsd/srl/cia.
|
||||
buffer_struct workingFile;
|
||||
} common;
|
||||
|
||||
@@ -282,23 +292,32 @@ typedef struct
|
||||
char *exheaderPath; // for .code details
|
||||
char *plainRegionPath; // prebuilt Plain Region
|
||||
char *romfsPath; // Prebuild _cleartext_ romfs binary
|
||||
|
||||
bool useSecCrypto;
|
||||
u8 keyXID;
|
||||
} ncch; // Ncch0 Build
|
||||
|
||||
struct{
|
||||
bool useSDKStockData; // incase we want to use the SDK stock data, for whatever reason.
|
||||
bool dontModifyNcchTitleID;
|
||||
bool closeAlignWritableRegion;
|
||||
char *cverCiaPath;
|
||||
|
||||
u8 cverDataType;
|
||||
char *cverDataPath;
|
||||
} cci; // CCI Settings
|
||||
|
||||
struct{
|
||||
bool randomTitleKey;
|
||||
bool encryptCia;
|
||||
bool DlcContent;
|
||||
bool includeUpdateNcch;
|
||||
|
||||
bool useNormTitleVer;
|
||||
bool useDataTitleVer;
|
||||
u16 titleVersion[3];
|
||||
|
||||
u32 deviceId;
|
||||
u32 eshopAccId;
|
||||
|
||||
u64 contentId[CIA_MAX_CONTENT]; // For CIA
|
||||
} cia; // CIA Settings
|
||||
@@ -306,6 +325,6 @@ typedef struct
|
||||
|
||||
// Prototypes
|
||||
|
||||
void init_UserSettings(user_settings *usr_settings);
|
||||
void free_UserSettings(user_settings *usr_settings);
|
||||
void init_UserSettings(user_settings *set);
|
||||
void free_UserSettings(user_settings *set);
|
||||
int ParseArgs(int argc, char *argv[], user_settings *usr_settings);
|
||||
+80
-48
@@ -1,25 +1,9 @@
|
||||
#include "lib.h"
|
||||
#include "utf.h"
|
||||
|
||||
// Memory
|
||||
void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base)
|
||||
{
|
||||
char tmp[size][2];
|
||||
unsigned char *byte_array = malloc(size*sizeof(unsigned char));
|
||||
memset(byte_array, 0, size);
|
||||
memset(destination, 0, size);
|
||||
memset(tmp, 0, size*2);
|
||||
|
||||
for (int i = 0; i < size; i ++){
|
||||
tmp[i][0] = source[(i*2)];
|
||||
tmp[i][1] = source[((i*2)+1)];
|
||||
tmp[i][2] = '\0';
|
||||
byte_array[i] = (unsigned char)strtol(tmp[i], NULL, base);
|
||||
}
|
||||
endian_memcpy(destination,byte_array,size,endianness);
|
||||
free(byte_array);
|
||||
}
|
||||
#include "polarssl/base64.h"
|
||||
|
||||
// Memory
|
||||
void endian_memcpy(u8 *destination, u8 *source, u32 size, int endianness)
|
||||
{
|
||||
for (u32 i = 0; i < size; i++){
|
||||
@@ -65,13 +49,13 @@ u64 align(u64 value, u64 alignment)
|
||||
return value;
|
||||
}
|
||||
|
||||
u64 min_u64(u64 a, u64 b)
|
||||
u64 min64(u64 a, u64 b)
|
||||
{
|
||||
if(a < b) return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
u64 max_u64(u64 a, u64 b)
|
||||
u64 max64(u64 a, u64 b)
|
||||
{
|
||||
if(a > b) return a;
|
||||
return b;
|
||||
@@ -187,6 +171,56 @@ int str_utf8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Base64
|
||||
bool IsValidB64Char(char chr)
|
||||
{
|
||||
return (isalnum(chr) || chr == '+' || chr == '/' || chr == '=');
|
||||
}
|
||||
|
||||
u32 b64_strlen(char *str)
|
||||
{
|
||||
u32 count = 0;
|
||||
u32 i = 0;
|
||||
while(str[i] != 0x0){
|
||||
if(IsValidB64Char(str[i])) {
|
||||
//printf("Is Valid: %c\n",str[i]);
|
||||
count++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void b64_strcpy(char *dst, char *src)
|
||||
{
|
||||
u32 src_len = strlen(src);
|
||||
u32 j = 0;
|
||||
for(u32 i = 0; i < src_len; i++){
|
||||
if(IsValidB64Char(src[i])){
|
||||
dst[j] = src[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
dst[j] = 0;
|
||||
|
||||
//memdump(stdout,"src: ",(u8*)src,src_len+1);
|
||||
//memdump(stdout,"dst: ",(u8*)dst,j+1);
|
||||
}
|
||||
|
||||
int b64_decode(u8 *dst, char *src, u32 dst_size)
|
||||
{
|
||||
int ret;
|
||||
u32 size = dst_size;
|
||||
|
||||
ret = base64_decode(dst,(size_t*)&size,(const u8*)src,strlen(src));
|
||||
|
||||
if(size != dst_size)
|
||||
ret = POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Pseudo-Random Number Generator
|
||||
void initRand(void)
|
||||
{
|
||||
@@ -227,7 +261,7 @@ bool AssertFile(char *filename)
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 GetFileSize_u64(char *filename)
|
||||
u64 GetFileSize64(char *filename)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
struct _stat64 st;
|
||||
@@ -262,7 +296,7 @@ char *getcwdir(char *buffer,int maxlen)
|
||||
#endif
|
||||
}
|
||||
|
||||
int TruncateFile_u64(char *filename, u64 filelen)
|
||||
int TruncateFile64(char *filename, u64 filelen)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE fh;
|
||||
@@ -291,7 +325,7 @@ int TruncateFile_u64(char *filename, u64 filelen)
|
||||
|
||||
// Wide Char IO
|
||||
#ifdef _WIN32
|
||||
u64 wGetFileSize_u64(u16 *filename)
|
||||
u64 wGetFileSize64(u16 *filename)
|
||||
{
|
||||
struct _stat64 st;
|
||||
_wstat64((wchar_t*)filename, &st);
|
||||
@@ -302,12 +336,10 @@ u64 wGetFileSize_u64(u16 *filename)
|
||||
//IO Misc
|
||||
u8* ImportFile(char *file, u64 size)
|
||||
{
|
||||
u64 fsize = GetFileSize_u64(file);
|
||||
if(size > 0){
|
||||
if(size != fsize){
|
||||
fprintf(stderr,"[!] %s has an invalid size (0x%"PRIx64")\n",file, fsize);
|
||||
return NULL;
|
||||
}
|
||||
u64 fsize = GetFileSize64(file);
|
||||
if(size > 0 && size != fsize){
|
||||
fprintf(stderr,"[!] %s has an invalid size (0x%"PRIx64")\n",file, fsize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8 *data = (u8*)calloc(1,fsize);
|
||||
@@ -328,7 +360,7 @@ void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output)
|
||||
fwrite(buffer,size,1,output);
|
||||
}
|
||||
|
||||
void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file)
|
||||
void ReadFile64(void *outbuff, u64 size, u64 offset, FILE *file)
|
||||
{
|
||||
fseek_64(file,offset);
|
||||
fread(outbuff,size,1,file);
|
||||
@@ -368,32 +400,32 @@ u32 u8_to_u32(u8 *value, u8 endianness)
|
||||
|
||||
u64 u8_to_u64(u8 *value, u8 endianness)
|
||||
{
|
||||
u64 u64_return = 0;
|
||||
u64 ret = 0;
|
||||
switch(endianness){
|
||||
case(BE):
|
||||
u64_return |= (u64)value[7]<<0;
|
||||
u64_return |= (u64)value[6]<<8;
|
||||
u64_return |= (u64)value[5]<<16;
|
||||
u64_return |= (u64)value[4]<<24;
|
||||
u64_return |= (u64)value[3]<<32;
|
||||
u64_return |= (u64)value[2]<<40;
|
||||
u64_return |= (u64)value[1]<<48;
|
||||
u64_return |= (u64)value[0]<<56;
|
||||
ret |= (u64)value[7]<<0;
|
||||
ret |= (u64)value[6]<<8;
|
||||
ret |= (u64)value[5]<<16;
|
||||
ret |= (u64)value[4]<<24;
|
||||
ret |= (u64)value[3]<<32;
|
||||
ret |= (u64)value[2]<<40;
|
||||
ret |= (u64)value[1]<<48;
|
||||
ret |= (u64)value[0]<<56;
|
||||
break;
|
||||
//return (value[7]<<0) | (value[6]<<8) | (value[5]<<16) | (value[4]<<24) | (value[3]<<32) | (value[2]<<40) | (value[1]<<48) | (value[0]<<56);
|
||||
case(LE):
|
||||
u64_return |= (u64)value[0]<<0;
|
||||
u64_return |= (u64)value[1]<<8;
|
||||
u64_return |= (u64)value[2]<<16;
|
||||
u64_return |= (u64)value[3]<<24;
|
||||
u64_return |= (u64)value[4]<<32;
|
||||
u64_return |= (u64)value[5]<<40;
|
||||
u64_return |= (u64)value[6]<<48;
|
||||
u64_return |= (u64)value[7]<<56;
|
||||
ret |= (u64)value[0]<<0;
|
||||
ret |= (u64)value[1]<<8;
|
||||
ret |= (u64)value[2]<<16;
|
||||
ret |= (u64)value[3]<<24;
|
||||
ret |= (u64)value[4]<<32;
|
||||
ret |= (u64)value[5]<<40;
|
||||
ret |= (u64)value[6]<<48;
|
||||
ret |= (u64)value[7]<<56;
|
||||
break;
|
||||
//return (value[0]<<0) | (value[1]<<8) | (value[2]<<16) | (value[3]<<24) | (value[4]<<32) | (value[5]<<40) | (value[6]<<48) | (value[7]<<56);
|
||||
}
|
||||
return u64_return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int u16_to_u8(u8 *out_value, u16 in_value, u8 endianness)
|
||||
|
||||
+12
-7
@@ -7,7 +7,6 @@ typedef struct
|
||||
} buffer_struct;
|
||||
|
||||
// Memory
|
||||
void char_to_u8_array(unsigned char destination[], char source[], int size, int endianness, int base);
|
||||
void endian_memcpy(u8 *destination, u8 *source, u32 size, int endianness);
|
||||
int CopyData(u8 **dest, u8 *source, u64 size);
|
||||
void rndset(void *ptr, u64 num);
|
||||
@@ -15,8 +14,8 @@ void clrmem(void *ptr, u64 num);
|
||||
|
||||
// MISC
|
||||
u64 align(u64 value, u64 alignment);
|
||||
u64 min_u64(u64 a, u64 b);
|
||||
u64 max_u64(u64 a, u64 b);
|
||||
u64 min64(u64 a, u64 b);
|
||||
u64 max64(u64 a, u64 b);
|
||||
|
||||
// Strings
|
||||
void memdump(FILE* fout, const char* prefix, const u8* data, u32 size);
|
||||
@@ -28,6 +27,12 @@ int str_u32_to_u16(u16 **dst, u32 *dst_len, u32 *src, u32 src_len);
|
||||
int str_utf8_to_u16(u16 **dst, u32 *dst_len, u8 *src, u32 src_len);
|
||||
#endif
|
||||
|
||||
// Base64
|
||||
bool IsValidB64Char(char chr);
|
||||
u32 b64_strlen(char *str);
|
||||
void b64_strcpy(char *dst, char *src);
|
||||
int b64_decode(u8 *dst, char *src, u32 dst_size);
|
||||
|
||||
// Pseudo-Random Number Generator
|
||||
void initRand(void);
|
||||
u8 u8GetRand(void);
|
||||
@@ -37,20 +42,20 @@ u64 u64GetRand(void);
|
||||
|
||||
//Char IO
|
||||
bool AssertFile(char *filename);
|
||||
u64 GetFileSize_u64(char *filename);
|
||||
u64 GetFileSize64(char *filename);
|
||||
int makedir(const char* dir);
|
||||
char *getcwdir(char *buffer,int maxlen);
|
||||
int TruncateFile_u64(char *filename, u64 filelen);
|
||||
int TruncateFile64(char *filename, u64 filelen);
|
||||
|
||||
//Wide Char IO
|
||||
#ifdef _WIN32
|
||||
u64 wGetFileSize_u64(u16 *filename);
|
||||
u64 wGetFileSize64(u16 *filename);
|
||||
#endif
|
||||
|
||||
//IO Misc
|
||||
u8* ImportFile(char *file, u64 size);
|
||||
void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output);
|
||||
void ReadFile_64(void *outbuff, u64 size, u64 offset, FILE *file);
|
||||
void ReadFile64(void *outbuff, u64 size, u64 offset, FILE *file);
|
||||
int fseek_64(FILE *fp, u64 file_pos);
|
||||
|
||||
//Data Size conversion
|
||||
|
||||
@@ -11,17 +11,14 @@ void CheckEvent(ctr_yaml_context *ctx);
|
||||
void BadYamlFormatting(void);
|
||||
|
||||
// Code
|
||||
int GetYamlSettings(user_settings *set)
|
||||
int GetRsfSettings(user_settings *set)
|
||||
{
|
||||
memset(&set->common.rsfSet,0,sizeof(rsf_settings));
|
||||
int ret = 0;
|
||||
if(set->common.rsfPath) {
|
||||
FILE *rsf = fopen(set->common.rsfPath,"rb");
|
||||
if(!rsf) {
|
||||
if(!AssertFile(set->common.rsfPath)) {
|
||||
fprintf(stderr,"[RSF ERROR] Failed to open %s\n",set->common.rsfPath);
|
||||
return FAILED_TO_OPEN_FILE;
|
||||
}
|
||||
fclose(rsf);
|
||||
ret = ParseSpecFile(&set->common.rsfSet,set->common.rsfPath, &set->dname);
|
||||
}
|
||||
return ret;
|
||||
|
||||
@@ -31,7 +31,7 @@ typedef struct
|
||||
} ctr_yaml_context;
|
||||
|
||||
// Public Prototypes
|
||||
int GetYamlSettings(user_settings *set);
|
||||
int GetRsfSettings(user_settings *set);
|
||||
|
||||
// For scalar events
|
||||
char *GetYamlString(ctr_yaml_context *ctx);
|
||||
|
||||
Reference in New Issue
Block a user