Compare commits

..

16 Commits
3.3.0 ... 3.3.1

Author SHA1 Message Date
Matt Nadareski
cdc9171615 Bump version 2024-12-03 13:07:59 -05:00
Matt Nadareski
21451c5294 Update WiseUnpacker to 1.5.4 2024-12-03 11:58:04 -05:00
Matt Nadareski
dea35ca158 Update WiseUnpacker to 1.5.3 2024-12-03 06:53:32 -05:00
Matt Nadareski
7d96e7b333 Enable more embedded archive types 2024-12-03 06:26:39 -05:00
Matt Nadareski
4f493626cb Use default extraction for Wise finally 2024-12-03 06:14:30 -05:00
Matt Nadareski
03a2dff668 Try reading files if streams fail 2024-12-03 06:00:03 -05:00
Matt Nadareski
0d213274b5 Update WiseUnpacker to 1.5.2 2024-12-03 05:06:52 -05:00
TheRogueArchivist
80d3b8d8bb Add sources for SafeDisc detections up through V1 (#341)
Also fix a false positive in ASPack due to an overly generic check, and fix a comment.
2024-12-03 04:25:50 -05:00
Matt Nadareski
e788ad9287 Ensure keys in a better way 2024-12-03 03:54:55 -05:00
Matt Nadareski
c70b5f6ec8 Increase extraction safety 2024-12-03 03:43:39 -05:00
Matt Nadareski
6b7ad781b7 Update UnshieldSharp to 1.9.2 2024-12-03 03:34:07 -05:00
Matt Nadareski
9d60a4d1ec Fix output directory issues 2024-12-03 03:24:24 -05:00
Matt Nadareski
ec091ada95 Ensure all protections are split properly 2024-12-03 03:09:52 -05:00
TheRogueArchivist
c2547295bf Check .data/DATA sections for ASPack as well (#340)
Also add some comments regarding ASProtect.
2024-12-03 02:40:28 -05:00
Matt Nadareski
58707feb72 Debug data debugged data 2024-12-03 02:09:19 -05:00
Matt Nadareski
7efe622990 Update Serialization to 1.8.1 2024-12-03 01:15:30 -05:00
23 changed files with 257 additions and 161 deletions

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net9.0</TargetFrameworks>
@@ -17,7 +17,7 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="SabreTools.Serialization" Version="1.8.0" />
<PackageReference Include="SabreTools.Serialization" Version="1.8.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@@ -3,7 +3,7 @@ using Xunit;
namespace BinaryObjectScanner.Test
{
public class ScannerTests
public class ProtectionDictionaryTests
{
#region ProcessProtectionString
@@ -11,7 +11,7 @@ namespace BinaryObjectScanner.Test
public void ProcessProtectionString_Null_Empty()
{
string? protection = null;
List<string> actual = Scanner.ProcessProtectionString(protection);
List<string> actual = ProtectionDictionary.ProcessProtectionString(protection);
Assert.Empty(actual);
}
@@ -19,7 +19,7 @@ namespace BinaryObjectScanner.Test
public void ProcessProtectionString_Empty_Empty()
{
string? protection = string.Empty;
List<string> actual = Scanner.ProcessProtectionString(protection);
List<string> actual = ProtectionDictionary.ProcessProtectionString(protection);
Assert.Empty(actual);
}
@@ -27,7 +27,7 @@ namespace BinaryObjectScanner.Test
public void ProcessProtectionString_NoIndicator_Single()
{
string? protection = "item1";
List<string> actual = Scanner.ProcessProtectionString(protection);
List<string> actual = ProtectionDictionary.ProcessProtectionString(protection);
Assert.Single(actual);
}
@@ -35,7 +35,7 @@ namespace BinaryObjectScanner.Test
public void ProcessProtectionString_Indicator_Multiple()
{
string? protection = "item1;item2";
List<string> actual = Scanner.ProcessProtectionString(protection);
List<string> actual = ProtectionDictionary.ProcessProtectionString(protection);
Assert.Equal(2, actual.Count);
}

View File

@@ -11,7 +11,7 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.3.0</Version>
<Version>3.3.1</Version>
<!-- Mostly added due to external libraries -->
<WarningsNotAsErrors>CS8600;CS8601;CS8602;CS8603;CS8604;CS8605;CS8618;CS8625;CS8634;CS8765;IL3000;NU5100</WarningsNotAsErrors>
@@ -92,9 +92,9 @@
<PackageReference Include="SabreTools.IO" Version="1.6.1" />
<PackageReference Include="SabreTools.Matching" Version="1.5.0" />
<PackageReference Include="SabreTools.Models" Version="1.5.5" />
<PackageReference Include="SabreTools.Serialization" Version="1.8.0" />
<PackageReference Include="UnshieldSharp" Version="1.9.1" />
<PackageReference Include="WiseUnpacker" Version="1.5.1" />
<PackageReference Include="SabreTools.Serialization" Version="1.8.1" />
<PackageReference Include="UnshieldSharp" Version="1.9.2" />
<PackageReference Include="WiseUnpacker" Version="1.5.4" />
</ItemGroup>
</Project>

View File

@@ -30,6 +30,9 @@ namespace BinaryObjectScanner.FileType
// Not supported for .NET Framework 2.0 or .NET Framework 3.5 due to library support
return false;
#else
if (stream == null || !stream.CanRead)
return false;
try
{
using var msi = new CompoundFile(stream, CFSUpdateMode.ReadOnly, CFSConfiguration.Default);

View File

@@ -25,6 +25,9 @@ namespace BinaryObjectScanner.FileType
{
try
{
if (!File.Exists(file))
return false;
var archive = new ISv3(file);
foreach (var cfile in archive.Files)
{
@@ -39,10 +42,8 @@ namespace BinaryObjectScanner.FileType
if (fileContents == null || !string.IsNullOrEmpty(error))
continue;
using (FileStream fs = File.OpenWrite(tempFile))
{
fs.Write(fileContents, 0, fileContents.Length);
}
using FileStream fs = File.OpenWrite(tempFile);
fs.Write(fileContents, 0, fileContents.Length);
}
catch (Exception ex)
{

View File

@@ -54,6 +54,9 @@ namespace BinaryObjectScanner.FileType
try
{
if (!File.Exists(file))
return false;
var cabfile = InstallShieldCabinet.Open(file);
if (cabfile?.HeaderList == null)
return false;
@@ -77,6 +80,10 @@ namespace BinaryObjectScanner.FileType
tempFile = Path.Combine(outDir, $"BAD_FILENAME{i}");
}
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
cabfile.FileSave(i, tempFile);
}
catch (Exception ex)

View File

@@ -32,6 +32,9 @@ namespace BinaryObjectScanner.FileType
#else
try
{
if (!File.Exists(file))
return false;
// Try to open the archive and listfile
var mpqArchive = new MpqArchive(file, FileAccess.Read);
string? listfile = null;

View File

@@ -33,6 +33,9 @@ namespace BinaryObjectScanner.FileType
#else
try
{
if (!File.Exists(file))
return false;
// Loop over each entry
var cabArchive = new MSCabinet(file);
foreach (var compressedFile in cabArchive.GetFiles())

View File

@@ -24,6 +24,9 @@ namespace BinaryObjectScanner.FileType
/// <inheritdoc/>
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
if (stream == null || !stream.CanRead)
return false;
try
{
var data = Decompressor.Decompress(stream);

View File

@@ -42,7 +42,12 @@ namespace BinaryObjectScanner.FileType
try
{
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
using var zipFile = ZipArchive.Open(stream, readerOptions);
var zipFile = ZipArchive.Open(stream, readerOptions);
// Try to read the file path if no entries are found
if (zipFile.Entries.Count == 0 && !string.IsNullOrEmpty(file) && File.Exists(file))
zipFile = ZipArchive.Open(file, readerOptions);
foreach (var entry in zipFile.Entries)
{
try

View File

@@ -42,7 +42,12 @@ namespace BinaryObjectScanner.FileType
try
{
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
using RarArchive rarFile = RarArchive.Open(stream, readerOptions);
RarArchive rarFile = RarArchive.Open(stream, readerOptions);
// Try to read the file path if no entries are found
if (rarFile.Entries.Count == 0 && !string.IsNullOrEmpty(file) && File.Exists(file))
rarFile = RarArchive.Open(file, readerOptions);
if (!rarFile.IsComplete)
return false;

View File

@@ -42,7 +42,12 @@ namespace BinaryObjectScanner.FileType
try
{
var readerOptions = new ReaderOptions() { LookForHeader = lookForHeader };
using var sevenZip = SevenZipArchive.Open(stream, readerOptions);
var sevenZip = SevenZipArchive.Open(stream, readerOptions);
// Try to read the file path if no entries are found
if (sevenZip.Entries.Count == 0 && !string.IsNullOrEmpty(file) && File.Exists(file))
sevenZip = SevenZipArchive.Open(file, readerOptions);
foreach (var entry in sevenZip.Entries)
{
try

View File

@@ -32,7 +32,12 @@ namespace BinaryObjectScanner.FileType
#if NET462_OR_GREATER || NETCOREAPP
try
{
using var tarFile = TarArchive.Open(stream);
var tarFile = TarArchive.Open(stream);
// Try to read the file path if no entries are found
if (tarFile.Entries.Count == 0 && !string.IsNullOrEmpty(file) && File.Exists(file))
tarFile = TarArchive.Open(file);
foreach (var entry in tarFile.Entries)
{
try

View File

@@ -26,6 +26,9 @@ namespace BinaryObjectScanner.FileType
public bool Extract(Stream? stream, string file, string outDir, bool includeDebug)
{
#if NET462_OR_GREATER || NETCOREAPP
if (stream == null || !stream.CanRead)
return false;
try
{
// Try opening the stream

View File

@@ -7,6 +7,7 @@ using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Packer
{
// TODO: Add extraction
// TODO: Research and add support for ASProtect. It seems to be an additional layer of protection for ASPack, making detecting it separately more difficult.
public class ASPack : IExtractableExecutable<PortableExecutable>
{
/// <inheritdoc/>
@@ -35,6 +36,16 @@ namespace BinaryObjectScanner.Packer
return match;
}
// Get the .data/DATA section, if it exists
var dataSectionRaw = pex.GetFirstSectionData(".data") ?? pex.GetFirstSectionData("DATA");
if (dataSectionRaw != null)
{
var matchers = GenerateMatchers();
var match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
}
return null;
}
@@ -552,6 +563,38 @@ namespace BinaryObjectScanner.Packer
0x1C, 0x00
}, "ASPack 2.x (without Poly) -> Solodovnikov Alexey"),
// Commented out due to "ASPack 2.1" getting detected before this. More research is needed.
// Based on detection rules from https://github.com/x64dbg/yarasigs/blob/master/Old_Internal_PEiD.yara
/* new(new byte?[]
{
0x60, 0xE8, 0x03, 0x00, 0x00, 0x00, 0xE9, 0xEB,
0x04, 0x5D, 0x45, 0x55, 0xC3, 0xE8, 0x01, 0x00,
0x00, 0x00, 0xEB, 0x5D, 0xBB, 0xED, 0xFF, 0xFF,
0xFF, 0x03, 0xDD, 0x81, 0xEB, 0x00, null, null,
null, 0x80, 0x7D, 0x4D, 0x01, 0x75, 0x0C, 0x8B,
0x74, 0x24, 0x28, 0x83, 0xFE, 0x01, 0x89, 0x5D,
0x4E, 0x75, 0x31, 0x8D, 0x45, 0x53, 0x50, 0x53,
0xFF, 0xB5, null, 0x09, 0x00, 0x00, 0x8D, 0x45,
0x35, 0x50, 0xE9, 0x82, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, null,
0x00, 0x00, 0x00, 0x00, 0xB8, 0xF8, 0xC0, 0xA5,
0x23, 0x50, 0x50, 0x03, 0x45, 0x4E, 0x5B, 0x85,
0xC0, 0x74, 0x1C, 0xEB, 0x01, 0xE8, 0x81, 0xFB,
0xF8, 0xC0, 0xA5, 0x23, 0x74, 0x35, 0x33, 0xD2,
0x56, 0x6A, 0x00, 0x56, 0xFF, 0x75, 0x4E, 0xFF,
0xD0, 0x5E, 0x83, 0xFE, 0x00, 0x75, 0x24, 0x33,
0xD2, 0x8B, 0x45, 0x41, 0x85, 0xC0, 0x74, 0x07,
0x52, 0x52, 0xFF, 0x75, 0x35, 0xFF, 0xD0, 0x8B,
0x45, 0x35, 0x85, 0xC0, 0x74, 0x0D, 0x68, 0x00,
0x80, 0x00, 0x00, 0x6A, 0x00, 0xFF, 0x75, 0x35,
0xFF, 0x55, 0x3D, 0x5B, 0x0B, 0xDB, 0x61, 0x75,
0x06, 0x6A, 0x01, 0x58, 0xC2, 0x0C, 0x00, 0x33,
0xC0, 0xF7, 0xD8, 0x1B, 0xC0, 0x40, 0xC2, 0x0C,
0x00
}, "ASProtect SKE 2.x -> Solodovnikov Alexey"), */
#endregion
#region 2.xx (Long)
@@ -578,7 +621,8 @@ namespace BinaryObjectScanner.Packer
#region Short
new(new byte?[] { 0x75, 0x00, 0xE9 }, "ASPack 1.05b"),
// Disabled due to being too prone to false positives.
// new(new byte?[] { 0x75, 0x00, 0xE9 }, "ASPack 1.05b"),
new(new byte?[] { 0x90, 0x90, 0x90, 0x75, 0x00, 0xE9 }, "ASPack 1.06.1b"),

View File

@@ -22,18 +22,29 @@ namespace BinaryObjectScanner.Packer
{
if (value == null || value is not byte[] ba)
continue;
if (!ba.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
continue;
return "Embedded Archive";
if (ba.StartsWith([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C]))
return "Embedded 7-Zip Archive";
if (ba.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
return "Embedded PKZIP Archive";
if (ba.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00]))
return "Embedded RAR Archive";
if (ba.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00]))
return "Embedded RAR Archive";
}
}
// Check the overlay, if it exists
if (pex.OverlayData != null && pex.OverlayData.Length > 0)
{
if (pex.OverlayData.StartsWith([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C]))
return "Embedded 7-Zip Archive";
if (pex.OverlayData.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
return "Embedded Archive";
return "Embedded PKZIP Archive";
if (pex.OverlayData.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00]))
return "Embedded RAR Archive";
if (pex.OverlayData.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00]))
return "Embedded RAR Archive";
}
return null;
@@ -60,11 +71,20 @@ namespace BinaryObjectScanner.Packer
return false;
// Only process the overlay if it has an archive signature
if (!overlayData.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
string extension = string.Empty;
if (overlayData.StartsWith([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C]))
extension = "7z";
else if (overlayData.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
extension = "zip";
else if (overlayData.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00]))
extension = "rar";
else if (overlayData.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00]))
extension = "rar";
else
return false;
// Create the temp filename
string tempFile = $"embedded_overlay.zip";
string tempFile = $"embedded_overlay.{extension}";
tempFile = Path.Combine(outDir, tempFile);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))
@@ -100,13 +120,24 @@ namespace BinaryObjectScanner.Packer
{
if (value == null || value is not byte[] ba)
continue;
if (!ba.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
// Only process the resource if it has an archive signature
string extension = string.Empty;
if (ba.StartsWith([0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C]))
extension = "7z";
else if (ba.StartsWith(SabreTools.Models.PKZIP.Constants.LocalFileHeaderSignatureBytes))
extension = "zip";
else if (ba.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00]))
extension = "rar";
else if (ba.StartsWith([0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00]))
extension = "rar";
else
continue;
try
{
// Create the temp filename
string tempFile = $"embedded_resource_{i++}.zip";
string tempFile = $"embedded_resource_{i++}.{extension}";
tempFile = Path.Combine(outDir, tempFile);
var directoryName = Path.GetDirectoryName(tempFile);
if (directoryName != null && !Directory.Exists(directoryName))

View File

@@ -88,87 +88,8 @@ namespace BinaryObjectScanner.Packer
{
try
{
// Get the matching PE format
var format = GetPEFormat(pex);
if (format == null)
return false;
// Get the overlay data for easier reading
int overlayOffset = 0, dataStart = 0;
var overlayData = pex.OverlayData;
if (overlayData == null)
return false;
// Skip over the additional DLL name, if we expect it
if (format.Dll)
{
// Read the name length
byte dllNameLength = overlayData.ReadByte(ref overlayOffset);
dataStart++;
// Read the name, if it exists
if (dllNameLength != 0)
{
// Ignore the name for now
_ = overlayData.ReadBytes(ref overlayOffset, dllNameLength);
dataStart += dllNameLength;
// Named DLLs also have a DLL length that we ignore
_ = overlayData.ReadUInt32(ref overlayOffset);
dataStart += 4;
}
}
// Check if flags are consistent
if (!format.NoCrc)
{
// Unlike WiseUnpacker, we ignore the flag value here
_ = overlayData.ReadUInt32(ref overlayOffset);
}
// Ensure that we have an archive end
if (format.ArchiveEnd > 0)
{
overlayOffset = (int)(dataStart + format.ArchiveEnd);
int archiveEndLoaded = overlayData.ReadInt32(ref overlayOffset);
if (archiveEndLoaded != 0)
format.ArchiveEnd = archiveEndLoaded;
}
// Skip to the start of the archive
overlayOffset = (int)(dataStart + format.ArchiveStart);
// Skip over the initialization text, if we expect it
if (format.InitText)
{
int initTextLength = overlayData.ReadByte(ref overlayOffset);
_ = overlayData.ReadBytes(ref overlayOffset, initTextLength);
}
// Cache the current offset in the overlay as the "start of data"
int offsetReal = overlayOffset;
// If the first entry is PKZIP, we assume it's an embedded zipfile
var magic = overlayData.ReadBytes(ref overlayOffset, 4); overlayOffset -= 4;
bool pkzip = magic?.StartsWith(new byte?[] { (byte)'P', (byte)'K' }) ?? false;
// Create the output directory
Directory.CreateDirectory(outDir);
// If we have PKZIP
if (pkzip)
{
string tempFile = Path.Combine(outDir, "WISEDATA.zip");
using Stream tempStream = File.Open(tempFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
tempStream.Write(overlayData, overlayOffset, overlayData.Length - overlayOffset);
return true;
}
// If we have DEFLATE -- TODO: Port implementation here or use DeflateStream
else
{
return Extractor.ExtractTo(file, outDir);
}
return Extractor.ExtractTo(file, outDir);
}
catch (Exception ex)
{

View File

@@ -102,12 +102,19 @@ namespace BinaryObjectScanner.Protection
if (name.OptionalEquals("SafeDisc", StringComparison.OrdinalIgnoreCase))
return "SafeDisc";
// Found in Redump entries 20729 and 65569.
// Get the debug data
if (pex.FindCodeViewDebugTableByPath("SafeDisc").Count > 0)
return "SafeDisc";
if (pex.FindCodeViewDebugTableByPath("Safedisk").Count > 0)
return "SafeDisc";
try
{
// Found in Redump entries 20729 and 65569.
// Get the debug data
if (pex.FindCodeViewDebugTableByPath("SafeDisc").Count > 0)
return "SafeDisc";
if (pex.FindCodeViewDebugTableByPath("Safedisk").Count > 0)
return "SafeDisc";
}
catch
{
// Absorb inconsistent debug data errors
}
// TODO: Investigate various section names:
// "STLPORT_" - Found in Redump entry 11638.

View File

@@ -171,7 +171,7 @@ namespace BinaryObjectScanner.Protection
if (cDilla != null)
results.AddRange(cDilla);
// Run C-Dilla directory checks
// Run FLEXnet directory checks
var flexNet = FLEXNetCheckDirectoryPath(path, files);
if (flexNet != null)
results.AddRange(flexNet);
@@ -550,28 +550,70 @@ namespace BinaryObjectScanner.Protection
// Found in Redump entry 66005.
"1.00.025"
// Source not documented.
// Found in Redump entries 1882, 30049, 34828, 35922, 38212, 84280, and 97611.
or "1.00.026"
// Found in Redump entries 31575 and 41923.
or "1.00.030"
// Found in Redump entries 1883 and 42114.
or "1.00.032"
// Found in Redump entries 36223 and 40770.
or "1.00.035"
// Found in Redump entries 42155 and 47574.
or "1.01.034"
// Found in Redump entry 51459.
or "1.01.038"
// Found in Redump entries 34562 and 63304.
or "1.01.043"
// Found in Redump entries 61731 and 81619.
or "1.01.044"
// Found in Redump entries 29073 and 31149.
or "1.06.000"
// Found in Redump entries 9718 and 46756.
or "1.07.000"
// Found in Redump entries 12885 and 66210.
or "1.09.000"
// Found in Redump entries 3569, 3570, 37523, 66586.
or "1.11.000"
// Found in Redump entries 21154, 37982, 108632.
or "1.20.000"
// Found in Redump entries 17024/37920.
or "1.20.001"
// Found in Redump entries 28708, 31526, 43321, 55080, 75501.
or "1.30.010"
// Found in Redump entries 9617 and 49552.
or "1.35.000"
// Found in Redump entries 2595 and 30121.
or "1.40.004"
// Found in Redump entries 1887, 44350, 61047, and 63323.
or "1.41.000"
// Found in Redump entries 37832 and 42091.
or "1.41.001"
// Found in Redump entries 30555 and 55078.
or "1.45.011"
// Found in Redump entries 28810 and 62935.
or "1.50.020"
// Source not documented.
or "2.05.030"
or "2.10.030"
or "2.30.030"

View File

@@ -21,13 +21,17 @@ namespace BinaryObjectScanner
/// </summary>
/// <param name="key">Key to add information to</param>
/// <param name="value">String value to add</param>
public void Append(string key, string value)
public void Append(string key, string? value)
{
// If the value is empty, don't add it
if (value == null || value.Trim().Length == 0)
return;
Append(key, [value]);
EnsureKey(key);
foreach (string subValue in ProcessProtectionString(value))
{
this[key].Enqueue(subValue);
}
}
/// <summary>
@@ -37,9 +41,6 @@ namespace BinaryObjectScanner
/// <param name="values">String value array to add</param>
public void Append(string key, string[] values)
{
// Use a placeholder value if the key is null
key ??= "NO FILENAME";
// Add the key if needed and then append the lists
EnsureKey(key);
foreach (string value in values)
@@ -47,7 +48,10 @@ namespace BinaryObjectScanner
if (value == null || value.Trim().Length == 0)
continue;
this[key].Enqueue(value);
foreach (string subValue in ProcessProtectionString(value))
{
this[key].Enqueue(subValue);
}
}
}
@@ -181,15 +185,49 @@ namespace BinaryObjectScanner
if (values == null)
return;
EnsureKey(key);
foreach (string value in values)
{
if (value == null || value.Trim().Length == 0)
continue;
this[key].Enqueue(value);
foreach (string subValue in ProcessProtectionString(value))
{
this[key].Enqueue(subValue);
}
}
}
#region Helpers
/// <summary>
/// Process a protection string if it includes multiple protections
/// </summary>
/// <param name="protection">Protection string to process</param>
/// <returns>Set of protections parsed, empty on error</returns>
internal static List<string> ProcessProtectionString(string? protection)
{
// If we have an invalid protection string
if (string.IsNullOrEmpty(protection))
return [];
// Setup the output queue
var protections = new List<string>();
// If we have an indicator of multiple protections
if (protection!.Contains(";"))
{
var splitProtections = protection.Split(';');
protections.AddRange(splitProtections);
}
else
{
protections.Add(protection);
}
return protections;
}
/// <summary>
/// Ensure the collection for the given key exists
/// </summary>
@@ -202,5 +240,7 @@ namespace BinaryObjectScanner
TryAdd(key, new ConcurrentQueue<string>());
#endif
}
#endregion
}
}

View File

@@ -284,7 +284,7 @@ namespace BinaryObjectScanner
else
{
var subProtection = detectable.Detect(stream, fileName, _options.IncludeDebug);
protections.Append(fileName, ProcessProtectionString(subProtection));
protections.Append(fileName, subProtection);
}
}
@@ -395,8 +395,8 @@ namespace BinaryObjectScanner
if (File.Exists(path))
{
var protection = impl.CheckFilePath(path!);
var subProtections = ProcessProtectionString(protection);
protections.AddRange(subProtections);
if (protection != null)
protections.Add(protection);
}
// If we have a directory path
@@ -411,37 +411,5 @@ namespace BinaryObjectScanner
}
#endregion
#region Helpers
/// <summary>
/// Process a protection string if it includes multiple protections
/// </summary>
/// <param name="protection">Protection string to process</param>
/// <returns>Set of protections parsed, empty on error</returns>
internal static List<string> ProcessProtectionString(string? protection)
{
// If we have an invalid protection string
if (string.IsNullOrEmpty(protection))
return [];
// Setup the output queue
var protections = new List<string>();
// If we have an indicator of multiple protections
if (protection!.Contains(";"))
{
var splitProtections = protection.Split(';');
protections.AddRange(splitProtections);
}
else
{
protections.Add(protection);
}
return protections;
}
#endregion
}
}

View File

@@ -9,7 +9,7 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.3.0</Version>
<Version>3.3.1</Version>
</PropertyGroup>
<!-- Support All Frameworks -->
@@ -37,7 +37,7 @@
<ItemGroup>
<PackageReference Include="SabreTools.IO" Version="1.6.1" />
<PackageReference Include="SabreTools.Serialization" Version="1.8.0" />
<PackageReference Include="SabreTools.Serialization" Version="1.8.1" />
</ItemGroup>
</Project>

View File

@@ -9,7 +9,7 @@
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.3.0</Version>
<Version>3.3.1</Version>
</PropertyGroup>
<!-- Support All Frameworks -->