diff --git a/SabreTools.Models/SecuROM/Constants.cs b/SabreTools.Models/SecuROM/Constants.cs
index 362307e..f5b7efd 100644
--- a/SabreTools.Models/SecuROM/Constants.cs
+++ b/SabreTools.Models/SecuROM/Constants.cs
@@ -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
}
}
\ No newline at end of file
diff --git a/SabreTools.Models/SecuROM/DFAFile.cs b/SabreTools.Models/SecuROM/DFAFile.cs
index 1a87f9a..69dbfd4 100644
--- a/SabreTools.Models/SecuROM/DFAFile.cs
+++ b/SabreTools.Models/SecuROM/DFAFile.cs
@@ -8,7 +8,7 @@ namespace SabreTools.Models.SecuROM
public class DFAFile
{
///
- /// "SDFA" 0x04 0x00 0x00 0x00;
+ /// "SDFA" 0x04 0x00 0x00 0x00
///
/// 8 bytes
public byte[]? Signature { get; set; }
diff --git a/SabreTools.Models/SecuROM/Enums.cs b/SabreTools.Models/SecuROM/Enums.cs
new file mode 100644
index 0000000..ab05174
--- /dev/null
+++ b/SabreTools.Models/SecuROM/Enums.cs
@@ -0,0 +1,36 @@
+namespace SabreTools.Models.SecuROM
+{
+ public enum MatroshkaEntryType : uint
+ {
+ ///
+ /// Helper or activation executable
+ ///
+ Helper = 0x01,
+
+ ///
+ /// Main executable, usually one of the following:
+ /// - RC-encrypted executable to be decrypted later
+ /// - Main game program executable
+ /// - Revoker executable
+ ///
+ /// Usually the second entry
+ Main = 0x02,
+
+ ///
+ /// Required libraries for the main executable
+ ///
+ ///
+ /// Examples include:
+ /// - DFA.dll for RC-encrypted executables
+ /// - paul.dll for PA-protected games
+ /// - remover.exe for revocation
+ /// executables.
+ ///
+ Dependency = 0x04,
+
+ ///
+ /// Similar use to
+ ///
+ Unknown0x08 = 0x08,
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/SecuROM/MatroshkaEntry.cs b/SabreTools.Models/SecuROM/MatroshkaEntry.cs
new file mode 100644
index 0000000..ae0da16
--- /dev/null
+++ b/SabreTools.Models/SecuROM/MatroshkaEntry.cs
@@ -0,0 +1,57 @@
+namespace SabreTools.Models.SecuROM
+{
+ public class MatroshkaEntry
+ {
+ ///
+ /// File entry path
+ /// - Older versions are always 256 bytes
+ /// - Newer versions are always 512 bytes
+ ///
+ /// Length may be tied to unknown values in header
+ public byte[]? Path { get; set; }
+
+ ///
+ /// Type of the entry data
+ ///
+ public MatroshkaEntryType EntryType { get; set; }
+
+ ///
+ /// Data size
+ ///
+ public uint Size { get; set; }
+
+ ///
+ /// Data offset within the package
+ ///
+ public uint Offset { get; set; }
+
+ ///
+ /// Unknown value only seen in later versions
+ ///
+ public uint? Unknown { get; set; }
+
+ ///
+ /// File modification time, stored in NTFS filetime.
+ ///
+ ///
+ public ulong ModifiedTime { get; set; }
+
+ ///
+ /// File creation time, stored in NTFS filetime.
+ ///
+ ///
+ public ulong CreatedTime { get; set; }
+
+ ///
+ /// File access time, stored in NTFS filetime.
+ ///
+ ///
+ public ulong AccessedTime { get; set; }
+
+ ///
+ /// MD5 hash of the data
+ ///
+ /// 16 bytes
+ public byte[]? MD5 { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/SabreTools.Models/SecuROM/MatroshkaPackage.cs b/SabreTools.Models/SecuROM/MatroshkaPackage.cs
new file mode 100644
index 0000000..a0a80e7
--- /dev/null
+++ b/SabreTools.Models/SecuROM/MatroshkaPackage.cs
@@ -0,0 +1,70 @@
+namespace SabreTools.Models.SecuROM
+{
+ ///
+ /// 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.
+ ///
+ public class MatroshkaPackage
+ {
+ ///
+ /// "MatR"
+ ///
+ /// 4 bytes
+ public string? Signature { get; set; }
+
+ ///
+ /// Number of internal entries
+ ///
+ public uint EntryCount { get; set; }
+
+ #region Release Control only
+
+ ///
+ /// One of four unknown values only observed on RC matroschka sections
+ ///
+ /// Only values of 0 or 1 have been found
+ public uint? UnknownRCValue1 { get; set; }
+
+ ///
+ /// One of four unknown values only observed on RC matroschka sections
+ ///
+ /// Only values of 0 or 1 have been found
+ public uint? UnknownRCValue2 { get; set; }
+
+ ///
+ /// One of four unknown values only observed on RC matroschka sections
+ ///
+ /// Only values of 0 or 1 have been found
+ public uint? UnknownRCValue3 { get; set; }
+
+ ///
+ /// 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).
+ ///
+ public string? UnknownRCString { get; set; }
+
+ ///
+ /// One of four unknown values only observed on RC matroschka sections,
+ /// possibly padding for alignment
+ ///
+ /// Only a value of 0 have been found
+ public uint? UnknownRCValue4 { get; set; }
+
+ #endregion
+
+ ///
+ /// Entries array whose length is given by
+ ///
+ public MatroshkaEntry[]? Entries { get; set; }
+ }
+}
\ No newline at end of file