Compare commits

..

29 Commits

Author SHA1 Message Date
Matt Nadareski
4989956a91 Bump version 2024-09-28 13:13:06 -04:00
Matt Nadareski
14849f45da Remove redundant reports in Macrovision code 2024-09-27 13:24:19 -04:00
TheRogueArchivist
28ebc14fe1 Fix various archive formats not extracting folders (#323)
Fixes folder extraction for 7z, RAR, and WinRAR SFX. Applied same fix to tar, but more is needed for it to work properly.
2024-09-26 01:15:38 -04:00
TheRogueArchivist
54cb996fce [WIP] Add 7-Zip SFX extraction (#321)
* Add 7-Zip SFX extraction

Newest SharpCompress added support for extracting 7-Zip SFX files, so we can add support for them here too.

* Clean up 7z SFX extraction method

* Remove unneeded import

* Use file instead of stream for 7z SFX

* Update 7z SFX to be more consistent with other packers
2024-09-26 00:30:25 -04:00
Matt Nadareski
8df58fa4d4 This doesn't inherit from anything 2024-09-25 11:25:52 -04:00
TheRogueArchivist
422add9827 Update SharpCompress to 0.38.0 (#320) 2024-09-25 11:01:16 -04:00
TheRogueArchivist
59435903eb Small update to nProtect comments (#319)
Add new confirmed game to use GameGuard, and start a known version list.
2024-09-12 02:33:17 -04:00
TheRogueArchivist
95ee417e00 Small update to SafeWrap comments (#318)
* Small update to SafeWrap comments

* Further additions to SafeWrap comments
2024-09-05 01:22:11 -04:00
Matt Nadareski
df913372bf Add more SecuROM PA checks (fixes #313) 2024-08-08 08:55:46 -04:00
TheRogueArchivist
2f1c76b7f9 Add EA Anti Cheat detection (#314)
* Add EA Anti Cheat detection

* Make a check more exact
2024-08-02 12:34:43 -04:00
Matt Nadareski
18e57c8182 Fix minor formatting issue 2024-08-02 12:23:05 -04:00
TheRogueArchivist
b4e2117c4b Confirm one SafeCast version (#309) 2024-08-02 00:07:12 -04:00
Matt Nadareski
1bb5ff9e18 Fix README a bit 2024-07-20 21:54:55 -04:00
TheRogueArchivist
a46cae469d Fix scans that use directory name in Windows (#312)
Removes ``.Replace("\\", "/")``, as it was messing with folder paths on Windows.
2024-07-13 01:29:45 -04:00
TheRogueArchivist
b564ff214d Add initial Channelware detection (#311) 2024-07-12 12:35:26 -04:00
TheRogueArchivist
0744a10de0 Improve phenoProtect detection (#307) 2024-07-04 22:16:11 -04:00
HeroponRikiBestest
343ca9497e Fix #.##.xx version number writing second x digit to first digit (#310) 2024-07-04 22:13:49 -04:00
Matt Nadareski
861958527d Fix under-matched runtimes 2024-06-26 12:44:32 -04:00
Matt Nadareski
a6b9dca291 Only copy DLLs for win-x86 2024-06-26 11:53:10 -04:00
Matt Nadareski
18c05cb49d Update workflow runtimes 2024-06-26 11:34:31 -04:00
Matt Nadareski
ed3e58af6c Update publishing to cooler version 2024-06-26 11:32:20 -04:00
Matt Nadareski
e3eed76826 Make debug table reading safer, kinda 2024-06-20 11:26:20 -04:00
Matt Nadareski
7eb86b223f Fix build script 2024-06-17 16:16:11 -04:00
Matt Nadareski
a4ee4529ca Bump version 2024-06-17 16:15:04 -04:00
Matt Nadareski
abc68d8503 Update Serialization to 1.6.7 2024-06-13 11:20:33 -04:00
TheRogueArchivist
aaff4bad1b Add new Alpha-ROM checks (#306) 2024-06-07 13:11:24 -04:00
TheRogueArchivist
d5c81857c3 Update Roxxe detections (#305) 2024-06-05 09:37:37 -04:00
TheRogueArchivist
c2594cdd2d Add checks for Macrovision SecDrv Update Installer (#304) 2024-06-02 19:43:15 -04:00
Matt Nadareski
2412042cef Update Serialization to 1.6.6 2024-06-02 19:42:49 -04:00
28 changed files with 587 additions and 128 deletions

View File

@@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
project: [Test]
runtime: [win-x86, win-x64, linux-x64, osx-x64] #[win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64]
runtime: [win-x86, win-x64, win-arm64, linux-x64, linux-arm64, osx-x64]
framework: [net8.0] #[net20, net35, net40, net452, net472, net48, netcoreapp3.1, net5.0, net6.0, net7.0, net8.0]
conf: [Release, Debug]

View File

@@ -11,7 +11,7 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.1.12</Version>
<Version>3.1.14</Version>
<!-- Mostly added due to external libraries -->
<WarningsNotAsErrors>CS0162;CS0612;CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8618;CS8625;CS8634;CS8765;IL3000;NU5100</WarningsNotAsErrors>
@@ -53,7 +53,7 @@
</PropertyGroup>
<!-- These are needed for dealing with native Windows DLLs -->
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`))">
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND $(RuntimeIdentifier.StartsWith(`win-x86`))">
<Content Include="*.dll">
<Pack>true</Pack>
<PackagePath>contentFiles;content</PackagePath>
@@ -75,7 +75,7 @@
<PackageReference Include="OpenMcdf" Version="2.3.1" />
</ItemGroup>
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net452`))">
<PackageReference Include="SharpCompress" Version="0.37.2" />
<PackageReference Include="SharpCompress" Version="0.38.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith(`net4`)) AND !$(TargetFramework.StartsWith(`net40`))">
@@ -88,7 +88,7 @@
<PackageReference Include="SabreTools.IO" Version="1.4.11" />
<PackageReference Include="SabreTools.Matching" Version="1.3.1" />
<PackageReference Include="SabreTools.Models" Version="1.4.8" />
<PackageReference Include="SabreTools.Serialization" Version="1.6.5" />
<PackageReference Include="SabreTools.Serialization" Version="1.6.7" />
<PackageReference Include="UnshieldSharp" Version="1.8.3" />
<PackageReference Include="WiseUnpacker" Version="1.4.2" />
</ItemGroup>

View File

@@ -50,7 +50,14 @@ namespace BinaryObjectScanner.FileType
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)

View File

@@ -50,7 +50,14 @@ namespace BinaryObjectScanner.FileType
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)

View File

@@ -50,7 +50,15 @@ namespace BinaryObjectScanner.FileType
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
// TODO: Fix bug with extracting folders from tar.
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)

View File

@@ -54,6 +54,14 @@ namespace BinaryObjectScanner.FileType
else if (fileContent.Contains("Please enter a valid registration number"))
protections.Add("CD-Key / Serial");
// Channelware
// Found in "README.TXT" in Redump entry 116358.
if (fileContent.Contains("This application is a Channelware-activated product."))
protections.Add("Channelware");
// Found in "Swr.dat" in the "TOYSTORY" installation folder from Redump entry 12354.
if (fileContent.Contains("cwsw.com/authts"))
protections.Add("Channelware");
// CopyKiller
// Found in "autorun.dat" in CopyKiller versions 3.62 and 3.64.
if (fileContent.Contains("CopyKiller CD-Protection V3.6x"))
@@ -100,8 +108,14 @@ namespace BinaryObjectScanner.FileType
protections.Add("MediaMax CD-3");
// phenoProtect
// Found in Redump entry 84082.
if (fileContent.Contains("phenoProtect"))
protections.Add("phenoProtect");
// Additional check to minimize overmatching.
if (fileContent.Contains("InstallSHIELD Software Coporation"))
// Found in Redump entry 102493.
if (fileContent.Contains("COPYPROTECTION_FAILEDR"))
protections.Add("phenoProtect");
// Rainbow Sentinel
// Found in "SENTW95.HLP" and "SENTINEL.HLP" in BA entry "Autodesk AutoCAD LT 98 (1998) (CD) [English] [Dutch]".

View File

@@ -1,10 +1,16 @@
using System;
using System.IO;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
#if NET462_OR_GREATER || NETCOREAPP
using SharpCompress.Archives;
using SharpCompress.Archives.SevenZip;
using SharpCompress.Readers;
#endif
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
public class SevenZipSFX : IExtractablePortableExecutable, IPortableExecutableCheck
{
/// <inheritdoc/>
@@ -47,7 +53,57 @@ namespace BinaryObjectScanner.Packer
/// <inheritdoc/>
public string? Extract(string file, PortableExecutable pex, bool includeDebug)
{
if (!File.Exists(file))
return null;
#if NET462_OR_GREATER || NETCOREAPP
try
{
// Create a temp output directory
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
using (SevenZipArchive sevenZipFile = SevenZipArchive.Open(file, new ReaderOptions() { LookForHeader = true }))
{
foreach (var entry in sevenZipFile.Entries)
{
try
{
// If the entry is a directory
if (entry.IsDirectory)
continue;
// If the entry has an invalid key
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
}
}
}
return tempPath;
}
catch (Exception ex)
{
if (includeDebug) Console.WriteLine(ex);
return null;
}
#else
return null;
#endif
}
}
}

View File

@@ -39,15 +39,15 @@ namespace BinaryObjectScanner.Packer
try
{
// Should be using stream instead of file, but stream fails to extract anything. My guess is that the executable portion of the archive is causing stream to fail, but not file.
using (RarArchive zipFile = RarArchive.Open(file, new ReaderOptions() { LookForHeader = true }))
using (RarArchive rarFile = RarArchive.Open(file, new ReaderOptions() { LookForHeader = true }))
{
if (!zipFile.IsComplete)
if (!rarFile.IsComplete)
return null;
string tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempPath);
foreach (var entry in zipFile.Entries)
foreach (var entry in rarFile.Entries)
{
try
{
@@ -59,7 +59,14 @@ namespace BinaryObjectScanner.Packer
if (entry.Key == null)
continue;
// If we have a partial entry due to an incomplete multi-part archive, skip it
if (!entry.IsComplete)
continue;
string tempFile = Path.Combine(tempPath, entry.Key);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
entry.WriteToFile(tempFile);
}
catch (Exception ex)

View File

@@ -76,7 +76,6 @@ namespace BinaryObjectScanner.Packer
/// <summary>
/// Handle common extraction between executable types
/// </summary>
/// <inheritdoc/>
public static string? Extract(string file, bool includeDebug)
{
#if NET462_OR_GREATER || NETCOREAPP

View File

@@ -71,6 +71,12 @@ namespace BinaryObjectScanner.Protection
{
if (strs.Any(s => s.Contains("This Game is Japan Only")))
return "Alpha-ROM";
// Found in "Filechk.exe" in Redump entry 115358.
if (strs.Any(s => s.Contains("AlphaCheck.exe")))
return "Alpha-ROM";
// Found in "Uninstall.exe" in Redump entry 115358.
if (strs.Any(s => s.Contains("AlphaCheck.dat")))
return "Alpha-ROM";
}
// Get the overlay data, if it exists

View File

@@ -0,0 +1,121 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using System.IO;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// Channelware was an online activation DRM.
///
/// Official websites:
///
/// https://web.archive.org/web/19980212121046/http://www.channelware.com/index.html
/// https://web.archive.org/web/20021002225705/http://cwsw.com/Home/default.asp
/// https://web.archive.org/web/20040101180929/http://www.netactive.com/Home/
///
/// TODO:
/// Add version detection. Redump entry 116358 is version 1.x and Redump entry 12354 is 2.x, but the file versions are inconsistent.
/// Investigate "NetActive Reach", which is is either a newer version of this DRM, or a new DRM created by the same company. (https://web.archive.org/web/20040101162921/http://www.netactive.com/Products/)
/// </summary>
public class Channelware : IPathCheck, IPortableExecutableCheck
{
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
// Found in "AbeWincw.dll" in Redump entry 116358 and in "TOYSGMcw.dll" in the "TOYSTORY" installation folder from Redump entry 12354.
var name = pex.ProductName;
if (name?.Equals("ChannelWare Utilities") == true)
return "Channelware";
// Found in "cwbrowse.exe" in the "Channelware" folder installed from Redump entry 12354.
if (name?.Equals("Channelware Browser Launcher") == true)
return "Channelware";
// Found in "cwuninst.exe" in the "Channelware" folder installed from Redump entry 12354.
if (name?.Equals("Channelware Launcher Uninstall Application") == true)
return "Channelware";
// Found in "cwbrowse.exe" in the "Channelware\CWBrowse" folder installed from Redump entry 116358.
if (name?.Equals("Channelware Authorization Server Browser Launcher") == true)
return "Channelware";
name = pex.FileDescription;
// Found in "cwuninst.exe" in the "Channelware" folder installed from Redump entry 12354.
if (name?.Equals("Channelware Launcher Uninstall") == true)
return "Channelware";
name = pex.LegalTrademarks;
// Found in "CWAuto.dll" and "Upgrader.exe" in the "TOYSTORY" installation folder from Redump entry 12354.
if (name?.Equals("Channelware") == true)
return "Channelware";
return null;
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
var matchers = new List<PathMatchSet>
{
// Found in Redump entries 12354 and 116358.
new(new FilePathMatch("cwlaunch.hlp"), "Channelware"),
// Found in the "Channelware\CWBrowse" folder installed from Redump entry 116358, and in the "Channelware" folder installed from Redump entry 12354.
new(new FilePathMatch("cwbrowse.exe"), "Channelware"),
// Found in the "Channelware" folder installed from Redump entry 12354.
new(new FilePathMatch("cwuninst.exe"), "Channelware"),
new(new FilePathMatch("chanwr.ini"), "Channelware"),
new(new FilePathMatch("CWAuto.dll"), "Channelware"),
// Found in Redump entry 116358.
new(Path.Combine("CWare", "install.exe"), "Channelware"),
// Found in Redump entry 12354.
new(Path.Combine("cware", "Install.exe"), "Channelware"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// Found in Redump entries 12354 and 116358.
new(new FilePathMatch("cwlaunch.hlp"), "Channelware"),
// Found in the "Channelware\CWBrowse" folder installed from Redump entry 116358, and in the "Channelware" folder installed from Redump entry 12354.
new(new FilePathMatch("cwbrowse.exe"), "Channelware"),
// Found in the "Channelware" folder installed from Redump entry 12354.
new(new FilePathMatch("cwuninst.exe"), "Channelware"),
new(new FilePathMatch("chanwr.ini"), "Channelware"),
new(new FilePathMatch("CWAuto.dll"), "Channelware"),
// Found in Redump entry 116358.
new(Path.Combine("CWare", "install.exe"), "Channelware"),
// Found in Redump entry 12354.
new(Path.Combine("cware", "Install.exe"), "Channelware"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -0,0 +1,88 @@
#if NET40_OR_GREATER || NETCOREAPP
using System.Collections.Concurrent;
#endif
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
/// <summary>
/// EA Anti Cheat is a kernel-level anti-cheat developed and used by EA. (https://www.ea.com/security/news/eaac-deep-dive).
/// List of games that contain EA Anti Cheat on Steam: https://steamdb.info/tech/AntiCheat/EA_AntiCheat/
///
/// An EasyAntiCheat installer is present in the file "EAAntiCheat.Installer.Tool.exe" found in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
/// This could indicate that EasyAntiCheat is directly integrated into EA Anti Cheat.
///
/// The internal name appears to be "skyfall", as this is the Internal Name set to several EA Anti Cheat files, and the string "C:\dev\gitlab-runner\builds\r5uPUG7E\0\anticheat\skyfall\Build\Retail\EAAntiCheat.Installer.pdb" is present in "EAAntiCheat.Installer.Tool.exe".
/// </summary>
public class EAAntiCheat : IPathCheck, IPortableExecutableCheck
{
// TODO: Add support for detecting older versions, especially versions made before Easy Anti-Cheat was purchased by Epic Games.
/// <inheritdoc/>
public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
if (sections == null)
return null;
var name = pex.FileDescription;
// Found in "EAAntiCheat.GameServiceLauncher.exe" and "EAAntiCheat.Installer.exe" in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
if (!string.IsNullOrEmpty(name) && name!.Contains("EA Anticheat"))
return "EA Anti Cheat";
name = pex.ProductName;
// Found in "EAAntiCheat.GameServiceLauncher.exe" and "EAAntiCheat.Installer.exe" in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
if (!string.IsNullOrEmpty(name) && name!.Contains("EA Anticheat"))
return "EA Anti Cheat";
name = pex.InternalName;
// Found in "EAAntiCheat.GameServiceLauncher.exe" and "EAAntiCheat.Installer.exe" in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
if (!string.IsNullOrEmpty(name) && name!.Equals("skyfall"))
return "EA Anti Cheat";
// TODO: Add check for "EA SPEAR AntiCheat Engineering" in ASN.1 certificate data. Found in files "EAAntiCheat.GameServiceLauncher.dll", "EAAntiCheat.GameServiceLauncher.exe", "EAAntiCheat.Installer.exe", and "preloader_l.dll".
return null;
}
/// <inheritdoc/>
#if NET20 || NET35
public Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#else
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files)
#endif
{
var matchers = new List<PathMatchSet>
{
// Found in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
new(new FilePathMatch("EAAntiCheat.cfg"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.GameServiceLauncher.dll"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.GameServiceLauncher.exe"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.splash.png"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.Installer.exe"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.Installer.Tool.exe"), "EA Anti Cheat"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
// Found in "Plants vs. Zombies: Battle for Neighborville" (Steam Depot 1262241, Manifest 8124759833120741594).
new(new FilePathMatch("EAAntiCheat.cfg"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.GameServiceLauncher.dll"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.GameServiceLauncher.exe"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.splash.png"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.Installer.exe"), "EA Anti Cheat"),
new(new FilePathMatch("EAAntiCheat.Installer.Tool.exe"), "EA Anti Cheat"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);
}
}
}

View File

@@ -63,20 +63,20 @@ namespace BinaryObjectScanner.Protection
new(new List<PathMatch>
{
#if NET20 || NET35
new(Path.Combine(Path.Combine("BIN", "WIN32"), "MQ2SETUP.EXE").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine(Path.Combine("BIN", "WIN32"), "MQSTART.EXE").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine(Path.Combine("BIN", "WIN32"), "MQ2SETUP.EXE")),
new(Path.Combine(Path.Combine("BIN", "WIN32"), "MQSTART.EXE")),
#else
new(Path.Combine("BIN", "WIN32", "MQ2SETUP.EXE").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("BIN", "WIN32", "MQSTART.EXE").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("BIN", "WIN32", "MQ2SETUP.EXE")),
new(Path.Combine("BIN", "WIN32", "MQSTART.EXE")),
#endif
}, "LabelGate CD2 Media Player"),
// All of these are also found present on all known LabelGate CD2 releases, though an additional file "RESERVED.DAT" is found in the same directory in at least one release (Product ID SVWC-7185)
new(new List<PathMatch>
{
new(Path.Combine("MQDISC", "LICENSE.TXT").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("MQDISC", "MQDISC.INI").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("MQDISC", "START.INI").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("MQDISC", "LICENSE.TXT")),
new(Path.Combine("MQDISC", "MQDISC.INI")),
new(Path.Combine("MQDISC", "START.INI")),
}, "LabelGate CD2"),
};

View File

@@ -72,6 +72,10 @@ namespace BinaryObjectScanner.Protection
return "SafeDisc Lite";
if (strs.Any(s => s.Contains("LTDLL_Unwrap")))
return "SafeDisc Lite";
// Present in "Setup.exe" from the earlier "safedisc.exe" driver update provided by Macrovision.
if (strs.Any(s => s.Contains("Failed to get the DRVMGT.DLL Setup API address")))
return "Macrovision SecDrv Update Installer";
}
var name = pex.FileDescription;
@@ -79,14 +83,23 @@ namespace BinaryObjectScanner.Protection
if (name?.Equals("SafeDisc SRV Tool APP", StringComparison.OrdinalIgnoreCase) == true)
return $"SafeDisc SRV Tool APP {GetSafeDiscDiagExecutableVersion(pex)}";
// Present in "Setup.exe" from the later "safedisc.exe" driver update provided by Macrovision.
if (name?.Equals("Macrovision SecDrv Update", StringComparison.OrdinalIgnoreCase) == true)
return "Macrovision SecDrv Update Installer";
// Present on all "CLOKSPL.DLL" versions before SafeDisc 1.06.000. Found on Redump entries 61731 and 66004.
name = pex.ProductName;
if (name?.Equals("SafeDisc CDROM Protection System", StringComparison.OrdinalIgnoreCase) == true)
return "SafeDisc 1.00.025-1.01.044";
// Present in "Diag.exe" files from SafeDisc 4.50.000+.
else if (name?.Equals("SafeDisc SRV Tool APP", StringComparison.OrdinalIgnoreCase) == true)
return $"SafeDisc SRV Tool APP {GetSafeDiscDiagExecutableVersion(pex)}";
// Present in "Setup.exe" from the later "safedisc.exe" driver update provided by Macrovision.
if (name?.Equals("Macrovision SecDrv Update", StringComparison.OrdinalIgnoreCase) == true)
return "Macrovision SecDrv Update Installer";
// Present on all "CLOKSPL.EXE" versions before SafeDisc 1.06.000. Found on Redump entries 61731 and 66004.
// Only found so far on SafeDisc 1.00.025-1.01.044, but the report is currently left generic due to the generic nature of the check.
name = pex.FileDescription;
@@ -95,8 +108,12 @@ namespace BinaryObjectScanner.Protection
// Found in Redump entries 20729 and 65569.
// Get the debug data
if (pex.FindCodeViewDebugTableByPath("SafeDisc").Any() || pex.FindCodeViewDebugTableByPath("Safedisk").Any())
return "SafeDisc";
try
{
if (pex.FindCodeViewDebugTableByPath("SafeDisc").Any() || pex.FindCodeViewDebugTableByPath("Safedisk").Any())
return "SafeDisc";
}
catch { }
// TODO: Investigate various section names:
// "STLPORT_" - Found in Redump entry 11638.

View File

@@ -7,7 +7,7 @@ namespace BinaryObjectScanner.Protection
/// It's used (to an unknown extent) within SafeCast and SafeDisc (https://web.archive.org/web/20030829044647/http://www.macrovision.com:80/solutions/software/SafeWrap_FAQ_July2003.pdf Section #3).
/// It can be used separately from any other Macrovision product, such as (supposedly) for RioPort (https://www.cdrinfo.com/d7/content/macrovision-invests-next-generation-security-and-transport-technologies-internet-delivery).
/// No direct SafeWrap only sample has currently been found, nor is it exactly clear what parts of SafeCast/SafeDisc are SafeWrap.
/// It's claimed that SafeWrap uses one DLL and one .SYS "security driver" (https://www.cdrinfo.com/d7/content/macrovision-invests-next-generation-security-and-transport-technologies-internet-delivery Section #30).
/// It's claimed that SafeWrap uses one DLL and one .SYS "security driver" (https://web.archive.org/web/20030829044647/http://www.macrovision.com:80/solutions/software/SafeWrap_FAQ_July2003.pdf Section #30).
/// This would appear to be referring to the "drvmgt.dll" and "secdrv.sys" files, the latter of which is officially referred to as the "Macrovision SECURITY Driver" in some SafeDisc versions.
/// This may not be fully accurate, as not all of these files are known to always be used with SafeCast, though this does need further investigation.
/// The .stxt* sections found in various Macrovision products may indicate SafeWrap, as they started being used around the time that SafeWrap was made public.
@@ -18,13 +18,17 @@ namespace BinaryObjectScanner.Protection
///
/// Further information and resources:
/// Macrovision press release that mentions SafeWrap: https://www.sec.gov/Archives/edgar/data/1027443/000100547701501658/ex99-1.txt
/// Macrionvision "Tamper-proof" blurb advertising SafeWrap: https://web.archive.org/web/20030412093353/http://www.macrovision.com/solutions/software/tamper.php3
/// SafeAudio news that mentions SafeWrap: https://www.cdmediaworld.com/hardware/cdrom/news/0201/safeaudio_3.shtml
/// The titles for a few audio DRM FAQ's include the text "SafeWrap™ Frequently Asked Questions" in the page title, but this may be a copy-paste error:
/// https://web.archive.org/web/20030324080804/http://www.macrovision.com:80/solutions/audio/images/SafeAudio_FAQ_Public_5-02.pdf + https://web.archive.org/web/20030403050432/http://www.macrovision.com:80/solutions/audio/Audio_protection_FAQ_Public_March2003.pdf
/// Eclipse SafeAudio news that mentions SafeWrap: http://www.eclipsedata.com/PDFs/21.pdf
/// Report to congress that mentions SafeWrap: https://www.uspto.gov/sites/default/files/web/offices/dcom/olia/teachreport.pdf
/// Patent that mentions possibly using SafeWrap: https://patents.google.com/patent/US7493289B2/en
/// MacroSafe presentation that mentions current customer of SafeWrap/SafeCast/SafeDisc: https://slideplayer.com/slide/6840826/
/// List of DRM companies and products: https://www1.villanova.edu/villanova/generalcounsel/copyright/digitized/companies.html
/// Forum post that briefly mentions SafeWrap: https://www.ttlg.com/forums/showthread.php?t=70035
/// Forum post (with no replies) that asks for information about SafeWrap: https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/9167-macrovision-anti-code-tampering-tool
/// Document that mentions SafeWrap as third-party security tool: https://www.cs.clemson.edu/course/cpsc420/material/Papers/Guide_AppSecurity.pdf
/// Japanese PDF that mentions SafeWrap: https://ipsj.ixsq.nii.ac.jp/ej/index.php?action=pages_view_main&active_action=repository_action_common_download&item_id=64743&item_no=1&attribute_id=1&file_no=1&page_id=13&block_id=8
/// Korean PDF that mentions SafeWrap: http://contents.kocw.or.kr/contents4/document/lec/2012/KonKuk_glocal/Nohyounghee1/9.pdf

View File

@@ -275,6 +275,8 @@ namespace BinaryObjectScanner.Protection
if (!string.IsNullOrEmpty(safeDisc))
resultsList.Add(safeDisc!);
// Clean the result list
resultsList = CleanResultList(resultsList);
if (resultsList != null && resultsList.Count > 0)
return string.Join(", ", [.. resultsList]);
@@ -551,16 +553,26 @@ namespace BinaryObjectScanner.Protection
// Version 1.04.000/1.4.0.0 can be found in "cdac01aa.dll" and "cdac01ba.dll" from IA item "ejay_nestle_trial", but needs further research.
// Found in Redump entry 83145.
"2.11.010"
// Found in IA item microsoft-software-jukebox-for-toshiba-1.0.
or "2.11.020"
// Source not documented.
or "2.11.060"
or "2.16.050"
// Found in Redump entry 90157 / IA item microsoft-software-jukebox-usa-hp-oem.
or "2.41.000"
// Source not documented.
or "2.60.030"
or "2.67.010" => "SafeCast",
// SafeCast (Unconfirmed)
// Found in Adobe Photoshop according to http://www.reversing.be/article.php?story=2006102413541932
"2.41.000"
or "2.42.000"
"2.42.000"
// Source not documented.
or "2.50.030"
or "2.51.000" => "SafeCast (Unconfirmed - Please report to us on GitHub)",
@@ -571,6 +583,8 @@ namespace BinaryObjectScanner.Protection
// SafeDisc (Confirmed)
// Found in Redump entry 66005.
"1.00.025"
// Source not documented.
or "1.00.026"
or "1.00.030"
or "1.00.032"
@@ -638,12 +652,25 @@ namespace BinaryObjectScanner.Protection
};
}
private List<string>? CleanResultList(List<string>? resultsList)
private static List<string>? CleanResultList(List<string>? resultsList)
{
// If we have an invalid result list
if (resultsList == null || resultsList.Count == 0)
return resultsList;
// Remove duplicates
if (resultsList.Contains("Macrovision Protected Application"))
{
if (resultsList.Contains("Macrovision Protected Application [Version Expunged]"))
resultsList = resultsList.Where(r => r != "Macrovision Protected Application").ToList();
else if (resultsList.Contains("Macrovision Protected Application (Entry point not present in the stxt371 section. Executable is either unprotected or nonfunctional)"))
resultsList = resultsList.Where(r => r != "Macrovision Protected Application").ToList();
else if (resultsList.Contains("Macrovision Protected Application (Generic detection - Report to us on GitHub)"))
resultsList = resultsList.Where(r => r != "Macrovision Protected Application").ToList();
else if (resultsList.Contains("Macrovision Protected Application (Report this to us on GitHub)"))
resultsList = resultsList.Where(r => r != "Macrovision Protected Application").ToList();
}
// Get distinct and order
return [.. resultsList.Distinct().OrderBy(s => s)];
}

View File

@@ -79,10 +79,10 @@ namespace BinaryObjectScanner.Protection
// TODO: Investigate the consistency of "\OMGEXTRA\INDX0000.XML" and "\OMGEXTRA\INDX0001.XML", they seem to only appear when bonus content is present ("Touch" by Amerie).
new(new List<PathMatch>
{
new(Path.Combine("OMGAUDIO", "00AUDTOC.DAT").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("OMGAUDIO", "01AUDSTR.DAT").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("OMGAUDIO", "05SRPCDS.DAT").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("OMGEXTRA", "OMGSVC.DAT").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("OMGAUDIO", "00AUDTOC.DAT")),
new(Path.Combine("OMGAUDIO", "01AUDSTR.DAT")),
new(Path.Combine("OMGAUDIO", "05SRPCDS.DAT")),
new(Path.Combine("OMGEXTRA", "OMGSVC.DAT")),
}, "OpenMG"),
// Always found together on OpenMG releases ("Touch" by Amerie, Redump entry 95010, and product ID SVWC-7185).

View File

@@ -4,6 +4,8 @@
{
// Currently implemented as a text file check, more checks are likely possible but currently unknown.
// Current checks based off Redump entry 84082 are found in the InstallShield setup.inx file, but the game also checks if the original disc is present in the drive after installation as well, so it seems unlikely for the InstallShield check to be relevant at that stage.
// A later version of it can be found in Redump entry 102493, which is found in the InstallShield setup.ins file, and also has a disc check when the game is run. On top of this, there is also a serial number check present. It is currently unknown how to uniquely detect either of them.
// The disc checks may be completely generic and undetectable, as these checks seem to be more lax than the installer checks.
// <see href="https://github.com/TheRogueArchivist/DRML/blob/main/entries/phenoProtect/phenoProtect.md"/>
}
}

View File

@@ -52,6 +52,14 @@ namespace BinaryObjectScanner.Protection
// return "Roxxe (Possibly remnants)";
}
// If any dialog boxes match
// Found in "Data6.OWP" in IA item "game4u-22-cd".
if (pex.FindDialogBoxByItemTitle("SharpTiny Version 1.0").Any())
return "Roxxe";
// Found in "Data8.OWP" in IA item "game4u-22-cd".
else if (pex.FindDialogBoxByItemTitle("T32xWin Version 1.0").Any())
return "Roxxe";
return null;
}

View File

@@ -26,6 +26,14 @@ namespace BinaryObjectScanner.Protection
if (name?.Contains("SecuROM PA") == true)
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
name = pex.InternalName;
if (name?.Equals("paul.dll") == true)
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
else if (name?.Equals("paul_dll_activate_and_play.dll") == true)
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
else if (name?.Equals("paul_dll_preview_and_review.dll") == true)
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
name = pex.OriginalFilename;
if (name?.Equals("paul_dll_activate_and_play.dll") == true)
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
@@ -205,7 +213,7 @@ namespace BinaryObjectScanner.Protection
byte[] subSubVersion = new byte[2];
subSubVersion[0] = (byte)(fileContent[index] ^ 42);
index++;
subSubVersion[0] = (byte)(fileContent[index] ^ 8);
subSubVersion[1] = (byte)(fileContent[index] ^ 8);
index += 2;
byte[] subSubSubVersion = new byte[4];

View File

@@ -76,10 +76,10 @@ namespace BinaryObjectScanner.ProtectionType
new(new List<PathMatch>
{
// d37f70489207014d7d0fbaa43b081a93e8030498
new(Path.Combine("Sys", "Devx.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("Sys", "Devx.sys")),
// a0acbc2f8e321e4f30c913c095e28af444058249
new(Path.Combine("Sys", "VtPr.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("Sys", "VtPr.sys")),
// SHA-1 is variable, file size is 81,920 bytes
new FilePathMatch("Wave.aif"),
@@ -99,16 +99,16 @@ namespace BinaryObjectScanner.ProtectionType
new(new List<PathMatch>
{
// f82339d797be6da92f5d9dadeae9025385159057
new(Path.Combine("9x", "Tamlx.alf").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("9x", "Tamlx.alf")),
// 933c004d3043863f019f5ffaf63402a30e65026c
new(Path.Combine("9x", "Tamlx.apt").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("9x", "Tamlx.apt")),
// d45745fa6b0d23fe0ee12e330ab85d5bf4e0e776
new(Path.Combine("NT", "enodpl.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("NT", "enodpl.sys")),
// f111eba05ca6e9061c557547420847d7fdee657d
new(Path.Combine("NT", "litdpl.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("NT", "litdpl.sys")),
}, "TAGES"),
// Currently only known to exist in "XIII" and "Beyond Good & Evil" (Redump entries 8774-8776, 45940-45941, 18690-18693, and presumably 21320, 21321, 21323, and 36124).
@@ -127,16 +127,16 @@ namespace BinaryObjectScanner.ProtectionType
new(new List<PathMatch>
{
// 40826e95f3ad8031b6debe15aca052c701288e04
new(Path.Combine("9x", "hwpsgt.vxd").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("9x", "hwpsgt.vxd")),
// f82339d797be6da92f5d9dadeae9025385159057
new(Path.Combine("9x", "lemsgt.vxd").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("9x", "lemsgt.vxd")),
// 43f407ecdc0d87a3713126b757ccaad07ade285f
new(Path.Combine("NT", "hwpsgt.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("NT", "hwpsgt.sys")),
// 548dd6359abbcc8c84ce346d078664eeedc716f7
new(Path.Combine("NT", "lemsgt.sys").Replace("\\", "/"), useEndsWith: true),
new(Path.Combine("NT", "lemsgt.sys")),
}, "TAGES"),
// The following files are supposed to only be found inside the driver setup executables, and are present in at least version 5.2.0.1 (Redump entry 15976).

View File

@@ -22,7 +22,7 @@ namespace BinaryObjectScanner.Protection
{
var matchers = new List<PathMatchSet>
{
new(Path.Combine("ZDAT", "webmast.dxx").Replace("\\", "/"), "Tivola Ring Protection [Check disc for physical ring]"),
new(Path.Combine("ZDAT", "webmast.dxx"), "Tivola Ring Protection [Check disc for physical ring]"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
@@ -33,7 +33,7 @@ namespace BinaryObjectScanner.Protection
{
var matchers = new List<PathMatchSet>
{
new(Path.Combine("ZDAT", "webmast.dxx").Replace("\\", "/"), "Tivola Ring Protection [Check disc for physical ring]"),
new(Path.Combine("ZDAT", "webmast.dxx"), "Tivola Ring Protection [Check disc for physical ring]"),
};
return MatchUtil.GetFirstMatch(path, matchers, any: true);

View File

@@ -21,9 +21,9 @@ namespace BinaryObjectScanner.Protection
var matchers = new List<PathMatchSet>
{
#if NET20 || NET35
new(Path.Combine(Path.Combine(path, "Zzxzz"), "Zzz.aze").Replace("\\", "/"), "Zzxzz"),
new(Path.Combine(Path.Combine(path, "Zzxzz"), "Zzz.aze"), "Zzxzz"),
#else
new(Path.Combine(path, "Zzxzz", "Zzz.aze").Replace("\\", "/"), "Zzxzz"),
new(Path.Combine(path, "Zzxzz", "Zzz.aze"), "Zzxzz"),
#endif
new($"Zzxzz/", "Zzxzz"),
};

View File

@@ -13,6 +13,8 @@ namespace BinaryObjectScanner.Protection
///
/// nProtect GameGuard (https://nprotect.com/kr/b2b/prod_gg.html) is anti-cheat software used in a fair amount of online games.
/// Partial list of games that use GameGuard: https://en.wikipedia.org/wiki/NProtect_GameGuard.
/// Known versions of GameGuard:
/// "2024.2.27.1" - Found in GameGuard.des in "Soulworker" (Steam Depot 1377581, Manifest 5092481117079359342).
///
/// nProtect KeyCrypt is an anti-keylogging product that seemingly has other DRM functions as well, such as shutting down processes it deems unnecessary (https://en.wikipedia.org/wiki/INCA_Internet#nProtect_Netizen,_nProtect_Personal,_nProtect_Keycrypt)
/// TODO: Verify the exact functions of KeyCrypt.
@@ -42,7 +44,7 @@ namespace BinaryObjectScanner.Protection
var name = pex.FileDescription;
// Found in "GameGuard.des" in Redump entry 90526 and 99598.
// Found in "GameGuard.des" in Redump entry 90526 and 99598, and "Soulworker" (Steam Depot 1377581, Manifest 5092481117079359342).
if (name?.Contains("nProtect GameGuard Launcher") == true)
return $"nProtect GameGuard ({pex.GetInternalVersion()})";

View File

@@ -1,7 +1,7 @@
# Binary Object Scanner
[![Build status](https://ci.appveyor.com/api/projects/status/gmdft5bk1h8a1c31?svg=true)](https://ci.appveyor.com/project/mnadareski/BinaryObjectScanner)
[![Build Test](https://github.com/SabreTools/BinaryObjectScanner/actions/workflows/build_test.yml/badge.svg)](https://github.com/SabreTools/BinaryObjectScanner/actions/workflows/build_test.yml)
[![Test Build](https://github.com/SabreTools/BinaryObjectScanner/actions/workflows/build_test.yml/badge.svg)](https://github.com/SabreTools/BinaryObjectScanner/actions/workflows/build_test.yml)
[![Nuget Pack](https://github.com/SabreTools/BinaryObjectScanner/actions/workflows/build_nupkg.yml/badge.svg)](https://github.com/SabreTools/BinaryObjectScanner/actions/workflows/build_nupkg.yml)
C# protection, packer, and archive scanning library. This currently compiles as a library so it can be used in any C# application. A reference application called `Test` is also included to demonstrate the abilities of the library. For an example of a program implementing the library, see [MPF](https://github.com/SabreTools/MPF).
@@ -26,6 +26,12 @@ The following projects have influenced this library:
Please visit our sibling project, [DRML](https://github.com/TheRogueArchivist/DRML), the DRM Library for a more in-depth look at some of the protections detected.
## Releases
For the most recent stable build, download the latest release here: [Releases Page](https://github.com/SabreTools/BinaryObjectScanner/releases)
For the latest WIP build here: [Rolling Release](https://github.com/SabreTools/BinaryObjectScanner/releases/tag/rolling)
## Compatibility Notes
Binary Object Scanner strives to have both full compatibility for scanning across .NET versions as well as across OSes. Unfortunately, this is not always the case. Please see the below list for known compatibility issues.
@@ -64,6 +70,7 @@ Below is a list of protections detected by BinaryObjectScanner. The two columns
| CD-X | False | True | Unconfirmed¹ |
| CDSHiELD SE | True | False | |
| Cenga ProtectDVD | True | True | |
| Channelware | True | True | Version finding and detection of later versions unimplemented |
| ChosenBytes CodeLock | True | True | Partially unconfirmed² |
| CopyKiller | True | True | |
| CopyLok/CodeLok | True | False | |
@@ -75,6 +82,7 @@ Below is a list of protections detected by BinaryObjectScanner. The two columns
| DiscGuard | True | True | Partially unconfirmed² |
| DVD-Movie-PROTECT | False | True | Unconfirmed¹ |
| DVD Crypt | False | True | Unconfirmed¹ |
| EA Anti Cheat | True | True | |
| EA Protections | True | False | Including EA CDKey and EA DRM. |
| Easy Anti-Cheat | True | True | |
| Engine32 | True | False | |
@@ -177,7 +185,7 @@ Below is a list of game engines detected by BinaryObjectScanner. The two columns
| Protection Name | Content Check | Path Check | Notes |
| --------------- | ------------- | ---------- | ----- |
| RenderWare | Yes | No | No | |
| RenderWare | Yes | No | |
## Container Formats

View File

@@ -2,7 +2,6 @@
<PropertyGroup>
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
@@ -11,6 +10,20 @@
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<!-- Support All Frameworks -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net4`))">
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
</PropertyGroup>
<!-- Set a build flag for Windows specifically -->
<PropertyGroup Condition="'$(RuntimeIdentifier)'=='win-x86'">
@@ -31,7 +44,7 @@
<PackageReference Include="SabreTools.IO" Version="1.4.11" />
<PackageReference Include="SabreTools.Matching" Version="1.3.1" />
<PackageReference Include="SabreTools.Models" Version="1.4.8" />
<PackageReference Include="SabreTools.Serialization" Version="1.6.5" />
<PackageReference Include="SabreTools.Serialization" Version="1.6.7" />
<PackageReference Include="UnshieldSharp" Version="1.8.3" />
</ItemGroup>

View File

@@ -1,4 +1,4 @@
#! /bin/bash
#!/bin/bash
# This batch file assumes the following:
# - .NET 8.0 (or newer) SDK is installed and in PATH
@@ -12,9 +12,8 @@
USE_ALL=false
NO_BUILD=false
NO_ARCHIVE=false
while getopts "uba" OPTION
do
case $OPTION in
while getopts "uba" OPTION; do
case $OPTION in
u)
USE_ALL=true
;;
@@ -35,29 +34,34 @@ done
BUILD_FOLDER=$PWD
# Set the current commit hash
COMMIT=`git log --pretty=%H -1`
COMMIT=$(git log --pretty=%H -1)
# Output the selected options
echo "Selected Options:"
echo " Use all frameworks (-u) $USE_ALL"
echo " No build (-b) $NO_BUILD"
echo " No archive (-a) $NO_ARCHIVE"
echo " "
# Create the build matrix arrays
FRAMEWORKS=("net8.0")
RUNTIMES=("win-x86" "win-x64" "linux-x64" "osx-x64")
RUNTIMES=("win-x86" "win-x64" "win-arm64" "linux-x64" "linux-arm64" "osx-x64" "osx-arm64")
# Use expanded lists, if requested
if [ $USE_ALL = true ]
then
if [ $USE_ALL = true ]; then
FRAMEWORKS=("net20" "net35" "net40" "net452" "net462" "net472" "net48" "netcoreapp3.1" "net5.0" "net6.0" "net7.0" "net8.0")
RUNTIMES=("win-x86" "win-x64" "win-arm64" "linux-x64" "linux-arm64" "osx-x64")
fi
# Create the filter arrays
SINGLE_FILE_CAPABLE=("net5.0" "net6.0" "net7.0" "net8.0")
VALID_APPLE_FRAMEWORKS=("net6.0" "net7.0" "net8.0")
VALID_CROSS_PLATFORM_FRAMEWORKS=("netcoreapp3.1" "net5.0" "net6.0" "net7.0" "net8.0")
VALID_CROSS_PLATFORM_RUNTIMES=("win-arm64" "linux-x64" "linux-arm64" "osx-x64")
VALID_CROSS_PLATFORM_RUNTIMES=("win-arm64" "linux-x64" "linux-arm64" "osx-x64" "osx-arm64")
NON_DLL_FRAMEWORKS=("net20" "net35" "net40")
NON_DLL_RUNTIMES=("win-x64" "win-arm64" "linux-x64" "linux-arm64" "osx-x64")
NON_DLL_RUNTIMES=("win-x64" "win-arm64" "linux-x64" "linux-arm64" "osx-x64" "osx-arm64")
# Only build if requested
if [ $NO_BUILD = false ]
then
if [ $NO_BUILD = false ]; then
# Restore Nuget packages for all builds
echo "Restoring Nuget packages"
dotnet restore
@@ -66,23 +70,39 @@ then
dotnet pack BinaryObjectScanner/BinaryObjectScanner.csproj --output $BUILD_FOLDER
# Build Test
for FRAMEWORK in "${FRAMEWORKS[@]}"
do
for RUNTIME in "${RUNTIMES[@]}"
do
for FRAMEWORK in "${FRAMEWORKS[@]}"; do
for RUNTIME in "${RUNTIMES[@]}"; do
# Output the current build
echo "===== Build Test - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if [ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ] && [ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]
then
continue
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
echo "Skipped due to invalid combination"
continue
fi
fi
# If we have Apple silicon but an unsupported framework
if [[ ! $(echo ${VALID_APPLE_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [ $RUNTIME = "osx-arm64" ]; then
echo "Skipped due to no Apple Silicon support"
continue
fi
fi
# Only .NET 5 and above can publish to a single file
if [[ $(echo ${SINGLE_FILE_CAPABLE[@]} | fgrep -w $FRAMEWORK) ]]
then
dotnet publish Test/Test.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
if [[ $(echo ${SINGLE_FILE_CAPABLE[@]} | fgrep -w $FRAMEWORK) ]]; then
# Only include Debug if building all
if [ $USE_ALL = true ]; then
dotnet publish Test/Test.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
fi
dotnet publish Test/Test.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
else
dotnet publish Test/Test.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
# Only include Debug if building all
if [ $USE_ALL = true ]; then
dotnet publish Test/Test.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
fi
dotnet publish Test/Test.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
fi
done
@@ -90,29 +110,44 @@ then
fi
# Only create archives if requested
if [ $NO_ARCHIVE = false ]
then
if [ $NO_ARCHIVE = false ]; then
# Create Test archives
for FRAMEWORK in "${FRAMEWORKS[@]}"
do
for RUNTIME in "${RUNTIMES[@]}"
do
for FRAMEWORK in "${FRAMEWORKS[@]}"; do
for RUNTIME in "${RUNTIMES[@]}"; do
# Output the current build
echo "===== Archive Test - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if [ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ] && [ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]
then
continue
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
echo "Skipped due to invalid combination"
continue
fi
fi
cd $BUILD_FOLDER/Test/bin/Debug/${FRAMEWORK}/${RUNTIME}/publish/
if [ $(echo ${NON_DLL_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ] || [ $(echo ${NON_DLL_RUNTIMES[@]} | fgrep -w $RUNTIME) ]
then
zip -r $BUILD_FOLDER/BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_debug.zip . -x 'CascLib.dll' -x 'mspack.dll' -x 'StormLib.dll'
else
zip -r $BUILD_FOLDER/BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_debug.zip .
# If we have Apple silicon but an unsupported framework
if [[ ! $(echo ${VALID_APPLE_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [ $RUNTIME = "osx-arm64" ]; then
echo "Skipped due to no Apple Silicon support"
continue
fi
fi
# Only include Debug if building all
if [ $USE_ALL = true ]; then
cd $BUILD_FOLDER/Test/bin/Debug/${FRAMEWORK}/${RUNTIME}/publish/
if [[ $(echo ${NON_DLL_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
zip -r $BUILD_FOLDER/BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_debug.zip . -x 'CascLib.dll' -x 'mspack.dll' -x 'StormLib.dll'
elif [[ $(echo ${NON_DLL_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
zip -r $BUILD_FOLDER/BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_debug.zip . -x 'CascLib.dll' -x 'mspack.dll' -x 'StormLib.dll'
else
zip -r $BUILD_FOLDER/BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_debug.zip .
fi
fi
cd $BUILD_FOLDER/Test/bin/Release/${FRAMEWORK}/${RUNTIME}/publish/
if [ $(echo ${NON_DLL_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ] || [ $(echo ${NON_DLL_RUNTIMES[@]} | fgrep -w $RUNTIME) ]
then
if [[ $(echo ${NON_DLL_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
zip -r $BUILD_FOLDER/BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_release.zip . -x 'CascLib.dll' -x 'mspack.dll' -x 'StormLib.dll'
elif [[ $(echo ${NON_DLL_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
zip -r $BUILD_FOLDER/BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_release.zip . -x 'CascLib.dll' -x 'mspack.dll' -x 'StormLib.dll'
else
zip -r $BUILD_FOLDER/BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_release.zip .
@@ -122,4 +157,4 @@ then
# Reset the directory
cd $BUILD_FOLDER
fi
fi

View File

@@ -27,27 +27,32 @@ $BUILD_FOLDER = $PSScriptRoot
# Set the current commit hash
$COMMIT = git log --pretty=format:"%H" -1
# Output the selected options
Write-Host "Selected Options:"
Write-Host " Use all frameworks (-UseAll) $USE_ALL"
Write-Host " No build (-NoBuild) $NO_BUILD"
Write-Host " No archive (-NoArchive) $NO_ARCHIVE"
Write-Host " "
# Create the build matrix arrays
$FRAMEWORKS = @('net8.0')
$RUNTIMES = @('win-x86', 'win-x64', 'linux-x64', 'osx-x64')
$RUNTIMES = @('win-x86', 'win-x64', 'win-arm64', 'linux-x64', 'linux-arm64', 'osx-x64', 'osx-arm64')
# Use expanded lists, if requested
if ($USE_ALL.IsPresent)
{
if ($USE_ALL.IsPresent) {
$FRAMEWORKS = @('net20', 'net35', 'net40', 'net452', 'net462', 'net472', 'net48', 'netcoreapp3.1', 'net5.0', 'net6.0', 'net7.0', 'net8.0')
$RUNTIMES = @('win-x86', 'win-x64', 'win-arm64', 'linux-x64', 'linux-arm64', 'osx-x64')
}
# Create the filter arrays
$SINGLE_FILE_CAPABLE = @('net5.0', 'net6.0', 'net7.0', 'net8.0')
$VALID_APPLE_FRAMEWORKS = @('net6.0', 'net7.0', 'net8.0')
$VALID_CROSS_PLATFORM_FRAMEWORKS = @('netcoreapp3.1', 'net5.0', 'net6.0', 'net7.0', 'net8.0')
$VALID_CROSS_PLATFORM_RUNTIMES = @('win-arm64', 'linux-x64', 'linux-arm64', 'osx-x64')
$VALID_CROSS_PLATFORM_RUNTIMES = @('win-arm64', 'linux-x64', 'linux-arm64', 'osx-x64', 'osx-arm64')
$NON_DLL_FRAMEWORKS = @('net20', 'net35', 'net40')
$NON_DLL_RUNTIMES = @('win-x64', 'win-arm64', 'linux-x64', 'linux-arm64', 'osx-x64')
$NON_DLL_RUNTIMES = @('win-x64', 'win-arm64', 'linux-x64', 'linux-arm64', 'osx-x64', 'osx-arm64')
# Only build if requested
if (!$NO_BUILD.IsPresent)
{
if (!$NO_BUILD.IsPresent) {
# Restore Nuget packages for all builds
Write-Host "Restoring Nuget packages"
dotnet restore
@@ -56,25 +61,36 @@ if (!$NO_BUILD.IsPresent)
dotnet pack BinaryObjectScanner\BinaryObjectScanner.csproj --output $BUILD_FOLDER
# Build Test
foreach ($FRAMEWORK in $FRAMEWORKS)
{
foreach ($RUNTIME in $RUNTIMES)
{
foreach ($FRAMEWORK in $FRAMEWORKS) {
foreach ($RUNTIME in $RUNTIMES) {
# Output the current build
Write-Host "===== Build Test - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME)
{
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME) {
Write-Host "Skipped due to invalid combination"
continue
}
# If we have Apple silicon but an unsupported framework
if ($VALID_APPLE_FRAMEWORKS -notcontains $FRAMEWORK -and $RUNTIME -eq 'osx-arm64') {
Write-Host "Skipped due to no Apple Silicon support"
continue
}
# Only .NET 5 and above can publish to a single file
if ($SINGLE_FILE_CAPABLE -contains $FRAMEWORK)
{
dotnet publish Test\Test.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
if ($SINGLE_FILE_CAPABLE -contains $FRAMEWORK) {
# Only include Debug if building all
if ($USE_ALL.IsPresent) {
dotnet publish Test\Test.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
}
dotnet publish Test\Test.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
}
else
{
dotnet publish Test\Test.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
else {
# Only include Debug if building all
if ($USE_ALL.IsPresent) {
dotnet publish Test\Test.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
}
dotnet publish Test\Test.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
}
}
@@ -82,35 +98,41 @@ if (!$NO_BUILD.IsPresent)
}
# Only create archives if requested
if (!$NO_ARCHIVE.IsPresent)
{
if (!$NO_ARCHIVE.IsPresent) {
# Create Test archives
foreach ($FRAMEWORK in $FRAMEWORKS)
{
foreach ($RUNTIME in $RUNTIMES)
{
foreach ($FRAMEWORK in $FRAMEWORKS) {
foreach ($RUNTIME in $RUNTIMES) {
# Output the current build
Write-Host "===== Archive Test - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME)
{
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME) {
Write-Host "Skipped due to invalid combination"
continue
}
Set-Location -Path $BUILD_FOLDER\Test\bin\Debug\${FRAMEWORK}\${RUNTIME}\publish\
if ($NON_DLL_FRAMEWORKS -contains $FRAMEWORK -or $NON_DLL_RUNTIMES -contains $RUNTIME)
{
7z a -tzip -x'!CascLib.dll' -x'!mspack.dll' -x'!StormLib.dll' $BUILD_FOLDER\BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_debug.zip *
# If we have Apple silicon but an unsupported framework
if ($VALID_APPLE_FRAMEWORKS -notcontains $FRAMEWORK -and $RUNTIME -eq 'osx-arm64') {
Write-Host "Skipped due to no Apple Silicon support"
continue
}
else
{
7z a -tzip $BUILD_FOLDER\BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_debug.zip *
# Only include Debug if building all
if ($USE_ALL.IsPresent) {
Set-Location -Path $BUILD_FOLDER\Test\bin\Debug\${FRAMEWORK}\${RUNTIME}\publish\
if ($NON_DLL_FRAMEWORKS -contains $FRAMEWORK -or $NON_DLL_RUNTIMES -contains $RUNTIME) {
7z a -tzip -x'!CascLib.dll' -x'!mspack.dll' -x'!StormLib.dll' $BUILD_FOLDER\BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_debug.zip *
}
else {
7z a -tzip $BUILD_FOLDER\BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_debug.zip *
}
}
Set-Location -Path $BUILD_FOLDER\Test\bin\Release\${FRAMEWORK}\${RUNTIME}\publish\
if ($NON_DLL_FRAMEWORKS -contains $FRAMEWORK -or $NON_DLL_RUNTIMES -contains $RUNTIME)
{
if ($NON_DLL_FRAMEWORKS -contains $FRAMEWORK -or $NON_DLL_RUNTIMES -contains $RUNTIME) {
7z a -tzip -x'!CascLib.dll' -x'!mspack.dll' -x'!StormLib.dll' $BUILD_FOLDER\BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_release.zip *
}
else
{
else {
7z a -tzip $BUILD_FOLDER\BinaryObjectScanner_${FRAMEWORK}_${RUNTIME}_release.zip *
}
}