Add N3DS to models

This commit is contained in:
Matt Nadareski
2023-01-06 15:20:10 -08:00
parent 68283554e9
commit 80986978cb
25 changed files with 1731 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// The kernel capability descriptors are passed to svcCreateProcess.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/NCCH/Extended_Header#ARM11_Kernel_Capabilities"/>
public sealed class ARM11KernelCapabilities
{
/// <summary>
/// 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)
/// </summary>
public byte[][] Descriptors;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved;
}
}

View File

@@ -0,0 +1,66 @@
namespace BurnOutSharp.Models.N3DS
{
/// <see href="https://www.3dbrew.org/wiki/NCCH/Extended_Header#ARM11_Local_System_Capabilities"/>
public sealed class ARM11LocalSystemCapabilities
{
/// <summary>
/// Program ID
/// </summary>
public byte[] ProgramID;
/// <summary>
/// Core version (The Title ID low of the required FIRM)
/// </summary>
public uint CoreVersion;
/// <summary>
/// Flag1 (implemented starting from 8.0.0-18).
/// </summary>
public ARM11LSCFlag1 Flag1;
/// <summary>
/// Flag2 (implemented starting from 8.0.0-18).
/// </summary>
public ARM11LSCFlag2 Flag2;
/// <summary>
/// Flag0
/// </summary>
public ARM11LSCFlag0 Flag0;
/// <summary>
/// Priority
/// </summary>
public byte Priority;
/// <summary>
/// Resource limit descriptors. The first byte here controls the maximum allowed CpuTime.
/// </summary>
public byte[][] ResourceLimitDescriptors;
/// <summary>
/// Storage info
/// </summary>
public StorageInfo StorageInfo;
/// <summary>
/// Service access control
/// </summary>
public byte[][] ServiceAccessControl;
/// <summary>
/// Extended service access control, support for this was implemented with 9.3.0-X.
/// </summary>
public byte[][] ExtendedServiceAccessControl;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved;
/// <summary>
/// Resource limit category. (0 = APPLICATION, 1 = SYS_APPLET, 2 = LIB_APPLET, 3 = OTHER (sysmodules running under the BASE memregion))
/// </summary>
public ResourceLimitCategory ResourceLimitCategory;
}
}

View File

@@ -0,0 +1,17 @@
namespace BurnOutSharp.Models.N3DS
{
/// <see href="https://www.3dbrew.org/wiki/NCCH/Extended_Header#ARM9_Access_Control"/>
public sealed class ARM9AccessControl
{
/// <summary>
/// Descriptors
/// </summary>
public ARM9AccessControlDescriptors[] Descriptors;
/// <summary>
/// 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.
/// </summary>
public byte DescriptorVersion;
}
}

View File

@@ -0,0 +1,21 @@
namespace BurnOutSharp.Models.N3DS
{
/// <see href="https://www.3dbrew.org/wiki/NCCH/Extended_Header#Access_Control_Info"/>
public sealed class AccessControlInfo
{
/// <summary>
/// ARM11 local system capabilities
/// </summary>
public ARM11LocalSystemCapabilities ARM11LocalSystemCapabilities;
/// <summary>
/// ARM11 kernel capabilities
/// </summary>
public ARM11KernelCapabilities ARM11KernelCapabilities;
/// <summary>
/// ARM9 access control
/// </summary>
public ARM9AccessControl ARM9AccessControl;
}
}

View File

@@ -0,0 +1,94 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// 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.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/CIA"/>
public sealed class CIAHeader
{
/// <summary>
/// Archive header size, usually 0x2020 bytes
/// </summary>
public int HeaderSize;
/// <summary>
/// Type
/// </summary>
public ushort Type;
/// <summary>
/// Version
/// </summary>
public ushort Version;
/// <summary>
/// Certificate chain size
/// </summary>
public int CertificateChainSize;
/// <summary>
/// Ticket size
/// </summary>
public int TicketSize;
/// <summary>
/// TMD file size
/// </summary>
public int TMDFileSize;
/// <summary>
/// Meta size (0 if no Meta data is present)
/// </summary>
public int MetaSize;
/// <summary>
/// Content size
/// </summary>
public long ContentSize;
/// <summary>
/// Content Index
/// </summary>
public byte[] ContentIndex;
#region Content Index
/// <summary>
/// Certificate chain
/// </summary>
/// <remarks>
/// https://www.3dbrew.org/wiki/CIA#Certificate_Chain
/// </remarks>
public Certificate[] CertificateChain;
/// <summary>
/// Ticket
/// </summary>
public Ticket Ticket;
/// <summary>
/// TMD file data
/// </summary>
public TitleMetadata TMDFileData;
/// <summary>
/// Content file data
/// </summary>
public NCCHHeader[] Partitions;
/// <summary>
/// Meta file data (Not a necessary component)
/// </summary>
public MetaFile MetaFileData;
#endregion
}
}

