Start using ProtectionDictionary

This commit is contained in:
Matt Nadareski
2024-10-31 21:10:06 -04:00
parent 9a3fde0518
commit 683cfb6306
6 changed files with 78 additions and 426 deletions

View File

@@ -10,7 +10,6 @@ using System.Threading.Tasks;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Utilities;
using SabreTools.Serialization.Wrappers;
using static BinaryObjectScanner.Utilities.Dictionary;
namespace BinaryObjectScanner
{
@@ -49,18 +48,10 @@ namespace BinaryObjectScanner
/// <param name="path">Path of the file or directory to check</param>
/// <param name="scanner">Scanner object to use for options and scanning</param>
/// <returns>Set of protections in file, null on error</returns>
#if NET20 || NET35
public static Dictionary<string, Queue<string>> HandlePathChecks(string path, IEnumerable<string>? files)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>> HandlePathChecks(string path, IEnumerable<string>? files)
#endif
public static ProtectionDictionary HandlePathChecks(string path, IEnumerable<string>? files)
{
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
var protections = new ProtectionDictionary();
// Preprocess the list of files
files = files?.Select(f => f.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar))?.ToList();
@@ -74,7 +65,7 @@ namespace BinaryObjectScanner
{
var subProtections = checkClass?.PerformCheck(path, files);
if (subProtections != null)
AppendToDictionary(protections, path, subProtections);
protections.Append(path, subProtections);
#if NET20 || NET35
}
#else
@@ -114,11 +105,7 @@ namespace BinaryObjectScanner
/// <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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractable impl, string fileName, Stream? stream, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractable impl, string fileName, Stream? stream, Scanner scanner)
#endif
public static ProtectionDictionary? HandleExtractable(IExtractable impl, string fileName, Stream? stream, Scanner scanner)
{
// If the extractable file itself fails
try
@@ -142,8 +129,8 @@ namespace BinaryObjectScanner
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
subProtections.StripFromKeys(tempPath);
subProtections.PrependToKeys(fileName);
return subProtections;
}
catch (Exception ex)
@@ -162,11 +149,7 @@ namespace BinaryObjectScanner
/// <param name="mz">MSDOS 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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractableMSDOSExecutable impl, string fileName, MSDOS mz, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractableMSDOSExecutable impl, string fileName, MSDOS mz, Scanner scanner)
#endif
public static ProtectionDictionary? HandleExtractable(IExtractableMSDOSExecutable impl, string fileName, MSDOS mz, Scanner scanner)
{
// If the extractable file itself fails
try
@@ -190,8 +173,8 @@ namespace BinaryObjectScanner
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
subProtections.StripFromKeys(tempPath);
subProtections.PrependToKeys(fileName);
return subProtections;
}
catch (Exception ex)
@@ -210,11 +193,7 @@ namespace BinaryObjectScanner
/// <param name="lex">LinearExecutable 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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractableLinearExecutable impl, string fileName, LinearExecutable lex, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractableLinearExecutable impl, string fileName, LinearExecutable lex, Scanner scanner)
#endif
public static ProtectionDictionary? HandleExtractable(IExtractableLinearExecutable impl, string fileName, LinearExecutable lex, Scanner scanner)
{
// If the extractable file itself fails
try
@@ -238,8 +217,8 @@ namespace BinaryObjectScanner
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
subProtections.StripFromKeys(tempPath);
subProtections.PrependToKeys(fileName);
return subProtections;
}
catch (Exception ex)
@@ -258,11 +237,7 @@ namespace BinaryObjectScanner
/// <param name="nex">NewExecutable 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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractableNewExecutable impl, string fileName, NewExecutable nex, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractableNewExecutable impl, string fileName, NewExecutable nex, Scanner scanner)
#endif
public static ProtectionDictionary? HandleExtractable(IExtractableNewExecutable impl, string fileName, NewExecutable nex, Scanner scanner)
{
// If the extractable file itself fails
try
@@ -286,8 +261,8 @@ namespace BinaryObjectScanner
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
subProtections.StripFromKeys(tempPath);
subProtections.PrependToKeys(fileName);
return subProtections;
}
catch (Exception ex)
@@ -306,11 +281,7 @@ namespace BinaryObjectScanner
/// <param name="pex">PortableExecutable 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>
#if NET20 || NET35
public static Dictionary<string, Queue<string>>? HandleExtractable(IExtractablePortableExecutable impl, string fileName, PortableExecutable pex, Scanner scanner)
#else
public static ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractable(IExtractablePortableExecutable impl, string fileName, PortableExecutable pex, Scanner scanner)
#endif
public static ProtectionDictionary? HandleExtractable(IExtractablePortableExecutable impl, string fileName, PortableExecutable pex, Scanner scanner)
{
// If the extractable file itself fails
try
@@ -334,8 +305,8 @@ namespace BinaryObjectScanner
}
// Prepare the returned protections
StripFromKeys(subProtections, tempPath);
PrependToKeys(subProtections, fileName);
subProtections.StripFromKeys(tempPath);
subProtections.PrependToKeys(fileName);
return subProtections;
}
catch (Exception ex)

