mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-04-29 01:50:24 +00:00
Rearrange Executable-related things
This commit is contained in:
@@ -24,6 +24,8 @@
|
||||
<ProjectReference Include="..\BinaryObjectScanner.Compression\BinaryObjectScanner.Compression.csproj" />
|
||||
<ProjectReference Include="..\BinaryObjectScanner.Interfaces\BinaryObjectScanner.Interfaces.csproj" />
|
||||
<ProjectReference Include="..\BinaryObjectScanner.Matching\BinaryObjectScanner.Matching.csproj" />
|
||||
<ProjectReference Include="..\BinaryObjectScanner.Packer\BinaryObjectScanner.Packer.csproj" />
|
||||
<ProjectReference Include="..\BinaryObjectScanner.Protection\BinaryObjectScanner.Protection.csproj" />
|
||||
<ProjectReference Include="..\BinaryObjectScanner.Wrappers\BinaryObjectScanner.Wrappers.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using BinaryObjectScanner.Utilities;
|
||||
using BinaryObjectScanner.Wrappers;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
@@ -8,11 +16,100 @@ namespace BinaryObjectScanner.FileType
|
||||
/// Executable or library
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Due to the complexity of executables, all actual handling is offloaded to
|
||||
/// Due to the complexity of executables, all extraction handling
|
||||
/// another class that is used by the scanner
|
||||
/// </remarks>
|
||||
public class Executable : IDetectable, IExtractable
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Determines if packers are counted as detected protections or not
|
||||
/// </summary>
|
||||
public bool IncludePackers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IContentCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<IContentCheck> ContentCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (contentCheckClasses == null)
|
||||
contentCheckClasses = InitCheckClasses<IContentCheck>();
|
||||
|
||||
return contentCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all ILinearExecutableCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<ILinearExecutableCheck> LinearExecutableCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (linearExecutableCheckClasses == null)
|
||||
linearExecutableCheckClasses = InitCheckClasses<ILinearExecutableCheck>();
|
||||
|
||||
return linearExecutableCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all INewExecutableCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<INewExecutableCheck> NewExecutableCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (newExecutableCheckClasses == null)
|
||||
newExecutableCheckClasses = InitCheckClasses<INewExecutableCheck>();
|
||||
|
||||
return newExecutableCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPortableExecutableCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<IPortableExecutableCheck> PortableExecutableCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (portableExecutableCheckClasses == null)
|
||||
portableExecutableCheckClasses = InitCheckClasses<IPortableExecutableCheck>();
|
||||
|
||||
return portableExecutableCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Instances
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IContentCheck types
|
||||
/// </summary>
|
||||
private static IEnumerable<IContentCheck> contentCheckClasses;
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all ILinearExecutableCheck types
|
||||
/// </summary>
|
||||
private static IEnumerable<ILinearExecutableCheck> linearExecutableCheckClasses;
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all INewExecutableCheck types
|
||||
/// </summary>
|
||||
private static IEnumerable<INewExecutableCheck> newExecutableCheckClasses;
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPortableExecutableCheck types
|
||||
/// </summary>
|
||||
private static IEnumerable<IPortableExecutableCheck> portableExecutableCheckClasses;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Detect(string file, bool includeDebug)
|
||||
{
|
||||
@@ -26,10 +123,48 @@ namespace BinaryObjectScanner.FileType
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>This implementation should never be invoked</remarks>
|
||||
public string Detect(Stream stream, string file, bool includeDebug)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
// Try to create a wrapper for the proper executable type
|
||||
var wrapper = WrapperFactory.CreateExecutableWrapper(stream);
|
||||
if (wrapper == null)
|
||||
return null;
|
||||
|
||||
// Create the internal queue
|
||||
var protections = new ConcurrentQueue<string>();
|
||||
|
||||
// Only use generic content checks if we're in debug mode
|
||||
if (includeDebug)
|
||||
{
|
||||
var subProtections = RunContentChecks(file, stream, includeDebug);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections.Values.ToArray());
|
||||
}
|
||||
|
||||
if (wrapper is MSDOS)
|
||||
{
|
||||
// No-op until protection classes implmented
|
||||
}
|
||||
else if (wrapper is LinearExecutable lex)
|
||||
{
|
||||
var subProtections = RunLinearExecutableChecks(file, stream, lex, includeDebug);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections.Values.ToArray());
|
||||
}
|
||||
else if (wrapper is NewExecutable nex)
|
||||
{
|
||||
var subProtections = RunNewExecutableChecks(file, stream, nex, includeDebug);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections.Values.ToArray());
|
||||
}
|
||||
else if (wrapper is PortableExecutable pex)
|
||||
{
|
||||
var subProtections = RunPortableExecutableChecks(file, stream, pex, includeDebug);
|
||||
if (subProtections != null)
|
||||
protections.AddRange(subProtections.Values.ToArray());
|
||||
}
|
||||
|
||||
return string.Join(";", protections);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -50,5 +185,186 @@ namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
#region Check Runners
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all content check implementations
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the source file of the stream, for tracking</param>
|
||||
/// <param name="stream">Stream to scan the contents of</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public ConcurrentDictionary<IContentCheck, string> RunContentChecks(string file, Stream stream, bool includeDebug)
|
||||
{
|
||||
// If we have an invalid file
|
||||
if (string.IsNullOrWhiteSpace(file))
|
||||
return null;
|
||||
else if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
// Read the file contents
|
||||
byte[] fileContent = null;
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
fileContent = br.ReadBytes((int)stream.Length);
|
||||
if (fileContent == null)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<IContentCheck, string>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(ContentCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
string protection = checkClass.CheckContents(file, fileContent, includeDebug);
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return;
|
||||
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !IncludePackers)
|
||||
return;
|
||||
|
||||
protections.TryAdd(checkClass, protection);
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all linear executable check implementations
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="lex">Executable to scan</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public ConcurrentDictionary<ILinearExecutableCheck, string> RunLinearExecutableChecks(string file, Stream stream, LinearExecutable lex, bool includeDebug)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<ILinearExecutableCheck, string>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(LinearExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
string protection = checkClass.CheckLinearExecutable(file, lex, includeDebug);
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return;
|
||||
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !IncludePackers)
|
||||
return;
|
||||
|
||||
protections.TryAdd(checkClass, protection);
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all new executable check implementations
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="nex">Executable to scan</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public ConcurrentDictionary<INewExecutableCheck, string> RunNewExecutableChecks(string file, Stream stream, NewExecutable nex, bool includeDebug)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<INewExecutableCheck, string>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(NewExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
string protection = checkClass.CheckNewExecutable(file, nex, includeDebug);
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return;
|
||||
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !IncludePackers)
|
||||
return;
|
||||
|
||||
protections.TryAdd(checkClass, protection);
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all portable executable check implementations
|
||||
/// </summary>
|
||||
/// <param name="file">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="pex">Executable to scan</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public ConcurrentDictionary<IPortableExecutableCheck, string> RunPortableExecutableChecks(string file, Stream stream, PortableExecutable pex, bool includeDebug)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<IPortableExecutableCheck, string>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(PortableExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
string protection = checkClass.CheckPortableExecutable(file, pex, includeDebug);
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return;
|
||||
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !IncludePackers)
|
||||
return;
|
||||
|
||||
protections.TryAdd(checkClass, protection);
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initializers
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all implementations of a type
|
||||
/// </summary>
|
||||
private static IEnumerable<T> InitCheckClasses<T>()
|
||||
=> InitCheckClasses<T>(typeof(BinaryObjectScanner.Packer._DUMMY).Assembly)
|
||||
.Concat(InitCheckClasses<T>(typeof(BinaryObjectScanner.Protection._DUMMY).Assembly));
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all implementations of a type
|
||||
/// </summary>
|
||||
private static IEnumerable<T> InitCheckClasses<T>(Assembly assembly)
|
||||
{
|
||||
return assembly.GetTypes()
|
||||
.Where(t => t.IsClass && t.GetInterface(typeof(T).Name) != null)
|
||||
.Select(t => (T)Activator.CreateInstance(t));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Check to see if an implementation is a packer using reflection
|
||||
/// </summary>
|
||||
/// <param name="impl">Implementation that was last used to check</param>
|
||||
private static bool CheckIfPacker(object impl)
|
||||
{
|
||||
return impl.GetType().Namespace.ToLowerInvariant().Contains("packer");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,150 +3,45 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using BinaryObjectScanner.Utilities;
|
||||
using BinaryObjectScanner.Wrappers;
|
||||
using static BinaryObjectScanner.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp
|
||||
{
|
||||
internal static class Handler
|
||||
{
|
||||
#region Public Collections
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPathCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<IPathCheck> PathCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pathCheckClasses == null)
|
||||
pathCheckClasses = InitCheckClasses<IPathCheck>();
|
||||
|
||||
return pathCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Instances
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPathCheck types
|
||||
/// </summary>
|
||||
private static IEnumerable<IPathCheck> pathCheckClasses;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Multiple Implementation Wrappers
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all content check implementations
|
||||
/// </summary>
|
||||
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
|
||||
/// <param name="stream">Stream to scan the contents of</param>
|
||||
/// <param name="scanner">Scanner object to use for options and scanning</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public static ConcurrentQueue<string> HandleContentChecks(string fileName, Stream stream, Scanner scanner)
|
||||
{
|
||||
// If we have an invalid file
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
return null;
|
||||
else if (!File.Exists(fileName))
|
||||
return null;
|
||||
|
||||
// Read the file contents
|
||||
byte[] fileContent = null;
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
fileContent = br.ReadBytes((int)stream.Length);
|
||||
if (fileContent == null)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create the output queue
|
||||
var protections = new ConcurrentQueue<string>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(ScanningClasses.ContentCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var subProtections = checkClass.PerformCheck(fileName, fileContent, scanner.IncludeDebug);
|
||||
if (subProtections != null)
|
||||
{
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !scanner.ScanPackers)
|
||||
return;
|
||||
|
||||
protections.AddRange(subProtections);
|
||||
}
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all linear executable check implementations
|
||||
/// </summary>
|
||||
/// <param name="fileName">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="lex">Executable to scan</param>
|
||||
/// <param name="scanner">Scanner object to use for options and scanning</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandleLinearExecutableChecks(string fileName, Stream stream, LinearExecutable lex, Scanner scanner)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(ScanningClasses.LinearExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var subProtections = checkClass.PerformCheck(fileName, lex, scanner.IncludeDebug);
|
||||
if (subProtections == null)
|
||||
return;
|
||||
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !scanner.ScanPackers)
|
||||
return;
|
||||
|
||||
// Add all found protections to the output
|
||||
AppendToDictionary(protections, fileName, subProtections);
|
||||
|
||||
// If we have an extractable implementation
|
||||
if (checkClass is IExtractable extractable)
|
||||
{
|
||||
var extractedProtections = HandleExtractable(extractable, fileName, stream, scanner);
|
||||
if (extractedProtections != null)
|
||||
AppendToDictionary(protections, extractedProtections);
|
||||
}
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all new executable check implementations
|
||||
/// </summary>
|
||||
/// <param name="fileName">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="nex">Executable to scan</param>
|
||||
/// <param name="scanner">Scanner object to use for options and scanning</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandleNewExecutableChecks(string fileName, Stream stream, NewExecutable nex, Scanner scanner)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(ScanningClasses.NewExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var subProtections = checkClass.PerformCheck(fileName, nex, scanner.IncludeDebug);
|
||||
if (subProtections == null)
|
||||
return;
|
||||
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !scanner.ScanPackers)
|
||||
return;
|
||||
|
||||
// Add all found protections to the output
|
||||
AppendToDictionary(protections, fileName, subProtections);
|
||||
|
||||
// If we have an extractable implementation
|
||||
if (checkClass is IExtractable extractable)
|
||||
{
|
||||
var extractedProtections = HandleExtractable(extractable, fileName, stream, scanner);
|
||||
if (extractedProtections != null)
|
||||
AppendToDictionary(protections, extractedProtections);
|
||||
}
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single path based on all path check implementations
|
||||
/// </summary>
|
||||
@@ -162,7 +57,7 @@ namespace BurnOutSharp
|
||||
files = files?.Select(f => f.Replace('\\', '/'))?.ToList();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(ScanningClasses.PathCheckClasses, checkClass =>
|
||||
Parallel.ForEach(PathCheckClasses, checkClass =>
|
||||
{
|
||||
var subProtections = checkClass.PerformCheck(path, files);
|
||||
if (subProtections != null)
|
||||
@@ -172,45 +67,6 @@ namespace BurnOutSharp
|
||||
return protections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a single file based on all portable executable check implementations
|
||||
/// </summary>
|
||||
/// <param name="fileName">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="pex">Executable to scan</param>
|
||||
/// <param name="scanner">Scanner object to use for options and scanning</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandlePortableExecutableChecks(string fileName, Stream stream, PortableExecutable pex, Scanner scanner)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
|
||||
|
||||
// Iterate through all checks
|
||||
Parallel.ForEach(ScanningClasses.PortableExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var subProtections = checkClass.PerformCheck(fileName, pex, scanner.IncludeDebug);
|
||||
if (subProtections == null)
|
||||
return;
|
||||
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !scanner.ScanPackers)
|
||||
return;
|
||||
|
||||
// Add all found protections to the output
|
||||
AppendToDictionary(protections, fileName, subProtections);
|
||||
|
||||
// If we have an extractable implementation
|
||||
if (checkClass is IExtractable extractable)
|
||||
{
|
||||
var extractedProtections = HandleExtractable(extractable, fileName, stream, scanner);
|
||||
if (extractedProtections != null)
|
||||
AppendToDictionary(protections, extractedProtections);
|
||||
}
|
||||
});
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Single Implementation Handlers
|
||||
@@ -273,48 +129,6 @@ namespace BurnOutSharp
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an IContentCheck implementation
|
||||
/// </summary>
|
||||
/// <param name="impl">IDetectable class representing the check</param>
|
||||
/// <param name="fileName">Name of the source file of the byte array, for tracking</param>
|
||||
/// <param name="fileContent">Contents of the source file</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
private static ConcurrentQueue<string> PerformCheck(this IContentCheck impl, string fileName, byte[] fileContent, bool includeDebug)
|
||||
{
|
||||
string protection = impl.CheckContents(fileName, fileContent, includeDebug);
|
||||
return ProcessProtectionString(protection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an ILinearExecutableCheck implementation
|
||||
/// </summary>
|
||||
/// <param name="impl">ILinearExecutableCheck class representing the check</param>
|
||||
/// <param name="fileName">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="lex">LinearExecutable to check</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
private static ConcurrentQueue<string> PerformCheck(this ILinearExecutableCheck impl, string fileName, LinearExecutable lex, bool includeDebug)
|
||||
{
|
||||
string protection = impl.CheckLinearExecutable(fileName, lex, includeDebug);
|
||||
return ProcessProtectionString(protection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an INewExecutableCheck implementation
|
||||
/// </summary>
|
||||
/// <param name="impl">INewExecutableCheck class representing the check</param>
|
||||
/// <param name="fileName">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="nex">NewExecutable to check</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
private static ConcurrentQueue<string> PerformCheck(this INewExecutableCheck impl, string fileName, NewExecutable nex, bool includeDebug)
|
||||
{
|
||||
string protection = impl.CheckNewExecutable(fileName, nex, includeDebug);
|
||||
return ProcessProtectionString(protection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an IPathCheck implementation
|
||||
/// </summary>
|
||||
@@ -350,33 +164,31 @@ namespace BurnOutSharp
|
||||
return protections;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initializers
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an IPortableExecutableCheck implementation
|
||||
/// Initialize all implementations of a type
|
||||
/// </summary>
|
||||
/// <param name="impl">IPortableExecutableCheck class representing the check</param>
|
||||
/// <param name="fileName">Name of the source file of the executable, for tracking</param>
|
||||
/// <param name="pex">NewExecutable to check</param>
|
||||
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
private static ConcurrentQueue<string> PerformCheck(this IPortableExecutableCheck impl, string fileName, PortableExecutable pex, bool includeDebug)
|
||||
private static IEnumerable<T> InitCheckClasses<T>()
|
||||
=> InitCheckClasses<T>(typeof(BinaryObjectScanner.Packer._DUMMY).Assembly)
|
||||
.Concat(InitCheckClasses<T>(typeof(BinaryObjectScanner.Protection._DUMMY).Assembly));
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all implementations of a type
|
||||
/// </summary>
|
||||
private static IEnumerable<T> InitCheckClasses<T>(Assembly assembly)
|
||||
{
|
||||
string protection = impl.CheckPortableExecutable(fileName, pex, includeDebug);
|
||||
return ProcessProtectionString(protection);
|
||||
return assembly.GetTypes()
|
||||
.Where(t => t.IsClass && t.GetInterface(typeof(T).Name) != null)
|
||||
.Select(t => (T)Activator.CreateInstance(t));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Check to see if an implementation is a packer using reflection
|
||||
/// </summary>
|
||||
/// <param name="impl">Implementation that was last used to check</param>
|
||||
private static bool CheckIfPacker(object impl)
|
||||
{
|
||||
return impl.GetType().Namespace.ToLowerInvariant().Contains("packer");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a protection string if it includes multiple protections
|
||||
/// </summary>
|
||||
|
||||
@@ -4,7 +4,9 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BinaryObjectScanner.FileType;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using BinaryObjectScanner.Utilities;
|
||||
using BinaryObjectScanner.Wrappers;
|
||||
using static BinaryObjectScanner.Utilities.Dictionary;
|
||||
@@ -297,9 +299,18 @@ namespace BurnOutSharp
|
||||
{
|
||||
// If we have an executable, it needs to bypass normal handling
|
||||
// TODO: Write custom executable handling
|
||||
if (detectable is Executable)
|
||||
if (detectable is Executable executable)
|
||||
{
|
||||
ProcessExecutable(fileName, stream, protections);
|
||||
executable.IncludePackers = ScanPackers;
|
||||
|
||||
// TODO: Enable this after IExtractable is properly implemented for Executable
|
||||
//var subProtections = Handler.HandleDetectable(executable, fileName, stream, IncludeDebug);
|
||||
//if (subProtections != null)
|
||||
// AppendToDictionary(protections, fileName, subProtections);
|
||||
|
||||
var subProtections = ProcessExecutable(executable, fileName, stream);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
|
||||
// Otherwise, use the default implementation
|
||||
@@ -366,26 +377,29 @@ namespace BurnOutSharp
|
||||
/// <summary>
|
||||
/// Process scanning for an Executable type
|
||||
/// </summary>
|
||||
/// <param name="executable">Executable instance for processing</param>
|
||||
/// <param name="fileName">Name of the source file of the stream, for tracking</param>
|
||||
/// <param name="stream">Stream to scan the contents of</param>
|
||||
/// <param name="protections">Current set of protections to append to</param>
|
||||
/// <remarks>
|
||||
/// Ideally, we wouldn't need to circumvent the proper handling of file types just for Executable,
|
||||
/// but due to the complexity of scanning, this is not currently possible.
|
||||
/// </remarks>
|
||||
private void ProcessExecutable(string fileName, Stream stream, ConcurrentDictionary<string, ConcurrentQueue<string>> protections)
|
||||
private ConcurrentDictionary<string, ConcurrentQueue<string>> ProcessExecutable(Executable executable, string fileName, Stream stream)
|
||||
{
|
||||
// Try to create a wrapper for the proper executable type
|
||||
var wrapper = WrapperFactory.CreateExecutableWrapper(stream);
|
||||
if (wrapper == null)
|
||||
return;
|
||||
return null;
|
||||
|
||||
// Create the output dictionary
|
||||
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
|
||||
|
||||
// Only use generic content checks if we're in debug mode
|
||||
if (IncludeDebug)
|
||||
{
|
||||
var subProtections = Handler.HandleContentChecks(fileName, stream, this);
|
||||
var subProtections = executable.RunContentChecks(fileName, stream, IncludeDebug);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, fileName, subProtections);
|
||||
AppendToDictionary(protections, fileName, subProtections.Values.ToArray());
|
||||
}
|
||||
|
||||
if (wrapper is MSDOS)
|
||||
@@ -394,22 +408,63 @@ namespace BurnOutSharp
|
||||
}
|
||||
else if (wrapper is LinearExecutable lex)
|
||||
{
|
||||
var subProtections = Handler.HandleLinearExecutableChecks(fileName, stream, lex, this);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, subProtections);
|
||||
var subProtections = executable.RunLinearExecutableChecks(fileName, stream, lex, IncludeDebug);
|
||||
if (subProtections == null)
|
||||
return protections;
|
||||
|
||||
// Append the returned values
|
||||
AppendToDictionary(protections, fileName, subProtections.Values.ToArray());
|
||||
|
||||
// If we have any extractable packers
|
||||
var extractables = subProtections.Keys.Where(c => c is IExtractable).Select(c => c as IExtractable);
|
||||
Parallel.ForEach(extractables, extractable =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var extractedProtections = Handler.HandleExtractable(extractable, fileName, stream, this);
|
||||
if (extractedProtections != null)
|
||||
AppendToDictionary(protections, extractedProtections);
|
||||
});
|
||||
}
|
||||
else if (wrapper is NewExecutable nex)
|
||||
{
|
||||
var subProtections = Handler.HandleNewExecutableChecks(fileName, stream, nex, this);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, subProtections);
|
||||
var subProtections = executable.RunNewExecutableChecks(fileName, stream, nex, IncludeDebug);
|
||||
if (subProtections == null)
|
||||
return protections;
|
||||
|
||||
// Append the returned values
|
||||
AppendToDictionary(protections, fileName, subProtections.Values.ToArray());
|
||||
|
||||
// If we have any extractable packers
|
||||
var extractables = subProtections.Keys.Where(c => c is IExtractable).Select(c => c as IExtractable);
|
||||
Parallel.ForEach(extractables, extractable =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var extractedProtections = Handler.HandleExtractable(extractable, fileName, stream, this);
|
||||
if (extractedProtections != null)
|
||||
AppendToDictionary(protections, extractedProtections);
|
||||
});
|
||||
}
|
||||
else if (wrapper is PortableExecutable pex)
|
||||
{
|
||||
var subProtections = Handler.HandlePortableExecutableChecks(fileName, stream, pex, this);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, subProtections);
|
||||
var subProtections = executable.RunPortableExecutableChecks(fileName, stream, pex, IncludeDebug);
|
||||
if (subProtections == null)
|
||||
return protections;
|
||||
|
||||
// Append the returned values
|
||||
AppendToDictionary(protections, fileName, subProtections.Values.ToArray());
|
||||
|
||||
// If we have any extractable packers
|
||||
var extractables = subProtections.Keys.Where(c => c is IExtractable).Select(c => c as IExtractable);
|
||||
Parallel.ForEach(extractables, extractable =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var extractedProtections = Handler.HandleExtractable(extractable, fileName, stream, this);
|
||||
if (extractedProtections != null)
|
||||
AppendToDictionary(protections, extractedProtections);
|
||||
});
|
||||
}
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BurnOutSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// Statically-generated lists of scanning classes
|
||||
/// </summary>
|
||||
internal static class ScanningClasses
|
||||
{
|
||||
#region Public Collections
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IContentCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<IContentCheck> ContentCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (contentCheckClasses == null)
|
||||
contentCheckClasses = InitCheckClasses<IContentCheck>();
|
||||
|
||||
return contentCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IExtractable types
|
||||
/// </summary>
|
||||
public static IEnumerable<IExtractable> ExtractableClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (extractableClasses == null)
|
||||
extractableClasses = InitCheckClasses<IExtractable>();
|
||||
|
||||
return extractableClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all ILinearExecutableCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<ILinearExecutableCheck> LinearExecutableCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (linearExecutableCheckClasses == null)
|
||||
linearExecutableCheckClasses = InitCheckClasses<ILinearExecutableCheck>();
|
||||
|
||||
return linearExecutableCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all INewExecutableCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<INewExecutableCheck> NewExecutableCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (newExecutableCheckClasses == null)
|
||||
newExecutableCheckClasses = InitCheckClasses<INewExecutableCheck>();
|
||||
|
||||
return newExecutableCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPathCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<IPathCheck> PathCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pathCheckClasses == null)
|
||||
pathCheckClasses = InitCheckClasses<IPathCheck>();
|
||||
|
||||
return pathCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPortableExecutableCheck types
|
||||
/// </summary>
|
||||
public static IEnumerable<IPortableExecutableCheck> PortableExecutableCheckClasses
|
||||
{
|
||||
get
|
||||
{
|
||||
if (portableExecutableCheckClasses == null)
|
||||
portableExecutableCheckClasses = InitCheckClasses<IPortableExecutableCheck>();
|
||||
|
||||
return portableExecutableCheckClasses;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Instances
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IContentCheck types
|
||||
/// </summary>
|
||||
private static IEnumerable<IContentCheck> contentCheckClasses;
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IExtractable types
|
||||
/// </summary>
|
||||
private static IEnumerable<IExtractable> extractableClasses;
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all ILinearExecutableCheck types
|
||||
/// </summary>
|
||||
private static IEnumerable<ILinearExecutableCheck> linearExecutableCheckClasses;
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all INewExecutableCheck types
|
||||
/// </summary>
|
||||
private static IEnumerable<INewExecutableCheck> newExecutableCheckClasses;
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPathCheck types
|
||||
/// </summary>
|
||||
private static IEnumerable<IPathCheck> pathCheckClasses;
|
||||
|
||||
/// <summary>
|
||||
/// Cache for all IPortableExecutableCheck types
|
||||
/// </summary>
|
||||
private static IEnumerable<IPortableExecutableCheck> portableExecutableCheckClasses;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Initializers
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all implementations of a type
|
||||
/// </summary>
|
||||
private static IEnumerable<T> InitCheckClasses<T>()
|
||||
=> InitCheckClasses<T>(typeof(BinaryObjectScanner.Packer._DUMMY).Assembly)
|
||||
.Concat(InitCheckClasses<T>(typeof(BinaryObjectScanner.Protection._DUMMY).Assembly));
|
||||
|
||||
/// <summary>
|
||||
/// Initialize all implementations of a type
|
||||
/// </summary>
|
||||
private static IEnumerable<T> InitCheckClasses<T>(Assembly assembly)
|
||||
{
|
||||
return assembly.GetTypes()
|
||||
.Where(t => t.IsClass && t.GetInterface(typeof(T).Name) != null)
|
||||
.Select(t => (T)Activator.CreateInstance(t));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user