View File

@@ -0,0 +1,36 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// 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.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/NCCH/Extended_Header"/>
public sealed class CXIExtendedHeader
{
/// <summary>
/// SCI
/// </summary>
public SystemControlInfo SCI;
/// <summary>
/// ACI
/// </summary>
public AccessControlInfo ACI;
/// <summary>
/// AccessDesc signature (RSA-2048-SHA256)
/// </summary>
public byte[] AccessDescSignature;
/// <summary>
/// NCCH HDR RSA-2048 public key
/// </summary>
public byte[] NCCHHDRPublicKey;
/// <summary>
/// ACI (for limitation of first ACI)
/// </summary>
public AccessControlInfo ACIForLimitations;
}
}

View File

@@ -0,0 +1,77 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// 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.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/Certificates"/>
public sealed class Certificate
{
/// <summary>
/// Signature Type
/// </summary>
public SignatureType SignatureType;
/// <summary>
/// Signature size
/// </summary>
public ushort SignatureSize;
/// <summary>
/// Padding size
/// </summary>
public byte PaddingSize;
/// <summary>
/// Signature
/// </summary>
public byte[] Signature;
/// <summary>
/// Issuer
/// </summary>
public string Issuer;
/// <summary>
/// Key Type
/// </summary>
public PublicKeyType KeyType;
/// <summary>
/// Name
/// </summary>
public string Name;
/// <summary>
/// Expiration time as UNIX Timestamp, used at least for CTCert
/// </summary>
public uint ExpirationTime;
// This contains the Public Key(i.e. Modulus & Public Exponent)
#region RSA
/// <summary>
/// Modulus
/// </summary>
public byte[] Modulus;
/// <summary>
/// Public Exponent
/// </summary>
public uint PublicExponent;
#endregion
// This contains the ECC public key, and is as follows:
#region ECC
/// <summary>
/// Public Key
/// </summary>
public byte[] PublicKey;
#endregion
}
}

View File

@@ -0,0 +1,21 @@
namespace BurnOutSharp.Models.N3DS
{
/// <see href="https://www.3dbrew.org/wiki/NCCH/Extended_Header#Code_Set_Info"/>
public sealed class CodeSetInfo
{
/// <summary>
/// Address
/// </summary>
public byte[] Address;
/// <summary>
/// Physical region size (in page-multiples)
/// </summary>
public uint PhysicalRegionSizeInPages;
/// <summary>
/// Size (in bytes)
/// </summary>
public uint SizeInBytes;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,38 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// There is one of these for each content contained in this title.
/// (Determined by "Content Count" in the TMD Header).
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/Title_metadata#Content_chunk_records"/>
public sealed class ContentChunkRecord
{
/// <summary>
/// Content id
/// </summary>
public uint ContentId;
/// <summary>
/// Content index
/// </summary>
/// <remarks>
/// This does not apply to DLC.
/// </remarks>
public ContentIndex ContentIndex;
/// <summary>
/// Content type
/// </summary>
public TMDContentType ContentType;
/// <summary>
/// Content size
/// </summary>
public ulong ContentSize;
/// <summary>
/// SHA-256 hash
/// </summary>
public byte[] SHA256Hash;
}
}

View File

@@ -0,0 +1,24 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// There are 64 of these records, usually only the first is used.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/Title_metadata#Content_Info_Records"/>
public sealed class ContentInfoRecord
{
/// <summary>
/// Content index offset
/// </summary>
public ushort ContentIndexOffset;
/// <summary>
/// Content command count [k]
/// </summary>
public ushort ContentCommandCount;
/// <summary>
/// SHA-256 hash of the next k content records that have not been hashed yet
/// </summary>
public byte[] UnhashedContentRecordsSHA256Hash;
}
}

