diff --git a/BurnOutSharp/ProtectionType/SecuROM.cs b/BurnOutSharp/ProtectionType/SecuROM.cs index e9ac6f01..9014ec0d 100644 --- a/BurnOutSharp/ProtectionType/SecuROM.cs +++ b/BurnOutSharp/ProtectionType/SecuROM.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Text; +using BurnOutSharp.ExecutableType.Microsoft; using BurnOutSharp.Matching; using BurnOutSharp.Tools; @@ -10,53 +12,106 @@ namespace BurnOutSharp.ProtectionType public class SecuROM : IContentCheck, IPathCheck { /// - public List GetContentMatchSets() - { - return new List - { - // AddD + (char)0x03 + (char)0x00 + (char)0x00 + (char)0x00) - new ContentMatchSet(new byte?[] { 0x41, 0x64, 0x64, 0x44, 0x03, 0x00, 0x00, 0x00 }, GetV4Version, "SecuROM"), - - // (char)0xCA + (char)0xDD + (char)0xDD + (char)0xAC + (char)0x03 - new ContentMatchSet(new byte?[] { 0xCA, 0xDD, 0xDD, 0xAC, 0x03 }, GetV5Version, "SecuROM"), - - // .securom + (char)0xE0 + (char)0xC0 - new ContentMatchSet(new byte?[] - { - 0x2E, 0x73, 0x65, 0x63, 0x75, 0x72, 0x6F, 0x6D, - 0xE0, 0xC0 - }, GetV7Version, "SecuROM"), - - // .securom - new ContentMatchSet(new byte?[] { 0x2E, 0x73, 0x65, 0x63, 0x75, 0x72, 0x6F, 0x6D }, GetV7Version, "SecuROM"), - - // _and_play.dll + (char)0x00 + drm_pagui_doit - new ContentMatchSet(new byte?[] - { - 0x5F, 0x61, 0x6E, 0x64, 0x5F, 0x70, 0x6C, 0x61, - 0x79, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0x64, 0x72, - 0x6D, 0x5F, 0x70, 0x61, 0x67, 0x75, 0x69, 0x5F, - 0x64, 0x6F, 0x69, 0x74 - }, Utilities.GetFileVersion, "SecuROM Product Activation"), - - // S + (char)0x00 + e + (char)0x00 + c + (char)0x00 + u + (char)0x00 + R + (char)0x00 + O + (char)0x00 + M + (char)0x00 + + (char)0x00 + P + (char)0x00 + A + (char)0x00 - new ContentMatchSet(new byte?[] - { - 0x53, 0x00, 0x65, 0x00, 0x63, 0x00, 0x75, 0x00, - 0x52, 0x00, 0x4F, 0x00, 0x4D, 0x00, 0x20, 0x00, - 0x50, 0x00, 0x41, 0x00 - }, Utilities.GetFileVersion, "SecuROM Product Activation"), - - // .cms_t + (char)0x00 - new ContentMatchSet(new byte?[] { 0x2E, 0x63, 0x6D, 0x73, 0x5F, 0x74, 0x00 }, "SecuROM 1-3"), - - // .cms_d + (char)0x00 - new ContentMatchSet(new byte?[] { 0x2E, 0x63, 0x6D, 0x73, 0x5F, 0x64, 0x00 }, "SecuROM 1-3"), - }; - } + 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 .securom section, if it exists + var securomSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".securom")); + if (securomSection != null) + return $"SecuROM {GetV7Version(fileContent)}"; + + // Search after the last section + var lastSection = sections.LastOrDefault(); + if (lastSection != null) + { + int sectionAddr = (int)lastSection.PointerToRawData; + int sectionEnd = sectionAddr + (int)lastSection.VirtualSize; + var matchers = new List + { + // AddD + (char)0x03 + (char)0x00 + (char)0x00 + (char)0x00) + new ContentMatchSet( + new ContentMatch(new byte?[] { 0x41, 0x64, 0x64, 0x44, 0x03, 0x00, 0x00, 0x00 }, start: sectionEnd), + GetV4Version, "SecuROM"), + }; + + string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug); + if (!string.IsNullOrWhiteSpace(match)) + return match; + } + + // Get the sections 5+, if they exist (example names: .fmqyrx, .vcltz, .iywiak) + for (int i = 4; i < sections.Length; i++) + { + var nthSection = sections[i]; + string nthSectionName = Encoding.ASCII.GetString(nthSection.Name).Trim('\0'); + if (nthSection != null && nthSectionName != ".idata" && nthSectionName != ".rsrc") + { + int sectionAddr = (int)nthSection.PointerToRawData; + int sectionEnd = sectionAddr + (int)nthSection.VirtualSize; + var matchers = new List + { + // (char)0xCA + (char)0xDD + (char)0xDD + (char)0xAC + (char)0x03 + new ContentMatchSet( + new ContentMatch(new byte?[] { 0xCA, 0xDD, 0xDD, 0xAC, 0x03 }, start: sectionAddr, end: sectionEnd), + GetV5Version, "SecuROM"), + }; + + string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug); + if (!string.IsNullOrWhiteSpace(match)) + return match; + } + } + + // Get the .rdata section, if it exists + var rdataSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".rdata")); + if (rdataSection != null) + { + int sectionAddr = (int)rdataSection.PointerToRawData; + int sectionEnd = sectionAddr + (int)rdataSection.VirtualSize; + var matchers = new List + { + // drm_pagui_doit -- shortened from "_and_play.dll + (char)0x00 + drm_pagui_doit" + new ContentMatchSet( + new ContentMatch(new byte?[] + { + 0x64, 0x72, 0x6D, 0x5F, 0x70, 0x61, 0x67, 0x75, + 0x69, 0x5F, 0x64, 0x6F, 0x69, 0x74 + }, start: sectionAddr, end: sectionEnd), + Utilities.GetFileVersion, "SecuROM Product Activation"), + + // TODO: Re-enable this one if the above undermatches somehow + // // S + (char)0x00 + e + (char)0x00 + c + (char)0x00 + u + (char)0x00 + R + (char)0x00 + O + (char)0x00 + M + (char)0x00 + + (char)0x00 + P + (char)0x00 + A + (char)0x00 + // new ContentMatchSet( + // new ContentMatch(new byte?[] + // { + // 0x53, 0x00, 0x65, 0x00, 0x63, 0x00, 0x75, 0x00, + // 0x52, 0x00, 0x4F, 0x00, 0x4D, 0x00, 0x20, 0x00, + // 0x50, 0x00, 0x41, 0x00 + // }, start: sectionAddr, end: sectionEnd), + // Utilities.GetFileVersion, "SecuROM Product Activation"), + }; + + string match = MatchUtil.GetFirstMatch(file, fileContent, matchers, includeDebug); + if (!string.IsNullOrWhiteSpace(match)) + return match; + } + + // Get the .cms_d and .cms_t sections, if they exist -- TODO: Confirm if both are needed or either/or is fine + var cmsdSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".cms_d")); + var cmstSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".cms_t")); + if (cmsdSection != null || cmstSection != null) + return $"SecuROM 1-3"; + + return null; + } /// public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable files) @@ -151,7 +206,7 @@ namespace BurnOutSharp.ProtectionType return $"{version}.{subVersion[0]}{subVersion[1]}.{subSubVersion[0]}{subSubVersion[1]}.{subSubSubVersion[0]}{subSubSubVersion[1]}{subSubSubVersion[2]}{subSubSubVersion[3]}"; } - public static string GetV7Version(string file, byte[] fileContent, List positions) + private static string GetV7Version(byte[] fileContent) { int index = 236; byte[] bytes = new ReadOnlySpan(fileContent, index, 4).ToArray();