diff --git a/BurnOutSharp/Matching/ContentMatch.cs b/BurnOutSharp/Matching/ContentMatch.cs
new file mode 100644
index 00000000..9fef7cf9
--- /dev/null
+++ b/BurnOutSharp/Matching/ContentMatch.cs
@@ -0,0 +1,30 @@
+namespace BurnOutSharp.Matching
+{
+ ///
+ /// Single matching criteria
+ ///
+ internal class ContentMatch
+ {
+ ///
+ /// Content to match
+ ///
+ public byte?[] Needle { get; set; }
+
+ ///
+ /// Starting index for matching
+ ///
+ public int Start { get; set; }
+
+ ///
+ /// Ending index for matching
+ ///
+ public int End { get; set; }
+
+ public ContentMatch(byte?[] needle, int start = -1, int end = -1)
+ {
+ Needle = needle;
+ Start = start;
+ End = end;
+ }
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp/Matching/Matcher.cs b/BurnOutSharp/Matching/Matcher.cs
new file mode 100644
index 00000000..c4ff63da
--- /dev/null
+++ b/BurnOutSharp/Matching/Matcher.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace BurnOutSharp.Matching
+{
+ ///
+ /// Wrapper for a single set of matching criteria
+ ///
+ internal class Matcher
+ {
+ ///
+ /// Set of all content matches
+ ///
+ public IEnumerable ContentMatches { get; set; }
+
+ ///
+ /// Function to get a version for this Matcher
+ ///
+ public Func GetVersion { get; set; }
+
+ ///
+ /// Name of the protection to show
+ ///
+ public string ProtectionName { get; set; }
+
+ #region Constructors
+
+ public Matcher(byte?[] needle, string protectionName)
+ : this(new List() { needle }, null, protectionName) { }
+
+ public Matcher(List needles, string protectionName)
+ : this(needles, null, protectionName) { }
+
+ public Matcher(byte?[] needle, Func getVersion, string protectionName)
+ : this(new List() { needle }, getVersion, protectionName) { }
+
+ public Matcher(List needles, Func getVersion, string protectionName)
+ : this(needles.Select(n => new ContentMatch(n)).ToList(), getVersion, protectionName) { }
+
+ public Matcher(ContentMatch needle, string protectionName)
+ : this(new List() { needle }, null, protectionName) { }
+
+ public Matcher(List needles, string protectionName)
+ : this(needles, null, protectionName) { }
+
+ public Matcher(ContentMatch needle, Func getVersion, string protectionName)
+ : this(new List() { needle }, getVersion, protectionName) { }
+
+ public Matcher(List needles, Func getVersion, string protectionName)
+ {
+ ContentMatches = needles;
+ GetVersion = getVersion;
+ ProtectionName = protectionName;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp/PackerType/Armadillo.cs b/BurnOutSharp/PackerType/Armadillo.cs
index 26cfd701..cd3aafe3 100644
--- a/BurnOutSharp/PackerType/Armadillo.cs
+++ b/BurnOutSharp/PackerType/Armadillo.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -7,16 +8,16 @@ namespace BurnOutSharp.PackerType
///
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
- var mappings = new Dictionary
+ var matchers = new List
{
// .nicode + (char)0x00
- [new byte?[] { 0x2E, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0x00 }] = "Armadillo",
+ new Matcher(new byte?[] { 0x2E, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0x00 }, "Armadillo"),
// ARMDEBUG
- [new byte?[] { 0x41, 0x52, 0x4D, 0x44, 0x45, 0x42, 0x55, 0x47 }] = "Armadillo",
+ new Matcher(new byte?[] { 0x41, 0x52, 0x4D, 0x44, 0x45, 0x42, 0x55, 0x47 }, "Armadillo"),
};
- return Utilities.GetContentMatches(fileContent, mappings, includePosition);
+ return Utilities.GetContentMatches(fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/PackerType/EXEStealth.cs b/BurnOutSharp/PackerType/EXEStealth.cs
index b40c8c96..b4abfcb0 100644
--- a/BurnOutSharp/PackerType/EXEStealth.cs
+++ b/BurnOutSharp/PackerType/EXEStealth.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -7,13 +8,20 @@ namespace BurnOutSharp.PackerType
///
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
- var mappings = new Dictionary
+ var matchers = new List
{
// ??[[__[[_ + (char)0x00 + {{ + (char)0x0 + (char)0x00 + {{ + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + ?;??;??
- [new byte?[] { 0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B, 0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x3B, 0x3F, 0x3F, 0x3B, 0x3F, 0x3F }] = "EXE Stealth",
+ new Matcher(new byte?[]
+ {
+ 0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B,
+ 0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x3F, 0x3B, 0x3F, 0x3F, 0x3B, 0x3F,
+ 0x3F
+ }, "EXE Stealth"),
};
- return Utilities.GetContentMatches(fileContent, mappings, includePosition);
+ return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/PackerType/InnoSetup.cs b/BurnOutSharp/PackerType/InnoSetup.cs
index c8a76976..e73226be 100644
--- a/BurnOutSharp/PackerType/InnoSetup.cs
+++ b/BurnOutSharp/PackerType/InnoSetup.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -10,16 +11,19 @@ namespace BurnOutSharp.PackerType
///
public bool ShouldScan(byte[] magic) => true;
- ///
///
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
- // Inno
- byte?[] check = new byte?[] { 0x49, 0x6E, 0x6E, 0x6F };
- if (fileContent.FirstPosition(check, out int position) && position == 0x30)
- return $"Inno Setup {GetVersion(fileContent)}" + (includePosition ? $" (Index {position})" : string.Empty);
+ var matchers = new List
+ {
+ // Inno
+ new Matcher(
+ new ContentMatch(new byte?[] { 0x49, 0x6E, 0x6E, 0x6F }, start: 0x30, end: 0x31),
+ GetVersion,
+ "Inno Setup"),
+ };
- return null;
+ return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
}
///
@@ -42,7 +46,7 @@ namespace BurnOutSharp.PackerType
return null;
}
- private static string GetVersion(byte[] fileContent)
+ public static string GetVersion(string file, byte[] fileContent, int position)
{
byte[] signature = new ArraySegment(fileContent, 0x30, 12).ToArray();
diff --git a/BurnOutSharp/PackerType/NSIS.cs b/BurnOutSharp/PackerType/NSIS.cs
index aac78d72..fd7fd319 100644
--- a/BurnOutSharp/PackerType/NSIS.cs
+++ b/BurnOutSharp/PackerType/NSIS.cs
@@ -1,6 +1,8 @@
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Text;
+using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -9,23 +11,19 @@ namespace BurnOutSharp.PackerType
///
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
- // Nullsoft Install System
- byte?[] check = new byte?[] { 0x4e, 0x75, 0x6c, 0x6c, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d };
- if (fileContent.FirstPosition(check, out int position))
+ var matchers = new List
{
- string version = GetVersion(fileContent, position);
- return $"NSIS {version}" + (includePosition ? $" (Index {position})" : string.Empty);
- }
+ // Nullsoft Install System
+ new Matcher(new byte?[] { 0x4e, 0x75, 0x6c, 0x6c, 0x73, 0x6f, 0x66, 0x74, 0x20, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d }, GetVersion, "NSIS"),
- // NullsoftInst
- check = new byte?[] { 0x4e, 0x75, 0x6c, 0x6c, 0x73, 0x6f, 0x66, 0x74, 0x49, 0x6e, 0x73, 0x74 };
- if (fileContent.FirstPosition(check, out position))
- return $"NSIS" + (includePosition ? $" (Index {position})" : string.Empty);
+ // NullsoftInst
+ new Matcher(new byte?[] { 0x4e, 0x75, 0x6c, 0x6c, 0x73, 0x6f, 0x66, 0x74, 0x49, 0x6e, 0x73, 0x74 }, "NSIS"),
+ };
- return null;
+ return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
}
- private static string GetVersion(byte[] fileContent, int index)
+ public static string GetVersion(string file, byte[] fileContent, int index)
{
try
{
diff --git a/BurnOutSharp/PackerType/PECompact.cs b/BurnOutSharp/PackerType/PECompact.cs
index ac44c02e..e1d11dd9 100644
--- a/BurnOutSharp/PackerType/PECompact.cs
+++ b/BurnOutSharp/PackerType/PECompact.cs
@@ -1,5 +1,6 @@
using System;
-using System.IO;
+using System.Collections.Generic;
+using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -10,26 +11,24 @@ namespace BurnOutSharp.PackerType
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
// Another possible version string for version 1 is "PECO" (50 45 43 4F)
-
- // "pec1"
- byte?[] check = new byte?[] { 0x70, 0x65, 0x63, 0x31 };
- if (fileContent.FirstPosition(check, out int position, end: 2048))
- return "PE Compact 1" + (includePosition ? $" (Index {position})" : string.Empty);
-
- // "PEC2"
- check = new byte?[] { 0x50, 0x45, 0x43, 0x32 };
- if (fileContent.FirstPosition(check, out position, end: 2048))
+ var matchers = new List
{
- int version = BitConverter.ToInt16(fileContent, position + 4);
- return $"PE Compact 2 v{version}" + (includePosition ? $" (Index {position})" : string.Empty);
- }
+ // pec1
+ new Matcher(new byte?[] { 0x70, 0x65, 0x63, 0x31 }, "PE Compact 1"),
- // "PECompact2"
- check = new byte?[] { 0x50, 0x45, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x32 };
- if (fileContent.FirstPosition(check, out position))
- return "PE Compact 2" + (includePosition ? $" (Index {position})" : string.Empty);
+ // PEC2
+ new Matcher(new byte?[] { 0x50, 0x45, 0x43, 0x32 }, GetVersion, "PE Compact 2 v"),
- return null;
+ // PECompact2
+ new Matcher(new byte?[] { 0x50, 0x45, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x32 }, "PE Compact 2"),
+ };
+
+ return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
+ }
+
+ public static string GetVersion(string file, byte[] fileContent, int position)
+ {
+ return BitConverter.ToInt16(fileContent, position + 4).ToString();
}
}
}
diff --git a/BurnOutSharp/PackerType/SetupFactory.cs b/BurnOutSharp/PackerType/SetupFactory.cs
index 8347ffa7..e4a6a0c5 100644
--- a/BurnOutSharp/PackerType/SetupFactory.cs
+++ b/BurnOutSharp/PackerType/SetupFactory.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
+using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -11,27 +12,17 @@ namespace BurnOutSharp.PackerType
///
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
- /* Longer version of the check that can be used if false positves become an issue:
- "S.e.t.u.p. .F.a.c.t.o.r.y. .i.s. .a. .t.r.a.d.e.m.a.r.k. .o.f. .I.n.d.i.g.o. .R.o.s.e. .C.o.r.p.o.r.a.t.i.o.n"
- byte?[] check = new byte?[] { 0x53, 0x00, 0x65, 0x00, 0x74, 0x00, 0x75, 0x00, 0x70, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x79, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6D, 0x00, 0x61, 0x00, 0x72, 0x00, 0x6B, 0x00, 0x20, 0x00, 0x6F, 0x00, 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6E, 0x00, 0x64, 0x00, 0x69, 0x00, 0x67, 0x00, 0x6F, 0x00, 0x20, 0x00, 0x52, 0x00, 0x6F, 0x00, 0x73, 0x00, 0x65, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x70, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E }; */
- // "S.e.t.u.p. .F.a.c.t.o.r.y."
- byte?[] check = new byte?[] { 0x53, 0x00, 0x65, 0x00, 0x74, 0x00, 0x75, 0x00, 0x70, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x79, 0x00 };
- if (fileContent.FirstPosition(check, out int position))
+ // Longer version of the check that can be used if false positves become an issue:
+ // S.e.t.u.p. .F.a.c.t.o.r.y. .i.s. .a. .t.r.a.d.e.m.a.r.k. .o.f. .I.n.d.i.g.o. .R.o.s.e. .C.o.r.p.o.r.a.t.i.o.n
+ // byte?[] check = new byte?[] { 0x53, 0x00, 0x65, 0x00, 0x74, 0x00, 0x75, 0x00, 0x70, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x79, 0x00, 0x20, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x20, 0x00, 0x74, 0x00, 0x72, 0x00, 0x61, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6D, 0x00, 0x61, 0x00, 0x72, 0x00, 0x6B, 0x00, 0x20, 0x00, 0x6F, 0x00, 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6E, 0x00, 0x64, 0x00, 0x69, 0x00, 0x67, 0x00, 0x6F, 0x00, 0x20, 0x00, 0x52, 0x00, 0x6F, 0x00, 0x73, 0x00, 0x65, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x70, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E };
+
+ var matchers = new List
{
- // Check the manifest version first
- string version = Utilities.GetManifestVersion(fileContent);
- if (!string.IsNullOrEmpty(version))
- return $"Setup Factory {version}" + (includePosition ? $" (Index {position})" : string.Empty);
-
- // Then check the file version
- version = Utilities.GetFileVersion(file);
- if (!string.IsNullOrEmpty(version))
- return $"Setup Factory {version}" + (includePosition ? $" (Index {position})" : string.Empty);
+ // S.e.t.u.p. .F.a.c.t.o.r.y.
+ new Matcher(new byte?[] { 0x53, 0x00, 0x65, 0x00, 0x74, 0x00, 0x75, 0x00, 0x70, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x79, 0x00 }, GetVersion, "Setup Factory"),
+ };
- return $"Setup Factory (Unknown Version)" + (includePosition ? $" (Index {position})" : string.Empty);
- }
-
- return null;
+ return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
}
///
@@ -52,5 +43,20 @@ namespace BurnOutSharp.PackerType
{
return null;
}
+
+ public static string GetVersion(string file, byte[] fileContent, int position)
+ {
+ // Check the manifest version first
+ string version = Utilities.GetManifestVersion(fileContent);
+ if (!string.IsNullOrEmpty(version))
+ return version;
+
+ // Then check the file version
+ version = Utilities.GetFileVersion(file);
+ if (!string.IsNullOrEmpty(version))
+ return version;
+
+ return null;
+ }
}
}
diff --git a/BurnOutSharp/PackerType/UPX.cs b/BurnOutSharp/PackerType/UPX.cs
index 6a863f45..eebfc4b9 100644
--- a/BurnOutSharp/PackerType/UPX.cs
+++ b/BurnOutSharp/PackerType/UPX.cs
@@ -1,4 +1,6 @@
+using System.Collections.Generic;
using System.Text;
+using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -7,50 +9,43 @@ namespace BurnOutSharp.PackerType
///
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
- // UPX!
- byte?[] check = new byte?[] { 0x55, 0x50, 0x58, 0x21 };
- if (fileContent.FirstPosition(check, out int position))
+ var matchers = new List
{
- string version = GetVersion(fileContent, position);
- return $"UPX {version}" + (includePosition ? $" (Index {position})" : string.Empty);
- }
+ // UPX!
+ new Matcher(new byte?[] { 0x55, 0x50, 0x58, 0x21 }, GetVersion, "Inno Setup"),
- // NOS
- check = new byte?[] { 0x55, 0x50, 0x58, 0x21 };
- if (fileContent.FirstPosition(check, out position))
- {
- string version = GetVersion(fileContent, position);
- return $"UPX (NOS Variant) {version}" + (includePosition ? $" (Index {position})" : string.Empty);
- }
+ // NOS
+ new Matcher(new byte?[] { 0x4E, 0x4F, 0x53 }, GetVersion, "UPX (NOS Variant)"),
- // UPX0
- check = new byte?[] { 0x55, 0x50, 0x58, 0x30 };
- if (fileContent.FirstPosition(check, out position, end: 2048))
- {
- // UPX1
- byte?[] check2 = new byte?[] { 0x55, 0x50, 0x58, 0x31 };
- if (fileContent.FirstPosition(check2, out int position2, end: 2048))
- {
- return $"UPX (Unknown Version)" + (includePosition ? $" (Index {position}, {position2})" : string.Empty);
- }
- }
+ new Matcher(
+ new List
+ {
+ // UPX0
+ new byte?[] { 0x55, 0x50, 0x58, 0x30 },
- // NOS0
- check = new byte?[] { 0x4E, 0x4F, 0x53, 0x30 };
- if (fileContent.FirstPosition(check, out position, end: 2048))
- {
- // NOS1
- byte?[] check2 = new byte?[] { 0x4E, 0x4F, 0x53, 0x31 };
- if (fileContent.FirstPosition(check2, out int position2, end: 2048))
- {
- return $"UPX (NOS Variant) (Unknown Version)" + (includePosition ? $" (Index {position}, {position2})" : string.Empty);
- }
- }
+ // UPX1
+ new byte?[] { 0x55, 0x50, 0x58, 0x31 },
+ },
+ "UPX (Unknown Version)"
+ ),
- return null;
+ new Matcher(
+ new List
+ {
+ // NOS0
+ new byte?[] { 0x4E, 0x4F, 0x53, 0x30 },
+
+ // NOS1
+ new byte?[] { 0x4E, 0x4F, 0x53, 0x31 },
+ },
+ "UPX (NOS Variant) (Unknown Version)"
+ ),
+ };
+
+ return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
}
- private static string GetVersion(byte[] fileContent, int index)
+ public static string GetVersion(string file, byte[] fileContent, int index)
{
try
{
diff --git a/BurnOutSharp/PackerType/WinRARSFX.cs b/BurnOutSharp/PackerType/WinRARSFX.cs
index ef2dad3e..e082a2e3 100644
--- a/BurnOutSharp/PackerType/WinRARSFX.cs
+++ b/BurnOutSharp/PackerType/WinRARSFX.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using BurnOutSharp.Matching;
using SharpCompress.Archives;
using SharpCompress.Archives.Rar;
@@ -14,13 +15,18 @@ namespace BurnOutSharp.PackerType
///
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
- var mappings = new Dictionary
+ var matchers = new List
{
// Software\WinRAR SFX
- [new byte?[] { 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x5C, 0x57, 0x69, 0x6E, 0x52, 0x41, 0x52, 0x20, 0x53, 0x46, 0x58 }] = "WinRAR SFX",
+ new Matcher(new byte?[]
+ {
+ 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
+ 0x5C, 0x57, 0x69, 0x6E, 0x52, 0x41, 0x52, 0x20,
+ 0x53, 0x46, 0x58
+ }, "WinRAR SFX"),
};
- return Utilities.GetContentMatches(fileContent, mappings, includePosition);
+ return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
}
public Dictionary> Scan(Scanner scanner, string file)
diff --git a/BurnOutSharp/PackerType/WinZipSFX.cs b/BurnOutSharp/PackerType/WinZipSFX.cs
index 3b79b3e9..d9b074d1 100644
--- a/BurnOutSharp/PackerType/WinZipSFX.cs
+++ b/BurnOutSharp/PackerType/WinZipSFX.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using BurnOutSharp.Matching;
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
@@ -14,17 +15,21 @@ namespace BurnOutSharp.PackerType
///
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
- // WinZip Self-Extractor
- byte?[] check = new byte?[] { 0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70, 0x20, 0x53, 0x65, 0x6C, 0x66, 0x2D, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6F, 0x72 };
- if (fileContent.FirstPosition(check, out int position))
- return $"WinZip SFX {GetVersion(fileContent)}" + (includePosition ? $" (Index {position})" : string.Empty);
+ var matchers = new List
+ {
+ // WinZip Self-Extractor
+ new Matcher(new byte?[]
+ {
+ 0x57, 0x69, 0x6E, 0x5A, 0x69, 0x70, 0x20, 0x53,
+ 0x65, 0x6C, 0x66, 0x2D, 0x45, 0x78, 0x74, 0x72,
+ 0x61, 0x63, 0x74, 0x6F, 0x72
+ }, GetVersion, "WinZip SFX"),
- // _winzip_
- check = new byte?[] { 0x5F, 0x77, 0x69, 0x6E, 0x7A, 0x69, 0x70, 0x5F };
- if (fileContent.FirstPosition(check, out position))
- return $"WinZip SFX {GetVersion(fileContent)}" + (includePosition ? $" (Index {position})" : string.Empty);
+ // _winzip_
+ new Matcher(new byte?[] { 0x5F, 0x77, 0x69, 0x6E, 0x7A, 0x69, 0x70, 0x5F }, GetVersion, "WinZip SFX"),
+ };
- return null;
+ return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
}
///
@@ -87,7 +92,7 @@ namespace BurnOutSharp.PackerType
return null;
}
- private static string GetVersion(byte[] fileContent)
+ public static string GetVersion(string file, byte[] fileContent, int position)
{
// Check the manifest version first
string version = Utilities.GetManifestVersion(fileContent);
diff --git a/BurnOutSharp/PackerType/WiseInstaller.cs b/BurnOutSharp/PackerType/WiseInstaller.cs
index 6d5d95ff..62595796 100644
--- a/BurnOutSharp/PackerType/WiseInstaller.cs
+++ b/BurnOutSharp/PackerType/WiseInstaller.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using BurnOutSharp.Matching;
using Wise = WiseUnpacker.WiseUnpacker;
namespace BurnOutSharp.PackerType
@@ -13,13 +14,13 @@ namespace BurnOutSharp.PackerType
///
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
- var mappings = new Dictionary
+ var matchers = new List
{
// WiseMain
- [new byte?[] { 0x57, 0x69, 0x73, 0x65, 0x4D, 0x61, 0x69, 0x6E }] = "Wise Installation Wizard Module",
+ new Matcher(new byte?[] { 0x57, 0x69, 0x73, 0x65, 0x4D, 0x61, 0x69, 0x6E }, "Wise Installation Wizard Module"),
};
- return Utilities.GetContentMatches(fileContent, mappings, includePosition);
+ return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
}
///
diff --git a/BurnOutSharp/PackerType/dotFuscator.cs b/BurnOutSharp/PackerType/dotFuscator.cs
index 910ffd30..5e7a696b 100644
--- a/BurnOutSharp/PackerType/dotFuscator.cs
+++ b/BurnOutSharp/PackerType/dotFuscator.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -7,13 +8,18 @@ namespace BurnOutSharp.PackerType
///
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
- var mappings = new Dictionary
+ var matchers = new List
{
// DotfuscatorAttribute
- [new byte?[] { 0x44, 0x6F, 0x74, 0x66, 0x75, 0x73, 0x63, 0x61, 0x74, 0x6F, 0x72, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65 }] = "dotFuscator",
+ new Matcher(new byte?[]
+ {
+ 0x44, 0x6F, 0x74, 0x66, 0x75, 0x73, 0x63, 0x61,
+ 0x74, 0x6F, 0x72, 0x41, 0x74, 0x74, 0x72, 0x69,
+ 0x62, 0x75, 0x74, 0x65
+ }, "dotFuscator"),
};
- return Utilities.GetContentMatches(fileContent, mappings, includePosition);
+ return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/Utilities.cs b/BurnOutSharp/Utilities.cs
index bcecf433..1a3e30f7 100644
--- a/BurnOutSharp/Utilities.cs
+++ b/BurnOutSharp/Utilities.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
+using BurnOutSharp.Matching;
namespace BurnOutSharp
{
@@ -246,49 +247,56 @@ namespace BurnOutSharp
#region Protection
///
- /// Get simple content matches for a given protection
+ /// Get content matches for a given protection
///
+ /// File to check for matches
/// Byte array representing the file contents
- /// Mapping of byte array to string for matching
+ /// Enumerable of matchers to be run on the file
/// True to include positional data, false otherwise
/// String representing the matched protection, null otherwise
- ///
- /// This is useful for checks that don't do anything special with versions or other positions.
/// TODO: Make variant of this that returns *all* content matches for later
- /// TODO: Make variant of this that can take multiple content checks per check for later
- ///
- public static string GetContentMatches(byte[] fileContent, Dictionary mappings, bool includePosition = false)
- {
- return GetVersionedContentMatches(fileContent, mappings.Select(kvp => (kvp.Key, (Func)null, kvp.Value)).ToList(), includePosition);
- }
-
- ///
- /// Get versioned content matches for a given protection
- ///
- /// Byte array representing the file contents
- /// Tuple of matching byte array, version method, and string to output
- /// True to include positional data, false otherwise
- /// String representing the matched protection, null otherwise
- ///
- /// This is useful for checks that don't do anything special with versions or other positions.
- /// TODO: Make variant of this that returns *all* content matches for later
- /// TODO: Make variant of this that can take multiple content checks per check for later
- ///
- public static string GetVersionedContentMatches(byte[] fileContent, List<(byte?[], Func, string)> mappings, bool includePosition = false)
+ public static string GetContentMatches(string file, byte[] fileContent, IEnumerable matchers, bool includePosition = false)
{
// If there's no mappings, we can't match
- if (mappings == null || !mappings.Any())
+ if (matchers == null || !matchers.Any())
return null;
// Loop through and try everything otherwise
- foreach (var mapping in mappings)
+ foreach (var matcher in matchers)
{
- if (fileContent.FirstPosition(mapping.Item1, out int position))
+ // Setup for a single matcher
+ bool allMatches = true;
+ List positions = new List();
+
+ // Loop through all content matches and make sure all pass
+ foreach (var contentMatch in matcher.ContentMatches)
{
- string version = mapping.Item2 == null ? string.Empty : (mapping.Item2(fileContent, position) ?? "Unknown Version");
- string protection = string.IsNullOrWhiteSpace(version) ? mapping.Item3 : $"{mapping.Item3} {version}";
- return protection + (includePosition ? $" (Index {position})" : string.Empty);
+ if (!fileContent.FirstPosition(contentMatch.Needle, out int position, contentMatch.Start, contentMatch.End))
+ {
+ allMatches = false;
+ break;
+ }
+ else
+ {
+ positions.Add(position);
+ }
}
+
+ // If not all matches pass, then we continue
+ if (!allMatches)
+ continue;
+
+ // Format the list of all positions found
+ string positionsString = string.Join(", ", positions);
+
+ // If we there is no version method, just return the protection name
+ if (matcher.GetVersion == null)
+ return (matcher.ProtectionName ?? "Unknown Protection") + (includePosition ? $" (Index {positionsString})" : string.Empty);
+
+ // Otherwise, invoke the version method
+ // TODO: Pass all positions to the version finding method
+ string version = matcher.GetVersion(file, fileContent, positions[0]) ?? "Unknown Version";
+ return $"{matcher.ProtectionName} {version}" + (includePosition ? $" (Index {positionsString})" : string.Empty);
}
return null;