View File

@@ -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,
/// <summary>
/// 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?
/// </summary>
Old3DSSystemMode = 0x0F | 0x10 | 0x20 | 0x40,
}
[Flags]
public enum ARM11LSCFlag1 : byte
{
EnableL2Cache = 0x01,
Cpuspeed_804MHz = 0x02,
}
[Flags]
public enum ARM11LSCFlag2 : byte
{
/// <summary>
/// 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?
/// </summary>
New3DSSystemMode = 0x01 | 0x02 | 0x04 | 0x08,
}
[Flags]
public enum BitMasks : byte
{
FixedCryptoKey = 0x01,
NoMountRomFs = 0x02,
NoCrypto = 0x04,
NewKeyYGenerator = 0x20,
}
public enum ContentIndex : ushort
{
/// <summary>
/// Main Content (.CXI for 3DS executable content/.CFA for 3DS Data Archives/.SRL for TWL content)
/// </summary>
MainContent = 0x0000,
/// <summary>
/// Home Menu Manual (.CFA)
/// </summary>
HomeMenuManual = 0x0001,
/// <summary>
/// DLP Child Container (.CFA)
/// </summary>
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,
}
}

View File

@@ -0,0 +1,33 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// 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.)
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/ExeFS#File_headers"/>
public sealed class ExeFSFileHeader
{
/// <summary>
/// File name
/// </summary>
public string FileName;
/// <summary>
/// File offset
/// </summary>
public uint FileOffset;
/// <summary>
/// File size
/// </summary>
public uint FileSize;
/// <summary>
/// SHA256 hash calculated over the entire file contents
/// </summary>
public byte[] FileHash;
}
}

View File

@@ -0,0 +1,26 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// 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.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/ExeFS"/>
public sealed class ExeFSHeader
{
/// <summary>
/// File headers (10 headers maximum, 16 bytes each)
/// </summary>
public ExeFSFileHeader[] FileHeaders;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved;
}
}

View File

@@ -0,0 +1,31 @@
namespace BurnOutSharp.Models.N3DS
{
/// <see href="https://www.3dbrew.org/wiki/CIA#Meta"/>
public sealed class MetaFile
{
/// <summary>
/// Title ID dependency list - Taken from the application's ExHeader
/// </summary>
public byte[] TitleIDDependencyList;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved1;
/// <summary>
/// Core Version
/// </summary>
public uint CoreVersion;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved2;
/// <summary>
/// Icon Data(.ICN) - Taken from the application's ExeFS
/// </summary>
public byte[] IconData;
}
}

View File

