diff --git a/BurnOutSharp/Factory.cs b/BurnOutSharp/Factory.cs
new file mode 100644
index 00000000..6a8997ba
--- /dev/null
+++ b/BurnOutSharp/Factory.cs
@@ -0,0 +1,83 @@
+using BinaryObjectScanner.Interfaces;
+using BinaryObjectScanner.Utilities;
+
+namespace BurnOutSharp
+{
+ internal static class Factory
+ {
+ ///
+ /// Create an instance of a detectable based on file type
+ ///
+ public static IDetectable CreateDetectable(SupportedFileType fileType)
+ {
+ switch (fileType)
+ {
+ case SupportedFileType.AACSMediaKeyBlock: return new BinaryObjectScanner.FileType.AACSMediaKeyBlock();
+ case SupportedFileType.BDPlusSVM: return new BinaryObjectScanner.FileType.BDPlusSVM();
+ //case SupportedFileType.CIA: return new BinaryObjectScanner.FileType.CIA();
+ case SupportedFileType.Executable: return new BinaryObjectScanner.FileType.Executable();
+ case SupportedFileType.LDSCRYPT: return new BinaryObjectScanner.FileType.LDSCRYPT();
+ //case SupportedFileType.N3DS: return new BinaryObjectScanner.FileType.N3DS();
+ //case SupportedFileType.Nitro: return new BinaryObjectScanner.FileType.Nitro();
+ case SupportedFileType.PLJ: return new BinaryObjectScanner.FileType.PLJ();
+ case SupportedFileType.SFFS: return new BinaryObjectScanner.FileType.SFFS();
+ case SupportedFileType.Textfile: return new BinaryObjectScanner.FileType.Textfile();
+ default: return null;
+ }
+ }
+
+ ///
+ /// Create an instance of an extractable based on file type
+ ///
+ public static IExtractable CreateExtractable(SupportedFileType fileType)
+ {
+ switch (fileType)
+ {
+ case SupportedFileType.BFPK: return new BinaryObjectScanner.FileType.BFPK();
+ case SupportedFileType.BSP: return new BinaryObjectScanner.FileType.BSP();
+ case SupportedFileType.BZip2: return new BinaryObjectScanner.FileType.BZip2();
+ case SupportedFileType.CFB: return new BinaryObjectScanner.FileType.CFB();
+ //case SupportedFileType.CIA: return new BinaryObjectScanner.FileType.CIA();
+ case SupportedFileType.Executable: return new BinaryObjectScanner.FileType.Executable();
+ case SupportedFileType.GCF: return new BinaryObjectScanner.FileType.GCF();
+ case SupportedFileType.GZIP: return new BinaryObjectScanner.FileType.GZIP();
+ case SupportedFileType.InstallShieldArchiveV3: return new BinaryObjectScanner.FileType.InstallShieldArchiveV3();
+ case SupportedFileType.InstallShieldCAB: return new BinaryObjectScanner.FileType.InstallShieldCAB();
+ case SupportedFileType.MicrosoftCAB: return new BinaryObjectScanner.FileType.MicrosoftCAB();
+ case SupportedFileType.MicrosoftLZ: return new BinaryObjectScanner.FileType.MicrosoftLZ();
+ case SupportedFileType.MPQ: return new BinaryObjectScanner.FileType.MPQ();
+ //case SupportedFileType.N3DS: return new BinaryObjectScanner.FileType.N3DS();
+ //case SupportedFileType.NCF: return new BinaryObjectScanner.FileType.NCF();
+ //case SupportedFileType.Nitro: return new BinaryObjectScanner.FileType.Nitro();
+ case SupportedFileType.PAK: return new BinaryObjectScanner.FileType.PAK();
+ case SupportedFileType.PFF: return new BinaryObjectScanner.FileType.PFF();
+ case SupportedFileType.PKZIP: return new BinaryObjectScanner.FileType.PKZIP();
+ //case SupportedFileType.PLJ: return new BinaryObjectScanner.FileType.PLJ();
+ //case SupportedFileType.Quantum: return new BinaryObjectScanner.FileType.Quantum();
+ case SupportedFileType.RAR: return new BinaryObjectScanner.FileType.RAR();
+ case SupportedFileType.SevenZip: return new BinaryObjectScanner.FileType.SevenZip();
+ case SupportedFileType.SFFS: return new BinaryObjectScanner.FileType.SFFS();
+ case SupportedFileType.SGA: return new BinaryObjectScanner.FileType.SGA();
+ case SupportedFileType.TapeArchive: return new BinaryObjectScanner.FileType.TapeArchive();
+ case SupportedFileType.VBSP: return new BinaryObjectScanner.FileType.VBSP();
+ case SupportedFileType.VPK: return new BinaryObjectScanner.FileType.VPK();
+ case SupportedFileType.WAD: return new BinaryObjectScanner.FileType.WAD();
+ case SupportedFileType.XZ: return new BinaryObjectScanner.FileType.XZ();
+ case SupportedFileType.XZP: return new BinaryObjectScanner.FileType.XZP();
+ default: return null;
+ }
+ }
+
+ ///
+ /// Create an instance of a scannable based on file type
+ ///
+ public static IScannable CreateScannable(SupportedFileType fileType)
+ {
+ switch (fileType)
+ {
+ case SupportedFileType.Executable: return new BinaryObjectScanner.FileType.Executable();
+ default: return null;
+ }
+ }
+ }
+}
diff --git a/BurnOutSharp/FileType/Executable.cs b/BurnOutSharp/FileType/Executable.cs
index 6f8160e2..1a8d4940 100644
--- a/BurnOutSharp/FileType/Executable.cs
+++ b/BurnOutSharp/FileType/Executable.cs
@@ -201,12 +201,7 @@ namespace BinaryObjectScanner.FileType
{
// Get the protection for the class, if possible
string protection = checkClass.CheckContents(file, fileContent, 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);
+ AppendToDictionary(protections, file, protection);
});
}
diff --git a/BurnOutSharp/Handler.cs b/BurnOutSharp/Handler.cs
new file mode 100644
index 00000000..8ece76c3
--- /dev/null
+++ b/BurnOutSharp/Handler.cs
@@ -0,0 +1,292 @@
+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
+
+ ///
+ /// Handle a single file based on all content check implementations
+ ///
+ /// Name of the source file of the stream, for tracking
+ /// Stream to scan the contents of
+ /// True to include packers in the output, false otherwise
+ /// True to include debug data, false otherwise
+ /// Set of protections in file, null on error
+ public static ConcurrentQueue 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();
+
+ // 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;
+ }
+
+ ///
+ /// Handle a single file based on all linear executable check implementations
+ ///
+ /// Name of the source file of the executable, for tracking
+ /// Executable to scan
+ /// True to include extractable contents in the output, false otherwise
+ /// True to include packers in the output, false otherwise
+ /// True to include debug data, false otherwise
+ /// Set of protections in file, null on error
+ public static ConcurrentDictionary> HandleNewExecutableChecks(string fileName, LinearExecutable lex, bool scanArchives, bool scanPackers, bool includeDebug)
+ {
+ // Create the output dictionary
+ var protections = new ConcurrentDictionary>();
+
+ // 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;
+ }
+
+ ///
+ /// Handle a single file based on all new executable check implementations
+ ///
+ /// Name of the source file of the executable, for tracking
+ /// Executable to scan
+ /// True to include extractable contents in the output, false otherwise
+ /// True to include packers in the output, false otherwise
+ /// True to include debug data, false otherwise
+ /// Set of protections in file, null on error
+ public static ConcurrentDictionary> HandleNewExecutableChecks(string fileName, NewExecutable nex, bool scanArchives, bool scanPackers, bool includeDebug)
+ {
+ // Create the output dictionary
+ var protections = new ConcurrentDictionary>();
+
+ // 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;
+ }
+
+ ///
+ /// Handle a single file based on all portable executable check implementations
+ ///
+ /// Name of the source file of the executable, for tracking
+ /// Executable to scan
+ /// True to include extractable contents in the output, false otherwise
+ /// True to include packers in the output, false otherwise
+ /// True to include debug data, false otherwise
+ /// Set of protections in file, null on error
+ public static ConcurrentDictionary> HandlePortableExecutableChecks(string fileName, PortableExecutable pex, bool scanArchives, bool scanPackers, bool includeDebug)
+ {
+ // Create the output dictionary
+ var protections = new ConcurrentDictionary>();
+
+ // 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
+
+ ///
+ /// Handle files based on an IContentCheck implementation
+ ///
+ /// IDetectable class representing the file type
+ /// Name of the source file of the byte array, for tracking
+ /// Contents of the source file
+ /// True to include debug data, false otherwise
+ /// Set of protections in file, null on error
+ public static ConcurrentQueue HandleContentCheck(IContentCheck impl, string fileName, byte[] fileContent, bool includeDebug)
+ {
+ string protection = impl.CheckContents(fileName, fileContent, includeDebug);
+ return ProcessProtectionString(protection);
+ }
+
+ ///
+ /// Handle files based on an IDetectable implementation
+ ///
+ /// IDetectable class representing the file type
+ /// Name of the source file of the stream, for tracking
+ /// Stream to scan the contents of
+ /// True to include debug data, false otherwise
+ /// Set of protections in file, null on error
+ public static ConcurrentQueue HandleDetectable(IDetectable impl, string fileName, Stream stream, bool includeDebug)
+ {
+ string protection = impl.Detect(stream, fileName, includeDebug);
+ return ProcessProtectionString(protection);
+ }
+
+ ///
+ /// Handle files based on an ILinearExecutableCheck implementation
+ ///
+ /// ILinearExecutableCheck class representing the file type
+ /// Name of the source file of the executable, for tracking
+ /// LinearExecutable to check
+ /// True to include debug data, false otherwise
+ /// Set of protections in file, null on error
+ public static ConcurrentQueue HandleLinearExecutableCheck(ILinearExecutableCheck impl, string fileName, LinearExecutable lex, bool includeDebug)
+ {
+ string protection = impl.CheckLinearExecutable(fileName, lex, includeDebug);
+ return ProcessProtectionString(protection);
+ }
+
+ ///
+ /// Handle files based on an INewExecutableCheck implementation
+ ///
+ /// INewExecutableCheck class representing the file type
+ /// Name of the source file of the executable, for tracking
+ /// NewExecutable to check
+ /// True to include debug data, false otherwise
+ /// Set of protections in file, null on error
+ public static ConcurrentQueue HandleNewExecutableCheck(INewExecutableCheck impl, string fileName, NewExecutable nex, bool includeDebug)
+ {
+ string protection = impl.CheckNewExecutable(fileName, nex, includeDebug);
+ return ProcessProtectionString(protection);
+ }
+
+ ///
+ /// Handle files based on an IPortableExecutableCheck implementation
+ ///
+ /// IPortableExecutableCheck class representing the file type
+ /// Name of the source file of the executable, for tracking
+ /// NewExecutable to check
+ /// True to include debug data, false otherwise
+ /// Set of protections in file, null on error
+ public static ConcurrentQueue HandlePortableExecutableCheck(IPortableExecutableCheck impl, string fileName, PortableExecutable pex, bool includeDebug)
+ {
+ string protection = impl.CheckPortableExecutable(fileName, pex, includeDebug);
+ return ProcessProtectionString(protection);
+ }
+
+ #endregion
+
+ #region Helpers
+
+ ///
+ /// Check to see if an implementation is a packer using reflection
+ ///
+ /// Implementation that was last used to check
+ private static bool CheckIfPacker(object impl)
+ {
+ return impl.GetType().Namespace.ToLowerInvariant().Contains("packer");
+ }
+
+ ///
+ /// Process a protection string if it includes multiple protections
+ ///
+ /// Protection string to process
+ /// Set of protections parsed, null on error
+ private static ConcurrentQueue ProcessProtectionString(string protection)
+ {
+ // If we have an invalid protection string
+ if (string.IsNullOrWhiteSpace(protection))
+ return null;
+
+ var protections = new ConcurrentQueue();
+
+ // 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
+ }
+}
diff --git a/BurnOutSharp/Scanner.cs b/BurnOutSharp/Scanner.cs
index 33cb8821..30762d80 100644
--- a/BurnOutSharp/Scanner.cs
+++ b/BurnOutSharp/Scanner.cs
@@ -136,7 +136,7 @@ namespace BurnOutSharp
if (ScanPaths)
{
var filePathProtections = GetFilePathProtections(file);
- AppendToDictionary(protections, filePathProtections);
+ AppendToDictionary(protections, file, filePathProtections);
}
// Scan for content-detectable protections
@@ -174,7 +174,7 @@ namespace BurnOutSharp
if (ScanPaths)
{
var filePathProtections = GetFilePathProtections(path);
- AppendToDictionary(protections, filePathProtections);
+ AppendToDictionary(protections, path, filePathProtections);
}
// Scan for content-detectable protections
@@ -248,7 +248,7 @@ namespace BurnOutSharp
///
/// Path of the file to scan
/// Dictionary of list of strings representing the found protections
- private ConcurrentDictionary> GetFilePathProtections(string path)
+ private ConcurrentQueue GetFilePathProtections(string path)
{
// Create an empty queue for protections
var protections = new ConcurrentQueue();
@@ -262,10 +262,7 @@ namespace BurnOutSharp
});
// Create and return the dictionary
- return new ConcurrentDictionary>
- {
- [path] = protections
- };
+ return protections;
}
///
@@ -345,11 +342,28 @@ namespace BurnOutSharp
#region Non-Archive File Types
// Create a detectable for the given file type
- var detectable = CreateDetectable(fileType);
+ var detectable = Factory.CreateDetectable(fileType);
// If we're scanning file contents
if (detectable != null && ScanContents)
{
+ // If we have an executable, it needs to bypass normal handling
+ // TODO: Write custom executable handling
+ if (detectable is Executable)
+ {
+ var subProtections = Handler.HandleDetectable(detectable, fileName, stream, IncludeDebug);
+ if (subProtections != null)
+ AppendToDictionary(protections, fileName, subProtections);
+ }
+
+ // Otherwise, use the default implementation
+ else
+ {
+ var subProtections = Handler.HandleDetectable(detectable, fileName, stream, IncludeDebug);
+ if (subProtections != null)
+ AppendToDictionary(protections, fileName, subProtections);
+ }
+
string subProtection = detectable.Detect(stream, fileName, IncludeDebug);
if (!string.IsNullOrWhiteSpace(subProtection))
{
@@ -367,7 +381,7 @@ namespace BurnOutSharp
}
// Create a scannable for the given file type
- var scannable = CreateScannable(fileType);
+ var scannable = Factory.CreateScannable(fileType);
// If we're scanning file contents
if (scannable != null && ScanContents)
@@ -381,31 +395,18 @@ namespace BurnOutSharp
#region Archive File Types
// Create an extractable for the given file type
- var extractable = CreateExtractable(fileType);
+ var extractable = Factory.CreateExtractable(fileType);
// 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)
{
var subProtections = HandleExtractable(extractable, fileName, stream);
if (subProtections != null)
AppendToDictionary(protections, subProtections);
-
- // The following code is disabled because it is untested, though it represents the likely path
- // for how this implementation will be completed.
-
- //Parallel.ForEach(ScanningClasses.ExtractableClasses, extractableClass =>
- //{
- // string tempDir = extractableClass.Extract(stream, fileName, IncludeDebug);
- // if (!string.IsNullOrWhiteSpace(tempDir))
- // {
- // var subProtections = HandleExtractable(extractable, fileName, stream);
- // if (subProtections != null)
- // AppendToDictionary(protections, subProtections);
- // }
- //});
}
// Otherwise, use the default implementation
@@ -434,85 +435,10 @@ namespace BurnOutSharp
#endregion
- #region Helpers
+ #region Interface Handlers
///
- /// Create an instance of a detectable based on file type
- ///
- private static IDetectable CreateDetectable(SupportedFileType fileType)
- {
- switch (fileType)
- {
- case SupportedFileType.AACSMediaKeyBlock: return new BinaryObjectScanner.FileType.AACSMediaKeyBlock();
- case SupportedFileType.BDPlusSVM: return new BinaryObjectScanner.FileType.BDPlusSVM();
- //case SupportedFileType.CIA: return new BinaryObjectScanner.FileType.CIA();
- case SupportedFileType.Executable: return new BinaryObjectScanner.FileType.Executable();
- case SupportedFileType.LDSCRYPT: return new BinaryObjectScanner.FileType.LDSCRYPT();
- //case SupportedFileType.N3DS: return new BinaryObjectScanner.FileType.N3DS();
- //case SupportedFileType.Nitro: return new BinaryObjectScanner.FileType.Nitro();
- case SupportedFileType.PLJ: return new BinaryObjectScanner.FileType.PLJ();
- case SupportedFileType.SFFS: return new BinaryObjectScanner.FileType.SFFS();
- case SupportedFileType.Textfile: return new BinaryObjectScanner.FileType.Textfile();
- default: return null;
- }
- }
-
- ///
- /// Create an instance of an extractable based on file type
- ///
- private static IExtractable CreateExtractable(SupportedFileType fileType)
- {
- switch (fileType)
- {
- case SupportedFileType.BFPK: return new BinaryObjectScanner.FileType.BFPK();
- case SupportedFileType.BSP: return new BinaryObjectScanner.FileType.BSP();
- case SupportedFileType.BZip2: return new BinaryObjectScanner.FileType.BZip2();
- case SupportedFileType.CFB: return new BinaryObjectScanner.FileType.CFB();
- //case SupportedFileType.CIA: return new BinaryObjectScanner.FileType.CIA();
- case SupportedFileType.Executable: return new BinaryObjectScanner.FileType.Executable();
- case SupportedFileType.GCF: return new BinaryObjectScanner.FileType.GCF();
- case SupportedFileType.GZIP: return new BinaryObjectScanner.FileType.GZIP();
- case SupportedFileType.InstallShieldArchiveV3: return new BinaryObjectScanner.FileType.InstallShieldArchiveV3();
- case SupportedFileType.InstallShieldCAB: return new BinaryObjectScanner.FileType.InstallShieldCAB();
- case SupportedFileType.MicrosoftCAB: return new BinaryObjectScanner.FileType.MicrosoftCAB();
- case SupportedFileType.MicrosoftLZ: return new BinaryObjectScanner.FileType.MicrosoftLZ();
- case SupportedFileType.MPQ: return new BinaryObjectScanner.FileType.MPQ();
- //case SupportedFileType.N3DS: return new BinaryObjectScanner.FileType.N3DS();
- //case SupportedFileType.NCF: return new BinaryObjectScanner.FileType.NCF();
- //case SupportedFileType.Nitro: return new BinaryObjectScanner.FileType.Nitro();
- case SupportedFileType.PAK: return new BinaryObjectScanner.FileType.PAK();
- case SupportedFileType.PFF: return new BinaryObjectScanner.FileType.PFF();
- case SupportedFileType.PKZIP: return new BinaryObjectScanner.FileType.PKZIP();
- //case SupportedFileType.PLJ: return new BinaryObjectScanner.FileType.PLJ();
- //case SupportedFileType.Quantum: return new BinaryObjectScanner.FileType.Quantum();
- case SupportedFileType.RAR: return new BinaryObjectScanner.FileType.RAR();
- case SupportedFileType.SevenZip: return new BinaryObjectScanner.FileType.SevenZip();
- case SupportedFileType.SFFS: return new BinaryObjectScanner.FileType.SFFS();
- case SupportedFileType.SGA: return new BinaryObjectScanner.FileType.SGA();
- case SupportedFileType.TapeArchive: return new BinaryObjectScanner.FileType.TapeArchive();
- case SupportedFileType.VBSP: return new BinaryObjectScanner.FileType.VBSP();
- case SupportedFileType.VPK: return new BinaryObjectScanner.FileType.VPK();
- case SupportedFileType.WAD: return new BinaryObjectScanner.FileType.WAD();
- case SupportedFileType.XZ: return new BinaryObjectScanner.FileType.XZ();
- case SupportedFileType.XZP: return new BinaryObjectScanner.FileType.XZP();
- default: return null;
- }
- }
-
- ///
- /// Create an instance of a scannable based on file type
- ///
- private static IScannable CreateScannable(SupportedFileType fileType)
- {
- switch (fileType)
- {
- case SupportedFileType.Executable: return new BinaryObjectScanner.FileType.Executable();
- default: return null;
- }
- }
-
- ///
- /// Handle extractable files based on an IExtractable implementation
+ /// Handle files based on an IExtractable implementation
///
/// IExtractable class representing the file type
/// Name of the source file of the stream, for tracking