diff --git a/BurnOutSharp.Models/N3DS/ARM11KernelCapabilities.cs b/BurnOutSharp.Models/N3DS/ARM11KernelCapabilities.cs new file mode 100644 index 00000000..94d03774 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/ARM11KernelCapabilities.cs @@ -0,0 +1,43 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// The kernel capability descriptors are passed to svcCreateProcess. + /// + /// + public sealed class ARM11KernelCapabilities + { + /// + /// Descriptors + /// ------------------- + /// Pattern of bits 20-31 Type Fields + /// 0b1110xxxxxxxx Interrupt info + /// 0b11110xxxxxxx System call mask Bits 24-26: System call mask table index; Bits 0-23: mask + /// 0b1111110xxxxx Kernel release version Bits 8-15: Major version; Bits 0-7: Minor version + /// 0b11111110xxxx Handle table size Bits 0-18: size + /// 0b111111110xxx Kernel flags + /// 0b11111111100x Map address range Describes a memory mapping like the 0b111111111110 descriptor, but an entire range rather than a single page is mapped.Another 0b11111111100x descriptor must follow this one to denote the(exclusive) end of the address range to map. + /// 0b111111111110 Map memory page Bits 0-19: page index to map(virtual address >> 12; the physical address is determined per-page according to Memory layout); Bit 20: Map read-only(otherwise read-write) + /// + /// ARM11 Kernel Flags + /// ------------------- + /// Bit Description + /// 0 Allow debug + /// 1 Force debug + /// 2 Allow non-alphanum + /// 3 Shared page writing + /// 4 Privilege priority + /// 5 Allow main() args + /// 6 Shared device memory + /// 7 Runnable on sleep + /// 8-11 Memory type(1: application, 2: system, 3: base) + /// 12 Special memory + /// 13 Process has access to CPU core 2 (New3DS only) + /// + public byte[][] Descriptors; + + /// + /// Reserved + /// + public byte[] Reserved; + } +} diff --git a/BurnOutSharp.Models/N3DS/ARM11LocalSystemCapabilities.cs b/BurnOutSharp.Models/N3DS/ARM11LocalSystemCapabilities.cs new file mode 100644 index 00000000..0d21a859 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/ARM11LocalSystemCapabilities.cs @@ -0,0 +1,66 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + public sealed class ARM11LocalSystemCapabilities + { + /// + /// Program ID + /// + public byte[] ProgramID; + + /// + /// Core version (The Title ID low of the required FIRM) + /// + public uint CoreVersion; + + /// + /// Flag1 (implemented starting from 8.0.0-18). + /// + public ARM11LSCFlag1 Flag1; + + /// + /// Flag2 (implemented starting from 8.0.0-18). + /// + public ARM11LSCFlag2 Flag2; + + /// + /// Flag0 + /// + public ARM11LSCFlag0 Flag0; + + /// + /// Priority + /// + public byte Priority; + + /// + /// Resource limit descriptors. The first byte here controls the maximum allowed CpuTime. + /// + public byte[][] ResourceLimitDescriptors; + + /// + /// Storage info + /// + public StorageInfo StorageInfo; + + /// + /// Service access control + /// + public byte[][] ServiceAccessControl; + + /// + /// Extended service access control, support for this was implemented with 9.3.0-X. + /// + public byte[][] ExtendedServiceAccessControl; + + /// + /// Reserved + /// + public byte[] Reserved; + + /// + /// Resource limit category. (0 = APPLICATION, 1 = SYS_APPLET, 2 = LIB_APPLET, 3 = OTHER (sysmodules running under the BASE memregion)) + /// + public ResourceLimitCategory ResourceLimitCategory; + } +} diff --git a/BurnOutSharp.Models/N3DS/ARM9AccessControl.cs b/BurnOutSharp.Models/N3DS/ARM9AccessControl.cs new file mode 100644 index 00000000..9bb45594 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/ARM9AccessControl.cs @@ -0,0 +1,17 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + public sealed class ARM9AccessControl + { + /// + /// Descriptors + /// + public ARM9AccessControlDescriptors[] Descriptors; + + /// + /// ARM9 Descriptor Version. Originally this value had to be ≥ 2. + /// Starting with 9.3.0-X this value has to be either value 2 or value 3. + /// + public byte DescriptorVersion; + } +} diff --git a/BurnOutSharp.Models/N3DS/AccessControlInfo.cs b/BurnOutSharp.Models/N3DS/AccessControlInfo.cs new file mode 100644 index 00000000..26afc8bc --- /dev/null +++ b/BurnOutSharp.Models/N3DS/AccessControlInfo.cs @@ -0,0 +1,21 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + public sealed class AccessControlInfo + { + /// + /// ARM11 local system capabilities + /// + public ARM11LocalSystemCapabilities ARM11LocalSystemCapabilities; + + /// + /// ARM11 kernel capabilities + /// + public ARM11KernelCapabilities ARM11KernelCapabilities; + + /// + /// ARM9 access control + /// + public ARM9AccessControl ARM9AccessControl; + } +} diff --git a/BurnOutSharp.Models/N3DS/CIAHeader.cs b/BurnOutSharp.Models/N3DS/CIAHeader.cs new file mode 100644 index 00000000..aec997ad --- /dev/null +++ b/BurnOutSharp.Models/N3DS/CIAHeader.cs @@ -0,0 +1,94 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// CIA stands for CTR Importable Archive. This format allows the installation of + /// titles to the 3DS. CIA files and titles on Nintendo's CDN contain identical data. + /// As a consequence, valid CIA files can be generated from CDN content. This also + /// means CIA files can contain anything that titles on Nintendo's CDN can contain. + /// + /// Under normal circumstances CIA files are used where downloading a title is + /// impractical or not possible. Such as distributing a Download Play child, or + /// installing forced Gamecard updates. Those CIA(s) are stored by the titles in + /// question, in an auxiliary CFA file. + /// + /// + public sealed class CIAHeader + { + /// + /// Archive header size, usually 0x2020 bytes + /// + public int HeaderSize; + + /// + /// Type + /// + public ushort Type; + + /// + /// Version + /// + public ushort Version; + + /// + /// Certificate chain size + /// + public int CertificateChainSize; + + /// + /// Ticket size + /// + public int TicketSize; + + /// + /// TMD file size + /// + public int TMDFileSize; + + /// + /// Meta size (0 if no Meta data is present) + /// + public int MetaSize; + + /// + /// Content size + /// + public long ContentSize; + + /// + /// Content Index + /// + public byte[] ContentIndex; + + #region Content Index + + /// + /// Certificate chain + /// + /// + /// https://www.3dbrew.org/wiki/CIA#Certificate_Chain + /// + public Certificate[] CertificateChain; + + /// + /// Ticket + /// + public Ticket Ticket; + + /// + /// TMD file data + /// + public TitleMetadata TMDFileData; + + /// + /// Content file data + /// + public NCCHHeader[] Partitions; + + /// + /// Meta file data (Not a necessary component) + /// + public MetaFile MetaFileData; + + #endregion + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/N3DS/CXIExtendedHeader.cs b/BurnOutSharp.Models/N3DS/CXIExtendedHeader.cs new file mode 100644 index 00000000..93a18121 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/CXIExtendedHeader.cs @@ -0,0 +1,36 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// The exheader has two sections: + /// - The actual exheader data, containing System Control Info (SCI) and Access Control Info (ACI); + /// - A signed copy of NCCH HDR public key, and exheader ACI. This version of the ACI is used as limitation to the actual ACI. + /// + /// + public sealed class CXIExtendedHeader + { + /// + /// SCI + /// + public SystemControlInfo SCI; + + /// + /// ACI + /// + public AccessControlInfo ACI; + + /// + /// AccessDesc signature (RSA-2048-SHA256) + /// + public byte[] AccessDescSignature; + + /// + /// NCCH HDR RSA-2048 public key + /// + public byte[] NCCHHDRPublicKey; + + /// + /// ACI (for limitation of first ACI) + /// + public AccessControlInfo ACIForLimitations; + } +} diff --git a/BurnOutSharp.Models/N3DS/Certificate.cs b/BurnOutSharp.Models/N3DS/Certificate.cs new file mode 100644 index 00000000..83a31c48 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/Certificate.cs @@ -0,0 +1,77 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// Certificates contain cryptography information for verifying Signatures. + /// These certificates are also signed. The parent/child relationship between + /// certificates, makes all the certificates effectively signed by 'Root', + /// the public key for which is stored in NATIVE_FIRM. + /// + /// + public sealed class Certificate + { + /// + /// Signature Type + /// + public SignatureType SignatureType; + + /// + /// Signature size + /// + public ushort SignatureSize; + + /// + /// Padding size + /// + public byte PaddingSize; + + /// + /// Signature + /// + public byte[] Signature; + + /// + /// Issuer + /// + public string Issuer; + + /// + /// Key Type + /// + public PublicKeyType KeyType; + + /// + /// Name + /// + public string Name; + + /// + /// Expiration time as UNIX Timestamp, used at least for CTCert + /// + public uint ExpirationTime; + + // This contains the Public Key(i.e. Modulus & Public Exponent) + #region RSA + + /// + /// Modulus + /// + public byte[] Modulus; + + /// + /// Public Exponent + /// + public uint PublicExponent; + + #endregion + + // This contains the ECC public key, and is as follows: + #region ECC + + /// + /// Public Key + /// + public byte[] PublicKey; + + #endregion + } +} diff --git a/BurnOutSharp.Models/N3DS/CodeSetInfo.cs b/BurnOutSharp.Models/N3DS/CodeSetInfo.cs new file mode 100644 index 00000000..a76db265 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/CodeSetInfo.cs @@ -0,0 +1,21 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + public sealed class CodeSetInfo + { + /// + /// Address + /// + public byte[] Address; + + /// + /// Physical region size (in page-multiples) + /// + public uint PhysicalRegionSizeInPages; + + /// + /// Size (in bytes) + /// + public uint SizeInBytes; + } +} diff --git a/BurnOutSharp.Models/N3DS/Constants.cs b/BurnOutSharp.Models/N3DS/Constants.cs new file mode 100644 index 00000000..d85148ff --- /dev/null +++ b/BurnOutSharp.Models/N3DS/Constants.cs @@ -0,0 +1,25 @@ +namespace BurnOutSharp.Models.N3DS +{ + public static class Constants + { + // ExeFS + public static readonly byte[] CodeSegmentName = new byte[] { 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x00, 0x00, 0x00 }; // .code\0\0\0 + + // NCCH + public const string NCCHMagicNumber = "NCCH"; + + // NCSD + public const string NCSDMagicNumber = "NCSD"; + + // RomFS + public const string RomFSMagicNumber = "IVFC"; + public const uint RomFSSecondMagicNumber = 0x10000; + + // Setup Keys and IVs + public static byte[] PlainCounter = new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + public static byte[] ExefsCounter = new byte[] { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + public static byte[] RomfsCounter = new byte[] { 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + public const int CXTExtendedDataHeaderLength = 0x800; + } +} diff --git a/BurnOutSharp.Models/N3DS/ContentChunkRecord.cs b/BurnOutSharp.Models/N3DS/ContentChunkRecord.cs new file mode 100644 index 00000000..66f7b1a7 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/ContentChunkRecord.cs @@ -0,0 +1,38 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// There is one of these for each content contained in this title. + /// (Determined by "Content Count" in the TMD Header). + /// + /// + public sealed class ContentChunkRecord + { + /// + /// Content id + /// + public uint ContentId; + + /// + /// Content index + /// + /// + /// This does not apply to DLC. + /// + public ContentIndex ContentIndex; + + /// + /// Content type + /// + public TMDContentType ContentType; + + /// + /// Content size + /// + public ulong ContentSize; + + /// + /// SHA-256 hash + /// + public byte[] SHA256Hash; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/N3DS/ContentInfoRecord.cs b/BurnOutSharp.Models/N3DS/ContentInfoRecord.cs new file mode 100644 index 00000000..1a6ef1ab --- /dev/null +++ b/BurnOutSharp.Models/N3DS/ContentInfoRecord.cs @@ -0,0 +1,24 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// There are 64 of these records, usually only the first is used. + /// + /// + public sealed class ContentInfoRecord + { + /// + /// Content index offset + /// + public ushort ContentIndexOffset; + + /// + /// Content command count [k] + /// + public ushort ContentCommandCount; + + /// + /// SHA-256 hash of the next k content records that have not been hashed yet + /// + public byte[] UnhashedContentRecordsSHA256Hash; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/N3DS/Enums.cs b/BurnOutSharp.Models/N3DS/Enums.cs new file mode 100644 index 00000000..94ddb9f4 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/Enums.cs @@ -0,0 +1,229 @@ +using System; + +namespace BurnOutSharp.Models.N3DS +{ + [Flags] + public enum ARM9AccessControlDescriptors : byte + { + MountNandRoot = 0x01, + MountNandroWriteAccess = 0x02, + MountTwlnRoot = 0x04, + MountWnandRoot = 0x08, + MountCardSPI = 0x0F, + UseSDIF3 = 0x10, + CreateSeed = 0x20, + UseCardSPI = 0x40, + SDApplication = 0x80, + MoundSdmcWriteAccess = 0xF0, + } + + [Flags] + public enum ARM11LSCFlag0 : byte + { + IdealProcessor = 0x01 | 0x02, + + AffinityMask = 0x04 | 0x08, + + /// + /// Value Description + /// 0 Prod (64MB of usable application memory) + /// 1 Undefined (unusable) + /// 2 Dev1 (96MB of usable application memory) + /// 3 Dev2 (80MB of usable application memory) + /// 4 Dev3 (72MB of usable application memory) + /// 5 Dev4 (32MB of usable application memory) + /// 6-7 Undefined Same as Prod? + /// + Old3DSSystemMode = 0x0F | 0x10 | 0x20 | 0x40, + } + + [Flags] + public enum ARM11LSCFlag1 : byte + { + EnableL2Cache = 0x01, + Cpuspeed_804MHz = 0x02, + } + + [Flags] + public enum ARM11LSCFlag2 : byte + { + /// + /// Value Description + /// 0 Legacy (use Old3DS system mode) + /// 1 Prod (124MB of usable application memory) + /// 2 Dev1 (178MB of usable application memory) + /// 3 Dev2 (124MB of usable application memory) + /// 4-7 Undefined Same as Prod? + /// + New3DSSystemMode = 0x01 | 0x02 | 0x04 | 0x08, + } + + [Flags] + public enum BitMasks : byte + { + FixedCryptoKey = 0x01, + NoMountRomFs = 0x02, + NoCrypto = 0x04, + NewKeyYGenerator = 0x20, + } + + public enum ContentIndex : ushort + { + /// + /// Main Content (.CXI for 3DS executable content/.CFA for 3DS Data Archives/.SRL for TWL content) + /// + MainContent = 0x0000, + + /// + /// Home Menu Manual (.CFA) + /// + HomeMenuManual = 0x0001, + + /// + /// DLP Child Container (.CFA) + /// + DLPChildContainer = 0x0002, + } + + public enum ContentPlatform : byte + { + CTR = 0x01, + Snake = 0x02, // New3DS + } + + [Flags] + public enum ContentType : byte + { + Data = 0x01, + Executable = 0x02, + SystemUpdate = 0x04, + Manual = 0x08, + Child = 0x04 | 0x08, + Trial = 0x10, + } + + public enum CryptoMethod : byte + { + Original = 0x00, + Seven = 0x01, + NineThree = 0x0A, + NineSix = 0x0B, + } + + [Flags] + public enum FilesystemAccessInfo : ulong + { + CategorySystemApplication = 0x1, + CategoryHardwareCheck = 0x2, + CategoryFilesystemTool = 0x4, + Debug = 0x8, + TWLCardBackup = 0x10, + TWLNANDData = 0x20, + BOSS = 0x40, + sdmcRoot = 0x80, + Core = 0x100, + nandRootroReadOnly = 0x200, + nandRootrw = 0x400, + nandrootroWriteAccess = 0x800, + CategorySystemSettings = 0x1000, + Cardboard = 0x2000, + ExportImportIVS = 0x4000, + sdmcRootWriteOnly = 0x8000, + SwitchCleanup = 0x10000, // Introduced in 3.0.0? + SavedataMove = 0x20000, // Introduced in 5.0.0 + Shop = 0x40000, // Introduced in 5.0.0 + Shell = 0x80000, // Introduced in 5.0.0 + CategoryHomeMenu = 0x100000, // Introduced in 6.0.0 + SeedDB = 0x200000, // Introduced in 9.6.0-X FIRM. Home Menu has this bit set starting with 9.6.0-X. + } + + public enum FilesystemType : ulong + { + None = 0, + Normal = 1, + FIRM = 3, + AGB_FIRMSave = 4, + } + + public enum MediaCardDeviceType : byte + { + NORFlash = 0x01, + None = 0x02, + BT = 0x03, + } + + public enum MediaPlatformIndex : byte + { + CTR = 0x01, + } + + public enum MediaTypeIndex : byte + { + InnerDevice = 0x00, + Card1 = 0x01, + Card2 = 0x02, + ExtendedDevice = 0x03, + } + + public enum NCCHFlags + { + CryptoMethod = 0x03, + ContentPlatform = 0x04, + ContentTypeBitMask = 0x05, + ContentUnitSize = 0x06, + BitMasks = 0x07, + } + + public enum NCSDFlags + { + BackupWriteWaitTime = 0x00, + MediaCardDevice3X = 0x03, + MediaPlatformIndex = 0x04, + MediaTypeIndex = 0x05, + MediaUnitSize = 0x06, + MediaCardDevice2X = 0x07, + } + + public enum PublicKeyType : uint + { + RSA_4096 = 0x00000000, + RSA_2048 = 0x01000000, + ECDSA = 0x02000000, + } + + public enum ResourceLimitCategory + { + APPLICATION = 0, + SYS_APPLET = 1, + LIB_APPLET = 2, + OTHER = 3, + } + + // Note: These are reversed because of how C# reads values + public enum SignatureType : uint + { + RSA_4096_SHA1 = 0x00000100, + RSA_2048_SHA1 = 0x01000100, + ECDSA_SHA1 = 0x02000100, + RSA_4096_SHA256 = 0x03000100, + RSA_2048_SHA256 = 0x04000100, + ECDSA_SHA256 = 0x05000100, + } + + [Flags] + public enum StorageInfoOtherAttributes : byte + { + NotUseROMFS = 0x01, + UseExtendedSavedataAccess = 0x02, + } + + [Flags] + public enum TMDContentType : ushort + { + Encrypted = 0x0001, + Disc = 0x0002, + CFM = 0x0004, + Optional = 0x4000, + Shared = 0x8000, + } +} diff --git a/BurnOutSharp.Models/N3DS/ExeFSFileHeader.cs b/BurnOutSharp.Models/N3DS/ExeFSFileHeader.cs new file mode 100644 index 00000000..7109f553 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/ExeFSFileHeader.cs @@ -0,0 +1,33 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// There are a maximum of 10 file headers in the ExeFS format. (This maximum + /// number of file headers is disputable, with makerom indicating a maximum of + /// 8 sections and makecia indicating a maximum of 10. From a non-SDK point of + /// view, the ExeFS header format can hold no more than 10 file headers within + /// the currently define size of 0x200 bytes.) + /// + /// + public sealed class ExeFSFileHeader + { + /// + /// File name + /// + public string FileName; + + /// + /// File offset + /// + public uint FileOffset; + + /// + /// File size + /// + public uint FileSize; + + /// + /// SHA256 hash calculated over the entire file contents + /// + public byte[] FileHash; + } +} diff --git a/BurnOutSharp.Models/N3DS/ExeFSHeader.cs b/BurnOutSharp.Models/N3DS/ExeFSHeader.cs new file mode 100644 index 00000000..9c6dda89 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/ExeFSHeader.cs @@ -0,0 +1,26 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// ExeFS or Executable Filesystem contains information related to the + /// executable program, and is the part of the CXI format. + /// + /// The ExeFS usually contains one or more of the following files: + /// - .code Contains the code binary, which can be optionally reverse-LZSS compressed via an exheader flag. + /// - logo Contains distribution licensing Binary data. + /// - banner Contains the banner which homemenu uses for this CXI. + /// - icon Contains the icon which homemenu displays for this CXI. + /// + /// + public sealed class ExeFSHeader + { + /// + /// File headers (10 headers maximum, 16 bytes each) + /// + public ExeFSFileHeader[] FileHeaders; + + /// + /// Reserved + /// + public byte[] Reserved; + } +} diff --git a/BurnOutSharp.Models/N3DS/MetaFile.cs b/BurnOutSharp.Models/N3DS/MetaFile.cs new file mode 100644 index 00000000..6962899a --- /dev/null +++ b/BurnOutSharp.Models/N3DS/MetaFile.cs @@ -0,0 +1,31 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + public sealed class MetaFile + { + /// + /// Title ID dependency list - Taken from the application's ExHeader + /// + public byte[] TitleIDDependencyList; + + /// + /// Reserved + /// + public byte[] Reserved1; + + /// + /// Core Version + /// + public uint CoreVersion; + + /// + /// Reserved + /// + public byte[] Reserved2; + + /// + /// Icon Data(.ICN) - Taken from the application's ExeFS + /// + public byte[] IconData; + } +} \ No newline at end of file diff --git a/BurnOutSharp.Models/N3DS/NCCHHeader.cs b/BurnOutSharp.Models/N3DS/NCCHHeader.cs new file mode 100644 index 00000000..34eaaef9 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/NCCHHeader.cs @@ -0,0 +1,156 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + public sealed class NCCHHeader + { + /// + /// RSA-2048 signature of the NCCH header, using SHA-256. + /// + public byte[] RSA2048Signature; + + /// + /// Magic ID, always 'NCCH' + /// + public string MagicID; + + /// + /// Content size, in media units (1 media unit = 0x200 bytes) + /// + public uint ContentSizeInMediaUnits; + + /// + /// Partition ID + /// + public ulong PartitionId; + + /// + /// Maker code + /// + public ushort MakerCode; + + /// + /// Version + /// + public ushort Version; + + /// + /// When ncchflag[7] = 0x20 starting with FIRM 9.6.0-X, this is compared with the first output u32 from a + /// SHA256 hash. The data used for that hash is 0x18-bytes: [0x10-long title-unique content lock seed] + /// [programID from NCCH + 0x118]. This hash is only used for verification of the content lock seed, and + /// is not the actual keyY. + /// + public uint VerificationHash; + + /// + /// Program ID + /// + public ulong ProgramId; + + /// + /// Reserved + /// + public byte[] Reserved1; + + /// + /// Logo Region SHA-256 hash. (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11) + /// + public byte[] LogoRegionHash; + + /// + /// Product code + /// + public byte[] ProductCode; + + /// + /// Extended header SHA-256 hash (SHA256 of 2x Alignment Size, beginning at 0x0 of ExHeader) + /// + public byte[] ExtendedHeaderHash; + + /// + /// Extended header size, in bytes + /// + public uint ExtendedHeaderSizeInBytes; + + /// + /// Reserved + /// + public byte[] Reserved2; + + /// + /// Flags + /// + public NCCHHeaderFlags Flags; + + /// + /// Plain region offset, in media units + /// + public uint PlainRegionOffsetInMediaUnits; + + /// + /// Plain region size, in media units + /// + public uint PlainRegionSizeInMediaUnits; + + /// + /// Logo Region offset, in media units (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11) + /// + public uint LogoRegionOffsetInMediaUnits; + + /// + /// Logo Region size, in media units (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11) + /// + public uint LogoRegionSizeInMediaUnits; + + /// + /// ExeFS offset, in media units + /// + public uint ExeFSOffsetInMediaUnits; + + /// + /// ExeFS size, in media units + /// + public uint ExeFSSizeInMediaUnits; + + /// + /// ExeFS hash region size, in media units + /// + public uint ExeFSHashRegionSizeInMediaUnits; + + /// + /// Reserved + /// + public byte[] Reserved3; + + /// + /// RomFS offset, in media units + /// + public uint RomFSOffsetInMediaUnits; + + /// + /// RomFS size, in media units + /// + public uint RomFSSizeInMediaUnits; + + /// + /// RomFS hash region size, in media units + /// + public uint RomFSHashRegionSizeInMediaUnits; + + /// + /// Reserved + /// + public byte[] Reserved4; + + /// + /// ExeFS superblock SHA-256 hash - (SHA-256 hash, starting at 0x0 of the ExeFS over the number of + /// media units specified in the ExeFS hash region size) + /// + public byte[] ExeFSSuperblockHash; + + /// + /// RomFS superblock SHA-256 hash - (SHA-256 hash, starting at 0x0 of the RomFS over the number + /// of media units specified in the RomFS hash region size) + /// + public byte[] RomFSSuperblockHash; + } +} diff --git a/BurnOutSharp.Models/N3DS/NCCHHeaderFlags.cs b/BurnOutSharp.Models/N3DS/NCCHHeaderFlags.cs new file mode 100644 index 00000000..e850b088 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/NCCHHeaderFlags.cs @@ -0,0 +1,49 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + public sealed class NCCHHeaderFlags + { + /// + /// Reserved + /// + public byte Reserved0; + + /// + /// Reserved + /// + public byte Reserved1; + + /// + /// Reserved + /// + public byte Reserved2; + + /// + /// Crypto Method: When this is non-zero, a NCCH crypto method using two keyslots is used. + /// + public CryptoMethod CryptoMethod; + + /// + /// Content Platform: 1 = CTR, 2 = snake (New 3DS). + /// + public ContentPlatform ContentPlatform; + + /// + /// Content Type Bit-masks: Data = 0x1, Executable = 0x2, SystemUpdate = 0x4, Manual = 0x8, + /// Child = (0x4|0x8), Trial = 0x10. When 'Data' is set, but not 'Executable', NCCH is a CFA. + /// Otherwise when 'Executable' is set, NCCH is a CXI. + /// + public ContentType MediaPlatformIndex; + + /// + /// Content Unit Size i.e. u32 ContentUnitSize = 0x200*2^flags[6]; + /// + public byte ContentUnitSize; + + /// + /// Bit-masks: FixedCryptoKey = 0x1, NoMountRomFs = 0x2, NoCrypto = 0x4, using a new keyY + /// generator = 0x20(starting with FIRM 9.6.0-X). + /// + public BitMasks BitMasks; + } +} diff --git a/BurnOutSharp.Models/N3DS/NCSDHeader.cs b/BurnOutSharp.Models/N3DS/NCSDHeader.cs new file mode 100644 index 00000000..7b718b7f --- /dev/null +++ b/BurnOutSharp.Models/N3DS/NCSDHeader.cs @@ -0,0 +1,196 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// There are two known specialisations of the NCSD container format: + /// - The CTR Cart Image (CCI) format, the 3DS' raw NAND format + /// - CCI is the format of game ROM images. + /// + /// CTR System Update (CSU) is a variant of CCI, where the only difference + /// is in the file extension. + /// + /// + public sealed class NCSDHeader + { + #region Common to all NCSD files + + /// + /// RSA-2048 SHA-256 signature of the NCSD header + /// + public byte[] RSA2048Signature; + + /// + /// Size of the NCSD image, in media units (1 media unit = 0x200 bytes) + /// + public uint ImageSizeInMediaUnits; + + /// + /// Media ID + /// + public byte[] MediaId; + + /// + /// Partitions FS type (0=None, 1=Normal, 3=FIRM, 4=AGB_FIRM save) + /// + public FilesystemType PartitionsFSType; + + /// + /// Partitions crypt type (each byte corresponds to a partition in the partition table) + /// + public byte[] PartitionsCryptType; + + /// + /// Offset & Length partition table, in media units + /// + public PartitionTableEntry[] PartitionsTable; + + #endregion + + #region CTR Cart Image (CCI) Specific + + /// + /// Exheader SHA-256 hash + /// + public byte[] ExheaderHash; + + /// + /// Additional header size + /// + public uint AdditionalHeaderSize; + + /// + /// Sector zero offset + /// + public uint SectorZeroOffset; + + /// + /// Partition Flags + /// + public byte[] PartitionFlags; + + /// + /// Partition ID table + /// + public byte[][] PartitionIdTable; + + /// + /// Reserved + /// + public byte[] Reserved1; + + /// + /// Reserved? + /// + public byte[] Reserved2; + + /// + /// Support for this was implemented with 9.6.0-X FIRM. Bit0=1 enables using bits 1-2, it's unknown + /// what these two bits are actually used for(the value of these two bits get compared with some other + /// value during NCSD verification/loading). This appears to enable a new, likely hardware-based, + /// antipiracy check on cartridges. + /// + public byte FirmUpdateByte1; + + /// + /// Support for this was implemented with 9.6.0-X FIRM, see below regarding save crypto. + /// + public byte FirmUpdateByte2; + + #endregion + + #region Raw NAND Format Specific + + /// + /// Unknown + /// + public byte[] Unknown; + + /// + /// Encrypted MBR partition-table, for the TWL partitions(key-data used for this keyslot is console-unique). + /// + public byte[] EncryptedMBR; + + #endregion + + #region Card Info Header + + /// + /// CARD2: Writable Address In Media Units (For 'On-Chip' Savedata). CARD1: Always 0xFFFFFFFF. + /// + public byte[] CARD2WritableAddressMediaUnits; + + /// + /// Card Info Bitmask + /// + public byte[] CardInfoBytemask; + + /// + /// Reserved1 + /// + public byte[] Reserved3; + + /// + /// Title version + /// + public ushort TitleVersion; + + /// + /// Card revision + /// + public ushort CardRevision; + + /// + /// Reserved2 + /// + public byte[] Reserved4; + + /// + /// Card seed keyY (first u64 is Media ID (same as first NCCH partitionId)) + /// + public byte[] CardSeedKeyY; + + /// + /// Encrypted card seed (AES-CCM, keyslot 0x3B for retail cards, see CTRCARD_SECSEED) /// + public byte[] EncryptedCardSeed; + + /// + /// Card seed AES-MAC + /// + public byte[] CardSeedAESMAC; + + /// + /// Card seed nonce + /// + public byte[] CardSeedNonce; + + /// + /// Reserved3 + /// + public byte[] Reserved5; + + /// + /// Copy of first NCCH header (excluding RSA signature) + /// + public NCCHHeader BackupHeader; + + #endregion + + #region Development Card Info Header Extension + + /// + /// CardDeviceReserved1 + /// + public byte[] CardDeviceReserved1; + + /// + /// TitleKey + /// + public byte[] TitleKey; + + /// + /// CardDeviceReserved2 + /// + public byte[] CardDeviceReserved2; + + #endregion + } +} diff --git a/BurnOutSharp.Models/N3DS/PartitionTableEntry.cs b/BurnOutSharp.Models/N3DS/PartitionTableEntry.cs new file mode 100644 index 00000000..9817f4ad --- /dev/null +++ b/BurnOutSharp.Models/N3DS/PartitionTableEntry.cs @@ -0,0 +1,19 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// Offset and Length partition table, in media units + /// + /// + public sealed class PartitionTableEntry + { + /// + /// Offset + /// + public uint Offset; + + /// + /// Length + /// + public uint Length; + } +} diff --git a/BurnOutSharp.Models/N3DS/RomFSHeader.cs b/BurnOutSharp.Models/N3DS/RomFSHeader.cs new file mode 100644 index 00000000..a951cd23 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/RomFSHeader.cs @@ -0,0 +1,85 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// RomFS (or Read-Only Filesystem) is part of the NCCH format, and is + /// used as external file storage. + /// + /// + public sealed class RomFSHeader + { + /// + /// Master hash size + /// + public uint MasterHashSize; + + /// + /// Level 1 logical offset + /// + public ulong Level1LogicalOffset; + + /// + /// Level 1 hashdata size + /// + public ulong Level1HashdataSize; + + /// + /// Level 1 block size, in log2 + /// + public uint Level1BlockSizeLog2; + + /// + /// Reserved + /// + public byte[] Reserved1; + + /// + /// Level 2 logical offset + /// + public ulong Level2LogicalOffset; + + /// + /// Level 2 hashdata size + /// + public ulong Level2HashdataSize; + + /// + /// Level 2 block size, in log2 + /// + public uint Level2BlockSizeLog2; + + /// + /// Reserved + /// + public byte[] Reserved2; + + /// + /// Level 3 logical offset + /// + public ulong Level3LogicalOffset; + + /// + /// Level 3 hashdata size + /// + public ulong Level3HashdataSize; + + /// + /// Level 3 block size, in log2 + /// + public uint Level3BlockSizeLog2; + + /// + /// Reserved + /// + public byte[] Reserved3; + + /// + /// Reserved + /// + public byte[] Reserved4; + + /// + /// Optional info size. + /// + public uint OptionalInfoSize; + } +} diff --git a/BurnOutSharp.Models/N3DS/StorageInfo.cs b/BurnOutSharp.Models/N3DS/StorageInfo.cs new file mode 100644 index 00000000..d5a1158c --- /dev/null +++ b/BurnOutSharp.Models/N3DS/StorageInfo.cs @@ -0,0 +1,34 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// Used in FSReg:Register. + /// + /// + public sealed class StorageInfo + { + /// + /// Extdata ID + /// + public byte[] ExtdataID; + + /// + /// System savedata IDs + /// + public byte[] SystemSavedataIDs; + + /// + /// Storage accessible unique IDs + /// + public byte[] StorageAccessibleUniqueIDs; + + /// + /// Filesystem access info + /// + public byte[] FilesystemAccessInfo; + + /// + /// Other attributes + /// + public StorageInfoOtherAttributes OtherAttributes; + } +} diff --git a/BurnOutSharp.Models/N3DS/SystemControlInfo.cs b/BurnOutSharp.Models/N3DS/SystemControlInfo.cs new file mode 100644 index 00000000..339960cc --- /dev/null +++ b/BurnOutSharp.Models/N3DS/SystemControlInfo.cs @@ -0,0 +1,66 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + public sealed class SystemControlInfo + { + /// + /// Application title (default is "CtrApp") + /// + public char[] ApplicationTitle; + + /// + /// Reserved + /// + public byte[] Reserved1; + + /// + /// Flag (bit 0: CompressExefsCode, bit 1: SDApplication) + /// + public byte Flag; + + /// + /// Remaster version + /// + public byte[] RemasterVersion; + + /// + /// Text code set info + /// + public CodeSetInfo TextCodesetInfo; + + /// + /// Stack size + /// + public uint StackSize; + + /// + /// Read-only code set info + /// + public CodeSetInfo ReadOnlyCodeSetInfo; + + /// + /// Reserved + /// + public byte[] Reserved2; + + /// + /// Data code set info + /// + public CodeSetInfo DataCodeSetInfo; + + /// + /// BSS size + /// + public uint BSSSize; + + /// + /// Dependency module (program ID) list + /// + public byte[][] DependencyModuleList; + + /// + /// SystemInfo + /// + public SystemInfo SystemInfo; + } +} diff --git a/BurnOutSharp.Models/N3DS/SystemInfo.cs b/BurnOutSharp.Models/N3DS/SystemInfo.cs new file mode 100644 index 00000000..8a7abae9 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/SystemInfo.cs @@ -0,0 +1,21 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + public sealed class SystemInfo + { + /// + /// SaveData Size + /// + public ulong SaveDataSize; + + /// + /// Jump ID + /// + public byte[] JumpID; + + /// + /// Reserved + /// + public byte[] Reserved; + } +} diff --git a/BurnOutSharp.Models/N3DS/Ticket.cs b/BurnOutSharp.Models/N3DS/Ticket.cs new file mode 100644 index 00000000..048990f6 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/Ticket.cs @@ -0,0 +1,174 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// A format used to store an encrypted titlekey (using 128-Bit AES-CBC). + /// With 3DS, the Ticket format was updated (now v1) from Wii/DSi format (v0). + /// + /// + public sealed class Ticket + { + /// + /// Signature Type + /// + public SignatureType SignatureType; + + /// + /// Signature size + /// + public ushort SignatureSize; + + /// + /// Padding size + /// + public byte PaddingSize; + + /// + /// Signature + /// + public byte[] Signature; + + /// + /// Issuer + /// + public string Issuer; + + /// + /// ECC PublicKey + /// + public byte[] ECCPublicKey; + + /// + /// Version (For 3DS this is always 1) + /// + public byte Version; + + /// + /// CaCrlVersion + /// + public byte CaCrlVersion; + + /// + /// SignerCrlVersion + /// + public byte SignerCrlVersion; + + /// + /// TitleKey (normal-key encrypted using one of the common keyYs; see below) + /// + /// + /// The titlekey is decrypted by using the AES engine with the ticket common-key keyslot. + /// The keyY is selected through an index (ticket offset 0xB1) into a plaintext array + /// of 6 keys ("common keyYs") stored in the data section of Process9. AES-CBC mode is used + /// where the IV is the big-endian titleID. Note that on a retail unit index0 is a retail keyY, + /// while on a dev-unit index0 is the dev common-key which is a normal-key. + /// (On retail for these keyYs, the hardware key-scrambler is used) + /// + /// The titlekey is used to decrypt content downloaded from the CDN using 128-bit AES-CBC with + /// the content index (as big endian u16, padded with trailing zeroes) as the IV. + /// + public byte[] TitleKey; + + /// + /// Reserved + /// + public byte Reserved1; + + /// + /// TicketID + /// + public ulong TicketID; + + /// + /// ConsoleID + /// + public uint ConsoleID; + + /// + /// TitleID + /// + public ulong TitleID; + + /// + /// Reserved + /// + public ushort Reserved2; + + /// + /// Ticket title version + /// + /// + /// The Ticket Title Version is generally the same as the title version stored in the + /// Title Metadata. Although it doesn't have to match the TMD version to be valid. + /// + public ushort TicketTitleVersion; + + /// + /// Reserved + /// + public ulong Reserved3; + + /// + /// License Type + /// + public byte LicenseType; + + /// + /// Index to the common keyY used for this ticket, usually 0x1 for retail system titles; + /// see below. + /// + public byte CommonKeyYIndex; + + /// + /// Reserved + /// + public byte[] Reserved4; + + /// + /// eShop Account ID? + /// + public uint eShopAccountID; + + /// + /// Reserved + /// + public byte Reserved5; + + /// + /// Audit + /// + public byte Audit; + + /// + /// Reserved + /// + public byte[] Reserved6; + + /// + /// Limits + /// + /// + /// In demos, the first u32 in the "Limits" section is 0x4, then the second u32 is the max-playcount. + /// + public int[] Limits; + + /// + /// The Content Index of a ticket has its own size defined within itself, + /// with seemingly a minimal of 20 bytes, the second u32 in big endian defines + /// the full value of X. + /// + public int ContentIndexSize; + + /// + /// Content Index + /// + public byte[] ContentIndex; + + /// + /// Certificate chain + /// + /// + /// https://www.3dbrew.org/wiki/Ticket#Certificate_Chain + /// + public Certificate[] CertificateChain; + } +} diff --git a/BurnOutSharp.Models/N3DS/TitleMetadata.cs b/BurnOutSharp.Models/N3DS/TitleMetadata.cs new file mode 100644 index 00000000..b99c4ca1 --- /dev/null +++ b/BurnOutSharp.Models/N3DS/TitleMetadata.cs @@ -0,0 +1,150 @@ +namespace BurnOutSharp.Models.N3DS +{ + /// + /// A format used to store information about a title (installed title, DLC, etc.) + /// and all its installed contents, including which contents they consist of and + /// their SHA256 hashes. + /// + /// + public sealed class TitleMetadata + { + /// + /// Signature Type + /// + public SignatureType SignatureType; + + /// + /// Signature size + /// + public ushort SignatureSize; + + /// + /// Padding size + /// + public byte PaddingSize; + + /// + /// Signature + /// + public byte[] Signature; + + /// + /// Signature Issuer + /// + public byte[] SignatureIssuer; + + /// + /// Version + /// + public byte Version; + + /// + /// CaCrlVersion + /// + public byte CaCrlVersion; + + /// + /// SignerCrlVersion + /// + public byte SignerCrlVersion; + + /// + /// Reserved + /// + public byte Reserved1; + + /// + /// System Version + /// + public ulong SystemVersion; + + /// + /// TitleID + /// + public ulong TitleID; + + /// + /// Title Type + /// + public uint TitleType; + + /// + /// Group ID + /// + public ushort GroupID; + + /// + /// Save Data Size in Little Endian (Bytes) (Also SRL Public Save Data Size) + /// + public uint SaveDataSize; + + /// + /// SRL Private Save Data Size in Little Endian (Bytes) + /// + public uint SRLPrivateSaveDataSize; + + /// + /// Reserved + /// + public uint Reserved2; + + /// + /// SRL Flag + /// + public byte SRLFlag; + + /// + /// Reserved + /// + public byte[] Reserved3; + + /// + /// Access Rights + /// + public uint AccessRights; + + /// + /// Title Version + /// + public ushort TitleVersion; + + /// + /// Content Count + /// + public ushort ContentCount; + + /// + /// Boot Content + /// + public ushort BootContent; + + /// + /// Padding + /// + public ushort Padding; + + /// + /// SHA-256 Hash of the Content Info Records + /// + public byte[] SHA256HashContentInfoRecords; + + /// + /// There are 64 of these records, usually only the first is used. + /// + public ContentInfoRecord[] ContentInfoRecords; + + /// + /// There is one of these for each content contained in this title. + /// (Determined by "Content Count" in the TMD Header). + /// + public ContentChunkRecord[] ContentChunkRecords; + + /// + /// Certificate chain + /// + /// + /// https://www.3dbrew.org/wiki/Title_metadata#Certificate_Chain + /// + public Certificate[] CertificateChain; + } +} \ No newline at end of file