@@ -0,0 +1,156 @@
namespace BurnOutSharp.Models.N3DS
{
/// <see href="https://www.3dbrew.org/wiki/NCCH#NCCH_Header"/>
public sealed class NCCHHeader
{
/// <summary>
/// RSA-2048 signature of the NCCH header, using SHA-256.
/// </summary>
public byte[] RSA2048Signature;
/// <summary>
/// Magic ID, always 'NCCH'
/// </summary>
public string MagicID;
/// <summary>
/// Content size, in media units (1 media unit = 0x200 bytes)
/// </summary>
public uint ContentSizeInMediaUnits;
/// <summary>
/// Partition ID
/// </summary>
public ulong PartitionId;
/// <summary>
/// Maker code
/// </summary>
public ushort MakerCode;
/// <summary>
/// Version
/// </summary>
public ushort Version;
/// <summary>
/// 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.
/// </summary>
public uint VerificationHash;
/// <summary>
/// Program ID
/// </summary>
public ulong ProgramId;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved1;
/// <summary>
/// Logo Region SHA-256 hash. (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11)
/// </summary>
public byte[] LogoRegionHash;
/// <summary>
/// Product code
/// </summary>
public byte[] ProductCode;
/// <summary>
/// Extended header SHA-256 hash (SHA256 of 2x Alignment Size, beginning at 0x0 of ExHeader)
/// </summary>
public byte[] ExtendedHeaderHash;
/// <summary>
/// Extended header size, in bytes
/// </summary>
public uint ExtendedHeaderSizeInBytes;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved2;
/// <summary>
/// Flags
/// </summary>
public NCCHHeaderFlags Flags;
/// <summary>
/// Plain region offset, in media units
/// </summary>
public uint PlainRegionOffsetInMediaUnits;
/// <summary>
/// Plain region size, in media units
/// </summary>
public uint PlainRegionSizeInMediaUnits;
/// <summary>
/// Logo Region offset, in media units (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11)
/// </summary>
public uint LogoRegionOffsetInMediaUnits;
/// <summary>
/// Logo Region size, in media units (For applications built with SDK 5+) (Supported from firmware: 5.0.0-11)
/// </summary>
public uint LogoRegionSizeInMediaUnits;
/// <summary>
/// ExeFS offset, in media units
/// </summary>
public uint ExeFSOffsetInMediaUnits;
/// <summary>
/// ExeFS size, in media units
/// </summary>
public uint ExeFSSizeInMediaUnits;
/// <summary>
/// ExeFS hash region size, in media units
/// </summary>
public uint ExeFSHashRegionSizeInMediaUnits;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved3;
/// <summary>
/// RomFS offset, in media units
/// </summary>
public uint RomFSOffsetInMediaUnits;
/// <summary>
/// RomFS size, in media units
/// </summary>
public uint RomFSSizeInMediaUnits;
/// <summary>
/// RomFS hash region size, in media units
/// </summary>
public uint RomFSHashRegionSizeInMediaUnits;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved4;
/// <summary>
/// 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)
/// </summary>
public byte[] ExeFSSuperblockHash;
/// <summary>
/// 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)
/// </summary>
public byte[] RomFSSuperblockHash;
}
}

View File

@@ -0,0 +1,49 @@
namespace BurnOutSharp.Models.N3DS
{
/// <see href="https://www.3dbrew.org/wiki/NCCH#NCCH_Flags"/>
public sealed class NCCHHeaderFlags
{
/// <summary>
/// Reserved
/// </summary>
public byte Reserved0;
/// <summary>
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// Reserved
/// </summary>
public byte Reserved2;
/// <summary>
/// Crypto Method: When this is non-zero, a NCCH crypto method using two keyslots is used.
/// </summary>
public CryptoMethod CryptoMethod;
/// <summary>
/// Content Platform: 1 = CTR, 2 = snake (New 3DS).
/// </summary>
public ContentPlatform ContentPlatform;
/// <summary>
/// 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.
/// </summary>
public ContentType MediaPlatformIndex;
/// <summary>
/// Content Unit Size i.e. u32 ContentUnitSize = 0x200*2^flags[6];
/// </summary>
public byte ContentUnitSize;
/// <summary>
/// Bit-masks: FixedCryptoKey = 0x1, NoMountRomFs = 0x2, NoCrypto = 0x4, using a new keyY
/// generator = 0x20(starting with FIRM 9.6.0-X).
/// </summary>
public BitMasks BitMasks;
}
}

View File

