From 0dd71d72ca620174b71bd2490fedc30e748e339b Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 30 Oct 2020 23:56:27 -0700 Subject: [PATCH] Add new, but unused, Scanner class --- BurnOutSharp/Scanner.cs | 585 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 585 insertions(+) create mode 100644 BurnOutSharp/Scanner.cs diff --git a/BurnOutSharp/Scanner.cs b/BurnOutSharp/Scanner.cs new file mode 100644 index 00000000..07dd4301 --- /dev/null +++ b/BurnOutSharp/Scanner.cs @@ -0,0 +1,585 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using BurnOutSharp.FileType; +using BurnOutSharp.ProtectionType; + +namespace BurnOutSharp +{ + // TODO: Use the file progress everywhere + // TODO: Re-enable direct stream scanning + // TODO: Should FileTypes be exposed directly as well so the scans can be exposed easier? + public class Scanner + { + /// + /// Optional progress callback during scanning + /// + public IProgress FileProgress { get; set; } = null; + + /// + /// List of paths that will be scanned with this object + /// + public List Paths { get; set; } = new List(); + + /// + /// Determines whether the byte position of found protection is included or not + /// + public bool IncludePosition { get; set; } = false; + + /// + /// Determines whether all files are scanned or just executables are + /// + public bool ScanAllFiles { get; set; } = false; + + /// + /// Determines whether archives are decompressed and scanned + /// + public bool ScanArchives { get; set; } = true; + + /// + /// Constructor + /// + /// Path to create a scanner for + /// Optional progress callback + public Scanner(string path, IProgress fileProgress = null) + { + Paths = new List { path }; + FileProgress = fileProgress; + } + + /// + /// Scan the list of paths and get all found protections + /// + /// Dictionary of list of strings representing the found protections + public Dictionary> GetProtections() + { + // If we have no paths, we can't scan + if (Paths == null || !Paths.Any()) + return null; + + // Loop through each path and get the returned values + var protections = new Dictionary>(); + foreach (string path in Paths) + { + // Directories scan each internal file individually + if (Directory.Exists(path)) + { + // Enumerate all files at first for easier access + var files = Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).ToList(); + + // Scan for path-detectable protections + var directoryPathProtections = GetPathProtections(path, files); + if (directoryPathProtections != null && directoryPathProtections.Any()) + { + foreach (string key in directoryPathProtections.Keys) + { + if (!protections.ContainsKey(key)) + protections[key] = new List(); + + protections[key].AddRange(directoryPathProtections[key]); + } + } + + // Scan each file in directory separately + foreach (string file in files) + { + // Scan for path-detectable protections + var filePathProtections = GetPathProtections(file); + if (filePathProtections != null && filePathProtections.Any()) + { + foreach (string key in filePathProtections.Keys) + { + if (!protections.ContainsKey(key)) + protections[key] = new List(); + + protections[key].AddRange(filePathProtections[key]); + } + } + + // Scan for content-detectable protections + var fileProtections = GetInternalProtections(file); + if (fileProtections != null && fileProtections.Any()) + { + foreach (string key in fileProtections.Keys) + { + if (!protections.ContainsKey(key)) + protections[key] = new List(); + + protections[key].AddRange(fileProtections[key]); + } + } + } + } + + // Scan a single file by itself + else if (File.Exists(path)) + { + // Scan for path-detectable protections + var filePathProtections = GetPathProtections(path); + if (filePathProtections != null && filePathProtections.Any()) + { + foreach (string key in filePathProtections.Keys) + { + if (!protections.ContainsKey(key)) + protections[key] = new List(); + + protections[key].AddRange(filePathProtections[key]); + } + } + + // Scan for content-detectable protections + var fileProtections = GetInternalProtections(path); + if (fileProtections != null && fileProtections.Any()) + { + foreach (string key in fileProtections.Keys) + { + if (!protections.ContainsKey(key)) + protections[key] = new List(); + + protections[key].AddRange(fileProtections[key]); + } + } + } + + // Throw on an invalid path + else + { + throw new FileNotFoundException($"{path} is not a directory or file, skipping..."); + } + } + + return protections; + } + + /// + /// Get the path-detectable protections associated with a single path + /// + /// Path of the directory or file to scan + /// Files contained within if the path is a directory + /// Dictionary of list of strings representing the found protections + public Dictionary> GetPathProtections(string path, List files = null) + { + List protections = new List(); + string protection; + + // If we have a directory, get the files in the directory for searching + bool isDirectory = false; + if (Directory.Exists(path)) + isDirectory = true; + + // AACS + protection = AACS.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Alpha-DVD + protection = AlphaDVD.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Bitpool + protection = Bitpool.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // ByteShield + protection = ByteShield.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Cactus Data Shield + protection = CactusDataShield.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // CD-Cops + protection = CDCops.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // CD-Lock + protection = CDLock.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // CD-Protector + protection = CDProtector.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // CD-X + protection = CDX.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + /* + // CopyKiller + protection = CopyKiller.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + */ + + // DiscGuard + protection = DiscGuard.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // DVD Crypt + protection = DVDCrypt.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // DVD-Movie-PROTECT + protection = DVDMoviePROTECT.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // FreeLock + protection = FreeLock.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Games for Windows - Live + protection = GFWL.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Hexalock AutoLock + protection = HexalockAutoLock.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Impulse Reactor + protection = ImpulseReactor.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // IndyVCD + protection = IndyVCD.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Key2Audio XS + protection = Key2AudioXS.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // LaserLock + protection = LaserLock.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // MediaCloQ + protection = MediaCloQ.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // MediaMax CD3 + protection = MediaMaxCD3.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Origin + protection = Origin.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Protect DVD-Video + protection = ProtectDVDVideo.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // SafeCast + protection = SafeCast.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // SafeDisc + protection = SafeDisc.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // SafeDisc Lite + protection = SafeDiscLite.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // SafeLock + protection = SafeLock.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // SecuROM + protection = SecuROM.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // SmartE + protection = SmartE.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // SoftLock + protection = SoftLock.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // SolidShield + protection = SolidShield.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // StarForce + protection = StarForce.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Steam + protection = Steam.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // TAGES + protection = Tages.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // TZCopyProtector + protection = TZCopyProtector.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Uplay + protection = Uplay.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // VOB ProtectCD/DVD + protection = VOBProtectCDDVD.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Winlock + protection = Winlock.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // WTM CD Protect + protection = WTMCDProtect.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // XCP + protection = XCP.CheckPath(path, files, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Zzxzz + protection = Zzxzz.CheckPath(path, isDirectory); + if (!string.IsNullOrWhiteSpace(protection)) + protections.Add(protection); + + // Create and return the dictionary + return new Dictionary> + { + [path] = protections + }; + } + + /// + /// Get the content-detectable protections associated with a single path + /// + /// Path to the file to scan + /// Dictionary of list of strings representing the found protections + private Dictionary> GetInternalProtections(string file) + { + // Quick sanity check before continuing + if (!File.Exists(file)) + return null; + + // Initialze the protections found + var protections = new Dictionary>(); + + // Get the extension for certain checks + string extension = Path.GetExtension(file).ToLower().TrimStart('.'); + + // Open the file and begin scanning + using (FileStream fs = File.OpenRead(file)) + { + // Get the first 16 bytes for matching + byte[] magic = new byte[16]; + try + { + fs.Read(magic, 0, 16); + fs.Seek(-16, SeekOrigin.Current); + } + catch + { + // We don't care what the issue was, we can't read or seek the file + return null; + } + + #region Non-Archive File Types + + // Executable + if (ScanAllFiles || Executable.ShouldScan(magic)) + { + var subProtections = Executable.Scan(fs, file, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // Text-based files + if (ScanAllFiles || Textfile.ShouldScan(magic, extension)) + { + var subProtections = Executable.Scan(fs, file, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + #endregion + + #region Archive File Types + + // 7-Zip archive + if (SevenZip.ShouldScan(magic)) + { + var subProtections = SevenZip.Scan(fs, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // BFPK archive + if (BFPK.ShouldScan(magic)) + { + var subProtections = BFPK.Scan(fs, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // BZip2 + if (BZip2.ShouldScan(magic)) + { + var subProtections = BZip2.Scan(fs, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // GZIP + if (GZIP.ShouldScan(magic)) + { + var subProtections = GZIP.Scan(fs, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // InstallShield Cabinet + if (file != null && InstallShieldCAB.ShouldScan(magic)) + { + var subProtections = InstallShieldCAB.Scan(file, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // Microsoft Cabinet + if (file != null && MicrosoftCAB.ShouldScan(magic)) + { + var subProtections = MicrosoftCAB.Scan(file, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // MSI + if (file != null && MSI.ShouldScan(magic)) + { + var subProtections = MSI.Scan(file, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // MPQ archive + if (file != null && MPQ.ShouldScan(magic)) + { + var subProtections = MPQ.Scan(file, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // PKZIP archive (and derivatives) + if (PKZIP.ShouldScan(magic)) + { + var subProtections = PKZIP.Scan(fs, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // RAR archive + if (RAR.ShouldScan(magic)) + { + var subProtections = RAR.Scan(fs, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // Tape Archive + if (TapeArchive.ShouldScan(magic)) + { + var subProtections = TapeArchive.Scan(fs, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // Valve archive formats + if (file != null && Valve.ShouldScan(magic)) + { + var subProtections = Valve.Scan(file, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + // XZ + if (XZ.ShouldScan(magic)) + { + var subProtections = XZ.Scan(fs, IncludePosition); + if (!protections.ContainsKey(file)) + protections[file] = new List(); + + protections[file] = subProtections; + } + + #endregion + } + + return protections; + } + } +}