diff --git a/BurnOutSharp/ProtectionType/ProtectDisc.cs b/BurnOutSharp/ProtectionType/ProtectDisc.cs
index 1172a148..4770c97c 100644
--- a/BurnOutSharp/ProtectionType/ProtectDisc.cs
+++ b/BurnOutSharp/ProtectionType/ProtectDisc.cs
@@ -1,314 +1,200 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
using System.Linq;
-using System.Threading;
+using BurnOutSharp.ExecutableType.Microsoft;
using BurnOutSharp.Matching;
-using BurnOutSharp.Tools;
namespace BurnOutSharp.ProtectionType
{
- public class ProtectDisc : IContentCheck
+ // TODO: Investigate the connection between this and VOB Protect CD/DVD
+ public class ProtectDISC : IContentCheck
{
///
- public List GetContentMatchSets()
- {
- return new List
- {
- // HúMETINF
- new ContentMatchSet(new byte?[] { 0x48, 0xFA, 0x4D, 0x45, 0x54, 0x49, 0x4E, 0x46 }, GetVersion76till10, "ProtectDisc"),
-
- // ACE-PCD
- new ContentMatchSet(new byte?[] { 0x41, 0x43, 0x45, 0x2D, 0x50, 0x43, 0x44 }, GetVersion6till8, "ProtectDisc"),
- };
- }
+ public List GetContentMatchSets() => null;
///
- public string CheckContents(string file, byte[] fileContent, bool includeDebug = false) => null;
-
- public static string GetVersion6till8(string file, byte[] fileContent, List positions)
+ public string CheckContents(string file, byte[] fileContent, bool includeDebug = false)
{
- string version = SearchProtectDiscVersion(file, fileContent);
- if (version.Length > 0)
+ // 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 4th section, if it exists (example names: ACE4)
+ var fourthSection = sections.Length < 4 ? null : sections[3];
+ if (fourthSection != null)
{
- string[] astrVersionArray = version.Split('.');
- return $"{astrVersionArray[0]}.{astrVersionArray[1]}.{astrVersionArray[2]} (Build {astrVersionArray[3]})";
+ int sectionAddr = (int)fourthSection.PointerToRawData;
+ int sectionEnd = sectionAddr + (int)fourthSection.VirtualSize;
+ var matchers = new List
+ {
+ // ACE-PCD
+ new ContentMatchSet(
+ new ContentMatch(new byte?[] { 0x41, 0x43, 0x45, 0x2D, 0x50, 0x43, 0x44 }, start: sectionAddr, end: sectionEnd),
+ GetVersion6till8, "ProtectDISC"),
+ };
+
+ string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
+ if (!string.IsNullOrWhiteSpace(match))
+ return match;
}
- return $"{GetVersionBuild6till8(fileContent, positions[0])}";
- }
-
- public static string GetVersion76till10(string file, byte[] fileContent, List positions)
- {
- string version = SearchProtectDiscVersion(file, fileContent);
- if (version.Length > 0)
+ // Get the last section (example names: ACE5, akxpxgcv, and piofinqb)
+ var lastSection = sections.LastOrDefault();
+ if (lastSection != null)
{
- string[] astrVersionArray = version.Split('.');
- if (astrVersionArray[0] == "9")
+ int sectionAddr = (int)lastSection.PointerToRawData;
+ int sectionEnd = sectionAddr + (int)lastSection.VirtualSize;
+ var matchers = new List
{
- if (GetVersionBuild76till10(fileContent, positions[0], out int ibuild).Length > 0)
- return $"{astrVersionArray[0]}.{astrVersionArray[1]}{astrVersionArray[2]}.{astrVersionArray[3]} (Build {ibuild})";
- }
- else
- {
- return $"{astrVersionArray[0]}.{astrVersionArray[1]}.{astrVersionArray[2]} (Build {astrVersionArray[3]})";
- }
+ // HúMETINF
+ new ContentMatchSet(
+ new ContentMatch(new byte?[] { 0x48, 0xFA, 0x4D, 0x45, 0x54, 0x49, 0x4E, 0x46 }, start: sectionAddr, end: sectionEnd),
+ GetVersion76till10, "ProtectDISC"),
+ };
+
+ string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug);
+ if (!string.IsNullOrWhiteSpace(match))
+ return match;
}
return null;
}
- private static string GetVersionBuild6till8(byte[] fileContent, int position)
+ public static string GetVersion6till8(string file, byte[] fileContent, List positions)
{
- string version;
- string strBuild;
+ string version, strBuild = string.Empty;
+ int index = positions[0] - 12;
- int index = position - 12;
- if (new ArraySegment(fileContent, index, 4).SequenceEqual(new byte[] { 0x0A, 0x0D, 0x0A, 0x0D })) // ProtectDisc 6-7 with Build Number in plain text
+ // Version 6-7 with Build Number in plain text
+ if (new ArraySegment(fileContent, index, 4).SequenceEqual(new byte[] { 0x0A, 0x0D, 0x0A, 0x0D }))
{
- index = position - 12 - 6;
+ index = positions[0] - 12 - 6;
- // ProtectDisc 7
+ // Version 7
if (new string(new ArraySegment(fileContent, index, 6).Select(b => (char)b).ToArray()) == "Henrik")
{
version = "7.1-7.5";
- index = position - 12 - 6 - 6;
+ index = positions[0] - 12 - 6 - 6;
}
- // ProtectDisc 6
+ // Version 6
else
{
+ // TODO: Figure out if the version can be more granular
version = "6";
- index = position - 12 - 10;
+ index = positions[0] - 12 - 10;
while (true) //search for e.g. "Build 050913 - September 2005"
{
if (Char.IsNumber((char)fileContent[index]))
break;
- index -= 1; //search upwards
+ index--; // Search upwards
}
index -= 5;
}
+
+ char[] arrBuild = new ArraySegment(fileContent, index, 6).Select(b => (char)b).ToArray();
+ if (!Int32.TryParse(new string(arrBuild), out int intBuild))
+ strBuild = $"[Build {new string(arrBuild).Trim()}]";
+ else
+ strBuild = $"[Build 0x{intBuild:X} / {intBuild}]";
+
+ return $"{version} {strBuild}".Trim();
}
else
{
- index = position + 28;
+ index = positions[0] + 28;
if (fileContent[index] == 0xFB)
return "7.6-7.x";
else
return "8.0";
}
-
- strBuild = new string(new ArraySegment(fileContent, index, 5).Select(b => (char)b).ToArray());
- return $"{version} (Build {strBuild})";
}
- private static string GetVersionBuild76till10(byte[] fileContent, int position, out int irefBuild)
+ public static string GetVersion76till10(string file, byte[] fileContent, List positions)
{
- int index = position + 37;
+ int index = positions[0] + 37;
byte subversion = fileContent[index];
- index++;
- index++;
+ index += 2;
byte version = fileContent[index];
- index = position + 49;
- irefBuild = BitConverter.ToInt32(fileContent, index);
- index = position + 53;
+ index = positions[0] + 49;
+ int irefBuild = BitConverter.ToInt32(fileContent, index);
+ index = positions[0] + 53;
byte versionindicatorPD9 = fileContent[index];
- index = position + 0x40;
+ index = positions[0] + 0x40;
byte subsubversionPD9x = fileContent[index];
index++;
byte subversionPD9x2 = fileContent[index];
index++;
byte subversionPD9x1 = fileContent[index];
- // version 7
+ // Version 7
if (version == 0xAC)
- return $"7.{subversion ^ 0x43} (Build {irefBuild})";
+ {
+ // TODO: Figure out if the version can be more granular
+ return $"7.{subversion ^ 0x43} [Build 0x{irefBuild:X} / {irefBuild}]";
+ }
- // version 8
+ // Version 8
else if (version == 0xA2)
{
if (subversion == 0x46)
{
if ((irefBuild & 0x3A00) == 0x3A00)
- return $"8.2 (Build {irefBuild})";
+ return $"8.2 [Build 0x{irefBuild:X} / {irefBuild}]";
else
- return $"8.1 (Build {irefBuild})";
+ return $"8.1 [Build 0x{irefBuild:X} / {irefBuild}]";
}
- return $"8.{subversion ^ 0x47} (Build {irefBuild})";
+ // TODO: Figure out if the version can be more granular
+ return $"8.{subversion ^ 0x47} [Build 0x{irefBuild:X} / {irefBuild}]";
}
- // version 9
+ // Version 9
else if (version == 0xA3)
{
- // version removed or not given
+ // Version removed or not given
if ((subversionPD9x2 == 0x5F && subversionPD9x1 == 0x61) || (subversionPD9x1 == 0 && subversionPD9x2 == 0))
{
if (versionindicatorPD9 == 0xB)
{
- return $"9.0-9.4 (Build {irefBuild})";
+ return $"9.0-9.4 [Build 0x{irefBuild:X} / {irefBuild}]";
}
else if (versionindicatorPD9 == 0xC)
{
+ // TODO: Figure out if the version can be more granular
if (subversionPD9x2 == 0x5F && subversionPD9x1 == 0x61)
- return $"9.5-9.11 (Build {irefBuild})";
+ return $"9.5-9.11 [Build 0x{irefBuild:X} / {irefBuild}]";
else if (subversionPD9x1 == 0 && subversionPD9x2 == 0)
- return $"9.11-9.20 (Build {irefBuild})";
- }
- else
- {
- return $"9.{subversionPD9x1}{subversionPD9x2}.{subsubversionPD9x} (Build {irefBuild})";
+ return $"9.11-9.20 [Build 0x{irefBuild:X} / {irefBuild}]";
}
}
+ else
+ {
+ return $"9.{subversionPD9x1}{subversionPD9x2}.{subsubversionPD9x} [Build 0x{irefBuild:X} / {irefBuild}]";
+ }
}
- // version 10
+ // Version 10
else if (version == 0xA0)
{
- // version removed
+ // Version removed -- TODO: Figure out if the version can be more granular
if (subversionPD9x1 != 0 || subversionPD9x2 != 0)
- return $"10.{subversionPD9x1}.{subsubversionPD9x} (Build {irefBuild})";
+ return $"10.{subversionPD9x1}.{subsubversionPD9x} [Build 0x{irefBuild:X} / {irefBuild}]";
else
- return $"10.x (Build {irefBuild})";
+ return $"10.x [Build 0x{irefBuild:X} / {irefBuild}]";
}
- // unknown version
+ // Unknown version
else
{
- return $"7.6-10.x (Build {irefBuild})";
+ return $"7.6-10.x [Build 0x{irefBuild:X} / {irefBuild}]";
}
return string.Empty;
}
-
- // TODO: Analyze this method and figure out if this can be done without attempting execution
- private static string SearchProtectDiscVersion(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);
- string pdPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ProtectDisc");
-
- // Clean up any temp files before attempting to run
- Utilities.SafeTempDelete("a*.tmp");
- Utilities.SafeTempDelete("PCD*.sys");
- if (Directory.Exists(pdPath))
- Utilities.SafeDelete(Path.Combine(pdPath, "p*.dll"));
-
- // Try to safely start the temp executable
- Process exe = EVORE.StartSafe(tempexe);
- if (exe == null)
- return string.Empty;
-
- string version = "";
- Process[] processes = new Process[0];
- DateTime timestart = DateTime.Now;
- do
- {
- exe.Refresh();
- string[] files = new string[0];
-
- // Check for ProtectDisc 8.2-x
- if (Directory.Exists(pdPath))
- files = Directory.GetFiles(pdPath, "p*.dll");
-
- if (files.Any())
- {
- string fileVersion = Utilities.GetFileVersion(files[0]);
- if (!string.IsNullOrWhiteSpace(fileVersion))
- {
- version = fileVersion;
-
- // ProtectDisc 9 uses a ProtectDisc-Core dll version 8.0.x
- if (version.StartsWith("8.0"))
- version = string.Empty;
-
- break;
- }
- }
-
- //check for ProtectDisc 7.1-8.1
- files = Directory.GetFiles(Path.GetTempPath(), "a*.tmp");
- if (files.Any())
- {
- string fileVersion = Utilities.GetFileVersion(files[0]);
- if (!string.IsNullOrWhiteSpace(fileVersion))
- {
- version = fileVersion;
- break;
- }
- }
-
- if (exe.HasExited)
- break;
-
- processes = Process.GetProcessesByName(exe.ProcessName);
- if (processes.Length == 2)
- {
- processes[0].Refresh();
- processes[1].Refresh();
- if (processes[1].WorkingSet64 > exe.WorkingSet64)
- exe = processes[1];
- else if (processes[0].WorkingSet64 > exe.WorkingSet64) //else if (processes[0].Modules.Count > exe.Modules.Count)
- exe = processes[0];
- }
- } while (processes.Length > 0 && DateTime.Now.Subtract(timestart).TotalSeconds < 20);
-
- Thread.Sleep(500);
- if (!exe.HasExited)
- {
- processes = Process.GetProcessesByName(exe.ProcessName);
- if (processes.Length == 2)
- {
- try
- {
- processes[0].Kill();
- }
- catch { }
- processes[0].Close();
- try
- {
- processes[1].Kill();
- }
- catch { }
- }
- else
- {
- exe.Refresh();
- try
- {
- exe.Kill();
- }
- catch { }
- }
- }
-
- exe.Close();
- Thread.Sleep(500);
-
- // Clean up any temp files after running
- Utilities.SafeDelete(tempexe);
- Utilities.SafeTempDelete("a*.tmp");
- Utilities.SafeTempDelete("PCD*.sys");
- if (Directory.Exists(pdPath))
- Utilities.SafeDelete(Path.Combine(pdPath, "p*.dll"));
-
- if (dependentDlls != null)
- {
- foreach (string dll in dependentDlls)
- {
- Utilities.SafeDelete(dll);
- }
- }
-
- return version;
- }
}
}