@@ -0,0 +1,196 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// 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.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/NCSD"/>
public sealed class NCSDHeader
{
#region Common to all NCSD files
/// <summary>
/// RSA-2048 SHA-256 signature of the NCSD header
/// </summary>
public byte[] RSA2048Signature;
/// <summary>
/// Size of the NCSD image, in media units (1 media unit = 0x200 bytes)
/// </summary>
public uint ImageSizeInMediaUnits;
/// <summary>
/// Media ID
/// </summary>
public byte[] MediaId;
/// <summary>
/// Partitions FS type (0=None, 1=Normal, 3=FIRM, 4=AGB_FIRM save)
/// </summary>
public FilesystemType PartitionsFSType;
/// <summary>
/// Partitions crypt type (each byte corresponds to a partition in the partition table)
/// </summary>
public byte[] PartitionsCryptType;
/// <summary>
/// Offset & Length partition table, in media units
/// </summary>
public PartitionTableEntry[] PartitionsTable;
#endregion
#region CTR Cart Image (CCI) Specific
/// <summary>
/// Exheader SHA-256 hash
/// </summary>
public byte[] ExheaderHash;
/// <summary>
/// Additional header size
/// </summary>
public uint AdditionalHeaderSize;
/// <summary>
/// Sector zero offset
/// </summary>
public uint SectorZeroOffset;
/// <summary>
/// Partition Flags
/// </summary>
public byte[] PartitionFlags;
/// <summary>
/// Partition ID table
/// </summary>
public byte[][] PartitionIdTable;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved1;
/// <summary>
/// Reserved?
/// </summary>
public byte[] Reserved2;
/// <summary>
/// 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.
/// </summary>
public byte FirmUpdateByte1;
/// <summary>
/// Support for this was implemented with 9.6.0-X FIRM, see below regarding save crypto.
/// </summary>
public byte FirmUpdateByte2;
#endregion
#region Raw NAND Format Specific
/// <summary>
/// Unknown
/// </summary>
public byte[] Unknown;
/// <summary>
/// Encrypted MBR partition-table, for the TWL partitions(key-data used for this keyslot is console-unique).
/// </summary>
public byte[] EncryptedMBR;
#endregion
#region Card Info Header
/// <summary>
/// CARD2: Writable Address In Media Units (For 'On-Chip' Savedata). CARD1: Always 0xFFFFFFFF.
/// </summary>
public byte[] CARD2WritableAddressMediaUnits;
/// <summary>
/// Card Info Bitmask
/// </summary>
public byte[] CardInfoBytemask;
/// <summary>
/// Reserved1
/// </summary>
public byte[] Reserved3;
/// <summary>
/// Title version
/// </summary>
public ushort TitleVersion;
/// <summary>
/// Card revision
/// </summary>
public ushort CardRevision;
/// <summary>
/// Reserved2
/// </summary>
public byte[] Reserved4;
/// <summary>
/// Card seed keyY (first u64 is Media ID (same as first NCCH partitionId))
/// </summary>
public byte[] CardSeedKeyY;
/// <summary>
/// Encrypted card seed (AES-CCM, keyslot 0x3B for retail cards, see CTRCARD_SECSEED) /// </summary>
public byte[] EncryptedCardSeed;
/// <summary>
/// Card seed AES-MAC
/// </summary>
public byte[] CardSeedAESMAC;
/// <summary>
/// Card seed nonce
/// </summary>
public byte[] CardSeedNonce;
/// <summary>
/// Reserved3
/// </summary>
public byte[] Reserved5;
/// <summary>
/// Copy of first NCCH header (excluding RSA signature)
/// </summary>
public NCCHHeader BackupHeader;
#endregion
#region Development Card Info Header Extension
/// <summary>
/// CardDeviceReserved1
/// </summary>
public byte[] CardDeviceReserved1;
/// <summary>
/// TitleKey
/// </summary>
public byte[] TitleKey;
/// <summary>
/// CardDeviceReserved2
/// </summary>
public byte[] CardDeviceReserved2;
#endregion
}
}

View File

@@ -0,0 +1,19 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// Offset and Length partition table, in media units
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/NCSD#NCSD_header"/>
public sealed class PartitionTableEntry
{
/// <summary>
/// Offset
/// </summary>
public uint Offset;
/// <summary>
/// Length
/// </summary>
public uint Length;
}
}

View File

@@ -0,0 +1,85 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// RomFS (or Read-Only Filesystem) is part of the NCCH format, and is
/// used as external file storage.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/RomFS"/>
public sealed class RomFSHeader
{
/// <summary>
/// Master hash size
/// </summary>
public uint MasterHashSize;
/// <summary>
/// Level 1 logical offset
/// </summary>
public ulong Level1LogicalOffset;
/// <summary>
/// Level 1 hashdata size
/// </summary>
public ulong Level1HashdataSize;
/// <summary>
/// Level 1 block size, in log2
/// </summary>
public uint Level1BlockSizeLog2;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved1;
/// <summary>
/// Level 2 logical offset
/// </summary>
public ulong Level2LogicalOffset;
/// <summary>
/// Level 2 hashdata size
/// </summary>
public ulong Level2HashdataSize;
/// <summary>
/// Level 2 block size, in log2
/// </summary>
public uint Level2BlockSizeLog2;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved2;
/// <summary>
/// Level 3 logical offset
/// </summary>
public ulong Level3LogicalOffset;
/// <summary>
/// Level 3 hashdata size
/// </summary>
public ulong Level3HashdataSize;
/// <summary>
/// Level 3 block size, in log2
/// </summary>
public uint Level3BlockSizeLog2;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved3;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved4;
/// <summary>
/// Optional info size.
/// </summary>
public uint OptionalInfoSize;
}
}