View File

@@ -20,7 +20,7 @@ namespace BinaryObjectScanner.Interfaces
/// <param name="files">Enumerable of strings representing files in a directory</param>
/// <remarks>This can do some limited content checking as well, but it's suggested to use a content check instead, if possible</remarks>
#if NET20 || NET35
Queue<string> CheckDirectoryPath(string path, IEnumerable<string>? files);
List<string> CheckDirectoryPath(string path, IEnumerable<string>? files);
#else
ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string>? files);
#endif

View File

@@ -48,8 +48,8 @@ namespace BinaryObjectScanner
// Add the key if needed and then append the lists
#if NET20 || NET35
if (!original.ContainsKey(key))
original[key] = new Queue<string>();
if (!ContainsKey(key))
this[key] = new Queue<string>();
#else
TryAdd(key, new ConcurrentQueue<string>());
#endif
@@ -72,8 +72,8 @@ namespace BinaryObjectScanner
// Add the key if needed and then append the lists
#if NET20 || NET35
if (!original.ContainsKey(key))
original[key] = new Queue<string>();
if (!ContainsKey(key))
this[key] = new Queue<string>();
#else
TryAdd(key, new ConcurrentQueue<string>());
#endif
@@ -94,8 +94,8 @@ namespace BinaryObjectScanner
foreach (string key in addition.Keys)
{
#if NET20 || NET35
if (!original.ContainsKey(key))
original[key] = new Queue<string>();
if (!ContainsKey(key))
this[key] = new Queue<string>();
#else
TryAdd(key, new ConcurrentQueue<string>());
#endif

View File

@@ -17,7 +17,6 @@ using BinaryObjectScanner.Utilities;
using SabreTools.IO.Extensions;
using SabreTools.Serialization.Interfaces;
using SabreTools.Serialization.Wrappers;
using static BinaryObjectScanner.Utilities.Dictionary;
namespace BinaryObjectScanner
{
@@ -92,24 +91,14 @@ namespace BinaryObjectScanner
/// </summary>
/// <param name="path">Path to scan</param>
/// <returns>Dictionary of list of strings representing the found protections</returns>
#if NET20 || NET35
public Dictionary<string, Queue<string>>? GetProtections(string path)
#else
public ConcurrentDictionary<string, ConcurrentQueue<string>>? GetProtections(string path)
#endif
{
return GetProtections([path]);
}
public ProtectionDictionary? GetProtections(string path)
=> GetProtections([path]);
/// <summary>
/// Scan the list of paths and get all found protections
/// </summary>
/// <returns>Dictionary of list of strings representing the found protections</returns>
#if NET20 || NET35
public Dictionary<string, Queue<string>>? GetProtections(List<string>? paths)
#else
public ConcurrentDictionary<string, ConcurrentQueue<string>>? GetProtections(List<string>? paths)
#endif
public ProtectionDictionary? GetProtections(List<string>? paths)
{
// If we have no paths, we can't scan
if (paths == null || !paths.Any())
@@ -126,11 +115,7 @@ namespace BinaryObjectScanner
string tempFilePathWithGuid = Path.Combine(tempFilePath, Guid.NewGuid().ToString());
// Loop through each path and get the returned values
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
var protections = new ProtectionDictionary();
foreach (string path in paths)
{
// Directories scan each internal file individually
@@ -143,7 +128,7 @@ namespace BinaryObjectScanner
if (ScanPaths)
{
var directoryPathProtections = Handler.HandlePathChecks(path, files);
AppendToDictionary(protections, directoryPathProtections);
protections.Append(directoryPathProtections);
}
// Scan each file in directory separately
@@ -164,25 +149,14 @@ namespace BinaryObjectScanner
if (ScanPaths)
{
var filePathProtections = Handler.HandlePathChecks(file, files: null);
AppendToDictionary(protections, filePathProtections);
if (filePathProtections != null && filePathProtections.Any())
protections.Append(filePathProtections);
}
// Scan for content-detectable protections
var fileProtections = GetInternalProtections(file);
if (fileProtections != null && fileProtections.Any())
{
foreach (string key in fileProtections.Keys)
{
if (!protections.ContainsKey(key))
#if NET20 || NET35
protections[key] = new Queue<string>();
#else
protections[key] = new ConcurrentQueue<string>();
#endif
protections[key].AddRange(fileProtections[key]);
}
}
protections.Append(fileProtections);
// Checkpoint
protections.TryGetValue(file, out var fullProtectionList);
@@ -206,25 +180,14 @@ namespace BinaryObjectScanner
if (ScanPaths)
{
var filePathProtections = Handler.HandlePathChecks(path, files: null);
AppendToDictionary(protections, filePathProtections);
if (filePathProtections != null && filePathProtections.Any())
protections.Append(filePathProtections);
}
// Scan for content-detectable protections
var fileProtections = GetInternalProtections(path);
if (fileProtections != null && fileProtections.Any())
{
foreach (string key in fileProtections.Keys)
{
if (!protections.ContainsKey(key))
#if NET20 || NET35
protections[key] = new Queue<string>();
#else
protections[key] = new ConcurrentQueue<string>();
#endif
protections[key].AddRange(fileProtections[key]);
}
}
protections.Append(fileProtections);
// Checkpoint
protections.TryGetValue(path, out var fullProtectionList);
@@ -241,7 +204,7 @@ namespace BinaryObjectScanner
}
// Clear out any empty keys
ClearEmptyKeys(protections);
protections.ClearEmptyKeys();
// If we're in debug, output the elasped time to console
if (IncludeDebug)
@@ -255,11 +218,7 @@ namespace BinaryObjectScanner
/// </summary>
/// <param name="file">Path to the file to scan</param>
/// <returns>Dictionary of list of strings representing the found protections</returns>
#if NET20 || NET35
private Dictionary<string, Queue<string>>? GetInternalProtections(string file)
#else
private ConcurrentDictionary<string, ConcurrentQueue<string>>? GetInternalProtections(string file)
#endif
private ProtectionDictionary? GetInternalProtections(string file)
{
// Quick sanity check before continuing
if (!File.Exists(file))
@@ -275,13 +234,9 @@ namespace BinaryObjectScanner
{
if (IncludeDebug) Console.WriteLine(ex);
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
AppendToDictionary(protections, file, IncludeDebug ? ex.ToString() : "[Exception opening file, please try again]");
ClearEmptyKeys(protections);
var protections = new ProtectionDictionary();
protections.Append(file, IncludeDebug ? ex.ToString() : "[Exception opening file, please try again]");
protections.ClearEmptyKeys();
return protections;
}
}
@@ -292,22 +247,14 @@ namespace BinaryObjectScanner
/// <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>Dictionary of list of strings representing the found protections</returns>
#if NET20 || NET35
private Dictionary<string, Queue<string>>? GetInternalProtections(string fileName, Stream stream)
#else
private ConcurrentDictionary<string, ConcurrentQueue<string>>? GetInternalProtections(string fileName, Stream stream)
#endif
private ProtectionDictionary? GetInternalProtections(string fileName, Stream stream)
{
// Quick sanity check before continuing
if (stream == null || !stream.CanRead || !stream.CanSeek)
return null;
// Initialize the protections found
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
var protections = new ProtectionDictionary();
// Get the extension for certain checks
string extension = Path.GetExtension(fileName).ToLower().TrimStart('.');
@@ -349,7 +296,7 @@ namespace BinaryObjectScanner
executable.IncludePackers = ScanPackers;
var subProtections = ProcessExecutable(executable, fileName, stream);
if (subProtections != null)
AppendToDictionary(protections, subProtections);
protections.Append(subProtections);
}
// Otherwise, use the default implementation
@@ -357,7 +304,7 @@ namespace BinaryObjectScanner
{
var subProtections = Handler.HandleDetectable(detectable, fileName, stream, IncludeDebug);
if (subProtections != null)
AppendToDictionary(protections, fileName, subProtections);
protections.Append(fileName, subProtections);
}
var subProtection = detectable.Detect(stream, fileName, IncludeDebug);
@@ -367,11 +314,11 @@ namespace BinaryObjectScanner
if (subProtection.Contains(';'))
{
var splitProtections = subProtection!.Split(';');
AppendToDictionary(protections, fileName, splitProtections);
protections.Append(fileName, splitProtections);
}
else
{
AppendToDictionary(protections, fileName, subProtection!);
protections.Append(fileName, subProtection!);
}
}
}
@@ -388,7 +335,7 @@ namespace BinaryObjectScanner
{
var subProtections = Handler.HandleExtractable(extractable, fileName, stream, this);
if (subProtections != null)
AppendToDictionary(protections, subProtections);
protections.Append(subProtections);
}
#endregion
@@ -396,11 +343,11 @@ namespace BinaryObjectScanner
catch (Exception ex)
{
if (IncludeDebug) Console.WriteLine(ex);
AppendToDictionary(protections, fileName, IncludeDebug ? ex.ToString() : "[Exception opening file, please try again]");
protections.Append(fileName, IncludeDebug ? ex.ToString() : "[Exception opening file, please try again]");
}
// Clear out any empty keys
ClearEmptyKeys(protections);
protections.ClearEmptyKeys();
return protections;
}
@@ -419,11 +366,7 @@ namespace BinaryObjectScanner
/// 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>
#if NET20 || NET35
private Dictionary<string, Queue<string>>? ProcessExecutable(Executable executable, string fileName, Stream stream)
#else
private ConcurrentDictionary<string, ConcurrentQueue<string>>? ProcessExecutable(Executable executable, string fileName, Stream stream)
#endif
private ProtectionDictionary? ProcessExecutable(Executable executable, string fileName, Stream stream)
{
// Try to create a wrapper for the proper executable type
IWrapper? wrapper;
@@ -440,18 +383,14 @@ namespace BinaryObjectScanner
}
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
var protections = new ProtectionDictionary();
// Only use generic content checks if we're in debug mode
if (IncludeDebug)
{
var subProtections = executable.RunContentChecks(fileName, stream, IncludeDebug);
if (subProtections != null)
AppendToDictionary(protections, fileName, subProtections.Values.ToArray());
protections.Append(fileName, subProtections.Values.ToArray());
}
if (wrapper is MSDOS mz)
@@ -461,12 +400,12 @@ namespace BinaryObjectScanner
return protections;
// Append the returned values
AppendToDictionary(protections, fileName, subProtections.Values.ToArray());
protections.Append(fileName, subProtections.Values.ToArray());
// If we have any extractable packers
var extractedProtections = HandleExtractableProtections(subProtections.Keys, fileName, mz);
if (extractedProtections != null)
AppendToDictionary(protections, extractedProtections);
protections.Append(extractedProtections);
}
else if (wrapper is LinearExecutable lex)
{
@@ -475,12 +414,12 @@ namespace BinaryObjectScanner
return protections;
// Append the returned values
AppendToDictionary(protections, fileName, subProtections.Values.ToArray());
protections.Append(fileName, subProtections.Values.ToArray());
// If we have any extractable packers
var extractedProtections = HandleExtractableProtections(subProtections.Keys, fileName, lex);
if (extractedProtections != null)
AppendToDictionary(protections, extractedProtections);
protections.Append(extractedProtections);
}
else if (wrapper is NewExecutable nex)
{
@@ -489,12 +428,12 @@ namespace BinaryObjectScanner
return protections;
// Append the returned values
AppendToDictionary(protections, fileName, subProtections.Values.ToArray());
protections.Append(fileName, subProtections.Values.ToArray());
// If we have any extractable packers
var extractedProtections = HandleExtractableProtections(subProtections.Keys, fileName, nex);
if (extractedProtections != null)
AppendToDictionary(protections, extractedProtections);
protections.Append(extractedProtections);
}
else if (wrapper is PortableExecutable pex)
{
@@ -503,12 +442,12 @@ namespace BinaryObjectScanner
return protections;
// Append the returned values
AppendToDictionary(protections, fileName, subProtections.Values.ToArray());
protections.Append(fileName, subProtections.Values.ToArray());
// If we have any extractable packers
var extractedProtections = HandleExtractableProtections(subProtections.Keys, fileName, pex);
if (extractedProtections != null)
AppendToDictionary(protections, extractedProtections);
protections.Append(extractedProtections);
}
return protections;
@@ -522,9 +461,9 @@ namespace BinaryObjectScanner
/// <param name="mz">MSDOS to scan the contents of</param>
/// <returns>Set of protections found from extraction, null on error</returns>
#if NET20 || NET35
private Dictionary<string, Queue<string>>? HandleExtractableProtections<T>(Dictionary<T, string>.KeyCollection? classes, string fileName, MSDOS mz)
private ProtectionDictionary? HandleExtractableProtections<T>(Dictionary<T, string>.KeyCollection? classes, string fileName, MSDOS mz)
#else
private ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractableProtections(IEnumerable<object>? classes, string fileName, MSDOS mz)
private ProtectionDictionary? HandleExtractableProtections(IEnumerable<object>? classes, string fileName, MSDOS mz)
#endif
{
// If we have an invalid set of classes
@@ -532,11 +471,7 @@ namespace BinaryObjectScanner
return null;
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
var protections = new ProtectionDictionary();
// If we have any extractable packers
var extractables = classes.Where(c => c is IExtractableMSDOSExecutable).Select(c => c as IExtractableMSDOSExecutable);
@@ -557,7 +492,7 @@ namespace BinaryObjectScanner
// Get the protection for the class, if possible
var extractedProtections = Handler.HandleExtractable(extractable, fileName, mz, this);
if (extractedProtections != null)
AppendToDictionary(protections, extractedProtections);
protections.Append(extractedProtections);
#if NET20 || NET35
}
#else
@@ -575,9 +510,9 @@ namespace BinaryObjectScanner
/// <param name="lex">LinearExecutable to scan the contents of</param>
/// <returns>Set of protections found from extraction, null on error</returns>
#if NET20 || NET35
private Dictionary<string, Queue<string>>? HandleExtractableProtections<T>(Dictionary<T, string>.KeyCollection? classes, string fileName, LinearExecutable lex)
private ProtectionDictionary? HandleExtractableProtections<T>(Dictionary<T, string>.KeyCollection? classes, string fileName, LinearExecutable lex)
#else
private ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractableProtections(IEnumerable<object>? classes, string fileName, LinearExecutable lex)
private ProtectionDictionary? HandleExtractableProtections(IEnumerable<object>? classes, string fileName, LinearExecutable lex)
#endif
{
// If we have an invalid set of classes
@@ -585,11 +520,7 @@ namespace BinaryObjectScanner
return null;
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
var protections = new ProtectionDictionary();
// If we have any extractable packers
var extractables = classes.Where(c => c is IExtractableLinearExecutable).Select(c => c as IExtractableLinearExecutable);
@@ -610,7 +541,7 @@ namespace BinaryObjectScanner
// Get the protection for the class, if possible
var extractedProtections = Handler.HandleExtractable(extractable, fileName, lex, this);
if (extractedProtections != null)
AppendToDictionary(protections, extractedProtections);
protections.Append(extractedProtections);
#if NET20 || NET35
}
#else
@@ -628,9 +559,9 @@ namespace BinaryObjectScanner
/// <param name="nex">NewExecutable to scan the contents of</param>
/// <returns>Set of protections found from extraction, null on error</returns>
#if NET20 || NET35
private Dictionary<string, Queue<string>>? HandleExtractableProtections<T>(Dictionary<T, string>.KeyCollection? classes, string fileName, NewExecutable nex)
private ProtectionDictionary? HandleExtractableProtections<T>(Dictionary<T, string>.KeyCollection? classes, string fileName, NewExecutable nex)
#else
private ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractableProtections(IEnumerable<object>? classes, string fileName, NewExecutable nex)
private ProtectionDictionary? HandleExtractableProtections(IEnumerable<object>? classes, string fileName, NewExecutable nex)
#endif
{
// If we have an invalid set of classes
@@ -638,11 +569,7 @@ namespace BinaryObjectScanner
return null;
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
var protections = new ProtectionDictionary();
// If we have any extractable packers
var extractables = classes.Where(c => c is IExtractableNewExecutable).Select(c => c as IExtractableNewExecutable);
@@ -663,7 +590,7 @@ namespace BinaryObjectScanner
// Get the protection for the class, if possible
var extractedProtections = Handler.HandleExtractable(extractable, fileName, nex, this);
if (extractedProtections != null)
AppendToDictionary(protections, extractedProtections);
protections.Append(extractedProtections);
#if NET20 || NET35
}
#else
@@ -681,9 +608,9 @@ namespace BinaryObjectScanner
/// <param name="pex">PortableExecutable to scan the contents of</param>
/// <returns>Set of protections found from extraction, null on error</returns>
#if NET20 || NET35
private Dictionary<string, Queue<string>>? HandleExtractableProtections<T>(Dictionary<T, string>.KeyCollection? classes, string fileName, PortableExecutable pex)
private ProtectionDictionary? HandleExtractableProtections<T>(Dictionary<T, string>.KeyCollection? classes, string fileName, PortableExecutable pex)
#else
private ConcurrentDictionary<string, ConcurrentQueue<string>>? HandleExtractableProtections(IEnumerable<object>? classes, string fileName, PortableExecutable pex)
private ProtectionDictionary? HandleExtractableProtections(IEnumerable<object>? classes, string fileName, PortableExecutable pex)
#endif
{
// If we have an invalid set of classes
@@ -691,11 +618,7 @@ namespace BinaryObjectScanner
return null;
// Create the output dictionary
#if NET20 || NET35
var protections = new Dictionary<string, Queue<string>>();
#else
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
#endif
var protections = new ProtectionDictionary();
// If we have any extractable packers
var extractables = classes.Where(c => c is IExtractablePortableExecutable).Select(c => c as IExtractablePortableExecutable);
@@ -716,7 +639,7 @@ namespace BinaryObjectScanner
// Get the protection for the class, if possible
var extractedProtections = Handler.HandleExtractable(extractable, fileName, pex, this);
if (extractedProtections != null)
AppendToDictionary(protections, extractedProtections);
protections.Append(extractedProtections);
#if NET20 || NET35
}
#else

