mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-07-20 15:55:15 +00:00
Add extended header parsing for N3DS
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Models.N3DS;
|
||||
@@ -105,7 +106,33 @@ namespace BurnOutSharp.Builders
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Parse partition extended headers (decrypted only)
|
||||
#region Extended Headers
|
||||
|
||||
// Create the extended header table
|
||||
cart.NCCHExtendedHeaders = new NCCHExtendedHeader[8];
|
||||
|
||||
// Iterate and build the extended headers
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// If we have an encrypted or invalid partition
|
||||
if (cart.Partitions[i].MagicID != NCCHMagicNumber)
|
||||
continue;
|
||||
|
||||
// Get the extended header offset
|
||||
long mediaUnitSize = (uint)(0x200 * Math.Pow(2, header.PartitionFlags[(int)NCSDFlags.MediaUnitSize]));
|
||||
long offset = (cart.Header.PartitionsTable[i].Offset * mediaUnitSize) + 0x200;
|
||||
if (offset < 0 || offset >= data.Length)
|
||||
continue;
|
||||
|
||||
// Seek to the extended header
|
||||
data.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
// Parse the extended header
|
||||
cart.NCCHExtendedHeaders[i] = ParseNCCHExtendedHeader(data);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Parse ExeFS file entries (decrypted only)
|
||||
// TODO: Parse ExeFS filename table (decrypted only)
|
||||
|
||||
@@ -349,6 +376,209 @@ namespace BurnOutSharp.Builders
|
||||
return testData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an NCCH extended header
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled NCCH extended header on success, null on error</returns>
|
||||
private static NCCHExtendedHeader ParseNCCHExtendedHeader(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
NCCHExtendedHeader extendedHeader = new NCCHExtendedHeader();
|
||||
|
||||
extendedHeader.SCI = ParseSystemControlInfo(data);
|
||||
if (extendedHeader.SCI == null)
|
||||
return null;
|
||||
|
||||
extendedHeader.ACI = ParseAccessControlInfo(data);
|
||||
if (extendedHeader.ACI == null)
|
||||
return null;
|
||||
|
||||
extendedHeader.AccessDescSignature = data.ReadBytes(0x100);
|
||||
extendedHeader.NCCHHDRPublicKey = data.ReadBytes(0x100);
|
||||
|
||||
extendedHeader.ACIForLimitations = ParseAccessControlInfo(data);
|
||||
if (extendedHeader.ACI == null)
|
||||
return null;
|
||||
|
||||
return extendedHeader;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a system control info
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled system control info on success, null on error</returns>
|
||||
private static SystemControlInfo ParseSystemControlInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
SystemControlInfo systemControlInfo = new SystemControlInfo();
|
||||
|
||||
byte[] applicationTitle = data.ReadBytes(8);
|
||||
systemControlInfo.ApplicationTitle = Encoding.ASCII.GetString(applicationTitle).TrimEnd('\0');
|
||||
systemControlInfo.Reserved1 = data.ReadBytes(5);
|
||||
systemControlInfo.Flag = data.ReadByteValue();
|
||||
systemControlInfo.RemasterVersion = data.ReadUInt16();
|
||||
systemControlInfo.TextCodeSetInfo = ParseCodeSetInfo(data);
|
||||
systemControlInfo.StackSize = data.ReadUInt32();
|
||||
systemControlInfo.ReadOnlyCodeSetInfo = ParseCodeSetInfo(data);
|
||||
systemControlInfo.Reserved2 = data.ReadBytes(4);
|
||||
systemControlInfo.DataCodeSetInfo = ParseCodeSetInfo(data);
|
||||
systemControlInfo.BSSSize = data.ReadUInt32();
|
||||
systemControlInfo.DependencyModuleList = new ulong[48];
|
||||
for (int i = 0; i < 48; i++)
|
||||
{
|
||||
systemControlInfo.DependencyModuleList[i] = data.ReadUInt64();
|
||||
}
|
||||
systemControlInfo.SystemInfo = ParseSystemInfo(data);
|
||||
|
||||
return systemControlInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a code set info
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled code set info on success, null on error</returns>
|
||||
private static CodeSetInfo ParseCodeSetInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
CodeSetInfo codeSetInfo = new CodeSetInfo();
|
||||
|
||||
codeSetInfo.Address = data.ReadUInt32();
|
||||
codeSetInfo.PhysicalRegionSizeInPages = data.ReadUInt32();
|
||||
codeSetInfo.SizeInBytes = data.ReadUInt32();
|
||||
|
||||
return codeSetInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a system info
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled system info on success, null on error</returns>
|
||||
private static SystemInfo ParseSystemInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
SystemInfo systemInfo = new SystemInfo();
|
||||
|
||||
systemInfo.SaveDataSize = data.ReadUInt64();
|
||||
systemInfo.JumpID = data.ReadUInt64();
|
||||
systemInfo.Reserved = data.ReadBytes(0x30);
|
||||
|
||||
return systemInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an access control info
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled access control info on success, null on error</returns>
|
||||
private static AccessControlInfo ParseAccessControlInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
AccessControlInfo accessControlInfo = new AccessControlInfo();
|
||||
|
||||
accessControlInfo.ARM11LocalSystemCapabilities = ParseARM11LocalSystemCapabilities(data);
|
||||
accessControlInfo.ARM11KernelCapabilities = ParseARM11KernelCapabilities(data);
|
||||
accessControlInfo.ARM9AccessControl = ParseARM9AccessControl(data);
|
||||
|
||||
return accessControlInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an ARM11 local system capabilities
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled ARM11 local system capabilities on success, null on error</returns>
|
||||
private static ARM11LocalSystemCapabilities ParseARM11LocalSystemCapabilities(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
ARM11LocalSystemCapabilities arm11LocalSystemCapabilities = new ARM11LocalSystemCapabilities();
|
||||
|
||||
arm11LocalSystemCapabilities.ProgramID = data.ReadUInt64();
|
||||
arm11LocalSystemCapabilities.CoreVersion = data.ReadUInt32();
|
||||
arm11LocalSystemCapabilities.Flag1 = (ARM11LSCFlag1)data.ReadByteValue();
|
||||
arm11LocalSystemCapabilities.Flag2 = (ARM11LSCFlag2)data.ReadByteValue();
|
||||
arm11LocalSystemCapabilities.Flag0 = (ARM11LSCFlag0)data.ReadByteValue();
|
||||
arm11LocalSystemCapabilities.Priority = data.ReadByteValue();
|
||||
arm11LocalSystemCapabilities.ResourceLimitDescriptors = new ushort[16];
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
arm11LocalSystemCapabilities.ResourceLimitDescriptors[i] = data.ReadUInt16();
|
||||
}
|
||||
arm11LocalSystemCapabilities.StorageInfo = ParseStorageInfo(data);
|
||||
arm11LocalSystemCapabilities.ServiceAccessControl = new ulong[32];
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
arm11LocalSystemCapabilities.ServiceAccessControl[i] = data.ReadUInt64();
|
||||
}
|
||||
arm11LocalSystemCapabilities.ExtendedServiceAccessControl = new ulong[2];
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
arm11LocalSystemCapabilities.ExtendedServiceAccessControl[i] = data.ReadUInt64();
|
||||
}
|
||||
arm11LocalSystemCapabilities.Reserved = data.ReadBytes(0x0F);
|
||||
arm11LocalSystemCapabilities.ResourceLimitCategory = (ResourceLimitCategory)data.ReadByteValue();
|
||||
|
||||
return arm11LocalSystemCapabilities;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into a storage info
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled storage info on success, null on error</returns>
|
||||
private static StorageInfo ParseStorageInfo(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
StorageInfo storageInfo = new StorageInfo();
|
||||
|
||||
storageInfo.ExtdataID = data.ReadUInt64();
|
||||
storageInfo.SystemSavedataIDs = data.ReadBytes(8);
|
||||
storageInfo.StorageAccessibleUniqueIDs = data.ReadBytes(8);
|
||||
storageInfo.FileSystemAccessInfo = data.ReadBytes(7);
|
||||
storageInfo.OtherAttributes = (StorageInfoOtherAttributes)data.ReadByteValue();
|
||||
|
||||
return storageInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an ARM11 kernel capabilities
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled ARM11 kernel capabilities on success, null on error</returns>
|
||||
private static ARM11KernelCapabilities ParseARM11KernelCapabilities(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
ARM11KernelCapabilities arm11KernelCapabilities = new ARM11KernelCapabilities();
|
||||
|
||||
arm11KernelCapabilities.Descriptors = new uint[28];
|
||||
for (int i = 0; i < 28; i++)
|
||||
{
|
||||
arm11KernelCapabilities.Descriptors[i] = data.ReadUInt32();
|
||||
}
|
||||
arm11KernelCapabilities.Reserved = data.ReadBytes(0x10);
|
||||
|
||||
return arm11KernelCapabilities;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a Stream into an ARM11 access control
|
||||
/// </summary>
|
||||
/// <param name="data">Stream to parse</param>
|
||||
/// <returns>Filled ARM11 access control on success, null on error</returns>
|
||||
private static ARM9AccessControl ParseARM9AccessControl(Stream data)
|
||||
{
|
||||
// TODO: Use marshalling here instead of building
|
||||
ARM9AccessControl arm9AccessControl = new ARM9AccessControl();
|
||||
|
||||
arm9AccessControl.Descriptors = data.ReadBytes(15);
|
||||
arm9AccessControl.DescriptorVersion = data.ReadByteValue();
|
||||
|
||||
return arm9AccessControl;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
/// 12 Special memory
|
||||
/// 13 Process has access to CPU core 2 (New3DS only)
|
||||
/// </summary>
|
||||
public byte[][] Descriptors;
|
||||
/// TODO: Make enum for flag values
|
||||
public uint[] Descriptors;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/// <summary>
|
||||
/// Program ID
|
||||
/// </summary>
|
||||
public byte[] ProgramID;
|
||||
public ulong ProgramID;
|
||||
|
||||
/// <summary>
|
||||
/// Core version (The Title ID low of the required FIRM)
|
||||
@@ -36,7 +36,7 @@
|
||||
/// <summary>
|
||||
/// Resource limit descriptors. The first byte here controls the maximum allowed CpuTime.
|
||||
/// </summary>
|
||||
public byte[][] ResourceLimitDescriptors;
|
||||
public ushort[] ResourceLimitDescriptors;
|
||||
|
||||
/// <summary>
|
||||
/// Storage info
|
||||
@@ -46,12 +46,12 @@
|
||||
/// <summary>
|
||||
/// Service access control
|
||||
/// </summary>
|
||||
public byte[][] ServiceAccessControl;
|
||||
public ulong[] ServiceAccessControl;
|
||||
|
||||
/// <summary>
|
||||
/// Extended service access control, support for this was implemented with 9.3.0-X.
|
||||
/// </summary>
|
||||
public byte[][] ExtendedServiceAccessControl;
|
||||
public ulong[] ExtendedServiceAccessControl;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/// <summary>
|
||||
/// Descriptors
|
||||
/// </summary>
|
||||
public ARM9AccessControlDescriptors[] Descriptors;
|
||||
public byte[] Descriptors;
|
||||
|
||||
/// <summary>
|
||||
/// ARM9 Descriptor Version. Originally this value had to be ≥ 2.
|
||||
|
||||
@@ -24,5 +24,10 @@ namespace BurnOutSharp.Models.N3DS
|
||||
/// NCCH partitions
|
||||
/// </summary>
|
||||
public NCCHHeader[] Partitions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// NCCH extended headers
|
||||
/// </summary>
|
||||
public NCCHExtendedHeader[] NCCHExtendedHeaders { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
/// <summary>
|
||||
/// Address
|
||||
/// </summary>
|
||||
public byte[] Address;
|
||||
public uint Address;
|
||||
|
||||
/// <summary>
|
||||
/// Physical region size (in page-multiples)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace BurnOutSharp.Models.N3DS
|
||||
{
|
||||
// TODO: Fix this, I don't think it's correct
|
||||
[Flags]
|
||||
public enum ARM9AccessControlDescriptors : byte
|
||||
{
|
||||
@@ -14,7 +15,7 @@ namespace BurnOutSharp.Models.N3DS
|
||||
CreateSeed = 0x20,
|
||||
UseCardSPI = 0x40,
|
||||
SDApplication = 0x80,
|
||||
MoundSdmcWriteAccess = 0xF0,
|
||||
MountSdmcWriteAccess = 0xF0,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/// - 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
|
||||
public sealed class NCCHExtendedHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// SCI
|
||||
@@ -9,7 +9,7 @@
|
||||
/// <summary>
|
||||
/// Extdata ID
|
||||
/// </summary>
|
||||
public byte[] ExtdataID;
|
||||
public ulong ExtdataID;
|
||||
|
||||
/// <summary>
|
||||
/// System savedata IDs
|
||||
@@ -24,7 +24,9 @@
|
||||
/// <summary>
|
||||
/// Filesystem access info
|
||||
/// </summary>
|
||||
public byte[] FilesystemAccessInfo;
|
||||
/// TODO: Create enum for the flag values
|
||||
/// TODO: Combine with "other attributes"
|
||||
public byte[] FileSystemAccessInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Other attributes
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/// <summary>
|
||||
/// Application title (default is "CtrApp")
|
||||
/// </summary>
|
||||
public char[] ApplicationTitle;
|
||||
public string ApplicationTitle;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved
|
||||
@@ -21,12 +21,12 @@
|
||||
/// <summary>
|
||||
/// Remaster version
|
||||
/// </summary>
|
||||
public byte[] RemasterVersion;
|
||||
public ushort RemasterVersion;
|
||||
|
||||
/// <summary>
|
||||
/// Text code set info
|
||||
/// </summary>
|
||||
public CodeSetInfo TextCodesetInfo;
|
||||
public CodeSetInfo TextCodeSetInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Stack size
|
||||
@@ -56,7 +56,7 @@
|
||||
/// <summary>
|
||||
/// Dependency module (program ID) list
|
||||
/// </summary>
|
||||
public byte[][] DependencyModuleList;
|
||||
public ulong[] DependencyModuleList;
|
||||
|
||||
/// <summary>
|
||||
/// SystemInfo
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
/// <summary>
|
||||
/// Jump ID
|
||||
/// </summary>
|
||||
public byte[] JumpID;
|
||||
public ulong JumpID;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved
|
||||
|
||||
Reference in New Issue
Block a user