mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-02-13 13:45:57 +00:00
293 lines
13 KiB
C#
293 lines
13 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using BinaryObjectScanner.Interfaces;
|
|
using BinaryObjectScanner.Utilities;
|
|
using BinaryObjectScanner.Wrappers;
|
|
using static BinaryObjectScanner.Utilities.Dictionary;
|
|
|
|
namespace BurnOutSharp
|
|
{
|
|
// TODO: Implement IExtractable handler
|
|
// TODO: Implement IPathCheck handler
|
|
internal static class Handler
|
|
{
|
|
#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="scanPackers">True to include packers in the output, false otherwise</param>
|
|
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
|
/// <returns>Set of protections in file, null on error</returns>
|
|
public static ConcurrentQueue<string> HandleContentChecks(string fileName, Stream stream, bool scanPackers, bool includeDebug)
|
|
{
|
|
// 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 (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 = HandleContentCheck(checkClass, fileName, fileContent, includeDebug);
|
|
if (subProtections != null)
|
|
{
|
|
// If we are filtering the output of the check
|
|
if (!CheckIfPacker(checkClass) || !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="scanArchives">True to include extractable contents in the output, false otherwise</param>
|
|
/// <param name="scanPackers">True to include packers in the output, false otherwise</param>
|
|
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
|
/// <returns>Set of protections in file, null on error</returns>
|
|
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandleNewExecutableChecks(string fileName, LinearExecutable lex, bool scanArchives, bool scanPackers, bool includeDebug)
|
|
{
|
|
// 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 = HandleLinearExecutableCheck(checkClass, fileName, lex, includeDebug);
|
|
if (subProtections != null)
|
|
{
|
|
// If we are filtering the output of the check
|
|
if (!CheckIfPacker(checkClass) || !scanPackers)
|
|
return;
|
|
|
|
AppendToDictionary(protections, fileName, subProtections);
|
|
}
|
|
|
|
// TODO: Handle extractable implementations
|
|
});
|
|
|
|
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="scanArchives">True to include extractable contents in the output, false otherwise</param>
|
|
/// <param name="scanPackers">True to include packers in the output, false otherwise</param>
|
|
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
|
/// <returns>Set of protections in file, null on error</returns>
|
|
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandleNewExecutableChecks(string fileName, NewExecutable nex, bool scanArchives, bool scanPackers, bool includeDebug)
|
|
{
|
|
// 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 = HandleNewExecutableCheck(checkClass, fileName, nex, includeDebug);
|
|
if (subProtections != null)
|
|
{
|
|
// If we are filtering the output of the check
|
|
if (!CheckIfPacker(checkClass) || !scanPackers)
|
|
return;
|
|
|
|
AppendToDictionary(protections, fileName, subProtections);
|
|
}
|
|
|
|
// TODO: Handle extractable implementations
|
|
});
|
|
|
|
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="scanArchives">True to include extractable contents in the output, false otherwise</param>
|
|
/// <param name="scanPackers">True to include packers in the output, false otherwise</param>
|
|
/// <param name="includeDebug">True to include debug data, false otherwise</param>
|
|
/// <returns>Set of protections in file, null on error</returns>
|
|
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandlePortableExecutableChecks(string fileName, PortableExecutable pex, bool scanArchives, bool scanPackers, bool includeDebug)
|
|
{
|
|
// 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 = HandlePortableExecutableCheck(checkClass, fileName, pex, includeDebug);
|
|
if (subProtections != null)
|
|
{
|
|
// If we are filtering the output of the check
|
|
if (!CheckIfPacker(checkClass) || !scanPackers)
|
|
return;
|
|
|
|
AppendToDictionary(protections, fileName, subProtections);
|
|
}
|
|
|
|
// TODO: Handle extractable implementations
|
|
});
|
|
|
|
return protections;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Single Implementation Handlers
|
|
|
|
/// <summary>
|
|
/// Handle files based on an IContentCheck implementation
|
|
/// </summary>
|
|
/// <param name="impl">IDetectable class representing the file type</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>
|
|
public static ConcurrentQueue<string> HandleContentCheck(IContentCheck impl, string fileName, byte[] fileContent, bool includeDebug)
|
|
{
|
|
string protection = impl.CheckContents(fileName, fileContent, includeDebug);
|
|
return ProcessProtectionString(protection);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handle files based on an IDetectable implementation
|
|
/// </summary>
|
|
/// <param name="impl">IDetectable class representing the file type</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="includeDebug">True to include debug data, false otherwise</param>
|
|
/// <returns>Set of protections in file, null on error</returns>
|
|
public static ConcurrentQueue<string> HandleDetectable(IDetectable impl, string fileName, Stream stream, bool includeDebug)
|
|
{
|
|
string protection = impl.Detect(stream, fileName, includeDebug);
|
|
return ProcessProtectionString(protection);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handle files based on an ILinearExecutableCheck implementation
|
|
/// </summary>
|
|
/// <param name="impl">ILinearExecutableCheck class representing the file type</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>
|
|
public static ConcurrentQueue<string> HandleLinearExecutableCheck(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 file type</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>
|
|
public static ConcurrentQueue<string> HandleNewExecutableCheck(INewExecutableCheck impl, string fileName, NewExecutable nex, bool includeDebug)
|
|
{
|
|
string protection = impl.CheckNewExecutable(fileName, nex, includeDebug);
|
|
return ProcessProtectionString(protection);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handle files based on an IPortableExecutableCheck implementation
|
|
/// </summary>
|
|
/// <param name="impl">IPortableExecutableCheck class representing the file type</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>
|
|
public static ConcurrentQueue<string> HandlePortableExecutableCheck(IPortableExecutableCheck impl, string fileName, PortableExecutable pex, bool includeDebug)
|
|
{
|
|
string protection = impl.CheckPortableExecutable(fileName, pex, includeDebug);
|
|
return ProcessProtectionString(protection);
|
|
}
|
|
|
|
#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>
|
|
/// <param name="protection">Protection string to process</param>
|
|
/// <returns>Set of protections parsed, null on error</returns>
|
|
private static ConcurrentQueue<string> ProcessProtectionString(string protection)
|
|
{
|
|
// If we have an invalid protection string
|
|
if (string.IsNullOrWhiteSpace(protection))
|
|
return null;
|
|
|
|
var protections = new ConcurrentQueue<string>();
|
|
|
|
// If we have an indicator of multiple protections
|
|
if (protection.Contains(";"))
|
|
{
|
|
var splitProtections = protection.Split(';');
|
|
protections.AddRange(splitProtections);
|
|
}
|
|
else
|
|
{
|
|
protections.Enqueue(protection);
|
|
}
|
|
|
|
return protections;
|
|
}
|
|
|
|
|
|
#endregion
|
|
}
|
|
}
|