Use content matching helper, part 2

This commit is contained in:
Matt Nadareski
2021-03-21 15:24:23 -07:00
parent ab07eb96ce
commit 7e3ef544f0
14 changed files with 275 additions and 149 deletions

View File

@@ -0,0 +1,30 @@
namespace BurnOutSharp.Matching
{
/// <summary>
/// Single matching criteria
/// </summary>
internal class ContentMatch
{
/// <summary>
/// Content to match
/// </summary>
public byte?[] Needle { get; set; }
/// <summary>
/// Starting index for matching
/// </summary>
public int Start { get; set; }
/// <summary>
/// Ending index for matching
/// </summary>
public int End { get; set; }
public ContentMatch(byte?[] needle, int start = -1, int end = -1)
{
Needle = needle;
Start = start;
End = end;
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace BurnOutSharp.Matching
{
/// <summary>
/// Wrapper for a single set of matching criteria
/// </summary>
internal class Matcher
{
/// <summary>
/// Set of all content matches
/// </summary>
public IEnumerable<ContentMatch> ContentMatches { get; set; }
/// <summary>
/// Function to get a version for this Matcher
/// </summary>
public Func<string, byte[], int, string> GetVersion { get; set; }
/// <summary>
/// Name of the protection to show
/// </summary>
public string ProtectionName { get; set; }
#region Constructors
public Matcher(byte?[] needle, string protectionName)
: this(new List<byte?[]>() { needle }, null, protectionName) { }
public Matcher(List<byte?[]> needles, string protectionName)
: this(needles, null, protectionName) { }
public Matcher(byte?[] needle, Func<string, byte[], int, string> getVersion, string protectionName)
: this(new List<byte?[]>() { needle }, getVersion, protectionName) { }
public Matcher(List<byte?[]> needles, Func<string, byte[], int, string> getVersion, string protectionName)
: this(needles.Select(n => new ContentMatch(n)).ToList(), getVersion, protectionName) { }
public Matcher(ContentMatch needle, string protectionName)
: this(new List<ContentMatch>() { needle }, null, protectionName) { }
public Matcher(List<ContentMatch> needles, string protectionName)
: this(needles, null, protectionName) { }
public Matcher(ContentMatch needle, Func<string, byte[], int, string> getVersion, string protectionName)
: this(new List<ContentMatch>() { needle }, getVersion, protectionName) { }
public Matcher(List<ContentMatch> needles, Func<string, byte[], int, string> getVersion, string protectionName)
{
ContentMatches = needles;
GetVersion = getVersion;
ProtectionName = protectionName;
}
#endregion
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -7,16 +8,16 @@ namespace BurnOutSharp.PackerType
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var mappings = new Dictionary<byte?[], string>
var matchers = new List<Matcher>
{
// .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);
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -7,13 +8,20 @@ namespace BurnOutSharp.PackerType
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var mappings = new Dictionary<byte?[], string>
var matchers = new List<Matcher>
{
// ??[[__[[_ + (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);
}
}
}

View File

@@ -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
/// <inheritdoc/>
public bool ShouldScan(byte[] magic) => true;
/// <inheritdoc/>
/// <inheritdoc/>
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<Matcher>
{
// 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);
}
/// <inheritdoc/>
@@ -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<byte>(fileContent, 0x30, 12).ToArray();

View File

@@ -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
/// <inheritdoc/>
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<Matcher>
{
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
{

View File

@@ -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<Matcher>
{
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();
}
}
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -11,27 +12,17 @@ namespace BurnOutSharp.PackerType
/// <inheritdoc/>
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<Matcher>
{
// 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);
}
/// <inheritdoc/>
@@ -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;
}
}
}

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System.Text;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -7,50 +9,43 @@ namespace BurnOutSharp.PackerType
/// <inheritdoc/>
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<Matcher>
{
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<byte?[]>
{
// 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<byte?[]>
{
// 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
{

View File

@@ -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
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var mappings = new Dictionary<byte?[], string>
var matchers = new List<Matcher>
{
// 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<string, List<string>> Scan(Scanner scanner, string file)

View File

@@ -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
/// <inheritdoc/>
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<Matcher>
{
// 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);
}
/// <inheritdoc/>
@@ -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);

View File

@@ -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
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var mappings = new Dictionary<byte?[], string>
var matchers = new List<Matcher>
{
// 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);
}
/// <inheritdoc/>

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using BurnOutSharp.Matching;
namespace BurnOutSharp.PackerType
{
@@ -7,13 +8,18 @@ namespace BurnOutSharp.PackerType
/// <inheritdoc/>
public string CheckContents(string file, byte[] fileContent, bool includePosition = false)
{
var mappings = new Dictionary<byte?[], string>
var matchers = new List<Matcher>
{
// 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);
}
}
}

View File

@@ -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
/// <summary>
/// Get simple content matches for a given protection
/// Get content matches for a given protection
/// </summary>
/// <param name="file">File to check for matches</param>
/// <param name="fileContent">Byte array representing the file contents</param>
/// <param name="mappings">Mapping of byte array to string for matching</param>
/// <param name="matchers">Enumerable of matchers to be run on the file</param>
/// <param name="includePosition">True to include positional data, false otherwise</param>
/// <returns>String representing the matched protection, null otherwise</returns>
/// <remarks>
/// 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
/// </remarks>
public static string GetContentMatches(byte[] fileContent, Dictionary<byte?[], string> mappings, bool includePosition = false)
{
return GetVersionedContentMatches(fileContent, mappings.Select(kvp => (kvp.Key, (Func<byte[], int, string>)null, kvp.Value)).ToList(), includePosition);
}
/// <summary>
/// Get versioned content matches for a given protection
/// </summary>
/// <param name="fileContent">Byte array representing the file contents</param>
/// <param name="mappings">Tuple of matching byte array, version method, and string to output</param>
/// <param name="includePosition">True to include positional data, false otherwise</param>
/// <returns>String representing the matched protection, null otherwise</returns>
/// <remarks>
/// 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
/// </remarks>
public static string GetVersionedContentMatches(byte[] fileContent, List<(byte?[], Func<byte[], int, string>, string)> mappings, bool includePosition = false)
public static string GetContentMatches(string file, byte[] fileContent, IEnumerable<Matcher> 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<int> positions = new List<int>();
// 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;