Add SecuROM Matroshka models

All research thanks to HeroponRikiBestest
This commit is contained in:
Matt Nadareski
2025-07-21 09:11:37 -04:00
parent 4c76ce1230
commit 3d3275e3cb
5 changed files with 172 additions and 1 deletions

View File

@@ -110,5 +110,13 @@ namespace SabreTools.Models.SecuROM
#endregion
#endregion
#region Matroshka
public const string MatroshkaMagicString = "MatR";
public static readonly byte[] MatroshkaMagicBytes = [0x4D, 0x61, 0x74, 0x52];
#endregion
}
}

View File

@@ -8,7 +8,7 @@ namespace SabreTools.Models.SecuROM
public class DFAFile
{
/// <summary>
/// "SDFA" 0x04 0x00 0x00 0x00;
/// "SDFA" 0x04 0x00 0x00 0x00
/// </summary>
/// <remarks>8 bytes</remarks>
public byte[]? Signature { get; set; }

View File

@@ -0,0 +1,36 @@
namespace SabreTools.Models.SecuROM
{
public enum MatroshkaEntryType : uint
{
/// <summary>
/// Helper or activation executable
/// </summary>
Helper = 0x01,
/// <summary>
/// Main executable, usually one of the following:
/// - RC-encrypted executable to be decrypted later
/// - Main game program executable
/// - Revoker executable
/// </summary>
/// <remarks>Usually the second entry</remarks>
Main = 0x02,
/// <summary>
/// Required libraries for the main executable
/// </summary>
/// <remarks>
/// Examples include:
/// - DFA.dll for RC-encrypted executables
/// - paul.dll for PA-protected games
/// - remover.exe for revocation
/// executables.
/// </remarks>
Dependency = 0x04,
/// <summary>
/// Similar use to <see cref="Dependency"/>
/// </summary>
Unknown0x08 = 0x08,
}
}

View File

@@ -0,0 +1,57 @@
namespace SabreTools.Models.SecuROM
{
public class MatroshkaEntry
{
/// <summary>
/// File entry path
/// - Older versions are always 256 bytes
/// - Newer versions are always 512 bytes
/// </summary>
/// <remarks>Length may be tied to unknown values in header</remarks>
public byte[]? Path { get; set; }
/// <summary>
/// Type of the entry data
/// </summary>
public MatroshkaEntryType EntryType { get; set; }
/// <summary>
/// Data size
/// </summary>
public uint Size { get; set; }
/// <summary>
/// Data offset within the package
/// </summary>
public uint Offset { get; set; }
/// <summary>
/// Unknown value only seen in later versions
/// </summary>
public uint? Unknown { get; set; }
/// <summary>
/// File modification time, stored in NTFS filetime.
/// </summary>
/// <see href="https://learn.microsoft.com/en-us/windows/win32/sysinfo/file-times"/>
public ulong ModifiedTime { get; set; }
/// <summary>
/// File creation time, stored in NTFS filetime.
/// </summary>
/// <see href="https://learn.microsoft.com/en-us/windows/win32/sysinfo/file-times"/>
public ulong CreatedTime { get; set; }
/// <summary>
/// File access time, stored in NTFS filetime.
/// </summary>
/// <see href="https://learn.microsoft.com/en-us/windows/win32/sysinfo/file-times"/>
public ulong AccessedTime { get; set; }
/// <summary>
/// MD5 hash of the data
/// </summary>
/// <remarks>16 bytes</remarks>
public byte[]? MD5 { get; set; }
}
}

View File

@@ -0,0 +1,70 @@
namespace SabreTools.Models.SecuROM
{
/// <summary>
/// Securom Matroschka Package, a package contained in an executable as
/// a section. Offered by SecuROM, its main purpose seems to be managing
/// some sort of SecuROM-related operation involving multiple temporary
/// files contained within the package. Observed in Release Control
/// executables, Product Activation Revocation executables, and in some
/// regular Product-Activation-protected releases (such as the digital
/// download releases of Neverwinter Nights 2 and Test Drive Unlimited)
/// where the game executable, paul.dll and other PA-related files are
/// stored in the matroschka package.
/// </summary>
public class MatroshkaPackage
{
/// <summary>
/// "MatR"
/// </summary>
/// <remarks>4 bytes</remarks>
public string? Signature { get; set; }
/// <summary>
/// Number of internal entries
/// </summary>
public uint EntryCount { get; set; }
#region Release Control only
/// <summary>
/// One of four unknown values only observed on RC matroschka sections
/// </summary>
/// <remarks>Only values of 0 or 1 have been found</remarks>
public uint? UnknownRCValue1 { get; set; }
/// <summary>
/// One of four unknown values only observed on RC matroschka sections
/// </summary>
/// <remarks>Only values of 0 or 1 have been found</remarks>
public uint? UnknownRCValue2 { get; set; }
/// <summary>
/// One of four unknown values only observed on RC matroschka sections
/// </summary>
/// <remarks>Only values of 0 or 1 have been found</remarks>
public uint? UnknownRCValue3 { get; set; }
/// <summary>
/// Unknown 32-character string only observed on RC matroschka sections.
/// Due to encryption on later DFA-encrypted RC executables, this is the
/// most reliable way to identify which executables are using the same or
/// a different key (even if the encrypted executables inside can be
/// different).
/// </summary>
public string? UnknownRCString { get; set; }
/// <summary>
/// One of four unknown values only observed on RC matroschka sections,
/// possibly padding for alignment
/// </summary>
/// <remarks>Only a value of 0 have been found</remarks>
public uint? UnknownRCValue4 { get; set; }
#endregion
/// <summary>
/// Entries array whose length is given by <see cref="EntryCount"/>
/// </summary>
public MatroshkaEntry[]? Entries { get; set; }
}
}