View File

@@ -0,0 +1,34 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// Used in FSReg:Register.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/NCCH/Extended_Header#Storage_Info"/>
public sealed class StorageInfo
{
/// <summary>
/// Extdata ID
/// </summary>
public byte[] ExtdataID;
/// <summary>
/// System savedata IDs
/// </summary>
public byte[] SystemSavedataIDs;
/// <summary>
/// Storage accessible unique IDs
/// </summary>
public byte[] StorageAccessibleUniqueIDs;
/// <summary>
/// Filesystem access info
/// </summary>
public byte[] FilesystemAccessInfo;
/// <summary>
/// Other attributes
/// </summary>
public StorageInfoOtherAttributes OtherAttributes;
}
}

View File

@@ -0,0 +1,66 @@
namespace BurnOutSharp.Models.N3DS
{
/// <see href="https://www.3dbrew.org/wiki/NCCH/Extended_Header#System_Control_Info"/>
public sealed class SystemControlInfo
{
/// <summary>
/// Application title (default is "CtrApp")
/// </summary>
public char[] ApplicationTitle;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved1;
/// <summary>
/// Flag (bit 0: CompressExefsCode, bit 1: SDApplication)
/// </summary>
public byte Flag;
/// <summary>
/// Remaster version
/// </summary>
public byte[] RemasterVersion;
/// <summary>
/// Text code set info
/// </summary>
public CodeSetInfo TextCodesetInfo;
/// <summary>
/// Stack size
/// </summary>
public uint StackSize;
/// <summary>
/// Read-only code set info
/// </summary>
public CodeSetInfo ReadOnlyCodeSetInfo;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved2;
/// <summary>
/// Data code set info
/// </summary>
public CodeSetInfo DataCodeSetInfo;
/// <summary>
/// BSS size
/// </summary>
public uint BSSSize;
/// <summary>
/// Dependency module (program ID) list
/// </summary>
public byte[][] DependencyModuleList;
/// <summary>
/// SystemInfo
/// </summary>
public SystemInfo SystemInfo;
}
}

View File

@@ -0,0 +1,21 @@
namespace BurnOutSharp.Models.N3DS
{
/// <see href="https://www.3dbrew.org/wiki/NCCH/Extended_Header#System_Info"/>
public sealed class SystemInfo
{
/// <summary>
/// SaveData Size
/// </summary>
public ulong SaveDataSize;
/// <summary>
/// Jump ID
/// </summary>
public byte[] JumpID;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved;
}
}

View File

@@ -0,0 +1,174 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// 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).
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/Ticket"/>
public sealed class Ticket
{
/// <summary>
/// Signature Type
/// </summary>
public SignatureType SignatureType;
/// <summary>
/// Signature size
/// </summary>
public ushort SignatureSize;
/// <summary>
/// Padding size
/// </summary>
public byte PaddingSize;
/// <summary>
/// Signature
/// </summary>
public byte[] Signature;
/// <summary>
/// Issuer
/// </summary>
public string Issuer;
/// <summary>
/// ECC PublicKey
/// </summary>
public byte[] ECCPublicKey;
/// <summary>
/// Version (For 3DS this is always 1)
/// </summary>
public byte Version;
/// <summary>
/// CaCrlVersion
/// </summary>
public byte CaCrlVersion;
/// <summary>
/// SignerCrlVersion
/// </summary>
public byte SignerCrlVersion;
/// <summary>
/// TitleKey (normal-key encrypted using one of the common keyYs; see below)
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public byte[] TitleKey;
/// <summary>
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// TicketID
/// </summary>
public ulong TicketID;
/// <summary>
/// ConsoleID
/// </summary>
public uint ConsoleID;
/// <summary>
/// TitleID
/// </summary>
public ulong TitleID;
/// <summary>
/// Reserved
/// </summary>
public ushort Reserved2;
/// <summary>
/// Ticket title version
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public ushort TicketTitleVersion;
/// <summary>
/// Reserved
/// </summary>
public ulong Reserved3;
/// <summary>
/// License Type
/// </summary>
public byte LicenseType;
/// <summary>
/// Index to the common keyY used for this ticket, usually 0x1 for retail system titles;
/// see below.
/// </summary>
public byte CommonKeyYIndex;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved4;
/// <summary>
/// eShop Account ID?
/// </summary>
public uint eShopAccountID;
/// <summary>
/// Reserved
/// </summary>
public byte Reserved5;
/// <summary>
/// Audit
/// </summary>
public byte Audit;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved6;
/// <summary>
/// Limits
/// </summary>
/// <remarks>
/// In demos, the first u32 in the "Limits" section is 0x4, then the second u32 is the max-playcount.
/// </remarks>
public int[] Limits;
/// <summary>
/// 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.
/// </summary>
public int ContentIndexSize;
/// <summary>
/// Content Index
/// </summary>
public byte[] ContentIndex;
/// <summary>
/// Certificate chain
/// </summary>
/// <remarks>
/// https://www.3dbrew.org/wiki/Ticket#Certificate_Chain
/// </remarks>
public Certificate[] CertificateChain;
}
}

