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