From 33d59f6d3aeb4a4fed7bcf6ccccb1dd36ff1b15f Mon Sep 17 00:00:00 2001 From: d0k3 Date: Thu, 19 Aug 2021 21:09:13 +0200 Subject: [PATCH] Add 0x88 to NDS cart dumps trimmed size --- BuildFakeTicket.patch | 116 +++++++++++++++++++++++++++++++++++ Makefile | 6 +- arm9/source/game/tadx.c | 15 +++++ arm9/source/game/tadx.h | 39 ++++++++++++ arm9/source/utils/gameutil.c | 2 +- 5 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 BuildFakeTicket.patch create mode 100644 arm9/source/game/tadx.c create mode 100644 arm9/source/game/tadx.h diff --git a/BuildFakeTicket.patch b/BuildFakeTicket.patch new file mode 100644 index 0000000..e2c9836 --- /dev/null +++ b/BuildFakeTicket.patch @@ -0,0 +1,116 @@ +diff --git a/arm9/source/game/ticket.c b/arm9/source/game/ticket.c +index 14e5a7e..856f80a 100644 +--- a/arm9/source/game/ticket.c ++++ b/arm9/source/game/ticket.c +@@ -41,27 +41,80 @@ u32 ValidateTicketSignature(Ticket* ticket) { + return ret; + } + +-u32 BuildFakeTicket(Ticket* ticket, u8* title_id) { ++u32 BuildFakeTicket(Ticket** ticket, u32* ticket_size, const u8* title_id, u32 index_max) { ++ if (!ticket || !ticket_size) ++ return 1; ++ + static const u8 sig_type[4] = { TICKET_SIG_TYPE }; // RSA_2048 SHA256 +- static const u8 ticket_cnt_index[] = { // whatever this is +- 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 +- }; ++ ++ // calculate sizes and determine pointers to use ++ u32 rights_field_count = (min(index_max, 0x10000) + 1023) >> 10; // round up to 1024 and cap at 65536, and div by 1024 ++ u32 content_index_size = sizeof(TicketContentIndexMainHeader) + sizeof(TicketContentIndexDataHeader) + sizeof(TicketRightsField) * rights_field_count; ++ u32 _ticket_size = sizeof(Ticket) + content_index_size; ++ Ticket *_ticket; ++ ++ if (*ticket) { // if a pointer was pregiven ++ if (*ticket_size < _ticket_size) { // then check given boundary size ++ *ticket_size = _ticket_size; // if not enough, inform the actual needed size ++ return 2; // indicate a size error ++ } ++ _ticket = *ticket; // get the pointer if we good to go ++ } else // if not pregiven, allocate one ++ _ticket = (Ticket*)malloc(_ticket_size); ++ ++ if (!_ticket) ++ return 1; ++ + // set ticket all zero for a clean start +- memset(ticket, 0x00, TICKET_COMMON_SIZE); // 0xAC being size of this fake ticket's content index ++ memset(_ticket, 0x00, _ticket_size); + // fill ticket values +- memcpy(ticket->sig_type, sig_type, 4); +- memset(ticket->signature, 0xFF, 0x100); +- snprintf((char*) ticket->issuer, 0x40, IS_DEVKIT ? TICKET_ISSUER_DEV : TICKET_ISSUER); +- memset(ticket->ecdsa, 0xFF, 0x3C); +- ticket->version = 0x01; +- memset(ticket->titlekey, 0xFF, 16); +- memcpy(ticket->title_id, title_id, 8); +- ticket->commonkey_idx = 0x00; // eshop +- ticket->audit = 0x01; // whatever +- memcpy(ticket->content_index, ticket_cnt_index, sizeof(ticket_cnt_index)); +- memset(&ticket->content_index[sizeof(ticket_cnt_index)], 0xFF, 0x80); // 1024 content indexes ++ memcpy(_ticket->sig_type, sig_type, 4); ++ memset(_ticket->signature, 0xFF, 0x100); ++ snprintf((char*) _ticket->issuer, 0x40, IS_DEVKIT ? TICKET_ISSUER_DEV : TICKET_ISSUER); ++ memset(_ticket->ecdsa, 0xFF, 0x3C); ++ _ticket->version = 0x01; ++ memset(_ticket->titlekey, 0xFF, 16); ++ memcpy(_ticket->title_id, title_id, 8); ++ _ticket->commonkey_idx = 0x00; // eshop ++ _ticket->audit = 0x01; // whatever ++ ++ // fill in rights ++ TicketContentIndexMainHeader* mheader = (TicketContentIndexMainHeader*)&_ticket->content_index[0]; ++ TicketContentIndexDataHeader* dheader = (TicketContentIndexDataHeader*)&_ticket->content_index[0x14]; ++ TicketRightsField* rights = (TicketRightsField*)&_ticket->content_index[0x28]; ++ ++ // first main data header ++ mheader->unk1[1] = 0x1; mheader->unk2[1] = 0x14; ++ mheader->content_index_size[3] = (u8)(content_index_size >> 0); ++ mheader->content_index_size[2] = (u8)(content_index_size >> 8); ++ mheader->content_index_size[1] = (u8)(content_index_size >> 16); ++ mheader->content_index_size[0] = (u8)(content_index_size >> 24); ++ mheader->data_header_relative_offset[3] = 0x14; // relative offset for TicketContentIndexDataHeader ++ mheader->unk3[1] = 0x1; mheader->unk4[1] = 0x14; ++ ++ // then the data header ++ dheader->data_relative_offset[3] = 0x28; // relative offset for TicketRightsField ++ dheader->max_entry_count[3] = (u8)(rights_field_count >> 0); ++ dheader->max_entry_count[2] = (u8)(rights_field_count >> 8); ++ dheader->max_entry_count[1] = (u8)(rights_field_count >> 16); ++ dheader->max_entry_count[0] = (u8)(rights_field_count >> 24); ++ dheader->size_per_entry[3] = (u8)sizeof(TicketRightsField); // sizeof should be 0x84 ++ dheader->total_size_used[3] = (u8)((sizeof(TicketRightsField) * rights_field_count) >> 0); ++ dheader->total_size_used[2] = (u8)((sizeof(TicketRightsField) * rights_field_count) >> 8); ++ dheader->total_size_used[1] = (u8)((sizeof(TicketRightsField) * rights_field_count) >> 16); ++ dheader->total_size_used[0] = (u8)((sizeof(TicketRightsField) * rights_field_count) >> 24); ++ dheader->data_type[1] = 3; // right fields ++ ++ // now the right fields ++ // indexoffets must be in accending order to have the desired effect ++ for (u32 i = 0; i < rights_field_count; ++i) { ++ rights[i].indexoffset[1] = (u8)((1024 * i) >> 0); ++ rights[i].indexoffset[0] = (u8)((1024 * i) >> 8); ++ memset(&rights[i].rightsbitfield[0], 0xFF, sizeof(rights[0].rightsbitfield)); ++ } ++ ++ *ticket = _ticket; ++ *ticket_size = _ticket_size; + + return 0; + } +diff --git a/arm9/source/game/ticket.h b/arm9/source/game/ticket.h +index 956023d..28214ab 100644 +--- a/arm9/source/game/ticket.h ++++ b/arm9/source/game/ticket.h +@@ -97,7 +97,7 @@ typedef struct { + u32 ValidateTicket(Ticket* ticket); + u32 ValidateTwlTicket(Ticket* ticket); + u32 ValidateTicketSignature(Ticket* ticket); +-u32 BuildFakeTicket(Ticket* ticket, u8* title_id); ++u32 BuildFakeTicket(Ticket** ticket, u32* ticket_size, const u8* title_id, u32 index_max); + u32 GetTicketContentIndexSize(const Ticket* ticket); + u32 GetTicketSize(const Ticket* ticket); + u32 BuildTicketCert(u8* tickcert); diff --git a/Makefile b/Makefile index cfbec5c..c6d3945 100644 --- a/Makefile +++ b/Makefile @@ -24,11 +24,7 @@ ifeq ($(NTRBOOT),1) endif ifeq ($(OS),Windows_NT) - ifeq ($(TERM),cygwin) - PY3 := py -3 # Windows / CMD/PowerShell - else - PY3 := python3 # Windows / MSYS2 - endif + PY3 := py -3 # Windows / CMD/PowerShell else PY3 := python3 # Unix-like endif diff --git a/arm9/source/game/tadx.c b/arm9/source/game/tadx.c new file mode 100644 index 0000000..cf4064b --- /dev/null +++ b/arm9/source/game/tadx.c @@ -0,0 +1,15 @@ +#include "tadx.h" +#include "cia.h" + +u32 ValidateTadXHeader(TadXHeader* header) { + // super strict validation + if ((getbe32(header->size_header) != TADX_HEADER_SIZE) || + (getbe32(header->size_cert) != TADX_CERT_SIZE) || + (getbe32(header->size_ticket) != TICKET_TWL_SIZE) || + (getbe32(header->size_tmd) != TMD_SIZE_TWL) || + (getbe32(header->reserved0) != 0) || + (getbe32(header->reserved1) != 0) || + (getbe32(header->size_content) == 0)) + return 1; + return 0; +} diff --git a/arm9/source/game/tadx.h b/arm9/source/game/tadx.h new file mode 100644 index 0000000..adb7c41 --- /dev/null +++ b/arm9/source/game/tadx.h @@ -0,0 +1,39 @@ +#pragma once + +#include "common.h" +#include "ticket.h" +#include "tmd.h" + +#define TADX_HEADER_SIZE sizeof(TadXHeader) +#define TADX_CERT_SIZE 0xE80 + +#define TADX_OFFSET_CERT align(TADX_HEADER_SIZE, 40) +#define TADX_OFFSET_TICKET (TADX_OFFSET_CERT + align(TADX_CERT_SIZE, 40)) +#define TADX_OFFSET_TMD (TADX_OFFSET_TICKET + align(TICKET_TWL_SIZE, 40)) +#define TADX_OFFSET_CONTENT (TADX_OFFSET_TMD + align(TMD_SIZE_TWL, 40)) +#define TADX_OFFSET_CHUNK (TADX_OFFSET_TMD + TMD_SIZE_STUB) + +// this describes the TWL TAD exchangable format (similar to CIA) +// see: https://wiibrew.org/wiki/WAD_files#WAD_format +typedef struct { + u8 size_header[4]; + u8 type[2]; + u8 version[2]; + u8 size_cert[4]; + u8 reserved0[4]; + u8 size_ticket[4]; + u8 size_tmd[4]; + u8 size_content[4]; + u8 reserved1[4]; +} PACKED_STRUCT TadXHeader; + +typedef struct { + TadXHeader header; + u8 header_padding[0x40 - (TADX_HEADER_SIZE % 0x40)]; + u8 cert[TADX_CERT_SIZE]; + // cert is aligned and needs no padding + Ticket ticket; + u8 ticket_padding[0x40 - (TICKET_TWL_SIZE % 0x40)]; + u8 tmd[TMD_SIZE_TWL]; + u8 tmd_padding[0x40 - (TMD_SIZE_TWL % 40)]; +} PACKED_ALIGN(16) TadXStub; diff --git a/arm9/source/utils/gameutil.c b/arm9/source/utils/gameutil.c index b36b306..4437bf1 100644 --- a/arm9/source/utils/gameutil.c +++ b/arm9/source/utils/gameutil.c @@ -3218,7 +3218,7 @@ u64 GetGameFileTrimmedSize(const char* path) { return 0; if (hdr.unit_code != 0x00) // DSi or NDS+DSi trimsize = hdr.ntr_twl_rom_size; - else trimsize = hdr.ntr_rom_size; // regular NDS + else trimsize = hdr.ntr_rom_size + 0x88; // regular NDS } else { u8 hdr[0x200]; if (fvx_qread(path, &hdr, 0, 0x200, NULL) != FR_OK)