mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-04-23 22:55:05 +00:00
Gut Executable for now
This commit is contained in:
54
BinaryObjectScanner.FileType/Executable.cs
Normal file
54
BinaryObjectScanner.FileType/Executable.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Executable or library
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Due to the complexity of executables, all actual handling is offloaded to
|
||||
/// another class that is used by the scanner
|
||||
/// </remarks>
|
||||
public class Executable : IDetectable, IExtractable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string Detect(string file, bool includeDebug)
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Detect(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>This implementation should never be invoked</remarks>
|
||||
public string Detect(Stream stream, string file, bool includeDebug)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Extract(string file, bool includeDebug)
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>This implementation should never be invoked</remarks>
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,17 +67,5 @@ namespace BurnOutSharp
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of a scannable based on file type
|
||||
/// </summary>
|
||||
public static IScannable CreateScannable(SupportedFileType fileType)
|
||||
{
|
||||
switch (fileType)
|
||||
{
|
||||
case SupportedFileType.Executable: return new BinaryObjectScanner.FileType.Executable();
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,339 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BurnOutSharp;
|
||||
using BinaryObjectScanner.Interfaces;
|
||||
using BinaryObjectScanner.Wrappers;
|
||||
using static BinaryObjectScanner.Utilities.Dictionary;
|
||||
|
||||
namespace BinaryObjectScanner.FileType
|
||||
{
|
||||
/// <summary>
|
||||
/// Executable or library
|
||||
/// </summary>
|
||||
public class Executable : IDetectable, IExtractable, IScannable
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public string Detect(string file, bool includeDebug)
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Detect(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Detect(Stream stream, string file, bool includeDebug)
|
||||
{
|
||||
// Implementation notes:
|
||||
// - Executables may house more than one sort of packer/protection (see Textfile for details)
|
||||
// - The output of Detect directly influences which types of packers should be attempted for extraction
|
||||
// - There are no other file types that require this input, so is it worth changing the interface?
|
||||
// - Can this somehow delegate to the proper extractable type?
|
||||
|
||||
return null;
|
||||
|
||||
// The below code is a copy of what is currently in Scan, but without any of the
|
||||
// extraction code or packer filtering code. It is not currently enabled since it
|
||||
// is not as complete as the IScannable implementation and therefore cannot be reasonably
|
||||
// used as a replacement yet.
|
||||
|
||||
// Files can be protected in multiple ways
|
||||
var protections = new ConcurrentQueue<string>();
|
||||
|
||||
// Load the current file content for debug only
|
||||
byte[] fileContent = null;
|
||||
if (includeDebug)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
fileContent = br.ReadBytes((int)stream.Length);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the wrapper for the appropriate executable type
|
||||
WrapperBase wrapper = WrapperFactory.CreateExecutableWrapper(stream);
|
||||
if (wrapper == null)
|
||||
return null;
|
||||
|
||||
// Iterate through all generic content checks
|
||||
if (fileContent != null)
|
||||
{
|
||||
Parallel.ForEach(ScanningClasses.ContentCheckClasses, checkClass =>
|
||||
{
|
||||
string protection = checkClass.CheckContents(file, fileContent, includeDebug);
|
||||
protections.Enqueue(protection);
|
||||
});
|
||||
}
|
||||
|
||||
// If we have an MS-DOS executable
|
||||
if (wrapper is MSDOS mz)
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
// If we have a New Executable
|
||||
else if (wrapper is NewExecutable nex)
|
||||
{
|
||||
Parallel.ForEach(ScanningClasses.NewExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
string protection = checkClass.CheckNewExecutable(file, nex, includeDebug);
|
||||
protections.Enqueue(protection);
|
||||
});
|
||||
}
|
||||
|
||||
// If we have a Linear Executable
|
||||
else if (wrapper is LinearExecutable lex)
|
||||
{
|
||||
Parallel.ForEach(ScanningClasses.LinearExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
string protection = checkClass.CheckLinearExecutable(file, lex, includeDebug);
|
||||
protections.Enqueue(protection);
|
||||
});
|
||||
}
|
||||
|
||||
// If we have a Portable Executable
|
||||
else if (wrapper is PortableExecutable pex)
|
||||
{
|
||||
Parallel.ForEach(ScanningClasses.PortableExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
string protection = checkClass.CheckPortableExecutable(file, pex, includeDebug);
|
||||
protections.Enqueue(protection);
|
||||
});
|
||||
}
|
||||
|
||||
return string.Join(";", protections.ToArray());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Extract(string file, bool includeDebug)
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Extract(fs, file, includeDebug);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string Extract(Stream stream, string file, bool includeDebug)
|
||||
{
|
||||
// Implementation notes:
|
||||
// - Executables may house more than one sort of extractable packer/protection
|
||||
// - We currently have no way of defining what folder is output for a given extractable
|
||||
// - Everything else should be basically the same for other extractable types
|
||||
// - Which extractions to run is directly influenced by the detected protections
|
||||
// - Can this somehow delegate to the proper extractable type?
|
||||
// - Can we have a check in Scanner that then runs all extractable implementations if the class is Executable?
|
||||
|
||||
// The following packers fully implement IExtractable (extract and doesn't return null)
|
||||
// - <see cref="BinaryObjectScanner.Packer.CExe" />
|
||||
// - <see cref="BinaryObjectScanner.Packer.EmbeddedExecutable" />
|
||||
// - <see cref="BinaryObjectScanner.Packer.WinRARSFX" />
|
||||
// - <see cref="BinaryObjectScanner.Packer.WinZipSFX" />
|
||||
// - <see cref="BinaryObjectScanner.Packer.WiseInstaller" />
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
return null;
|
||||
|
||||
using (var fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return Scan(scanner, fs, file);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
|
||||
{
|
||||
// Files can be protected in multiple ways
|
||||
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
|
||||
|
||||
// Load the current file content for debug only
|
||||
byte[] fileContent = null;
|
||||
if (scanner.IncludeDebug)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(stream, Encoding.Default, true))
|
||||
{
|
||||
fileContent = br.ReadBytes((int)stream.Length);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
|
||||
// Enable for odd files, keep disabled otherwise
|
||||
// AppendToDictionary(protections, file, "[Out of memory attempting to open]");
|
||||
// return protections;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the wrapper for the appropriate executable type
|
||||
WrapperBase wrapper = WrapperFactory.CreateExecutableWrapper(stream);
|
||||
if (wrapper == null)
|
||||
return protections;
|
||||
|
||||
// Iterate through all generic content checks
|
||||
if (fileContent != null)
|
||||
{
|
||||
Parallel.ForEach(ScanningClasses.ContentCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
string protection = checkClass.CheckContents(file, fileContent, scanner.IncludeDebug);
|
||||
AppendToDictionary(protections, file, protection);
|
||||
});
|
||||
}
|
||||
|
||||
// If we have an MS-DOS executable
|
||||
if (wrapper is MSDOS mz)
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
// If we have a New Executable
|
||||
else if (wrapper is NewExecutable nex)
|
||||
{
|
||||
Parallel.ForEach(ScanningClasses.NewExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
string protection = checkClass.CheckNewExecutable(file, nex, scanner.IncludeDebug);
|
||||
if (ShouldAddProtection(checkClass, scanner.ScanPackers, protection))
|
||||
AppendToDictionary(protections, file, protection);
|
||||
|
||||
// If we had a protection, check if it is extractable
|
||||
if (!string.IsNullOrWhiteSpace(protection))
|
||||
HandleExtractable(scanner, stream, file, checkClass, protections);
|
||||
});
|
||||
}
|
||||
|
||||
// If we have a Linear Executable
|
||||
else if (wrapper is LinearExecutable lex)
|
||||
{
|
||||
Parallel.ForEach(ScanningClasses.LinearExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
string protection = checkClass.CheckLinearExecutable(file, lex, scanner.IncludeDebug);
|
||||
if (ShouldAddProtection(checkClass, scanner.ScanPackers, protection))
|
||||
AppendToDictionary(protections, file, protection);
|
||||
|
||||
// If we had a protection, check if it is extractable
|
||||
if (!string.IsNullOrWhiteSpace(protection))
|
||||
HandleExtractable(scanner, stream, file, checkClass, protections);
|
||||
});
|
||||
}
|
||||
|
||||
// If we have a Portable Executable
|
||||
else if (wrapper is PortableExecutable pex)
|
||||
{
|
||||
Parallel.ForEach(ScanningClasses.PortableExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
string protection = checkClass.CheckPortableExecutable(file, pex, scanner.IncludeDebug);
|
||||
if (ShouldAddProtection(checkClass, scanner.ScanPackers, protection))
|
||||
AppendToDictionary(protections, file, protection);
|
||||
|
||||
// If we had a protection, check if it is extractable
|
||||
if (!string.IsNullOrWhiteSpace(protection))
|
||||
HandleExtractable(scanner, stream, file, checkClass, protections);
|
||||
});
|
||||
}
|
||||
|
||||
return protections;
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Check to see if a protection should be added or not
|
||||
/// </summary>
|
||||
/// <param name="checkClass">Class that was last used to check</param>
|
||||
/// <param name="scanPackers">Determines if packers should be included in the output</param>
|
||||
/// <param name="protection">The protection result to be checked</param>
|
||||
private bool ShouldAddProtection(object checkClass, bool scanPackers, string protection)
|
||||
{
|
||||
// If we have an invalid protection
|
||||
if (string.IsNullOrWhiteSpace(protection))
|
||||
return false;
|
||||
|
||||
// If we have a valid content check based on settings
|
||||
if (scanPackers || !checkClass.GetType().Namespace.ToLowerInvariant().Contains("packer"))
|
||||
return true;
|
||||
|
||||
// Everything else fails
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle extractable protections and packers
|
||||
/// </summary>
|
||||
/// <param name="scanner">Scanner object for state tracking</param>
|
||||
/// <param name="stream">Stream representing the input file</param>
|
||||
/// <param name="file">Path to the input file</param>
|
||||
/// <param name="checkingClass">Class representing the current packer or protection</param>
|
||||
/// <param name="protections">Set of existing protections to append to</param>
|
||||
private static void HandleExtractable(Scanner scanner, Stream stream, string file, object checkingClass, ConcurrentDictionary<string, ConcurrentQueue<string>> protections)
|
||||
{
|
||||
// If we don't have an IExtractable implementation
|
||||
if (!(checkingClass is IExtractable extractable))
|
||||
return;
|
||||
|
||||
// If we have an invalid file
|
||||
if (file == null)
|
||||
return;
|
||||
|
||||
// If the extractable file itself fails
|
||||
try
|
||||
{
|
||||
// Extract and get the output path
|
||||
string tempPath = extractable.Extract(stream, file, scanner.IncludeDebug);
|
||||
if (tempPath != null)
|
||||
return;
|
||||
|
||||
// Collect and format all found protections
|
||||
var subProtections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Prepare the returned protections
|
||||
StripFromKeys(protections, tempPath);
|
||||
PrependToKeys(subProtections, file);
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ using static BinaryObjectScanner.Utilities.Dictionary;
|
||||
|
||||
namespace BurnOutSharp
|
||||
{
|
||||
// TODO: Implement IExtractable handler
|
||||
// TODO: Implement IPathCheck handler
|
||||
internal static class Handler
|
||||
{
|
||||
@@ -21,10 +20,9 @@ namespace BurnOutSharp
|
||||
/// </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>
|
||||
/// <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, bool scanPackers, bool includeDebug)
|
||||
public static ConcurrentQueue<string> HandleContentChecks(string fileName, Stream stream, Scanner scanner)
|
||||
{
|
||||
// If we have an invalid file
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
@@ -45,7 +43,7 @@ namespace BurnOutSharp
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (includeDebug) Console.WriteLine(ex);
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -56,11 +54,11 @@ namespace BurnOutSharp
|
||||
Parallel.ForEach(ScanningClasses.ContentCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var subProtections = HandleContentCheck(checkClass, fileName, fileContent, includeDebug);
|
||||
var subProtections = HandleContentCheck(checkClass, fileName, fileContent, scanner.IncludeDebug);
|
||||
if (subProtections != null)
|
||||
{
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !scanPackers)
|
||||
if (!CheckIfPacker(checkClass) || !scanner.ScanPackers)
|
||||
return;
|
||||
|
||||
protections.AddRange(subProtections);
|
||||
@@ -75,11 +73,9 @@ namespace BurnOutSharp
|
||||
/// </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>
|
||||
/// <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, LinearExecutable lex, bool scanArchives, bool scanPackers, bool includeDebug)
|
||||
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>>();
|
||||
@@ -88,17 +84,24 @@ namespace BurnOutSharp
|
||||
Parallel.ForEach(ScanningClasses.LinearExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var subProtections = HandleLinearExecutableCheck(checkClass, fileName, lex, includeDebug);
|
||||
if (subProtections != null)
|
||||
var subProtections = HandleLinearExecutableCheck(checkClass, 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)
|
||||
{
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !scanPackers)
|
||||
return;
|
||||
|
||||
AppendToDictionary(protections, fileName, subProtections);
|
||||
var extractedProtections = HandleExtractable(extractable, fileName, stream, scanner);
|
||||
if (extractedProtections != null)
|
||||
AppendToDictionary(protections, extractedProtections);
|
||||
}
|
||||
|
||||
// TODO: Handle extractable implementations
|
||||
});
|
||||
|
||||
return protections;
|
||||
@@ -109,11 +112,9 @@ namespace BurnOutSharp
|
||||
/// </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>
|
||||
/// <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, NewExecutable nex, bool scanArchives, bool scanPackers, bool includeDebug)
|
||||
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>>();
|
||||
@@ -122,17 +123,24 @@ namespace BurnOutSharp
|
||||
Parallel.ForEach(ScanningClasses.NewExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var subProtections = HandleNewExecutableCheck(checkClass, fileName, nex, includeDebug);
|
||||
if (subProtections != null)
|
||||
var subProtections = HandleNewExecutableCheck(checkClass, 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)
|
||||
{
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !scanPackers)
|
||||
return;
|
||||
|
||||
AppendToDictionary(protections, fileName, subProtections);
|
||||
var extractedProtections = HandleExtractable(extractable, fileName, stream, scanner);
|
||||
if (extractedProtections != null)
|
||||
AppendToDictionary(protections, extractedProtections);
|
||||
}
|
||||
|
||||
// TODO: Handle extractable implementations
|
||||
});
|
||||
|
||||
return protections;
|
||||
@@ -143,11 +151,9 @@ namespace BurnOutSharp
|
||||
/// </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>
|
||||
/// <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, PortableExecutable pex, bool scanArchives, bool scanPackers, bool includeDebug)
|
||||
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>>();
|
||||
@@ -156,17 +162,24 @@ namespace BurnOutSharp
|
||||
Parallel.ForEach(ScanningClasses.PortableExecutableCheckClasses, checkClass =>
|
||||
{
|
||||
// Get the protection for the class, if possible
|
||||
var subProtections = HandlePortableExecutableCheck(checkClass, fileName, pex, includeDebug);
|
||||
if (subProtections != null)
|
||||
var subProtections = HandlePortableExecutableCheck(checkClass, 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)
|
||||
{
|
||||
// If we are filtering the output of the check
|
||||
if (!CheckIfPacker(checkClass) || !scanPackers)
|
||||
return;
|
||||
|
||||
AppendToDictionary(protections, fileName, subProtections);
|
||||
var extractedProtections = HandleExtractable(extractable, fileName, stream, scanner);
|
||||
if (extractedProtections != null)
|
||||
AppendToDictionary(protections, extractedProtections);
|
||||
}
|
||||
|
||||
// TODO: Handle extractable implementations
|
||||
});
|
||||
|
||||
return protections;
|
||||
@@ -204,6 +217,50 @@ namespace BurnOutSharp
|
||||
return ProcessProtectionString(protection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an IExtractable 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="scanner">Scanner object to use on extractable contents</param>
|
||||
/// <returns>Set of protections in file, null on error</returns>
|
||||
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandleExtractable(IExtractable impl, string fileName, Stream stream, Scanner scanner)
|
||||
{
|
||||
// If the extractable file itself fails
|
||||
try
|
||||
{
|
||||
// Extract and get the output path
|
||||
string tempPath = impl.Extract(stream, fileName, scanner.IncludeDebug);
|
||||
if (tempPath == null)
|
||||
return null;
|
||||
|
||||
// Collect and format all found protections
|
||||
var subProtections = scanner.GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Prepare the returned protections
|
||||
StripFromKeys(subProtections, tempPath);
|
||||
PrependToKeys(subProtections, fileName);
|
||||
return subProtections;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (scanner.IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an ILinearExecutableCheck implementation
|
||||
/// </summary>
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using BurnOutSharp;
|
||||
|
||||
namespace BinaryObjectScanner.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Mark a file type as being able to be scanned
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is also used for packers, embedded archives, and other
|
||||
/// installer formats that may need to be "extracted" before they
|
||||
/// can be fully scanned.
|
||||
/// </remarks>
|
||||
public interface IScannable
|
||||
{
|
||||
/// <summary>
|
||||
/// Scan a file for all internal protections
|
||||
/// </summary>
|
||||
/// <param name="scanner">Scanner object for state tracking</param>
|
||||
/// <param name="file">Path to the input file</param>
|
||||
/// <returns>Dictionary mapping paths to protection lists</returns>
|
||||
/// <remarks>Ideally, this should just point to the other scan implementation</remarks>
|
||||
ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file);
|
||||
|
||||
/// <summary>
|
||||
/// Scan a stream for all internal protections
|
||||
/// </summary>
|
||||
/// <param name="scanner">Scanner object for state tracking</param>
|
||||
/// <param name="stream">Stream representing the input file</param>
|
||||
/// <param name="file">Path to the input file</param>
|
||||
/// <returns>Dictionary mapping paths to protection lists</returns>
|
||||
ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file);
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@ 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;
|
||||
|
||||
namespace BurnOutSharp
|
||||
@@ -351,9 +351,7 @@ namespace BurnOutSharp
|
||||
// TODO: Write custom executable handling
|
||||
if (detectable is Executable)
|
||||
{
|
||||
var subProtections = Handler.HandleDetectable(detectable, fileName, stream, IncludeDebug);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, fileName, subProtections);
|
||||
ProcessExecutable(fileName, stream, protections);
|
||||
}
|
||||
|
||||
// Otherwise, use the default implementation
|
||||
@@ -380,16 +378,6 @@ namespace BurnOutSharp
|
||||
}
|
||||
}
|
||||
|
||||
// Create a scannable for the given file type
|
||||
var scannable = Factory.CreateScannable(fileType);
|
||||
|
||||
// If we're scanning file contents
|
||||
if (scannable != null && ScanContents)
|
||||
{
|
||||
var subProtections = scannable.Scan(this, stream, fileName);
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Archive File Types
|
||||
@@ -400,19 +388,10 @@ namespace BurnOutSharp
|
||||
// If we're scanning archives
|
||||
if (extractable != null && ScanArchives)
|
||||
{
|
||||
// If we have an executable, it needs to bypass normal handling
|
||||
// TODO: Write custom executable handling
|
||||
if (extractable is Executable)
|
||||
// We only want to process non-executables
|
||||
if (!(extractable is Executable))
|
||||
{
|
||||
var subProtections = HandleExtractable(extractable, fileName, stream);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
|
||||
// Otherwise, use the default implementation
|
||||
else
|
||||
{
|
||||
var subProtections = HandleExtractable(extractable, fileName, stream);
|
||||
var subProtections = Handler.HandleExtractable(extractable, fileName, stream, this);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
@@ -423,7 +402,6 @@ namespace BurnOutSharp
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (IncludeDebug) Console.WriteLine(ex);
|
||||
|
||||
AppendToDictionary(protections, fileName, IncludeDebug ? ex.ToString() : "[Exception opening file, please try again]");
|
||||
}
|
||||
|
||||
@@ -435,49 +413,55 @@ namespace BurnOutSharp
|
||||
|
||||
#endregion
|
||||
|
||||
#region Interface Handlers
|
||||
#region Executable Handling
|
||||
|
||||
/// <summary>
|
||||
/// Handle files based on an IExtractable implementation
|
||||
/// Process scanning for an Executable type
|
||||
/// </summary>
|
||||
/// <param name="extractable">IExtractable 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>
|
||||
/// <returns>Set of protections in internal files, null on error</returns>
|
||||
private ConcurrentDictionary<string, ConcurrentQueue<string>> HandleExtractable(IExtractable extractable, string fileName, Stream stream)
|
||||
/// <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)
|
||||
{
|
||||
// If the extractable file itself fails
|
||||
try
|
||||
// Try to create a wrapper for the proper executable type
|
||||
var wrapper = WrapperFactory.CreateExecutableWrapper(stream);
|
||||
if (wrapper == null)
|
||||
return;
|
||||
|
||||
// Only use generic content checks if we're in debug mode
|
||||
if (IncludeDebug)
|
||||
{
|
||||
// Extract and get the output path
|
||||
string tempPath = extractable.Extract(stream, fileName, IncludeDebug);
|
||||
if (tempPath == null)
|
||||
return null;
|
||||
|
||||
// Collect and format all found protections
|
||||
var subProtections = GetProtections(tempPath);
|
||||
|
||||
// If temp directory cleanup fails
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempPath, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (IncludeDebug) Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
// Prepare the returned protections
|
||||
StripFromKeys(subProtections, tempPath);
|
||||
PrependToKeys(subProtections, fileName);
|
||||
return subProtections;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (IncludeDebug) Console.WriteLine(ex);
|
||||
var subProtections = Handler.HandleContentChecks(fileName, stream, this);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, fileName, subProtections);
|
||||
}
|
||||
|
||||
return null;
|
||||
if (wrapper is MSDOS)
|
||||
{
|
||||
// No-op until protection classes implmented
|
||||
}
|
||||
else if (wrapper is LinearExecutable lex)
|
||||
{
|
||||
var subProtections = Handler.HandleLinearExecutableChecks(fileName, stream, lex, this);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
else if (wrapper is NewExecutable nex)
|
||||
{
|
||||
var subProtections = Handler.HandleNewExecutableChecks(fileName, stream, nex, this);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
else if (wrapper is PortableExecutable pex)
|
||||
{
|
||||
var subProtections = Handler.HandlePortableExecutableChecks(fileName, stream, pex, this);
|
||||
if (subProtections != null)
|
||||
AppendToDictionary(protections, subProtections);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user