mirror of
https://github.com/SabreTools/NDecrypt.git
synced 2026-07-08 18:06:38 +00:00
Update libraries
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
@@ -48,7 +48,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BouncyCastle.NetCore" Version="1.9.0" />
|
||||
<PackageReference Include="SabreTools.Hashing" Version="1.2.1" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.4.11" />
|
||||
<PackageReference Include="SabreTools.IO" Version="1.4.12" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -5,6 +5,8 @@ using System.Numerics;
|
||||
using NDecrypt.Core;
|
||||
using SabreTools.Models.N3DS;
|
||||
using static NDecrypt.Core.Helper;
|
||||
using CIADeserializer = SabreTools.Serialization.Deserializers.CIA;
|
||||
using N3DSDeserializer = SabreTools.Serialization.Deserializers.N3DS;
|
||||
|
||||
namespace NDecrypt.N3DS
|
||||
{
|
||||
@@ -71,9 +73,9 @@ namespace NDecrypt.N3DS
|
||||
// Open the read and write on the same file for inplace processing
|
||||
using var reader = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
|
||||
using var writer = new BinaryWriter(File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite));
|
||||
|
||||
|
||||
// Deserialize the CIA information
|
||||
var cia = Serializer.ReadCIA(reader);
|
||||
var cia = ReadCIA(reader);
|
||||
if (cia == null)
|
||||
{
|
||||
Console.WriteLine("Error: Not a 3DS CIA!");
|
||||
@@ -284,7 +286,7 @@ namespace NDecrypt.N3DS
|
||||
uint mediaUnitSize = 0x200; // mediaUnitSize;
|
||||
|
||||
reader.BaseStream.Seek((tableEntry.Offset + ncchHeader.ExeFSOffsetInMediaUnits) * mediaUnitSize, SeekOrigin.Begin);
|
||||
var exefsHeader = Serializer.ReadExeFSHeader(reader);
|
||||
var exefsHeader = ReadExeFSHeader(reader);
|
||||
|
||||
// If the header failed to read, log and return
|
||||
if (exefsHeader?.FileHeaders == null)
|
||||
@@ -659,5 +661,59 @@ namespace NDecrypt.N3DS
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Serialization
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get a CIA header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>CIA header object, null on error</returns>
|
||||
private static CIA? ReadCIA(BinaryReader reader)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CIADeserializer.DeserializeStream(reader.BaseStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an ExeFS header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>ExeFS header object, null on error</returns>
|
||||
private static ExeFSHeader? ReadExeFSHeader(BinaryReader reader)
|
||||
{
|
||||
var header = new ExeFSHeader();
|
||||
|
||||
try
|
||||
{
|
||||
header.FileHeaders = new ExeFSFileHeader[10];
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
header.FileHeaders[i] = N3DSDeserializer.ParseExeFSFileHeader(reader.BaseStream)!;
|
||||
}
|
||||
|
||||
header.Reserved = reader.ReadBytes(0x20);
|
||||
|
||||
header.FileHashes = new byte[10][];
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
header.FileHashes[9 - i] = reader.ReadBytes(0x20);
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.Models" Version="1.4.9" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.4.10" />
|
||||
<PackageReference Include="SabreTools.Serialization" Version="1.6.8" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,781 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SabreTools.Models.N3DS;
|
||||
|
||||
namespace NDecrypt.N3DS
|
||||
{
|
||||
internal static class Serializer
|
||||
{
|
||||
#region Constants
|
||||
|
||||
private const string NCCHMagicNumber = "NCCH";
|
||||
private const string NCSDMagicNumber = "NCSD";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Reading
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get N3DS cart image, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <param name="development">True if development cart, false otherwise</param>
|
||||
/// <returns>N3DS cart image object, null on error</returns>
|
||||
public static Cart? ReadCart(BinaryReader reader, bool development)
|
||||
{
|
||||
var cart = new Cart();
|
||||
|
||||
try
|
||||
{
|
||||
cart.Header = ReadNCSDHeader(reader);
|
||||
if (cart.Header == null)
|
||||
return null;
|
||||
|
||||
if (cart.Header.PartitionsFSType == FilesystemType.Normal
|
||||
|| cart.Header.PartitionsFSType == FilesystemType.None)
|
||||
{
|
||||
cart.CardInfoHeader = ReadCardInfoHeader(reader);
|
||||
if (cart.CardInfoHeader == null)
|
||||
return null;
|
||||
|
||||
if (development)
|
||||
{
|
||||
cart.DevelopmentCardInfoHeader = ReadDevelopmentCardInfoHeader(reader);
|
||||
if (cart.DevelopmentCardInfoHeader == null)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
cart.Partitions = new NCCHHeader[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// Check the entry is valid
|
||||
var tableEntry = cart.Header.PartitionsTable![i];
|
||||
if (tableEntry == null || tableEntry.Offset == 0 || tableEntry.Length == 0)
|
||||
continue;
|
||||
|
||||
// Seek to the beginning of the NCCH partition
|
||||
long offset = tableEntry.Offset * cart.Header.ImageSizeInMediaUnits;
|
||||
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
cart.Partitions[i] = ReadNCCHHeader(reader, readSignature: true);
|
||||
}
|
||||
|
||||
return cart;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get a CIA header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>CIA header object, null on error</returns>
|
||||
public static CIA? ReadCIA(BinaryReader reader)
|
||||
{
|
||||
var cia = new CIA();
|
||||
|
||||
try
|
||||
{
|
||||
var header = new CIAHeader();
|
||||
|
||||
header.HeaderSize = reader.ReadUInt32();
|
||||
header.Type = reader.ReadUInt16();
|
||||
header.Version = reader.ReadUInt16();
|
||||
header.CertificateChainSize = reader.ReadUInt32();
|
||||
header.TicketSize = reader.ReadUInt32();
|
||||
header.TMDFileSize = reader.ReadUInt32();
|
||||
header.MetaSize = reader.ReadUInt32();
|
||||
header.ContentSize = reader.ReadUInt64();
|
||||
header.ContentIndex = reader.ReadBytes(0x2000);
|
||||
|
||||
cia.Header = header;
|
||||
|
||||
var certificateChain = new Certificate[3];
|
||||
if (reader.BaseStream.Position % 64 != 0)
|
||||
reader.BaseStream.Seek(64 - (reader.BaseStream.Position % 64), SeekOrigin.Current);
|
||||
|
||||
certificateChain[0] = ReadCertificate(reader)!; // CA
|
||||
certificateChain[1] = ReadCertificate(reader)!; // Ticket
|
||||
certificateChain[2] = ReadCertificate(reader)!; // TMD
|
||||
if (reader.BaseStream.Position % 64 != 0)
|
||||
reader.BaseStream.Seek(64 - (reader.BaseStream.Position % 64), SeekOrigin.Current);
|
||||
|
||||
cia.CertificateChain = certificateChain;
|
||||
|
||||
cia.Ticket = ReadTicket(reader, header.TicketSize);
|
||||
if (reader.BaseStream.Position % 64 != 0)
|
||||
reader.BaseStream.Seek(64 - (reader.BaseStream.Position % 64), SeekOrigin.Current);
|
||||
|
||||
cia.TMDFileData = ReadTitleMetadata(reader, header.TMDFileSize);
|
||||
if (reader.BaseStream.Position % 64 != 0)
|
||||
reader.BaseStream.Seek(64 - (reader.BaseStream.Position % 64), SeekOrigin.Current);
|
||||
|
||||
long startingPosition = reader.BaseStream.Position;
|
||||
var headers = new List<NCCHHeader>();
|
||||
while ((ulong)reader.BaseStream.Position < (ulong)startingPosition + header.ContentSize)
|
||||
{
|
||||
long initPosition = reader.BaseStream.Position;
|
||||
var ncchHeader = ReadNCCHHeader(reader, readSignature: true);
|
||||
if (ncchHeader == null)
|
||||
break;
|
||||
|
||||
headers.Add(ncchHeader);
|
||||
reader.BaseStream.Seek(initPosition + ncchHeader.ContentSizeInMediaUnits * 0x200, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
cia.Partitions = [.. headers];
|
||||
if (header.MetaSize > 0)
|
||||
cia.MetaData = ReadMetaData(reader);
|
||||
|
||||
return cia;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an ExeFS header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>ExeFS header object, null on error</returns>
|
||||
public static ExeFSHeader? ReadExeFSHeader(BinaryReader reader)
|
||||
{
|
||||
var header = new ExeFSHeader();
|
||||
|
||||
try
|
||||
{
|
||||
header.FileHeaders = new ExeFSFileHeader[10];
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
header.FileHeaders[i] = ReadExeFSFileHeader(reader)!;
|
||||
}
|
||||
|
||||
header.Reserved = reader.ReadBytes(0x20);
|
||||
|
||||
header.FileHashes = new byte[10][];
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
header.FileHashes[9 - i] = reader.ReadBytes(0x20);
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an NCCH header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <param name="readSignature">True if the RSA signature is read, false otherwise</param>
|
||||
/// <returns>NCCH header object, null on error</returns>
|
||||
public static NCCHHeader? ReadNCCHHeader(BinaryReader reader, bool readSignature)
|
||||
{
|
||||
var header = new NCCHHeader();
|
||||
|
||||
try
|
||||
{
|
||||
if (readSignature)
|
||||
header.RSA2048Signature = reader.ReadBytes(0x100);
|
||||
|
||||
if (new string(reader.ReadChars(4)) != NCCHMagicNumber)
|
||||
return null;
|
||||
|
||||
header.ContentSizeInMediaUnits = reader.ReadUInt32();
|
||||
header.PartitionId = reader.ReadUInt64();
|
||||
header.MakerCode = reader.ReadUInt16();
|
||||
header.Version = reader.ReadUInt16();
|
||||
header.VerificationHash = reader.ReadUInt32();
|
||||
header.ProgramId = reader.ReadBytes(8);
|
||||
header.Reserved1 = reader.ReadBytes(0x10);
|
||||
header.LogoRegionHash = reader.ReadBytes(0x20);
|
||||
byte[] productCodeBytes = reader.ReadBytes(0x10);
|
||||
header.ProductCode = Encoding.ASCII.GetString(productCodeBytes);
|
||||
header.ExtendedHeaderHash = reader.ReadBytes(0x20);
|
||||
header.ExtendedHeaderSizeInBytes = reader.ReadUInt32();
|
||||
header.Reserved2 = reader.ReadUInt32();
|
||||
header.Flags = ReadNCCHHeaderFlags(reader);
|
||||
header.PlainRegionOffsetInMediaUnits = reader.ReadUInt32();
|
||||
header.PlainRegionSizeInMediaUnits = reader.ReadUInt32();
|
||||
header.LogoRegionOffsetInMediaUnits = reader.ReadUInt32();
|
||||
header.LogoRegionSizeInMediaUnits = reader.ReadUInt32();
|
||||
header.ExeFSOffsetInMediaUnits = reader.ReadUInt32();
|
||||
header.ExeFSSizeInMediaUnits = reader.ReadUInt32();
|
||||
header.ExeFSHashRegionSizeInMediaUnits = reader.ReadUInt32();
|
||||
header.Reserved3 = reader.ReadUInt32();
|
||||
header.RomFSOffsetInMediaUnits = reader.ReadUInt32();
|
||||
header.RomFSSizeInMediaUnits = reader.ReadUInt32();
|
||||
header.RomFSHashRegionSizeInMediaUnits = reader.ReadUInt32();
|
||||
header.Reserved4 = reader.ReadUInt32();
|
||||
header.ExeFSSuperblockHash = reader.ReadBytes(0x20);
|
||||
header.RomFSSuperblockHash = reader.ReadBytes(0x20);
|
||||
|
||||
return header;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an CardInfo header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>CardInfo header object, null on error</returns>
|
||||
private static CardInfoHeader? ReadCardInfoHeader(BinaryReader reader)
|
||||
{
|
||||
var header = new CardInfoHeader();
|
||||
|
||||
try
|
||||
{
|
||||
header.WritableAddressMediaUnits = reader.ReadUInt32();
|
||||
header.CardInfoBitmask = reader.ReadUInt32();
|
||||
header.Reserved3 = reader.ReadBytes(0x108);
|
||||
header.TitleVersion = reader.ReadUInt16();
|
||||
header.CardRevision = reader.ReadUInt16();
|
||||
header.Reserved4 = reader.ReadBytes(0xCD6);
|
||||
header.InitialData = ReadInitialData(reader);
|
||||
|
||||
return header;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get certificate, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>Certificate object, null on error</returns>
|
||||
private static Certificate? ReadCertificate(BinaryReader reader)
|
||||
{
|
||||
var ct = new Certificate();
|
||||
|
||||
try
|
||||
{
|
||||
ct.SignatureType = (SignatureType)reader.ReadUInt32();
|
||||
switch (ct.SignatureType)
|
||||
{
|
||||
case SignatureType.RSA_4096_SHA1:
|
||||
case SignatureType.RSA_4096_SHA256:
|
||||
ct.SignatureSize = 0x200;
|
||||
ct.PaddingSize = 0x3C;
|
||||
break;
|
||||
case SignatureType.RSA_2048_SHA1:
|
||||
case SignatureType.RSA_2048_SHA256:
|
||||
ct.SignatureSize = 0x100;
|
||||
ct.PaddingSize = 0x3C;
|
||||
break;
|
||||
case SignatureType.ECDSA_SHA1:
|
||||
case SignatureType.ECDSA_SHA256:
|
||||
ct.SignatureSize = 0x03C;
|
||||
ct.PaddingSize = 0x40;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
ct.Signature = reader.ReadBytes(ct.SignatureSize);
|
||||
reader.ReadBytes(ct.PaddingSize); // Padding
|
||||
byte[] issuerBytes = reader.ReadBytes(0x40);
|
||||
ct.Issuer = Encoding.ASCII.GetString(issuerBytes);
|
||||
ct.KeyType = (PublicKeyType)reader.ReadUInt32();
|
||||
byte[] nameBytes = reader.ReadBytes(0x40);
|
||||
ct.Name = Encoding.ASCII.GetString(nameBytes);
|
||||
ct.ExpirationTime = reader.ReadUInt32();
|
||||
|
||||
switch (ct.KeyType)
|
||||
{
|
||||
case PublicKeyType.RSA_4096:
|
||||
ct.RSAModulus = reader.ReadBytes(0x200);
|
||||
ct.RSAPublicExponent = reader.ReadUInt32();
|
||||
ct.RSAPadding = reader.ReadBytes(0x34);
|
||||
break;
|
||||
case PublicKeyType.RSA_2048:
|
||||
ct.RSAModulus = reader.ReadBytes(0x100);
|
||||
ct.RSAPublicExponent = reader.ReadUInt32();
|
||||
ct.RSAPadding = reader.ReadBytes(0x34);
|
||||
break;
|
||||
case PublicKeyType.EllipticCurve:
|
||||
ct.ECCPublicKey = reader.ReadBytes(0x3C);
|
||||
ct.ECCPadding = reader.ReadBytes(0x3C);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return ct;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get content chunk record, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>Content chunk record object, null on error</returns>
|
||||
private static ContentChunkRecord? ReadContentChunkRecord(BinaryReader reader)
|
||||
{
|
||||
var ccr = new ContentChunkRecord();
|
||||
|
||||
try
|
||||
{
|
||||
ccr.ContentId = reader.ReadUInt32();
|
||||
ccr.ContentIndex = (ContentIndex)reader.ReadUInt16();
|
||||
ccr.ContentType = (TMDContentType)reader.ReadUInt16();
|
||||
ccr.ContentSize = reader.ReadUInt64();
|
||||
ccr.SHA256Hash = reader.ReadBytes(0x20);
|
||||
return ccr;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get content info record, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>Content info record object, null on error</returns>
|
||||
private static ContentInfoRecord? ReadContentInfoRecord(BinaryReader reader)
|
||||
{
|
||||
var cir = new ContentInfoRecord();
|
||||
|
||||
try
|
||||
{
|
||||
cir.ContentIndexOffset = reader.ReadUInt16();
|
||||
cir.ContentCommandCount = reader.ReadUInt16();
|
||||
cir.UnhashedContentRecordsSHA256Hash = reader.ReadBytes(0x20);
|
||||
return cir;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an DevelopmentCardInfo header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>DevelopmentCardInfo object, null on error</returns>
|
||||
private static DevelopmentCardInfoHeader? ReadDevelopmentCardInfoHeader(BinaryReader reader)
|
||||
{
|
||||
var header = new DevelopmentCardInfoHeader();
|
||||
|
||||
try
|
||||
{
|
||||
header.CardDeviceReserved1 = reader.ReadBytes(0x200);
|
||||
header.TitleKey = reader.ReadBytes(0x10);
|
||||
header.CardDeviceReserved2 = reader.ReadBytes(0xF0);
|
||||
|
||||
return header;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an ExeFS file header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>ExeFS file header object, null on error</returns>
|
||||
private static ExeFSFileHeader? ReadExeFSFileHeader(BinaryReader reader)
|
||||
{
|
||||
var header = new ExeFSFileHeader();
|
||||
|
||||
try
|
||||
{
|
||||
byte[] fileNameBytes = reader.ReadBytes(8);
|
||||
header.FileName = Encoding.ASCII.GetString(fileNameBytes);
|
||||
header.FileOffset = reader.ReadUInt32();
|
||||
header.FileSize = reader.ReadUInt32();
|
||||
return header;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get inital data, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>Initial data object, null on error</returns>
|
||||
private static InitialData? ReadInitialData(BinaryReader reader)
|
||||
{
|
||||
var id = new InitialData();
|
||||
|
||||
try
|
||||
{
|
||||
id.CardSeedKeyY = reader.ReadBytes(0x10);
|
||||
id.EncryptedCardSeed = reader.ReadBytes(0x10);
|
||||
id.CardSeedAESMAC = reader.ReadBytes(0x10);
|
||||
id.CardSeedNonce = reader.ReadBytes(0x0C);
|
||||
id.Reserved = reader.ReadBytes(0xC4);
|
||||
id.BackupHeader = ReadNCCHHeader(reader, readSignature: false);
|
||||
|
||||
return id;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get the Metafile data, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>Metafile data object, null on error</returns>
|
||||
private static MetaData? ReadMetaData(BinaryReader reader)
|
||||
{
|
||||
var metaData = new MetaData();
|
||||
|
||||
try
|
||||
{
|
||||
metaData.TitleIDDependencyList = reader.ReadBytes(0x180);
|
||||
metaData.Reserved1 = reader.ReadBytes(0x180);
|
||||
metaData.CoreVersion = reader.ReadUInt32();
|
||||
metaData.Reserved2 = reader.ReadBytes(0xFC);
|
||||
metaData.IconData = reader.ReadBytes(0x36C0);
|
||||
|
||||
return metaData;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an NCCH header flags, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>NCCH header flags object, null on error</returns>
|
||||
private static NCCHHeaderFlags? ReadNCCHHeaderFlags(BinaryReader reader)
|
||||
{
|
||||
var flags = new NCCHHeaderFlags();
|
||||
|
||||
try
|
||||
{
|
||||
flags.Reserved0 = reader.ReadByte();
|
||||
flags.Reserved1 = reader.ReadByte();
|
||||
flags.Reserved2 = reader.ReadByte();
|
||||
flags.CryptoMethod = (CryptoMethod)reader.ReadByte();
|
||||
flags.ContentPlatform = (ContentPlatform)reader.ReadByte();
|
||||
flags.MediaPlatformIndex = (ContentType)reader.ReadByte();
|
||||
flags.ContentUnitSize = reader.ReadByte();
|
||||
flags.BitMasks = (BitMasks)reader.ReadByte();
|
||||
return flags;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an NCSD header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>NCSD header object, null on error</returns>
|
||||
private static NCSDHeader? ReadNCSDHeader(BinaryReader reader)
|
||||
{
|
||||
var header = new NCSDHeader();
|
||||
|
||||
try
|
||||
{
|
||||
header.RSA2048Signature = reader.ReadBytes(0x100);
|
||||
|
||||
if (new string(reader.ReadChars(4)) != NCSDMagicNumber)
|
||||
return null;
|
||||
|
||||
header.ImageSizeInMediaUnits = reader.ReadUInt32();
|
||||
header.MediaId = reader.ReadBytes(8);
|
||||
header.PartitionsFSType = (FilesystemType)reader.ReadUInt64();
|
||||
header.PartitionsCryptType = reader.ReadBytes(8);
|
||||
|
||||
header.PartitionsTable = new PartitionTableEntry[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
header.PartitionsTable[i] = ReadPartitionTableEntry(reader)!;
|
||||
}
|
||||
|
||||
if (header.PartitionsFSType == FilesystemType.Normal
|
||||
|| header.PartitionsFSType == FilesystemType.None)
|
||||
{
|
||||
header.ExheaderHash = reader.ReadBytes(0x20);
|
||||
header.AdditionalHeaderSize = reader.ReadUInt32();
|
||||
header.SectorZeroOffset = reader.ReadUInt32();
|
||||
header.PartitionFlags = reader.ReadBytes(8);
|
||||
|
||||
header.PartitionIdTable = new ulong[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
header.PartitionIdTable[i] = reader.ReadUInt64();
|
||||
}
|
||||
|
||||
header.Reserved1 = reader.ReadBytes(0x20);
|
||||
header.Reserved2 = reader.ReadBytes(0xE);
|
||||
header.FirmUpdateByte1 = reader.ReadByte();
|
||||
header.FirmUpdateByte2 = reader.ReadByte();
|
||||
}
|
||||
else if (header.PartitionsFSType == FilesystemType.FIRM)
|
||||
{
|
||||
header.Unknown = reader.ReadBytes(0x5E);
|
||||
header.EncryptedMBR = reader.ReadBytes(0x42);
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get partition table entry, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>Partition table entry object, null on error</returns>
|
||||
private static PartitionTableEntry? ReadPartitionTableEntry(BinaryReader reader)
|
||||
{
|
||||
var entry = new PartitionTableEntry();
|
||||
|
||||
try
|
||||
{
|
||||
entry.Offset = reader.ReadUInt32();
|
||||
entry.Length = reader.ReadUInt32();
|
||||
return entry;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get ticket, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <param name="ticketSize">Ticket size from the header</param>
|
||||
/// <returns>Ticket object, null on error</returns>
|
||||
private static Ticket? ReadTicket(BinaryReader reader, uint ticketSize)
|
||||
{
|
||||
var tk = new Ticket();
|
||||
|
||||
try
|
||||
{
|
||||
long startingPosition = reader.BaseStream.Position;
|
||||
|
||||
tk.SignatureType = (SignatureType)reader.ReadUInt32();
|
||||
switch (tk.SignatureType)
|
||||
{
|
||||
case SignatureType.RSA_4096_SHA1:
|
||||
case SignatureType.RSA_4096_SHA256:
|
||||
tk.SignatureSize = 0x200;
|
||||
tk.PaddingSize = 0x3C;
|
||||
break;
|
||||
case SignatureType.RSA_2048_SHA1:
|
||||
case SignatureType.RSA_2048_SHA256:
|
||||
tk.SignatureSize = 0x100;
|
||||
tk.PaddingSize = 0x3C;
|
||||
break;
|
||||
case SignatureType.ECDSA_SHA1:
|
||||
case SignatureType.ECDSA_SHA256:
|
||||
tk.SignatureSize = 0x03C;
|
||||
tk.PaddingSize = 0x40;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
tk.Signature = reader.ReadBytes(tk.SignatureSize);
|
||||
reader.ReadBytes(tk.PaddingSize); // Padding
|
||||
byte[] issuerBytes = reader.ReadBytes(0x40);
|
||||
tk.Issuer = Encoding.ASCII.GetString(issuerBytes);
|
||||
tk.ECCPublicKey = reader.ReadBytes(0x3C);
|
||||
tk.Version = reader.ReadByte();
|
||||
tk.CaCrlVersion = reader.ReadByte();
|
||||
tk.SignerCrlVersion = reader.ReadByte();
|
||||
tk.TitleKey = reader.ReadBytes(0x10);
|
||||
tk.Reserved1 = reader.ReadByte();
|
||||
tk.TicketID = reader.ReadUInt64();
|
||||
tk.ConsoleID = reader.ReadUInt32();
|
||||
tk.TitleID = reader.ReadUInt64();
|
||||
tk.Reserved2 = reader.ReadBytes(2);
|
||||
tk.TicketTitleVersion = reader.ReadUInt16();
|
||||
tk.Reserved3 = reader.ReadBytes(8);
|
||||
tk.LicenseType = reader.ReadByte();
|
||||
tk.CommonKeyYIndex = reader.ReadByte();
|
||||
tk.Reserved4 = reader.ReadBytes(0x2A);
|
||||
tk.eShopAccountID = reader.ReadUInt32();
|
||||
tk.Reserved5 = reader.ReadByte();
|
||||
tk.Audit = reader.ReadByte();
|
||||
tk.Reserved6 = reader.ReadBytes(0x42);
|
||||
|
||||
tk.Limits = new uint[0x10];
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
{
|
||||
tk.Limits[i] = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
reader.ReadBytes(4); // Seek to size in Content Index
|
||||
tk.ContentIndexSize = BitConverter.ToUInt32(reader.ReadBytes(4).Reverse().ToArray(), 0);
|
||||
reader.BaseStream.Seek(-8, SeekOrigin.Current);
|
||||
tk.ContentIndex = reader.ReadBytes((int)tk.ContentIndexSize);
|
||||
if (reader.BaseStream.Position % 64 != 0)
|
||||
reader.BaseStream.Seek(64 - (reader.BaseStream.Position % 64), SeekOrigin.Current);
|
||||
|
||||
if (ticketSize > (reader.BaseStream.Position - startingPosition) + (2 * 0x200))
|
||||
{
|
||||
tk.CertificateChain = new Certificate[2];
|
||||
tk.CertificateChain[0] = ReadCertificate(reader)!; // Ticket
|
||||
tk.CertificateChain[1] = ReadCertificate(reader)!; // CA
|
||||
}
|
||||
|
||||
return tk;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get ticket metadata, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <param name="metadataSize">Metadata size from the header</param>
|
||||
/// <returns>Title metadata object, null on error</returns>
|
||||
private static TitleMetadata? ReadTitleMetadata(BinaryReader reader, uint metadataSize)
|
||||
{
|
||||
var tm = new TitleMetadata();
|
||||
|
||||
try
|
||||
{
|
||||
long startingPosition = reader.BaseStream.Position;
|
||||
|
||||
tm.SignatureType = (SignatureType)reader.ReadUInt32();
|
||||
switch (tm.SignatureType)
|
||||
{
|
||||
case SignatureType.RSA_4096_SHA1:
|
||||
case SignatureType.RSA_4096_SHA256:
|
||||
tm.SignatureSize = 0x200;
|
||||
tm.PaddingSize = 0x3C;
|
||||
break;
|
||||
case SignatureType.RSA_2048_SHA1:
|
||||
case SignatureType.RSA_2048_SHA256:
|
||||
tm.SignatureSize = 0x100;
|
||||
tm.PaddingSize = 0x3C;
|
||||
break;
|
||||
case SignatureType.ECDSA_SHA1:
|
||||
case SignatureType.ECDSA_SHA256:
|
||||
tm.SignatureSize = 0x03C;
|
||||
tm.PaddingSize = 0x40;
|
||||
break;
|
||||
}
|
||||
|
||||
tm.Signature = reader.ReadBytes(tm.SignatureSize);
|
||||
tm.Padding1 = reader.ReadBytes(tm.PaddingSize);
|
||||
byte[] issuerBytes = reader.ReadBytes(0x40);
|
||||
tm.Issuer = Encoding.ASCII.GetString(issuerBytes);
|
||||
tm.Version = reader.ReadByte();
|
||||
tm.CaCrlVersion = reader.ReadByte();
|
||||
tm.SignerCrlVersion = reader.ReadByte();
|
||||
tm.Reserved1 = reader.ReadByte();
|
||||
tm.SystemVersion = reader.ReadUInt64();
|
||||
tm.TitleID = reader.ReadUInt64();
|
||||
tm.TitleType = reader.ReadUInt32();
|
||||
tm.GroupID = reader.ReadUInt16();
|
||||
tm.SaveDataSize = reader.ReadUInt32();
|
||||
tm.SRLPrivateSaveDataSize = reader.ReadUInt32();
|
||||
tm.Reserved2 = reader.ReadBytes(4);
|
||||
tm.SRLFlag = reader.ReadByte();
|
||||
tm.Reserved3 = reader.ReadBytes(0x31);
|
||||
tm.AccessRights = reader.ReadUInt32();
|
||||
tm.TitleVersion = reader.ReadUInt16();
|
||||
tm.ContentCount = BitConverter.ToUInt16(reader.ReadBytes(2).Reverse().ToArray(), 0);
|
||||
tm.BootContent = reader.ReadUInt16();
|
||||
tm.Padding2 = reader.ReadBytes(2);
|
||||
tm.SHA256HashContentInfoRecords = reader.ReadBytes(0x20);
|
||||
|
||||
tm.ContentInfoRecords = new ContentInfoRecord[64];
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
tm.ContentInfoRecords[i] = ReadContentInfoRecord(reader)!;
|
||||
}
|
||||
|
||||
tm.ContentChunkRecords = new ContentChunkRecord[tm.ContentCount];
|
||||
for (int i = 0; i < tm.ContentCount; i++)
|
||||
{
|
||||
tm.ContentChunkRecords[i] = ReadContentChunkRecord(reader)!;
|
||||
}
|
||||
|
||||
if (metadataSize > (reader.BaseStream.Position - startingPosition) + (2 * 0x200))
|
||||
{
|
||||
tm.CertificateChain = new Certificate[2];
|
||||
tm.CertificateChain[0] = ReadCertificate(reader)!; // TMD
|
||||
tm.CertificateChain[1] = ReadCertificate(reader)!; // CA
|
||||
}
|
||||
|
||||
return tm;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Writing
|
||||
|
||||
/// <summary>
|
||||
/// Write NCCH header flags to stream, if possible
|
||||
/// </summary>
|
||||
/// <param name="writer">BinaryWriter representing the output stream</param>
|
||||
public static void Write(NCCHHeaderFlags flags, BinaryWriter writer)
|
||||
{
|
||||
try
|
||||
{
|
||||
writer.Write(flags.Reserved0);
|
||||
writer.Write(flags.Reserved1);
|
||||
writer.Write(flags.Reserved2);
|
||||
writer.Write((byte)flags.CryptoMethod);
|
||||
writer.Write((byte)flags.ContentPlatform);
|
||||
writer.Write((byte)flags.MediaPlatformIndex);
|
||||
writer.Write(flags.ContentUnitSize);
|
||||
writer.Write((byte)flags.BitMasks);
|
||||
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Numerics;
|
||||
using NDecrypt.Core;
|
||||
using SabreTools.Models.N3DS;
|
||||
using static NDecrypt.Core.Helper;
|
||||
using N3DSDeserializer = SabreTools.Serialization.Deserializers.N3DS;
|
||||
|
||||
namespace NDecrypt.N3DS
|
||||
{
|
||||
@@ -72,7 +73,7 @@ namespace NDecrypt.N3DS
|
||||
using var writer = new BinaryWriter(File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite));
|
||||
|
||||
// Deserialize the cart information
|
||||
var cart = Serializer.ReadCart(reader, decryptArgs.Development);
|
||||
var cart = ReadCart(reader);
|
||||
if (cart?.Header == null || cart?.CardInfoHeader?.InitialData?.BackupHeader == null)
|
||||
{
|
||||
Console.WriteLine("Error: Not a 3DS cart image!");
|
||||
@@ -303,7 +304,7 @@ namespace NDecrypt.N3DS
|
||||
uint exeFsOffset = (partitionOffsetMU + exeFsOffsetMU + 1) * cart.MediaUnitSize();
|
||||
|
||||
reader.BaseStream.Seek(exeFsHeaderOffset, SeekOrigin.Begin);
|
||||
var exefsHeader = Serializer.ReadExeFSHeader(reader);
|
||||
var exefsHeader = ReadExeFSHeader(reader);
|
||||
|
||||
// If the header failed to read, log and return
|
||||
if (exefsHeader == null)
|
||||
@@ -744,5 +745,88 @@ namespace NDecrypt.N3DS
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Serialization
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get N3DS cart image, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>N3DS cart image object, null on error</returns>
|
||||
private static Cart? ReadCart(BinaryReader reader)
|
||||
{
|
||||
var cart = new Cart();
|
||||
|
||||
try
|
||||
{
|
||||
cart.Header = N3DSDeserializer.ParseNCSDHeader(reader.BaseStream);
|
||||
if (cart.Header == null)
|
||||
return null;
|
||||
|
||||
if (cart.Header.PartitionsFSType == FilesystemType.Normal
|
||||
|| cart.Header.PartitionsFSType == FilesystemType.None)
|
||||
{
|
||||
cart.CardInfoHeader = N3DSDeserializer.ParseCardInfoHeader(reader.BaseStream);
|
||||
if (cart.CardInfoHeader == null)
|
||||
return null;
|
||||
}
|
||||
|
||||
cart.Partitions = new NCCHHeader[8];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// Check the entry is valid
|
||||
var tableEntry = cart.Header.PartitionsTable![i];
|
||||
if (tableEntry == null || tableEntry.Offset == 0 || tableEntry.Length == 0)
|
||||
continue;
|
||||
|
||||
// Seek to the beginning of the NCCH partition
|
||||
long offset = tableEntry.Offset * cart.Header.ImageSizeInMediaUnits;
|
||||
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
cart.Partitions[i] = N3DSDeserializer.ParseNCCHHeader(reader.BaseStream, skipSignature: false);
|
||||
}
|
||||
|
||||
return cart;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an ExeFS header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>ExeFS header object, null on error</returns>
|
||||
private static ExeFSHeader? ReadExeFSHeader(BinaryReader reader)
|
||||
{
|
||||
var header = new ExeFSHeader();
|
||||
|
||||
try
|
||||
{
|
||||
header.FileHeaders = new ExeFSFileHeader[10];
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
header.FileHeaders[i] = N3DSDeserializer.ParseExeFSFileHeader(reader.BaseStream)!;
|
||||
}
|
||||
|
||||
header.Reserved = reader.ReadBytes(0x20);
|
||||
|
||||
header.FileHashes = new byte[10][];
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
header.FileHashes[9 - i] = reader.ReadBytes(0x20);
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using NDecrypt.Core;
|
||||
using SabreTools.Models.Nitro;
|
||||
using NitroDeserializer = SabreTools.Serialization.Deserializers.Nitro;
|
||||
|
||||
namespace NDecrypt.Nitro
|
||||
{
|
||||
@@ -43,7 +44,7 @@ namespace NDecrypt.Nitro
|
||||
using var writer = new BinaryWriter(File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite));
|
||||
|
||||
// Deserialize the cart information
|
||||
Cart? cart = Serializer.ReadCart(reader);
|
||||
Cart? cart = ReadCart(reader);
|
||||
if (cart == null)
|
||||
{
|
||||
Console.WriteLine("Error: Not a DS or DSi Rom!");
|
||||
@@ -360,5 +361,26 @@ namespace NDecrypt.Nitro
|
||||
_cardHash[i + 18 + 1] = tmp2;
|
||||
}
|
||||
}
|
||||
|
||||
#region Serialization
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an NDS/NDSi Cart, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>NDS/NDSi Cart object, null on error</returns>
|
||||
private static Cart? ReadCart(BinaryReader reader)
|
||||
{
|
||||
try
|
||||
{
|
||||
return NitroDeserializer.DeserializeStream(reader.BaseStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.Models" Version="1.4.9" />
|
||||
<PackageReference Include="SabreTools.Models" Version="1.4.10" />
|
||||
<PackageReference Include="SabreTools.Serialization" Version="1.6.8" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,176 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.Models.Nitro;
|
||||
|
||||
namespace NDecrypt.Nitro
|
||||
{
|
||||
internal static class Serializer
|
||||
{
|
||||
/// <summary>
|
||||
/// Read from a stream and get an NDS/NDSi Cart, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>NDS/NDSi Cart object, null on error</returns>
|
||||
public static Cart? ReadCart(BinaryReader reader)
|
||||
{
|
||||
var cart = new Cart();
|
||||
|
||||
try
|
||||
{
|
||||
cart.CommonHeader = ReadCommonHeader(reader);
|
||||
if (cart.CommonHeader == null)
|
||||
return null;
|
||||
|
||||
// If we have a DSi compatible title
|
||||
if (cart.CommonHeader.UnitCode == Unitcode.NDSPlusDSi
|
||||
|| cart.CommonHeader.UnitCode == Unitcode.DSi)
|
||||
{
|
||||
cart.ExtendedDSiHeader = ReadExtendedDSiHeader(reader);
|
||||
if (cart.ExtendedDSiHeader == null)
|
||||
return null;
|
||||
}
|
||||
|
||||
return cart;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get a common header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>Common header object, null on error</returns>
|
||||
private static CommonHeader? ReadCommonHeader(BinaryReader reader)
|
||||
{
|
||||
var header = new CommonHeader();
|
||||
|
||||
try
|
||||
{
|
||||
byte[] gameTitleBytes = reader.ReadBytes(0x0C);
|
||||
header.GameTitle = Encoding.ASCII.GetString(gameTitleBytes);
|
||||
header.GameCode = reader.ReadUInt32();
|
||||
byte[] makerCodeBytes = reader.ReadBytes(2);
|
||||
header.MakerCode = Encoding.ASCII.GetString(makerCodeBytes);
|
||||
header.UnitCode = (Unitcode)reader.ReadByte();
|
||||
header.EncryptionSeedSelect = reader.ReadByte();
|
||||
header.DeviceCapacity = reader.ReadByte();
|
||||
header.Reserved1 = reader.ReadBytes(7);
|
||||
header.GameRevision = reader.ReadUInt16();
|
||||
header.RomVersion = reader.ReadByte();
|
||||
header.InternalFlags = reader.ReadByte();
|
||||
header.ARM9RomOffset = reader.ReadUInt32();
|
||||
header.ARM9EntryAddress = reader.ReadUInt32();
|
||||
header.ARM9LoadAddress = reader.ReadUInt32();
|
||||
header.ARM9Size = reader.ReadUInt32();
|
||||
header.ARM7RomOffset = reader.ReadUInt32();
|
||||
header.ARM7EntryAddress = reader.ReadUInt32();
|
||||
header.ARM7LoadAddress = reader.ReadUInt32();
|
||||
header.ARM7Size = reader.ReadUInt32();
|
||||
header.FileNameTableOffset = reader.ReadUInt32();
|
||||
header.FileNameTableLength = reader.ReadUInt32();
|
||||
header.FileAllocationTableOffset = reader.ReadUInt32();
|
||||
header.FileAllocationTableLength = reader.ReadUInt32();
|
||||
header.ARM9OverlayOffset = reader.ReadUInt32();
|
||||
header.ARM9OverlayLength = reader.ReadUInt32();
|
||||
header.ARM7OverlayOffset = reader.ReadUInt32();
|
||||
header.ARM7OverlayLength = reader.ReadUInt32();
|
||||
header.SecureDisable = reader.ReadBytes(8);
|
||||
header.NTRRegionRomSize = reader.ReadUInt32();
|
||||
header.HeaderSize = reader.ReadUInt32();
|
||||
header.Reserved2 = reader.ReadBytes(56);
|
||||
header.NintendoLogo = reader.ReadBytes(156);
|
||||
header.NintendoLogoCRC = reader.ReadUInt16();
|
||||
header.DebuggerReserved = reader.ReadBytes(0x20);
|
||||
|
||||
return header;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an extended DSi header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <returns>Extended DSi header object, null on error</returns>
|
||||
private static ExtendedDSiHeader? ReadExtendedDSiHeader(BinaryReader reader)
|
||||
{
|
||||
var header = new ExtendedDSiHeader();
|
||||
|
||||
try
|
||||
{
|
||||
header.GlobalMBK15Settings = new uint[5];
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
header.GlobalMBK15Settings[i] = reader.ReadUInt32();
|
||||
}
|
||||
header.LocalMBK68SettingsARM9 = new uint[3];
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
header.LocalMBK68SettingsARM9[i] = reader.ReadUInt32();
|
||||
}
|
||||
header.LocalMBK68SettingsARM7 = new uint[3];
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
header.LocalMBK68SettingsARM7[i] = reader.ReadUInt32();
|
||||
}
|
||||
header.GlobalMBK9Setting = reader.ReadUInt32();
|
||||
header.RegionFlags = reader.ReadUInt32();
|
||||
header.AccessControl = reader.ReadUInt32();
|
||||
header.ARM7SCFGEXTMask = reader.ReadUInt32();
|
||||
header.ReservedFlags = reader.ReadUInt32();
|
||||
header.ARM9iRomOffset = reader.ReadUInt32();
|
||||
header.Reserved3 = reader.ReadUInt32();
|
||||
header.ARM9iLoadAddress = reader.ReadUInt32();
|
||||
header.ARM9iSize = reader.ReadUInt32();
|
||||
header.ARM7iRomOffset = reader.ReadUInt32();
|
||||
header.Reserved4 = reader.ReadUInt32();
|
||||
header.ARM7iLoadAddress = reader.ReadUInt32();
|
||||
header.ARM7iSize = reader.ReadUInt32();
|
||||
header.DigestNTRRegionOffset = reader.ReadUInt32();
|
||||
header.DigestNTRRegionLength = reader.ReadUInt32();
|
||||
header.DigestTWLRegionOffset = reader.ReadUInt32();
|
||||
header.DigestTWLRegionLength = reader.ReadUInt32();
|
||||
header.DigestSectorHashtableRegionOffset = reader.ReadUInt32();
|
||||
header.DigestSectorHashtableRegionLength = reader.ReadUInt32();
|
||||
header.DigestBlockHashtableRegionOffset = reader.ReadUInt32();
|
||||
header.DigestBlockHashtableRegionLength = reader.ReadUInt32();
|
||||
header.DigestSectorSize = reader.ReadUInt32();
|
||||
header.DigestBlockSectorCount = reader.ReadUInt32();
|
||||
header.IconBannerSize = reader.ReadUInt32();
|
||||
header.Unknown1 = reader.ReadUInt32();
|
||||
header.ModcryptArea1Offset = reader.ReadUInt32();
|
||||
header.ModcryptArea1Size = reader.ReadUInt32();
|
||||
header.ModcryptArea2Offset = reader.ReadUInt32();
|
||||
header.ModcryptArea2Size = reader.ReadUInt32();
|
||||
header.TitleID = reader.ReadBytes(8);
|
||||
header.DSiWarePublicSavSize = reader.ReadUInt32();
|
||||
header.DSiWarePrivateSavSize = reader.ReadUInt32();
|
||||
header.ReservedZero = reader.ReadBytes(176);
|
||||
header.Unknown2 = reader.ReadBytes(0x10);
|
||||
header.ARM9WithSecureAreaSHA1HMACHash = reader.ReadBytes(20);
|
||||
header.ARM7SHA1HMACHash = reader.ReadBytes(20);
|
||||
header.DigestMasterSHA1HMACHash = reader.ReadBytes(20);
|
||||
header.BannerSHA1HMACHash = reader.ReadBytes(20);
|
||||
header.ARM9iDecryptedSHA1HMACHash = reader.ReadBytes(20);
|
||||
header.ARM7iDecryptedSHA1HMACHash = reader.ReadBytes(20);
|
||||
header.Reserved5 = reader.ReadBytes(40);
|
||||
header.ARM9NoSecureAreaSHA1HMACHash = reader.ReadBytes(20);
|
||||
header.Reserved6 = reader.ReadBytes(2636);
|
||||
header.ReservedAndUnchecked = reader.ReadBytes(0x180);
|
||||
header.RSASignature = reader.ReadBytes(0x80);
|
||||
|
||||
return header;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user