View File

@@ -0,0 +1,150 @@
namespace BurnOutSharp.Models.N3DS
{
/// <summary>
/// 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.
/// </summary>
/// <see href="https://www.3dbrew.org/wiki/Title_metadata"/>
public sealed class TitleMetadata
{
/// <summary>
/// Signature Type
/// </summary>
public SignatureType SignatureType;
/// <summary>
/// Signature size
/// </summary>
public ushort SignatureSize;
/// <summary>
/// Padding size
/// </summary>
public byte PaddingSize;
/// <summary>
/// Signature
/// </summary>
public byte[] Signature;
/// <summary>
/// Signature Issuer
/// </summary>
public byte[] SignatureIssuer;
/// <summary>
/// Version
/// </summary>
public byte Version;
/// <summary>
/// CaCrlVersion
/// </summary>
public byte CaCrlVersion;
/// <summary>
/// SignerCrlVersion
/// </summary>
public byte SignerCrlVersion;
/// <summary>
/// Reserved
/// </summary>
public byte Reserved1;
/// <summary>
/// System Version
/// </summary>
public ulong SystemVersion;
/// <summary>
/// TitleID
/// </summary>
public ulong TitleID;
/// <summary>
/// Title Type
/// </summary>
public uint TitleType;
/// <summary>
/// Group ID
/// </summary>
public ushort GroupID;
/// <summary>
/// Save Data Size in Little Endian (Bytes) (Also SRL Public Save Data Size)
/// </summary>
public uint SaveDataSize;
/// <summary>
/// SRL Private Save Data Size in Little Endian (Bytes)
/// </summary>
public uint SRLPrivateSaveDataSize;
/// <summary>
/// Reserved
/// </summary>
public uint Reserved2;
/// <summary>
/// SRL Flag
/// </summary>
public byte SRLFlag;
/// <summary>
/// Reserved
/// </summary>
public byte[] Reserved3;
/// <summary>
/// Access Rights
/// </summary>
public uint AccessRights;
/// <summary>
/// Title Version
/// </summary>
public ushort TitleVersion;
/// <summary>
/// Content Count
/// </summary>
public ushort ContentCount;
/// <summary>
/// Boot Content
/// </summary>
public ushort BootContent;
/// <summary>
/// Padding
/// </summary>
public ushort Padding;
/// <summary>
/// SHA-256 Hash of the Content Info Records
/// </summary>
public byte[] SHA256HashContentInfoRecords;
/// <summary>
/// There are 64 of these records, usually only the first is used.
/// </summary>
public ContentInfoRecord[] ContentInfoRecords;
/// <summary>
/// There is one of these for each content contained in this title.
/// (Determined by "Content Count" in the TMD Header).
/// </summary>
public ContentChunkRecord[] ContentChunkRecords;
/// <summary>
/// Certificate chain
/// </summary>
/// <remarks>
/// https://www.3dbrew.org/wiki/Title_metadata#Certificate_Chain
/// </remarks>
public Certificate[] CertificateChain;
}
}