From 2d3d66f07779c2112500ae8ab0996466a9744019 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Thu, 2 Sep 2021 15:22:33 -0700 Subject: [PATCH] Convert SafeDisc to section based; add notes --- BurnOutSharp/ProtectionType/SafeDisc.cs | 262 +++++++++++++----------- 1 file changed, 139 insertions(+), 123 deletions(-) diff --git a/BurnOutSharp/ProtectionType/SafeDisc.cs b/BurnOutSharp/ProtectionType/SafeDisc.cs index bed1e286..37870d88 100644 --- a/BurnOutSharp/ProtectionType/SafeDisc.cs +++ b/BurnOutSharp/ProtectionType/SafeDisc.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Diagnostics; using System.IO; +using System.Linq; using System.Text; +using BurnOutSharp.ExecutableType.Microsoft; using BurnOutSharp.Matching; -using BurnOutSharp.Tools; namespace BurnOutSharp.ProtectionType { @@ -40,53 +40,84 @@ namespace BurnOutSharp.ProtectionType }; /// - public List GetContentMatchSets() - { - return new List - { - new ContentMatchSet(new List - { - // BoG_ *90.0&!! Yy> - new byte?[] - { - 0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30, - 0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59, - 0x79, 0x3E - }, - - // product activation library - new byte?[] - { - 0x70, 0x72, 0x6F, 0x64, 0x75, 0x63, 0x74, 0x20, - 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, - 0x6F, 0x6E, 0x20, 0x6C, 0x69, 0x62, 0x72, 0x61, - 0x72, 0x79 - }, - }, GetVersion, "SafeCast"), - - // BoG_ *90.0&!! Yy> - new ContentMatchSet(new byte?[] - { - 0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30, - 0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59, - 0x79, 0x3E - }, GetVersion, "SafeDisc"), - - // (char)0x00 + (char)0x00 + BoG_ - new ContentMatchSet(new byte?[] { 0x00, 0x00, 0x42, 0x6F, 0x47, 0x5F }, Get320to4xVersion, "SafeDisc"), - - // TODO: These two following are section headers. They should be converted to section header checks instead - - // stxt774 - new ContentMatchSet(new byte?[] { 0x73, 0x74, 0x78, 0x74, 0x37, 0x37, 0x34 }, Get320to4xVersion, "SafeDisc"), - - // stxt371 - new ContentMatchSet(new byte?[] { 0x73, 0x74, 0x78, 0x74, 0x33, 0x37, 0x31 }, Get320to4xVersion, "SafeDisc"), - }; - } + public List GetContentMatchSets() => null; /// - public string CheckContents(string file, byte[] fileContent, bool includeDebug = false) => null; + public string CheckContents(string file, byte[] fileContent, bool includeDebug = false) + { + // Get the sections from the executable, if possible + PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0); + var sections = pex?.SectionTable; + if (sections == null) + return null; + + // Get the .text section, if it exists + var textSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".text")); + if (textSection != null) + { + // This subtract is needed because BoG_ starts before the .text section + int sectionAddr = (int)textSection.PointerToRawData - 64; + int sectionEnd = sectionAddr + (int)textSection.VirtualSize; + var matchers = new List + { + // BoG_ *90.0&!! Yy> + new ContentMatchSet( + new ContentMatch(new byte?[] + { + 0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30, + 0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59, + 0x79, 0x3E + }, start: sectionAddr, end: sectionEnd), + GetVersion, "SafeDisc"), + + // (char)0x00 + (char)0x00 + BoG_ + new ContentMatchSet( + new ContentMatch(new byte?[] { 0x00, 0x00, 0x42, 0x6F, 0x47, 0x5F }, start: sectionAddr, end: sectionEnd), + Get320to4xVersion, "SafeDisc"), + }; + + string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug); + if (!string.IsNullOrWhiteSpace(match)) + return match; + } + + // Get the .data section, if it exists + var dataSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".data")); + if (dataSection != null) + { + int sectionAddr = (int)dataSection.PointerToRawData; + int sectionEnd = sectionAddr + (int)dataSection.VirtualSize; + var matchers = new List + { + // BoG_ *90.0&!! Yy> + new ContentMatchSet( + new ContentMatch(new byte?[] + { + 0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30, + 0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59, + 0x79, 0x3E + }, start: sectionAddr, end: sectionEnd), + GetVersion, "SafeDisc"), + + // (char)0x00 + (char)0x00 + BoG_ + new ContentMatchSet( + new ContentMatch(new byte?[] { 0x00, 0x00, 0x42, 0x6F, 0x47, 0x5F }, start: sectionAddr, end: sectionEnd), + Get320to4xVersion, "SafeDisc"), + }; + + string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug); + if (!string.IsNullOrWhiteSpace(match)) + return match; + } + + // Get the stxt371 and stxt774 sections, if they exist -- TODO: Confirm if both are needed or either/or is fine + var stxt371Section = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith("stxt371")); + var stxt774Section = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith("stxt774")); + if (stxt371Section != null || stxt774Section != null) + return $"SafeDisc {Get320to4xVersion(file, fileContent, null)}"; + + return null; + } /// public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable files) @@ -100,14 +131,8 @@ namespace BurnOutSharp.ProtectionType return MatchUtil.GetFirstMatch(path, pathMatchers, any: true); } - public static string Get320to4xVersion(string file, byte[] fileContent, List positions) - { - string version = SearchSafeDiscVersion(file, fileContent); - if (version.Length > 0) - return version; - - return "3.20-4.xx (version removed)"; - } + // TODO: Try to find a file that this actually triggers for + public static string Get320to4xVersion(string file, byte[] fileContent, List positions) => "3.20-4.xx (version removed)"; public static string GetVersion(string file, byte[] fileContent, List positions) { @@ -134,6 +159,7 @@ namespace BurnOutSharp.ProtectionType return $"{version}.{subVersion:00}.{subsubVersion:000}"; } + // TODO: Continue collecting SHA-1 hashes instead of sizes public static string GetDPlayerXVersion(string firstMatchedString, IEnumerable files) { if (firstMatchedString == null || !File.Exists(firstMatchedString)) @@ -144,12 +170,19 @@ namespace BurnOutSharp.ProtectionType return "1.0x"; else if (fi.Length == 155648) return "1.1x"; + + // a8ed1613d47d1b5064300ff070484528ebb20a3b - Bundled with 1.11.000 else if (fi.Length == 156160) return "1.1x-1.2x"; + + // ed680e9a13f593e7a80a69ee1035d956ab62212b + // 66d8589343e00fa3e11bbf462e38c6f502515bea - Bundled with 1.30.010 else if (fi.Length == 163328) return "1.3x"; else if (fi.Length == 165888) return "1.35"; + + // 5751ae2ee805d31227cfe7680f3c8be4ab8945a3 else if (fi.Length == 172544) return "1.40"; else if (fi.Length == 173568) @@ -158,10 +191,13 @@ namespace BurnOutSharp.ProtectionType return "1.4x"; else if (fi.Length == 138752) return "1.5x"; + + // f7a57f83bdc29040e20fd37cd0c6d7e6b2984180 - 78848 - Bundled with 1.00.030 else return "1"; } + // TODO: Continue collecting SHA-1 hashes instead of sizes public static string GetDrvmgtVersion(string firstMatchedString, IEnumerable files) { if (firstMatchedString == null || !File.Exists(firstMatchedString)) @@ -170,26 +206,50 @@ namespace BurnOutSharp.ProtectionType FileInfo fi = new FileInfo(firstMatchedString); if (fi.Length == 34816) return "1.0x"; + + // d31725ff99be44bc1bfff171f4c4705f786b8e91 + // 87c0da1b52681fa8052a915e85699738993bea72 - Bundled with 1.11.000 else if (fi.Length == 32256) return "1.1x-1.3x"; + + // 8e41db1c60bbac631b06ad4f94adb4214a0e65dc else if (fi.Length == 31744) return "1.4x"; + + // 04ed7ac39fe7a6fab497a498cbcff7da19bf0556 + // 5198da51184ca9f3a8096c6136f645b454a85f6c - Bundled with 2.30.030 + // 1437c8c149917c76f741c6dbee6b6b0cc0664f13 - Bundled with 2.40.010, 4.60.000 else if (fi.Length == 34304) return "1.5x-2.40"; + + // 27d5e7f7eee1f22ebdaa903a9e58a7fdb50ef82c else if (fi.Length == 35840) return "2.51-2.60"; + + // 88c7aa6e91c9ba5f2023318048e3c3571088776f else if (fi.Length == 40960) return "2.70"; + + // ea6e24b1f306391cd78a1e7c2f2c0c31828ef004 else if (fi.Length == 23552) return "2.80"; + + // e21ff43c2e663264d6cb11fbbc31eb1dcee42b1a + // b824ed257946eee93f438b25c855e9dde7a3671a + // 7c5ab9bdf965b70e60b99086519327168f43f362 - Bundled with 4.00.002 else if (fi.Length == 41472) return "2.90-3.10"; + + // ecb341ab36c5b3b912f568d347368a6a2def8d5f else if (fi.Length == 24064) return "3.15-3.20"; + + // a5247ec0ec50b8f470c93bf23e3f2514c402d5ad - 46592 - Bundled with 4.60.000 (2x) else - return "1-3"; + return "1-4"; } + // TODO: Continue collecting SHA-1 hashes instead of sizes public static string GetSecdrvVersion(string firstMatchedString, IEnumerable files) { if (firstMatchedString == null || !File.Exists(firstMatchedString)) @@ -198,96 +258,52 @@ namespace BurnOutSharp.ProtectionType FileInfo fi = new FileInfo(firstMatchedString); if (fi.Length == 20128) return "2.10"; + + // f68a1370660f8b94f896bbba8dc6e47644d19092 else if (fi.Length == 27440) return "2.30"; + + // 60bc8c3222081bf76466c521474d63714afd43cd else if (fi.Length == 28624) return "2.40"; + + // 08ceca66432278d8c4e0f448436b77583c3c61c8 else if (fi.Length == 18768) return "2.50"; + + // 10080eb46bf76ac9cf9ea74372cfa4313727f0ca else if (fi.Length == 28400) return "2.51"; else if (fi.Length == 29392) return "2.60"; + + // 832d359a6de191c788b0e61e33f3d01f8d793d3c else if (fi.Length == 11376) return "2.70"; + + // afcfaac945a5b47712719a5e6a7eb69e36a5a6e0 + // cb24fbe8aa23a49e95f3c83fb15123ffb01f43f4 else if (fi.Length == 12464) return "2.80"; + + // 0383b69f98d0a9c0383c8130d52d6b431c79ac48 else if (fi.Length == 12400) return "2.90"; else if (fi.Length == 12528) return "3.10"; else if (fi.Length == 12528) return "3.15"; + + // d7c9213cc78ff57f2f655b050c4d5ac065661aa9 else if (fi.Length == 11973) return "3.20"; + + // b64ad3ec82f2eb9fb854512cb59c25a771322181 - 14304 - Bundled wtih 1.11.000 + // ebf69b0a96adfc903b7e486708474dc864cc0c7c - 10848 - Bundled with 1.40.004 + // 2d9f54f35f5bacb8959ef3affdc3e4209a4629cb - 14368 - UNKNOWN + // fc6fedacc21a7244975b8f410ff8673285374cc2 - 163644 - Bundled with 4.00.002, 4.60.000 else - return "1-3"; - } - - // TODO: Analyze this method and figure out if this can be done without attempting execution - private static string SearchSafeDiscVersion(string file, byte[] fileContent) - { - // If the file isn't executable, don't even bother - if (!EVORE.IsPEExecutable(fileContent)) - return string.Empty; - - // Get some of the required paths - string tempexe = EVORE.MakeTempFile(fileContent); - string[] dependentDlls = EVORE.CopyDependentDlls(file, fileContent); - - // Clean up any temp files before attempting to run - Utilities.SafeTempDelete("~e*", isDirectory: true); - Utilities.SafeTempDelete("~e*", isDirectory: false); - - // Try to safely start the temp executable - Process exe = EVORE.StartSafe(tempexe); - if (exe == null) - return string.Empty; - - string version = ""; - DateTime timestart = DateTime.Now; - do - { - if (Directory.GetDirectories(Path.GetTempPath(), "~e*").Length > 0) - { - string[] files = Directory.GetFiles(Directory.GetDirectories(Path.GetTempPath(), "~e*")[0], "~de*.tmp"); - if (files.Length > 0) - { - StreamReader sr; - try - { - sr = new StreamReader(files[0], Encoding.Default); - string localFileContent = sr.ReadToEnd(); - sr.Close(); - int position = localFileContent.IndexOf("%ld.%ld.%ld, %ld, %s,") - 1; - if (position > -1) - version = localFileContent.Substring(position + 28, 12); - break; - } - catch { } - } - } - } while (!exe.HasExited && DateTime.Now.Subtract(timestart).TotalSeconds < 20); - - if (!exe.HasExited) - exe.Kill(); - - exe.Close(); - - // Clean up any temp files after running - Utilities.SafeDelete(tempexe); - Utilities.SafeTempDelete("~e*", isDirectory: true); - Utilities.SafeTempDelete("~e*", isDirectory: false); - - if (dependentDlls != null) - { - foreach (string dll in dependentDlls) - { - Utilities.SafeDelete(dll); - } - } - - return version; + return "1-4"; } } }