diff --git a/makerom/Makefile b/makerom/Makefile index 5293084a..48ecc523 100644 --- a/makerom/Makefile +++ b/makerom/Makefile @@ -1,7 +1,7 @@ # Makerom Sources 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 +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 = 11 +VER_MINOR = 12 OUTPUT = makerom main: build diff --git a/makerom/cia.c b/makerom/cia.c index b9ab061c..095fb28f 100644 --- a/makerom/cia.c +++ b/makerom/cia.c @@ -443,7 +443,7 @@ int ImportNcchContent(cia_settings *ciaset) return MEM_ERROR; } - ncch_hdr *ncch0hdr = (ncch_hdr*)(ciaset->ciaSections.content.buffer+0x100); + ncch_hdr *ncch0hdr = (ncch_hdr*)ciaset->ciaSections.content.buffer; for(int i = 1; i < ciaset->content.count; i++){ // Import u8 *ncchpos = (u8*)(ciaset->ciaSections.content.buffer+ciaset->content.offset[i]); @@ -629,24 +629,9 @@ int BuildCiaHdr(cia_settings *ciaset) ciaset->ciaSections.contentOffset = align(ciaset->ciaSections.tmdOffset+ciaset->ciaSections.tmd.size,0x40); ciaset->ciaSections.metaOffset = align(ciaset->ciaSections.contentOffset+ciaset->content.totalSize,0x40); - for(int i = 0; i < ciaset->content.count; i++){ - // This works by treating the 0x2000 byte index array as an array of 2048 u32 values - - // Used for determining which u32 chunk to write the value to - u16 section = ciaset->content.index[i]/32; - - // Calculating the value added to the u32 - u32 value = 1 << (0x1F-ciaset->content.index[i]); - - // Retrieving current u32 block - u32 cur_content_index_section = u8_to_u32(hdr->contentIndex+(sizeof(u32)*section),BE); - - // Adding value to block - cur_content_index_section += value; + for(int i = 0; i < ciaset->content.count; i++) + hdr->contentIndex[ciaset->content.index[i]/8] |= 1 << (7 - (ciaset->content.index[i] & 7)); - // Returning block - u32_to_u8(hdr->contentIndex+(sizeof(u32)*section),cur_content_index_section,BE); - } return 0; } diff --git a/makerom/elf.c b/makerom/elf.c index d30db0a5..7bd07ded 100644 --- a/makerom/elf.c +++ b/makerom/elf.c @@ -1,5 +1,6 @@ #include "lib.h" #include "ncch_build.h" +#include "exheader_read.h" #include "elf_hdr.h" #include "elf.h" #include "blz.h" @@ -113,7 +114,8 @@ int BuildExeFsCode(ncch_settings *set) if(result == NOT_ELF_FILE) fprintf(stderr,"[ELF ERROR] Not ELF File\n"); else if(result == NOT_ARM_ELF) fprintf(stderr,"[ELF ERROR] Not ARM ELF\n"); else if(result == NON_EXECUTABLE_ELF) fprintf(stderr,"[ELF ERROR] Not Executeable ELF\n"); - else if(result == NOT_FIND_CODE_SECTIONS) fprintf(stderr,"[ELF ERROR] Failed to retrieve code sections from ELF\n"); + else if(result == NOT_FIND_TEXT_SEGMENT) fprintf(stderr,"[ELF ERROR] Failed to retrieve text sections from ELF\n"); + else if(result == NOT_FIND_DATA_SEGMENT) fprintf(stderr,"[ELF ERROR] Failed to retrieve data sections from ELF\n"); else fprintf(stderr,"[ELF ERROR] Failed to process ELF file (%d)\n",result); } for(int i = 0; i < elf->activeSegments; i++) @@ -139,7 +141,10 @@ int ImportExeFsCodeBinaryFromFile(ncch_settings *set) { u32 size = set->componentFilePtrs.codeSize; u8 *buffer = malloc(size); - if(!buffer) {fprintf(stderr,"[ELF ERROR] Not enough memory\n"); return MEM_ERROR;} + if(!buffer) { + fprintf(stderr,"[ELF ERROR] Not enough memory\n"); + return MEM_ERROR; + } ReadFile64(buffer,size,0,set->componentFilePtrs.code); set->exefsSections.code.size = set->componentFilePtrs.codeSize; @@ -156,6 +161,36 @@ int ImportExeFsCodeBinaryFromFile(ncch_settings *set) set->exefsSections.code.size = size; set->exefsSections.code.buffer = buffer; } + + size = set->componentFilePtrs.exhdrSize; + if(size < sizeof(extended_hdr)){ + fprintf(stderr,"[ELF ERROR] Exheader code info template is too small\n"); + return FAILED_TO_IMPORT_FILE; + } + extended_hdr *exhdr = malloc(size); + if(!exhdr) { + fprintf(stderr,"[ELF ERROR] Not enough memory\n"); + return MEM_ERROR; + } + ReadFile64(exhdr,size,0,set->componentFilePtrs.exhdr); + + /* Setting code_segment data */ + set->codeDetails.textAddress = u8_to_u32(exhdr->codeSetInfo.text.address,LE); + set->codeDetails.textMaxPages = u8_to_u32(exhdr->codeSetInfo.text.numMaxPages,LE); + set->codeDetails.textSize = u8_to_u32(exhdr->codeSetInfo.text.codeSize,LE); + + set->codeDetails.roAddress = u8_to_u32(exhdr->codeSetInfo.rodata.address,LE); + set->codeDetails.roMaxPages = u8_to_u32(exhdr->codeSetInfo.rodata.numMaxPages,LE); + set->codeDetails.roSize = u8_to_u32(exhdr->codeSetInfo.rodata.codeSize,LE); + + set->codeDetails.rwAddress = u8_to_u32(exhdr->codeSetInfo.data.address,LE); + set->codeDetails.rwMaxPages = u8_to_u32(exhdr->codeSetInfo.data.numMaxPages,LE); + set->codeDetails.rwSize = u8_to_u32(exhdr->codeSetInfo.data.codeSize,LE); + + set->codeDetails.bssSize = u8_to_u32(exhdr->codeSetInfo.bssSize,LE); + + free(exhdr); + return 0; } @@ -239,9 +274,13 @@ int CreateExeFsCode(elf_context *elf, u8 *elfFile, ncch_settings *set) result = CreateCodeSegmentFromElf(&rwdata,elf,elfFile,set->rsfSet->ExeFs.ReadWrite,set->rsfSet->ExeFs.ReadWriteNum); if(result) return result; + /* Checking the existence of essential ELF Segments */ + if(!text.size) return NOT_FIND_TEXT_SEGMENT; + if(!rwdata.size) return NOT_FIND_DATA_SEGMENT; + /* Allocating Buffer for ExeFs Code */ u32 size = (text.maxPageNum + rodata.maxPageNum + rwdata.maxPageNum)*elf->pageSize; - u8 *code = malloc(size); + u8 *code = calloc(1,size); /* Writing Code into Buffer */ u8 *textPos = (code + 0); @@ -264,7 +303,7 @@ int CreateExeFsCode(elf_context *elf, u8 *elfFile, ncch_settings *set) set->exefsSections.code.buffer = code; } - /* Setting code_segment rwdata and freeing original buffers */ + /* Setting code_segment data and freeing original buffers */ set->codeDetails.textAddress = text.address; set->codeDetails.textMaxPages = text.maxPageNum; set->codeDetails.textSize = text.size; diff --git a/makerom/elf.h b/makerom/elf.h index 4ce9121b..269f2093 100644 --- a/makerom/elf.h +++ b/makerom/elf.h @@ -6,10 +6,11 @@ typedef enum NOT_ARM_ELF = -11, NON_EXECUTABLE_ELF = -12, ELF_SECTION_NOT_FOUND = -13, - NOT_FIND_CODE_SECTIONS = -14, - ELF_SEGMENT_SECTION_SIZE_MISMATCH = -15, - ELF_SEGMENTS_NOT_CONTINUOUS = -16, - ELF_SEGMENTS_NOT_FOUND = -17, + NOT_FIND_TEXT_SEGMENT = -14, + NOT_FIND_DATA_SEGMENT = -15, + ELF_SEGMENT_SECTION_SIZE_MISMATCH = -16, + ELF_SEGMENTS_NOT_CONTINUOUS = -17, + ELF_SEGMENTS_NOT_FOUND = -18, } elf_errors; typedef struct diff --git a/makerom/exheader.c b/makerom/exheader.c index 9c99f258..d7dba89a 100644 --- a/makerom/exheader.c +++ b/makerom/exheader.c @@ -121,17 +121,6 @@ int get_ExHeaderSettingsFromNcchset(exheader_settings *exhdrset, ncch_settings * fprintf(stderr,"[EXHEADER ERROR] Not enough memory\n"); return MEM_ERROR; } - - /* Import ExHeader Code Section template */ - if(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; - } - ReadFile64((ncchset->sections.exhdr.buffer+import_offset),import_size,import_offset,ncchset->componentFilePtrs.exhdr); - } /* Create ExHeader Struct for output */ exhdrset->exHdr = (extended_hdr*)ncchset->sections.exhdr.buffer; @@ -142,17 +131,17 @@ int get_ExHeaderSettingsFromNcchset(exheader_settings *exhdrset, ncch_settings * /* BSS Size */ u32_to_u8(exhdrset->exHdr->codeSetInfo.bssSize,ncchset->codeDetails.bssSize,LE); /* Data */ - u32_to_u8(exhdrset->exHdr->codeSetInfo.dataSectionInfo.address,ncchset->codeDetails.rwAddress,LE); - u32_to_u8(exhdrset->exHdr->codeSetInfo.dataSectionInfo.codeSize,ncchset->codeDetails.rwSize,LE); - u32_to_u8(exhdrset->exHdr->codeSetInfo.dataSectionInfo.numMaxPages,ncchset->codeDetails.rwMaxPages,LE); + u32_to_u8(exhdrset->exHdr->codeSetInfo.data.address,ncchset->codeDetails.rwAddress,LE); + u32_to_u8(exhdrset->exHdr->codeSetInfo.data.codeSize,ncchset->codeDetails.rwSize,LE); + u32_to_u8(exhdrset->exHdr->codeSetInfo.data.numMaxPages,ncchset->codeDetails.rwMaxPages,LE); /* RO */ - u32_to_u8(exhdrset->exHdr->codeSetInfo.readOnlySectionInfo.address,ncchset->codeDetails.roAddress,LE); - u32_to_u8(exhdrset->exHdr->codeSetInfo.readOnlySectionInfo.codeSize,ncchset->codeDetails.roSize,LE); - u32_to_u8(exhdrset->exHdr->codeSetInfo.readOnlySectionInfo.numMaxPages,ncchset->codeDetails.roMaxPages,LE); + u32_to_u8(exhdrset->exHdr->codeSetInfo.rodata.address,ncchset->codeDetails.roAddress,LE); + u32_to_u8(exhdrset->exHdr->codeSetInfo.rodata.codeSize,ncchset->codeDetails.roSize,LE); + u32_to_u8(exhdrset->exHdr->codeSetInfo.rodata.numMaxPages,ncchset->codeDetails.roMaxPages,LE); /* Text */ - u32_to_u8(exhdrset->exHdr->codeSetInfo.textSectionInfo.address,ncchset->codeDetails.textAddress,LE); - u32_to_u8(exhdrset->exHdr->codeSetInfo.textSectionInfo.codeSize,ncchset->codeDetails.textSize,LE); - u32_to_u8(exhdrset->exHdr->codeSetInfo.textSectionInfo.numMaxPages,ncchset->codeDetails.textMaxPages,LE); + u32_to_u8(exhdrset->exHdr->codeSetInfo.text.address,ncchset->codeDetails.textAddress,LE); + u32_to_u8(exhdrset->exHdr->codeSetInfo.text.codeSize,ncchset->codeDetails.textSize,LE); + u32_to_u8(exhdrset->exHdr->codeSetInfo.text.numMaxPages,ncchset->codeDetails.textMaxPages,LE); } /* Set Simple Flags */ diff --git a/makerom/exheader.h b/makerom/exheader.h index d2d216fb..ee1e2d45 100644 --- a/makerom/exheader.h +++ b/makerom/exheader.h @@ -99,11 +99,11 @@ typedef struct u8 padding0[5]; u8 flag; u8 remasterVersion[2]; // le u16 - exhdr_CodeSegmentInfo textSectionInfo; + exhdr_CodeSegmentInfo text; u8 stackSize[4]; // le u32 - exhdr_CodeSegmentInfo readOnlySectionInfo; + exhdr_CodeSegmentInfo rodata; u8 padding1[4]; - exhdr_CodeSegmentInfo dataSectionInfo; + exhdr_CodeSegmentInfo data; u8 bssSize[4]; // le u32 } exhdr_CodeSetInfo; diff --git a/makerom/ncch.c b/makerom/ncch.c index 98778727..10c4a92f 100644 --- a/makerom/ncch.c +++ b/makerom/ncch.c @@ -858,17 +858,16 @@ int ModifyNcchIds(u8 *ncch, u8 *titleId, u8 *programId, keys_struct *keys) ncch_hdr *hdr = (ncch_hdr*)ncch; - if(/*keys->rsa.requiresPresignedDesc && */!IsCfa(hdr)){ - fprintf(stderr,"[NCCH ERROR] CXI's ID cannot be modified without the ability to resign the AccessDesc\n"); // Not yet yet, requires AccessDesc Privk, may implement anyway later - return -1; - } - bool titleIdMatches = titleId == NULL? true : memcmp(titleId,hdr->titleId,8) == 0; bool programIdMatches = programId == NULL? true : memcmp(programId,hdr->programId,8) == 0; if(titleIdMatches && programIdMatches) return 0;// if no modification is required don't do anything + if(/*keys->rsa.requiresPresignedDesc && */!IsCfa(hdr)){ + fprintf(stderr,"[NCCH ERROR] CXI's ID cannot be modified without the ability to resign the AccessDesc\n"); // Not yet yet, requires AccessDesc Privk, may implement anyway later + return -1; + } ncch_info ncchInfo; u8 *romfs = NULL; diff --git a/makerom/tik.c b/makerom/tik.c index 352d5565..5f2e233c 100644 --- a/makerom/tik.c +++ b/makerom/tik.c @@ -3,32 +3,42 @@ #include "tik_build.h" // Private Prototypes -int SetupTicketBuffer(buffer_struct *tik); -int SetupTicketHeader(tik_hdr *hdr, cia_settings *ciaset); -int SignTicketHeader(tik_hdr *hdr, tik_signature *sig, keys_struct *keys); +int SetupTicketBuffer(cia_settings *set); +void SetupTicketHeader(tik_hdr *hdr, cia_settings *ciaset); +int SignTicketHeader(buffer_struct *tik, keys_struct *keys); void SetLimits(tik_hdr *hdr, cia_settings *ciaset); -void SetContentIndexData(tik_hdr *hdr, cia_settings *ciaset); +u32 GetContentIndexSegNum(cia_settings *set); +void SetContentIndexHeader(tik_content_index_hdr *hdr, cia_settings *set); +void SetContentIndexData(tik_content_index_struct *data, cia_settings *set); -int BuildTicket(cia_settings *ciaset) +int BuildTicket(cia_settings *set) { int result = 0; - result = SetupTicketBuffer(&ciaset->ciaSections.tik); + result = SetupTicketBuffer(set); if(result) return result; // Setting Ticket Struct Ptrs - tik_signature *sig = (tik_signature*)ciaset->ciaSections.tik.buffer; - tik_hdr *hdr = (tik_hdr*)(ciaset->ciaSections.tik.buffer+sizeof(tik_signature)); - - result = SetupTicketHeader(hdr,ciaset); - if(result) return result; - result = SignTicketHeader(hdr,sig,ciaset->keys); + buffer_struct *tik = &set->ciaSections.tik; + + tik_hdr *hdr = (tik_hdr*) (tik->buffer + sizeof(tik_signature)); + tik_content_index_hdr *idxHdr = (tik_content_index_hdr*) (tik->buffer + sizeof(tik_signature) + sizeof(tik_hdr)); + tik_content_index_struct *idxData = (tik_content_index_struct*) (tik->buffer + sizeof(tik_signature) + sizeof(tik_hdr) + sizeof(tik_content_index_hdr)); + + + SetupTicketHeader(hdr,set); + SetContentIndexHeader(idxHdr,set); + SetContentIndexData(idxData,set); + + result = SignTicketHeader(tik,set->keys); return 0; } -int SetupTicketBuffer(buffer_struct *tik) +int SetupTicketBuffer(cia_settings *set) { - tik->size = sizeof(tik_signature) + sizeof(tik_hdr); + buffer_struct *tik = &set->ciaSections.tik; + + tik->size = sizeof(tik_signature) + sizeof(tik_hdr) + sizeof(tik_content_index_hdr) + sizeof(tik_content_index_struct)*GetContentIndexSegNum(set); tik->buffer = calloc(1,tik->size); if(!tik->buffer) { fprintf(stderr,"[TIK ERROR] Not enough memory\n"); @@ -37,7 +47,7 @@ int SetupTicketBuffer(buffer_struct *tik) return 0; } -int SetupTicketHeader(tik_hdr *hdr, cia_settings *ciaset) +void SetupTicketHeader(tik_hdr *hdr, cia_settings *ciaset) { clrmem(hdr,sizeof(tik_hdr)); @@ -58,15 +68,19 @@ int SetupTicketHeader(tik_hdr *hdr, cia_settings *ciaset) memcpy(hdr->eshopAccId,ciaset->tik.eshopAccId,4); hdr->audit = ciaset->tik.audit; SetLimits(hdr,ciaset); - SetContentIndexData(hdr,ciaset); - return 0; } -int SignTicketHeader(tik_hdr *hdr, tik_signature *sig, keys_struct *keys) +int SignTicketHeader(buffer_struct *tik, keys_struct *keys) { + tik_signature *sig = (tik_signature*)tik->buffer; + u8 *data = tik->buffer + sizeof(tik_signature); + u32 len = tik->size - sizeof(tik_signature); + + clrmem(sig,sizeof(tik_signature)); u32_to_u8(sig->sigType,RSA_2048_SHA256,BE); - return ctr_sig((u8*)hdr,sizeof(tik_hdr),sig->data,keys->rsa.xsPub,keys->rsa.xsPvt,RSA_2048_SHA256,CTR_RSA_SIGN); + + return ctr_sig(data,len,sig->data,keys->rsa.xsPub,keys->rsa.xsPvt,RSA_2048_SHA256,CTR_RSA_SIGN); } int CryptTitleKey(u8 *EncTitleKey, u8 *DecTitleKey, u8 *TitleID, keys_struct *keys, u8 mode) @@ -94,10 +108,62 @@ void SetLimits(tik_hdr *hdr, cia_settings *ciaset) // TODO? memset(hdr->limits,0,0x40); } -void SetContentIndexData(tik_hdr *hdr, cia_settings *ciaset) // TODO? +u32 GetContentIndexSegNum(cia_settings *set) { - memset(hdr->contentIndex,0,0xAC); - memcpy(hdr->contentIndex,default_contentIndex,0x30); + u32 num, level, i; + + num = level = 0; + + for( i = 0; i < set->content.count; i++) + { + if(set->content.index[i] >= level) + { + level = roundup(set->content.index[i],0x400); + num++; + } + } + return num; +} + +void SetContentIndexHeader(tik_content_index_hdr *hdr, cia_settings *set) +{ + u32 hdrSize = sizeof(tik_content_index_hdr); + u32 segNum = GetContentIndexSegNum(set); + u32 segSize = sizeof(tik_content_index_struct); + u32 segTotalSize = segSize * segNum; + u32 totalSize = hdrSize + segTotalSize; + + u32_to_u8(hdr->unk0,0x00010014,BE); + u32_to_u8(hdr->totalSize,totalSize,BE); + u32_to_u8(hdr->unk1,0x00000014,BE); + u32_to_u8(hdr->unk2,0x00010014,BE); + u32_to_u8(hdr->unk3,0x00000000,BE); + u32_to_u8(hdr->hdrSize,hdrSize,BE); + u32_to_u8(hdr->segNum,segNum,BE); + u32_to_u8(hdr->segSize,segSize,BE); + u32_to_u8(hdr->segTotalSize,segTotalSize,BE); + u32_to_u8(hdr->unk4,0x00030000,BE); +} + +void SetContentIndexData(tik_content_index_struct *data, cia_settings *set) +{ + u32 level, i; + int j; + + j = -1; + level = 0; + + for( i = 0; i < set->content.count; i++) + { + if(set->content.index[i] >= level) + { + level = roundup(set->content.index[i],0x400); + j++; + u32_to_u8(data[j].level,(set->content.index[i]/0x400)*0x400,BE); + } + data[j].index[(set->content.index[i] & 0x3ff)/8] |= 1 << (set->content.index[i] & 0x7); + } + } tik_hdr *GetTikHdr(u8 *tik) diff --git a/makerom/tik.h b/makerom/tik.h index d8b7c054..8cc351d5 100644 --- a/makerom/tik.h +++ b/makerom/tik.h @@ -20,6 +20,26 @@ typedef enum right_AccessTitle = 5 } tik_item_rights; +typedef struct +{ + u8 unk0[4]; + u8 totalSize[4]; + u8 unk1[4]; + u8 unk2[4]; + u8 unk3[4]; + u8 hdrSize[4]; + u8 segNum[4]; + u8 segSize[4]; + u8 segTotalSize[4]; + u8 unk4[4]; +} tik_content_index_hdr; + +typedef struct +{ + u8 level[4]; + u8 index[0x80]; +} tik_content_index_struct; + typedef struct { u8 sigType[4]; @@ -50,7 +70,6 @@ typedef struct u8 audit; u8 padding5[0x42]; u8 limits[0x40]; - u8 contentIndex[0xAC]; } tik_hdr; diff --git a/makerom/user_settings.c b/makerom/user_settings.c index 423278bf..97505ab0 100644 --- a/makerom/user_settings.c +++ b/makerom/user_settings.c @@ -140,7 +140,7 @@ int SetArgument(int argc, int i, char *argv[], user_settings *set) PrintArgReqParam(argv[i],1); return USR_ARG_REQ_PARAM; } - if(strcasecmp(argv[i+1],"ncch") == 0) + if(strcasecmp(argv[i+1],"ncch") == 0 || strcasecmp(argv[i+1],"cxi") == 0 || strcasecmp(argv[i+1],"cfa") == 0) set->common.outFormat = NCCH; else if(strcasecmp(argv[i+1],"cci") == 0) set->common.outFormat = CCI; diff --git a/makerom/utils.c b/makerom/utils.c index bda3076b..450427fd 100644 --- a/makerom/utils.c +++ b/makerom/utils.c @@ -41,10 +41,15 @@ void clrmem(void *ptr, u64 num) } // Misc +u64 roundup(u64 value, u64 alignment) +{ + return value + alignment - value % alignment; +} + u64 align(u64 value, u64 alignment) { if(value % alignment != 0) - return value + alignment - value % alignment; + return roundup(value,alignment); else return value; } diff --git a/makerom/utils.h b/makerom/utils.h index 8c7d5a44..da32454f 100644 --- a/makerom/utils.h +++ b/makerom/utils.h @@ -13,6 +13,7 @@ void rndset(void *ptr, u64 num); void clrmem(void *ptr, u64 num); // MISC +u64 roundup(u64 value, u64 alignment); u64 align(u64 value, u64 alignment); u64 min64(u64 a, u64 b); u64 max64(u64 a, u64 b);