mirror of
https://github.com/SabreTools/SabreTools.Models.git
synced 2026-02-08 05:44:30 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f18b6c8850 | ||
|
|
8f1e49e464 | ||
|
|
6547242f93 | ||
|
|
edf00f3ab2 | ||
|
|
bce4736037 | ||
|
|
81f28974c0 | ||
|
|
30ebe84af4 | ||
|
|
b07fbdedd6 | ||
|
|
cd8fff4a86 | ||
|
|
3d3275e3cb | ||
|
|
4c76ce1230 | ||
|
|
0c4e3b4bf2 | ||
|
|
e8f4386199 | ||
|
|
ab66ccf3c5 | ||
|
|
cc60d54a33 | ||
|
|
e805f4cb9a | ||
|
|
328c893a38 |
11
.github/workflows/build_and_test.yml
vendored
11
.github/workflows/build_and_test.yml
vendored
@@ -16,7 +16,10 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
8.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
@@ -24,12 +27,6 @@ jobs:
|
||||
- name: Run publish script
|
||||
run: ./publish-nix.sh
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'Nuget Package'
|
||||
path: "*.nupkg,*.snupkg"
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
|
||||
5
.github/workflows/check_pr.yml
vendored
5
.github/workflows/check_pr.yml
vendored
@@ -11,7 +11,10 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 9.0.x
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
8.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
|
||||
16
SabreTools.Models/Listxml/Mess.cs
Normal file
16
SabreTools.Models/Listxml/Mess.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace SabreTools.Models.Listxml
|
||||
{
|
||||
[XmlRoot("mess")]
|
||||
public class Mess
|
||||
{
|
||||
[XmlAttribute("version")]
|
||||
public string? Version { get; set; }
|
||||
|
||||
[XmlElement("machine", typeof(Machine))]
|
||||
[XmlElement("game", typeof(Game))]
|
||||
public GameBase[]? Game { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,9 @@ namespace SabreTools.Models.Logiqx
|
||||
[XmlAttribute("name")]
|
||||
public string? Name { get; set; }
|
||||
|
||||
[XmlElement("dir", typeof(Game))]
|
||||
public Dir[]? Subdir { get; set; }
|
||||
|
||||
[XmlElement("game", typeof(Game))]
|
||||
[XmlElement("machine", typeof(Machine))]
|
||||
public GameBase[]? Game { get; set; }
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace SabreTools.Models.Metadata
|
||||
|
||||
string[]? asArray = Read<string[]>(key);
|
||||
if (asArray != null)
|
||||
#if NETFRAMEWORK
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0
|
||||
return string.Join(",", asArray);
|
||||
#else
|
||||
return string.Join(',', asArray);
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<NoWarn>CS0618</NoWarn>
|
||||
<NoWarn>CS0618;NETSDK1215</NoWarn>
|
||||
<Nullable>enable</Nullable>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.5.8</Version>
|
||||
<Version>1.6.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Description>Common models used by other SabreTools projects</Description>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2022-2024</Copyright>
|
||||
<Copyright>Copyright (c) Matt Nadareski 2022-2025</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Models</RepositoryUrl>
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SabreTools.Models.SafeDisc
|
||||
namespace SabreTools.Models.SafeDisc
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
|
||||
122
SabreTools.Models/SecuROM/Constants.cs
Normal file
122
SabreTools.Models/SecuROM/Constants.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
namespace SabreTools.Models.SecuROM
|
||||
{
|
||||
public static class Constants
|
||||
{
|
||||
#region DFA
|
||||
|
||||
public static readonly string DFAMagicString = "SDFA" + (char)0x04 + (char)0x00 + (char)0x00 + (char)0x00;
|
||||
|
||||
public static readonly byte[] DFAMagicBytes = [0x53, 0x44, 0x46, 0x41, 0x04, 0x00, 0x00, 0x00];
|
||||
|
||||
#region Keys
|
||||
|
||||
/// <summary>
|
||||
/// 128-bit value, possibly a GUID
|
||||
/// </summary>
|
||||
public const string COID = "COID";
|
||||
|
||||
/// <summary>
|
||||
/// 128-bit value, possibly a GUID
|
||||
/// </summary>
|
||||
/// <remarks>Only a value of D0 A2 25 C7 16 20 B7 43 99 74 2A BB 39 6B C3 57 has been found</remarks>
|
||||
public const string CUID = "CUID";
|
||||
|
||||
/// <summary>
|
||||
/// Encrypted data section
|
||||
/// </summary>
|
||||
public const string DATA = "DATA";
|
||||
|
||||
/// <summary>
|
||||
/// Header version (?)
|
||||
/// </summary>
|
||||
/// <remarks>Only a value of 0C 00 00 00 has been found</remarks>
|
||||
public const string HVER = "HVER";
|
||||
|
||||
/// <summary>
|
||||
/// Unknown value
|
||||
/// </summary>
|
||||
public const string INVE = "INVE";
|
||||
|
||||
/// <summary>
|
||||
/// Unknown key value
|
||||
/// </summary>
|
||||
public const string KEYB = "KEYB";
|
||||
|
||||
/// <summary>
|
||||
/// Unknown key value
|
||||
/// </summary>
|
||||
public const string KEYL = "KEYL";
|
||||
|
||||
/// <summary>
|
||||
/// MAC address (?)
|
||||
/// </summary>
|
||||
public const string MAC1 = "MAC1";
|
||||
|
||||
/// <summary>
|
||||
/// MAC address (?)
|
||||
/// </summary>
|
||||
public const string MAC2 = "MAC2";
|
||||
|
||||
/// <summary>
|
||||
/// Padding section
|
||||
/// </summary>
|
||||
/// <remarks>Only a length of 832 has been found</remarks>
|
||||
public const string PAD1 = "PAD1";
|
||||
|
||||
/// <summary>
|
||||
/// Private key ID (?)
|
||||
/// </summary>
|
||||
public const string PKID = "PKID";
|
||||
|
||||
/// <summary>
|
||||
/// Private key name (?)
|
||||
/// </summary>
|
||||
/// <remarks>Seemingly a UTF-16 string</remarks>
|
||||
public const string PKNA = "PKNA";
|
||||
|
||||
/// <summary>
|
||||
/// Size of the decrypted executable
|
||||
/// </summary>
|
||||
public const string RAWS = "RAWS";
|
||||
|
||||
/// <summary>
|
||||
/// 128-bit value, possibly a GUID
|
||||
/// </summary>
|
||||
/// <remarks>Only a value of all zeroes has been found</remarks>
|
||||
public const string SCID = "SCID";
|
||||
|
||||
/// <summary>
|
||||
/// Time stored in NTFS filetime
|
||||
/// </summary>
|
||||
/// <see href="https://learn.microsoft.com/en-us/windows/win32/sysinfo/file-times"/>
|
||||
public const string TIME = "TIME";
|
||||
|
||||
/// <summary>
|
||||
/// First URL to connect to
|
||||
/// </summary>
|
||||
public const string UR01 = "UR01";
|
||||
|
||||
/// <summary>
|
||||
/// Second URL to connect to
|
||||
/// </summary>
|
||||
public const string UR02 = "UR02";
|
||||
|
||||
/// <summary>
|
||||
/// Unknown value
|
||||
/// </summary>
|
||||
public const string XSPF = "XSPF";
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Matroshka
|
||||
|
||||
public const string MatroshkaMagicString = "MatR";
|
||||
|
||||
public static readonly byte[] MatroshkaMagicBytes = [0x4D, 0x61, 0x74, 0x52];
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
24
SabreTools.Models/SecuROM/DFAEntry.cs
Normal file
24
SabreTools.Models/SecuROM/DFAEntry.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace SabreTools.Models.SecuROM
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single key-length-value tuple in a
|
||||
/// SecuROM DFA file
|
||||
/// </summary>
|
||||
public class DFAEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Entry name, always 4 ASCII characters
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Length of the value in bytes
|
||||
/// </summary>
|
||||
public uint Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of the entry whose length is given by <see cref="Length"/>
|
||||
/// </summary>
|
||||
public byte[]? Value { get; set; }
|
||||
}
|
||||
}
|
||||
27
SabreTools.Models/SecuROM/DFAFile.cs
Normal file
27
SabreTools.Models/SecuROM/DFAFile.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace SabreTools.Models.SecuROM
|
||||
{
|
||||
/// <remarks>
|
||||
/// Most DFA-protected files seem to also have additional encryption,
|
||||
/// possibly SecuROM DFE. Only early RC-encrypted executables can be
|
||||
/// parsed beyond the initial header.
|
||||
/// </remarks>
|
||||
public class DFAFile
|
||||
{
|
||||
/// <summary>
|
||||
/// "SDFA" 0x04 0x00 0x00 0x00
|
||||
/// </summary>
|
||||
/// <remarks>8 bytes</remarks>
|
||||
public byte[]? Signature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unknown value, possibly a block or header size
|
||||
/// </summary>
|
||||
/// <remarks>Only a value of 0x400 has been found</remarks>
|
||||
public uint BlockOrHeaderSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All entries in the file
|
||||
/// </summary>
|
||||
public DFAEntry[]? Entries { get; set; }
|
||||
}
|
||||
}
|
||||
36
SabreTools.Models/SecuROM/Enums.cs
Normal file
36
SabreTools.Models/SecuROM/Enums.cs
Normal 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,
|
||||
}
|
||||
}
|
||||
59
SabreTools.Models/SecuROM/MatroshkaEntry.cs
Normal file
59
SabreTools.Models/SecuROM/MatroshkaEntry.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
namespace SabreTools.Models.SecuROM
|
||||
{
|
||||
public class MatroshkaEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// File entry path, either 256 or 512 bytes
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Versions without a key prefix are 256 bytes.
|
||||
/// Versions with key values either are 256 or 512 bytes.
|
||||
/// </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>
|
||||
/// <remarks>Possibly indicates that the offset is a 64-bit value</remarks>
|
||||
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; }
|
||||
}
|
||||
}
|
||||
79
SabreTools.Models/SecuROM/MatroshkaPackage.cs
Normal file
79
SabreTools.Models/SecuROM/MatroshkaPackage.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
namespace SabreTools.Models.SecuROM
|
||||
{
|
||||
/// <summary>
|
||||
/// Securom Matroschka Package PE section
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
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
|
||||
|
||||
// The combination of the 3 following values have only been seen in
|
||||
// one of 3 distinct patterns. The meaning of these patterns is unknown.
|
||||
// - 0 0 1
|
||||
// - 0 1 1
|
||||
// - 1 1 1
|
||||
// These values do not seem to have a link to whether the paths included
|
||||
// in entries are 256- or 512-byte. There also do not seem to be any links
|
||||
// between these values and the hex string values.
|
||||
|
||||
/// <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 a value of 1 has been found</remarks>
|
||||
public uint? UnknownRCValue3 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 32-character hex string
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Due to encryption on later DFA-encrypted RC executables, this is the
|
||||
/// most reliable way to identify which executables are using the same key.
|
||||
/// </remarks>
|
||||
public string? KeyHexString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Padding for alignment, always 0x00000000
|
||||
/// </summary>
|
||||
public uint? Padding { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Entries array whose length is given by <see cref="EntryCount"/>
|
||||
/// </summary>
|
||||
public MatroshkaEntry[]? Entries { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user