View File

@@ -1,238 +0,0 @@
using System;
#if NET20 || NET35
using System.Collections.Generic;
#else
using System.Collections.Concurrent;
#endif
using System.IO;
using System.Linq;
namespace BinaryObjectScanner.Utilities
{
/// <summary>
/// Dictionary manipulation methods
/// </summary>
public static class Dictionary
{
/// <summary>
/// Append one result to a results dictionary
/// </summary>
/// <param name="original">Dictionary to append to</param>
/// <param name="key">Key to add information to</param>
/// <param name="value">String value to add</param>
#if NET20 || NET35
public static void AppendToDictionary(Dictionary<string, Queue<string>> original, string key, string value)
#else
public static void AppendToDictionary(ConcurrentDictionary<string, ConcurrentQueue<string>> original, string key, string value)
#endif
{
// If the value is empty, don't add it
if (string.IsNullOrEmpty(value))
return;
#if NET20 || NET35
var values = new Queue<string>();
#else
var values = new ConcurrentQueue<string>();
#endif
values.Enqueue(value);
AppendToDictionary(original, key, values);
}
/// <summary>
/// Append one set of results to a results dictionary
/// </summary>
/// <param name="original">Dictionary to append to</param>
/// <param name="key">Key to add information to</param>
/// <param name="values">String value array to add</param>
#if NET20 || NET35
public static void AppendToDictionary(Dictionary<string, Queue<string>> original, string key, string[] values)
#else
public static void AppendToDictionary(ConcurrentDictionary<string, ConcurrentQueue<string>> original, string key, string[] values)
#endif
{
// If the dictionary is null, just return
if (original == null)
return;
// Use a placeholder value if the key is null
key ??= "NO FILENAME";
// Add the key if needed and then append the lists
#if NET20 || NET35
if (!original.ContainsKey(key))
original[key] = new Queue<string>();
#else
original.TryAdd(key, new ConcurrentQueue<string>());
#endif
original[key].AddRange(values);
}
/// <summary>
/// Append one set of results to a results dictionary
/// </summary>
/// <param name="original">Dictionary to append to</param>
/// <param name="key">Key to add information to</param>
/// <param name="value">String value to add</param>
#if NET20 || NET35
public static void AppendToDictionary(Dictionary<string, Queue<string>> original, string key, Queue<string> values)
#else
public static void AppendToDictionary(ConcurrentDictionary<string, ConcurrentQueue<string>> original, string key, ConcurrentQueue<string> values)
#endif
{
// If the dictionary is null, just return
if (original == null)
return;
// Use a placeholder value if the key is null
key ??= "NO FILENAME";
// Add the key if needed and then append the lists
#if NET20 || NET35
if (!original.ContainsKey(key))
original[key] = new Queue<string>();
#else
original.TryAdd(key, new ConcurrentQueue<string>());
#endif
original[key].AddRange(values);
}
/// <summary>
/// Append one results dictionary to another
/// </summary>
/// <param name="original">Dictionary to append to</param>
/// <param name="addition">Dictionary to pull from</param>
#if NET20 || NET35
public static void AppendToDictionary(Dictionary<string, Queue<string>> original, Dictionary<string, Queue<string>> addition)
#else
public static void AppendToDictionary(ConcurrentDictionary<string, ConcurrentQueue<string>> original, ConcurrentDictionary<string, ConcurrentQueue<string>> addition)
#endif
{
// If either dictionary is missing, just return
if (original == null || addition == null)
return;
// Loop through each of the addition keys and add accordingly
foreach (string key in addition.Keys)
{
#if NET20 || NET35
if (!original.ContainsKey(key))
original[key] = new Queue<string>();
#else
original.TryAdd(key, new ConcurrentQueue<string>());
#endif
original[key].AddRange(addition[key]);
}
}
/// <summary>
/// Remove empty or null keys from a results dictionary
/// </summary>
/// <param name="original">Dictionary to clean</param>
#if NET20 || NET35
public static void ClearEmptyKeys(Dictionary<string, Queue<string>> original)
#else
public static void ClearEmptyKeys(ConcurrentDictionary<string, ConcurrentQueue<string>> original)
#endif
{
// If the dictionary is missing, we can't do anything
if (original == null)
return;
// Get a list of all of the keys
var keys = original.Keys.ToList();
// Iterate and reset keys
for (int i = 0; i < keys.Count; i++)
{
// Get the current key
string key = keys[i];
// If the key is empty, remove it
if (original[key] == null || !original[key].Any())
#if NET20 || NET35
original.Remove(key);
#else
original.TryRemove(key, out _);
#endif
}
}
/// <summary>
/// Prepend a parent path from dictionary keys, if possible
/// </summary>
/// <param name="original">Dictionary to strip values from</param>
/// <param name="pathToPrepend">Path to strip from the keys</param>
#if NET20 || NET35
public static void PrependToKeys(Dictionary<string, Queue<string>>? original, string pathToPrepend)
#else
public static void PrependToKeys(ConcurrentDictionary<string, ConcurrentQueue<string>>? original, string pathToPrepend)
#endif
{
// If the dictionary is missing, we can't do anything
if (original == null)
return;
// Use a placeholder value if the path is null
pathToPrepend = (pathToPrepend ?? "ARCHIVE").TrimEnd(Path.DirectorySeparatorChar);
// Get a list of all of the keys
var keys = original.Keys.ToList();
// Iterate and reset keys
for (int i = 0; i < keys.Count; i++)
{
// Get the current key
string currentKey = keys[i];
// Otherwise, get the new key name and transfer over
string newKey = $"{pathToPrepend}{Path.DirectorySeparatorChar}{currentKey.Trim(Path.DirectorySeparatorChar)}";
original[newKey] = original[currentKey];
#if NET20 || NET35
original.Remove(currentKey);
#else
original.TryRemove(currentKey, out _);
#endif
}
}
/// <summary>
/// Strip a parent path from dictionary keys, if possible
/// </summary>
/// <param name="original">Dictionary to strip values from</param>
/// <param name="pathToStrip">Path to strip from the keys</param>
#if NET20 || NET35
public static void StripFromKeys(Dictionary<string, Queue<string>>? original, string? pathToStrip)
#else
public static void StripFromKeys(ConcurrentDictionary<string, ConcurrentQueue<string>>? original, string? pathToStrip)
#endif
{
// If either is missing, we can't do anything
if (original == null || string.IsNullOrEmpty(pathToStrip))
return;
// Get a list of all of the keys
var keys = original.Keys.ToList();
// Iterate and reset keys
for (int i = 0; i < keys.Count; i++)
{
// Get the current key
string currentKey = keys[i];
// If the key doesn't start with the path, don't touch it
if (!currentKey.StartsWith(pathToStrip, StringComparison.OrdinalIgnoreCase))
continue;
// Otherwise, get the new key name and transfer over
string newKey = currentKey.Substring(pathToStrip!.Length);
original[newKey] = original[currentKey];
#if NET20 || NET35
original.Remove(currentKey);
#else
original.TryRemove(currentKey, out _);
#endif
}
}
}
}

View File

@@ -43,11 +43,7 @@ namespace Test
/// </summary>
/// <param name="path">File or directory path</param>
/// <param name="protections">Dictionary of protections found, if any</param>
#if NET20 || NET35
private static void WriteProtectionResultFile(string path, Dictionary<string, Queue<string>>? protections)
#else
private static void WriteProtectionResultFile(string path, ConcurrentDictionary<string, ConcurrentQueue<string>>? protections)
#endif
private static void WriteProtectionResultFile(string path, ProtectionDictionary? protections)
{
if (protections == null)
{