mirror of
https://github.com/SabreTools/NDecrypt.git
synced 2026-09-22 06:45:07 +00:00
Read and use full headers
This commit is contained in:
@@ -160,14 +160,16 @@ namespace ThreeDS.Headers
|
||||
/// 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 Read(BinaryReader reader)
|
||||
public static NCCHHeader Read(BinaryReader reader, bool readSignature)
|
||||
{
|
||||
NCCHHeader header = new NCCHHeader();
|
||||
|
||||
try
|
||||
{
|
||||
header.RSA2048Signature = reader.ReadBytes(0x100);
|
||||
if (readSignature)
|
||||
header.RSA2048Signature = reader.ReadBytes(0x100);
|
||||
|
||||
if (new string(reader.ReadChars(4)) != NCCHMagicNumber)
|
||||
return null;
|
||||
|
||||
@@ -40,9 +40,34 @@ namespace ThreeDS.Headers
|
||||
/// </summary>
|
||||
public PartitionTableEntry[] PartitionsTable { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Executable Content (CXI)
|
||||
/// </summary>
|
||||
public PartitionTableEntry ExecutableContent { get { return PartitionsTable[0]; } }
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for E-Manual (CFA)
|
||||
/// </summary>
|
||||
public PartitionTableEntry EManual { get { return PartitionsTable[1]; } }
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Download Play Child container (CFA)
|
||||
/// </summary>
|
||||
public PartitionTableEntry DownloadPlayChildContainer { get { return PartitionsTable[2]; } }
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for New3DS Update Data (CFA)
|
||||
/// </summary>
|
||||
public PartitionTableEntry New3DSUpdateData { get { return PartitionsTable[6]; } }
|
||||
|
||||
/// <summary>
|
||||
/// Partition table entry for Update Data (CFA)
|
||||
/// </summary>
|
||||
public PartitionTableEntry UpdateData { get { return PartitionsTable[7]; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region For carts
|
||||
#region CTR Cart Image (CCI) Specific
|
||||
|
||||
/// <summary>
|
||||
/// Exheader SHA-256 hash
|
||||
@@ -62,13 +87,38 @@ namespace ThreeDS.Headers
|
||||
/// <summary>
|
||||
/// Partition Flags
|
||||
/// </summary>
|
||||
private byte[] partitionFlags;
|
||||
public byte BackupWriteWaitTime { get { return partitionFlags[(int)NCSDFlags.BackupWriteWaitTime]; } }
|
||||
public MediaCardDeviceType MediaCardDevice3X { get { return (MediaCardDeviceType)partitionFlags[(int)NCSDFlags.MediaCardDevice3X]; } }
|
||||
public MediaPlatformIndex MediaPlatformIndex { get { return (MediaPlatformIndex)partitionFlags[(int)NCSDFlags.MediaPlatformIndex]; } }
|
||||
public MediaTypeIndex MediaTypeIndex { get { return (MediaTypeIndex)partitionFlags[(int)NCSDFlags.MediaTypeIndex]; } }
|
||||
public uint SectorSize { get { return (uint)(0x200 * Math.Pow(2, partitionFlags[(int)NCSDFlags.MediaUnitSize])); } }
|
||||
public MediaCardDeviceType MediaCardDevice2X { get { return (MediaCardDeviceType)partitionFlags[(int)NCSDFlags.MediaCardDevice2X]; } }
|
||||
public byte[] PartitionFlags { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Backup Write Wait Time (The time to wait to write save to backup after the card is recognized (0-255
|
||||
/// seconds)).NATIVE_FIRM loads this flag from the gamecard NCSD header starting with 6.0.0-11.
|
||||
/// </summary>
|
||||
public byte BackupWriteWaitTime { get { return PartitionFlags[(int)NCSDFlags.BackupWriteWaitTime]; } }
|
||||
|
||||
/// <summary>
|
||||
/// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (SDK 3.X+)
|
||||
/// </summary>
|
||||
public MediaCardDeviceType MediaCardDevice3X { get { return (MediaCardDeviceType)PartitionFlags[(int)NCSDFlags.MediaCardDevice3X]; } }
|
||||
|
||||
/// <summary>
|
||||
/// Media Platform Index (1 = CTR)
|
||||
/// </summary>
|
||||
public MediaPlatformIndex MediaPlatformIndex { get { return (MediaPlatformIndex)PartitionFlags[(int)NCSDFlags.MediaPlatformIndex]; } }
|
||||
|
||||
/// <summary>
|
||||
/// Media Type Index (0 = Inner Device, 1 = Card1, 2 = Card2, 3 = Extended Device)
|
||||
/// </summary>
|
||||
public MediaTypeIndex MediaTypeIndex { get { return (MediaTypeIndex)PartitionFlags[(int)NCSDFlags.MediaTypeIndex]; } }
|
||||
|
||||
/// <summary>
|
||||
/// Media Unit Size i.e. u32 MediaUnitSize = 0x200*2^flags[6];
|
||||
/// </summary>
|
||||
public uint MediaUnitSize { get { return (uint)(0x200 * Math.Pow(2, PartitionFlags[(int)NCSDFlags.MediaUnitSize])); } }
|
||||
|
||||
/// <summary>
|
||||
/// Media Card Device (1 = NOR Flash, 2 = None, 3 = BT) (Only SDK 2.X)
|
||||
/// </summary>
|
||||
public MediaCardDeviceType MediaCardDevice2X { get { return (MediaCardDeviceType)PartitionFlags[(int)NCSDFlags.MediaCardDevice2X]; } }
|
||||
|
||||
/// <summary>
|
||||
/// Partition ID table
|
||||
@@ -96,11 +146,11 @@ namespace ThreeDS.Headers
|
||||
/// <summary>
|
||||
/// Support for this was implemented with 9.6.0-X FIRM, see below regarding save crypto.
|
||||
/// </summary>
|
||||
public byte FIrmUpdateByte2 { get; private set; }
|
||||
public byte FirmUpdateByte2 { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region For NAND
|
||||
#region Raw NAND Format Specific
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
@@ -114,12 +164,95 @@ namespace ThreeDS.Headers
|
||||
|
||||
#endregion
|
||||
|
||||
#region Card Info Header
|
||||
|
||||
/// <summary>
|
||||
/// CARD2: Writable Address In Media Units (For 'On-Chip' Savedata). CARD1: Always 0xFFFFFFFF.
|
||||
/// </summary>
|
||||
public byte[] CARD2WritableAddressMediaUnits { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Card Info Bitmask
|
||||
/// </summary>
|
||||
public byte[] CardInfoBytemask { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reserved1
|
||||
/// </summary>
|
||||
public byte[] Reserved3 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Title version
|
||||
/// </summary>
|
||||
public ushort TitleVersion { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Card revision
|
||||
/// </summary>
|
||||
public ushort CardRevision { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reserved2
|
||||
/// </summary>
|
||||
public byte[] Reserved4 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Card seed keyY (first u64 is Media ID (same as first NCCH partitionId))
|
||||
/// </summary>
|
||||
public byte[] CardSeedKeyY { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Encrypted card seed (AES-CCM, keyslot 0x3B for retail cards, see CTRCARD_SECSEED) /// </summary>
|
||||
public byte[] EncryptedCardSeed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Card seed AES-MAC
|
||||
/// </summary>
|
||||
public byte[] CardSeedAESMAC { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Card seed nonce
|
||||
/// </summary>
|
||||
public byte[] CardSeedNonce { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reserved3
|
||||
/// </summary>
|
||||
public byte[] Reserved5 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Copy of first NCCH header (excluding RSA signature)
|
||||
/// </summary>
|
||||
public NCCHHeader BackupHeader { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Development Card Info Header Extension
|
||||
|
||||
/// <summary>
|
||||
/// CardDeviceReserved1
|
||||
/// </summary>
|
||||
public byte[] CardDeviceReserved1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// TitleKey
|
||||
/// </summary>
|
||||
public byte[] TitleKey { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// CardDeviceReserved2
|
||||
/// </summary>
|
||||
public byte[] CardDeviceReserved2 { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Read from a stream and get an NCSD header, if possible
|
||||
/// </summary>
|
||||
/// <param name="reader">BinaryReader representing the input stream</param>
|
||||
/// <param name="development">True if development cart, false otherwise</param>
|
||||
/// <returns>NCSD header object, null on error</returns>
|
||||
public static NCSDHeader Read(BinaryReader reader)
|
||||
public static NCSDHeader Read(BinaryReader reader, bool development)
|
||||
{
|
||||
NCSDHeader header = new NCSDHeader();
|
||||
|
||||
@@ -145,7 +278,7 @@ namespace ThreeDS.Headers
|
||||
header.ExheaderHash = reader.ReadBytes(0x20);
|
||||
header.AdditionalHeaderSize = reader.ReadUInt32();
|
||||
header.SectorZeroOffset = reader.ReadUInt32();
|
||||
header.partitionFlags = reader.ReadBytes(8);
|
||||
header.PartitionFlags = reader.ReadBytes(8);
|
||||
|
||||
header.PartitionIdTable = new byte[8][];
|
||||
for (int i = 0; i < 8; i++)
|
||||
@@ -154,7 +287,27 @@ namespace ThreeDS.Headers
|
||||
header.Reserved1 = reader.ReadBytes(0x20);
|
||||
header.Reserved2 = reader.ReadBytes(0xE);
|
||||
header.FirmUpdateByte1 = reader.ReadByte();
|
||||
header.FIrmUpdateByte2 = reader.ReadByte();
|
||||
header.FirmUpdateByte2 = reader.ReadByte();
|
||||
|
||||
header.CARD2WritableAddressMediaUnits = reader.ReadBytes(4);
|
||||
header.CardInfoBytemask = reader.ReadBytes(4);
|
||||
header.Reserved3 = reader.ReadBytes(0x108);
|
||||
header.TitleVersion = reader.ReadUInt16();
|
||||
header.CardRevision = reader.ReadUInt16();
|
||||
header.Reserved4 = reader.ReadBytes(0xCEE);
|
||||
header.CardSeedKeyY = reader.ReadBytes(0x10);
|
||||
header.EncryptedCardSeed = reader.ReadBytes(0x10);
|
||||
header.CardSeedAESMAC = reader.ReadBytes(0x10);
|
||||
header.CardSeedNonce = reader.ReadBytes(0x10);
|
||||
header.Reserved5 = reader.ReadBytes(0xC4);
|
||||
header.BackupHeader = NCCHHeader.Read(reader, false);
|
||||
|
||||
if (development)
|
||||
{
|
||||
header.CardDeviceReserved1 = reader.ReadBytes(0x200);
|
||||
header.TitleKey = reader.ReadBytes(0x10);
|
||||
header.CardDeviceReserved2 = reader.ReadBytes(0xF0);
|
||||
}
|
||||
}
|
||||
else if (header.PartitionsFSType == FilesystemType.FIRM)
|
||||
{
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace ThreeDS
|
||||
using (BinaryReader f = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
|
||||
using (BinaryWriter g = new BinaryWriter(File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)))
|
||||
{
|
||||
NCSDHeader header = NCSDHeader.Read(f);
|
||||
NCSDHeader header = NCSDHeader.Read(f, development);
|
||||
if (header == null)
|
||||
{
|
||||
Console.WriteLine("Error: Not a 3DS Rom!");
|
||||
@@ -83,9 +83,9 @@ namespace ThreeDS
|
||||
}
|
||||
|
||||
// Seek to the beginning of the NCCH partition
|
||||
f.BaseStream.Seek((header.PartitionsTable[p].Offset * header.SectorSize), SeekOrigin.Begin);
|
||||
f.BaseStream.Seek((header.PartitionsTable[p].Offset * header.MediaUnitSize), SeekOrigin.Begin);
|
||||
|
||||
NCCHHeader partitionHeader = NCCHHeader.Read(f);
|
||||
NCCHHeader partitionHeader = NCCHHeader.Read(f, true);
|
||||
if (partitionHeader == null)
|
||||
{
|
||||
Console.WriteLine($"Partition {p} Unable to read NCCH header");
|
||||
@@ -108,12 +108,12 @@ namespace ThreeDS
|
||||
ProcessRomFS(f, g, header, p, partitionHeader, false);
|
||||
|
||||
// Write the new CryptoMethod
|
||||
g.BaseStream.Seek((header.PartitionsTable[p].Offset * header.SectorSize) + 0x18B, SeekOrigin.Begin);
|
||||
g.BaseStream.Seek((header.PartitionsTable[p].Offset * header.MediaUnitSize) + 0x18B, SeekOrigin.Begin);
|
||||
g.Write((byte)CryptoMethod.Original);
|
||||
g.Flush();
|
||||
|
||||
// Write the new BitMasks flag
|
||||
g.BaseStream.Seek((header.PartitionsTable[p].Offset * header.SectorSize) + 0x18F, SeekOrigin.Begin);
|
||||
g.BaseStream.Seek((header.PartitionsTable[p].Offset * header.MediaUnitSize) + 0x18F, SeekOrigin.Begin);
|
||||
BitMasks flag = partitionHeader.Flags.BitMasks;
|
||||
flag = flag & (BitMasks)((byte)(BitMasks.FixedCryptoKey | BitMasks.NewKeyYGenerator) ^ 0xFF);
|
||||
flag = (flag | BitMasks.NoCrypto);
|
||||
@@ -139,17 +139,13 @@ namespace ThreeDS
|
||||
using (BinaryReader f = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
|
||||
using (BinaryWriter g = new BinaryWriter(File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)))
|
||||
{
|
||||
NCSDHeader header = NCSDHeader.Read(f);
|
||||
NCSDHeader header = NCSDHeader.Read(f, development);
|
||||
if (header == null)
|
||||
{
|
||||
Console.WriteLine("Error: Not a 3DS Rom!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the backup flags
|
||||
f.BaseStream.Seek(0x1188, SeekOrigin.Begin);
|
||||
NCCHHeaderFlags backupFlags = NCCHHeaderFlags.Read(f);
|
||||
|
||||
// Iterate over all 8 NCCH partitions
|
||||
for (int p = 0; p < 8; p++)
|
||||
{
|
||||
@@ -160,9 +156,9 @@ namespace ThreeDS
|
||||
}
|
||||
|
||||
// Seek to the beginning of the NCCH partition
|
||||
f.BaseStream.Seek((header.PartitionsTable[p].Offset * header.SectorSize), SeekOrigin.Begin);
|
||||
f.BaseStream.Seek((header.PartitionsTable[p].Offset * header.MediaUnitSize), SeekOrigin.Begin);
|
||||
|
||||
NCCHHeader partitionHeader = NCCHHeader.Read(f);
|
||||
NCCHHeader partitionHeader = NCCHHeader.Read(f, true);
|
||||
if (partitionHeader == null)
|
||||
{
|
||||
Console.WriteLine($"Partition {p} Unable to read NCCH header");
|
||||
@@ -177,15 +173,15 @@ namespace ThreeDS
|
||||
}
|
||||
|
||||
// Determine the Keys to be used
|
||||
SetEncryptionKeys(partitionHeader.RSA2048Signature, backupFlags.BitMasks, backupFlags.CryptoMethod, p);
|
||||
SetEncryptionKeys(partitionHeader.RSA2048Signature, header.BackupHeader.Flags.BitMasks, header.BackupHeader.Flags.CryptoMethod, p);
|
||||
|
||||
// Encrypt each of the pieces if they exist
|
||||
ProcessExtendedHeader(f, g, header, p, partitionHeader, true);
|
||||
ProcessExeFS(f, g, header, p, partitionHeader, true);
|
||||
ProcessRomFS(f, g, header, p, partitionHeader, true, backupFlags);
|
||||
ProcessRomFS(f, g, header, p, partitionHeader, true, header.BackupHeader.Flags);
|
||||
|
||||
// Write the new CryptoMethod
|
||||
g.BaseStream.Seek((header.PartitionsTable[p].Offset * header.SectorSize) + 0x18B, SeekOrigin.Begin);
|
||||
g.BaseStream.Seek((header.PartitionsTable[p].Offset * header.MediaUnitSize) + 0x18B, SeekOrigin.Begin);
|
||||
if (p > 0)
|
||||
{
|
||||
g.Write((byte)CryptoMethod.Original); // For partitions 1 and up, set crypto-method to 0x00
|
||||
@@ -193,15 +189,15 @@ namespace ThreeDS
|
||||
}
|
||||
else
|
||||
{
|
||||
g.Write((byte)backupFlags.CryptoMethod); // If partition 0, restore crypto-method from backup flags
|
||||
g.Write((byte)header.BackupHeader.Flags.CryptoMethod); // If partition 0, restore crypto-method from backup flags
|
||||
g.Flush();
|
||||
}
|
||||
|
||||
// Write the new BitMasks flag
|
||||
g.BaseStream.Seek((header.PartitionsTable[p].Offset * header.SectorSize) + 0x18F, SeekOrigin.Begin);
|
||||
g.BaseStream.Seek((header.PartitionsTable[p].Offset * header.MediaUnitSize) + 0x18F, SeekOrigin.Begin);
|
||||
BitMasks flag = partitionHeader.Flags.BitMasks;
|
||||
flag = (flag & ((BitMasks.FixedCryptoKey | BitMasks.NewKeyYGenerator | BitMasks.NoCrypto) ^ (BitMasks)0xFF));
|
||||
flag = (flag | (BitMasks.FixedCryptoKey | BitMasks.NewKeyYGenerator) & backupFlags.BitMasks);
|
||||
flag = (flag | (BitMasks.FixedCryptoKey | BitMasks.NewKeyYGenerator) & header.BackupHeader.Flags.BitMasks);
|
||||
g.Write((byte)flag);
|
||||
g.Flush();
|
||||
}
|
||||
@@ -352,8 +348,8 @@ namespace ThreeDS
|
||||
{
|
||||
if (partitionHeader.ExtendedHeaderSizeInBytes > 0)
|
||||
{
|
||||
reader.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset * header.SectorSize) + 0x200, SeekOrigin.Begin);
|
||||
writer.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset * header.SectorSize) + 0x200, SeekOrigin.Begin);
|
||||
reader.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset * header.MediaUnitSize) + 0x200, SeekOrigin.Begin);
|
||||
writer.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset * header.MediaUnitSize) + 0x200, SeekOrigin.Begin);
|
||||
|
||||
Console.WriteLine($"Partition {partitionNumber} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + ": ExHeader");
|
||||
|
||||
@@ -387,7 +383,7 @@ namespace ThreeDS
|
||||
// For all but the original crypto method, process each of the files in the table
|
||||
if (partitionHeader.Flags.CryptoMethod != CryptoMethod.Original)
|
||||
{
|
||||
reader.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits) * header.SectorSize, SeekOrigin.Begin);
|
||||
reader.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits) * header.MediaUnitSize, SeekOrigin.Begin);
|
||||
ExeFSHeader exefsHeader = ExeFSHeader.Read(reader);
|
||||
if (exefsHeader != null)
|
||||
{
|
||||
@@ -399,15 +395,15 @@ namespace ThreeDS
|
||||
|
||||
uint datalenM = ((fileHeader.FileSize) / (1024 * 1024));
|
||||
uint datalenB = ((fileHeader.FileSize) % (1024 * 1024));
|
||||
uint ctroffset = ((fileHeader.FileOffset + header.SectorSize) / 0x10);
|
||||
uint ctroffset = ((fileHeader.FileOffset + header.MediaUnitSize) / 0x10);
|
||||
|
||||
byte[] exefsIVWithOffsetForHeader = AddToByteArray(partitionHeader.ExeFSIV, (int)ctroffset);
|
||||
|
||||
var firstCipher = CreateAESCipher(NormalKey, exefsIVWithOffsetForHeader, encrypt);
|
||||
var secondCipher = CreateAESCipher(NormalKey2C, exefsIVWithOffsetForHeader, !encrypt);
|
||||
|
||||
reader.BaseStream.Seek((((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits) + 1) * header.SectorSize) + fileHeader.FileOffset, SeekOrigin.Begin);
|
||||
writer.BaseStream.Seek((((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits) + 1) * header.SectorSize) + fileHeader.FileOffset, SeekOrigin.Begin);
|
||||
reader.BaseStream.Seek((((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits) + 1) * header.MediaUnitSize) + fileHeader.FileOffset, SeekOrigin.Begin);
|
||||
writer.BaseStream.Seek((((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits) + 1) * header.MediaUnitSize) + fileHeader.FileOffset, SeekOrigin.Begin);
|
||||
|
||||
if (datalenM > 0)
|
||||
{
|
||||
@@ -435,16 +431,16 @@ namespace ThreeDS
|
||||
ProcessExeFSFilenameTable(reader, writer, header, partitionNumber, partitionHeader, encrypt);
|
||||
|
||||
// Process the ExeFS
|
||||
int exefsSizeM = (int)((partitionHeader.ExeFSSizeInMediaUnits - 1) * header.SectorSize) / (1024 * 1024);
|
||||
int exefsSizeB = (int)((partitionHeader.ExeFSSizeInMediaUnits - 1) * header.SectorSize) % (1024 * 1024);
|
||||
int ctroffsetE = (int)(header.SectorSize / 0x10);
|
||||
int exefsSizeM = (int)((partitionHeader.ExeFSSizeInMediaUnits - 1) * header.MediaUnitSize) / (1024 * 1024);
|
||||
int exefsSizeB = (int)((partitionHeader.ExeFSSizeInMediaUnits - 1) * header.MediaUnitSize) % (1024 * 1024);
|
||||
int ctroffsetE = (int)(header.MediaUnitSize / 0x10);
|
||||
|
||||
byte[] exefsIVWithOffset = AddToByteArray(partitionHeader.ExeFSIV, ctroffsetE);
|
||||
|
||||
var exeFS = CreateAESCipher(NormalKey2C, exefsIVWithOffset, encrypt);
|
||||
|
||||
reader.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits + 1) * header.SectorSize, SeekOrigin.Begin);
|
||||
writer.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits + 1) * header.SectorSize, SeekOrigin.Begin);
|
||||
reader.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits + 1) * header.MediaUnitSize, SeekOrigin.Begin);
|
||||
writer.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits + 1) * header.MediaUnitSize, SeekOrigin.Begin);
|
||||
if (exefsSizeM > 0)
|
||||
{
|
||||
for (int i = 0; i < exefsSizeM; i++)
|
||||
@@ -479,13 +475,13 @@ namespace ThreeDS
|
||||
/// <param name="encrypt">True if we want to encrypt the extended header, false otherwise</param>
|
||||
private void ProcessExeFSFilenameTable(BinaryReader reader, BinaryWriter writer, NCSDHeader header, int partitionNumber, NCCHHeader partitionHeader, bool encrypt)
|
||||
{
|
||||
reader.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits) * header.SectorSize, SeekOrigin.Begin);
|
||||
writer.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits) * header.SectorSize, SeekOrigin.Begin);
|
||||
reader.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits) * header.MediaUnitSize, SeekOrigin.Begin);
|
||||
writer.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.ExeFSOffsetInMediaUnits) * header.MediaUnitSize, SeekOrigin.Begin);
|
||||
|
||||
Console.WriteLine($"Partition {partitionNumber} ExeFS: " + (encrypt ? "Encrypting" : "Decrypting") + $": ExeFS Filename Table");
|
||||
|
||||
var exeFSFilenameTable = CreateAESCipher(NormalKey2C, partitionHeader.ExeFSIV, encrypt);
|
||||
writer.Write(exeFSFilenameTable.ProcessBytes(reader.ReadBytes((int)header.SectorSize)));
|
||||
writer.Write(exeFSFilenameTable.ProcessBytes(reader.ReadBytes((int)header.MediaUnitSize)));
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
@@ -503,8 +499,8 @@ namespace ThreeDS
|
||||
{
|
||||
if (partitionHeader.RomFSOffsetInMediaUnits != 0)
|
||||
{
|
||||
int romfsSizeM = (int)(partitionHeader.RomFSSizeInMediaUnits * header.SectorSize) / (1024 * 1024);
|
||||
int romfsSizeB = (int)(partitionHeader.RomFSSizeInMediaUnits * header.SectorSize) % (1024 * 1024);
|
||||
int romfsSizeM = (int)(partitionHeader.RomFSSizeInMediaUnits * header.MediaUnitSize) / (1024 * 1024);
|
||||
int romfsSizeB = (int)(partitionHeader.RomFSSizeInMediaUnits * header.MediaUnitSize) % (1024 * 1024);
|
||||
|
||||
// Encrypting RomFS for partitions 1 and up always use Key0x2C
|
||||
if (encrypt && partitionNumber > 0)
|
||||
@@ -529,8 +525,8 @@ namespace ThreeDS
|
||||
|
||||
var cipher = CreateAESCipher(NormalKey, partitionHeader.RomFSIV, encrypt);
|
||||
|
||||
reader.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.RomFSOffsetInMediaUnits) * header.SectorSize, SeekOrigin.Begin);
|
||||
writer.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.RomFSOffsetInMediaUnits) * header.SectorSize, SeekOrigin.Begin);
|
||||
reader.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.RomFSOffsetInMediaUnits) * header.MediaUnitSize, SeekOrigin.Begin);
|
||||
writer.BaseStream.Seek((header.PartitionsTable[partitionNumber].Offset + partitionHeader.RomFSOffsetInMediaUnits) * header.MediaUnitSize, SeekOrigin.Begin);
|
||||
if (romfsSizeM > 0)
|
||||
{
|
||||
for (int i = 0; i < romfsSizeM; i++)
|
||||
|
||||
Reference in New Issue
Block a user