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 } }