using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; using BurnOutSharp.Matching; namespace BurnOutSharp.ProtectionType { public class SafeDisc : IContentCheck, IPathCheck { /// /// Set of all ContentMatchSets for this protection /// private static readonly List contentMatchers = 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"), // 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"), }; /// /// Set of all PathMatchSets for this protection /// private static readonly List pathMatchers = new List { new PathMatchSet(new List { new PathMatch("CLCD16.DLL", useEndsWith: true), new PathMatch("CLCD32.DLL", useEndsWith: true), new PathMatch("CLOKSPL.EXE", useEndsWith: true), new PathMatch(".icd", useEndsWith: true), }, "SafeDisc 1"), new PathMatchSet(new List { new PathMatch("00000001.TMP", useEndsWith: true), //new PathMatch(".016", useEndsWith: true), // Potentially over-matching //new PathMatch(".256", useEndsWith: true), // Potentially over-matching }, "SafeDisc 1-3"), new PathMatchSet(new PathMatch("00000002.TMP", useEndsWith: true), "SafeDisc 2"), new PathMatchSet(new PathMatch("DPLAYERX.DLL", useEndsWith: true), GetDPlayerXVersion, "SafeDisc (dplayerx.dll)"), new PathMatchSet(new PathMatch("drvmgt.dll", useEndsWith: true), GetDrvmgtVersion, "SafeDisc (drvmgt.dll)"), new PathMatchSet(new PathMatch("secdrv.sys", useEndsWith: true), GetSecdrvVersion, "SafeDisc (secdrv.sys)"), new PathMatchSet(".SafeDiscDVD.bundle", "SafeDisc for Macintosh"), }; /// public string CheckContents(string file, byte[] fileContent, bool includePosition = false) { return MatchUtil.GetFirstMatch(file, fileContent, contentMatchers, includePosition); } /// public List CheckDirectoryPath(string path, IEnumerable files) { return MatchUtil.GetAllMatches(files, pathMatchers, any: false); } /// public string CheckFilePath(string path) { 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)"; } public static string GetVersion(string file, byte[] fileContent, List positions) { int index = positions[0] + 20; // Begin reading after "BoG_ *90.0&!! Yy>" for old SafeDisc int version = BitConverter.ToInt32(fileContent, index); index += 4; int subVersion = BitConverter.ToInt32(fileContent, index); index += 4; int subsubVersion = BitConverter.ToInt32(fileContent, index); if (version != 0) return $"{version}.{subVersion:00}.{subsubVersion:000}"; index = positions[0] + 18 + 14; // Begin reading after "BoG_ *90.0&!! Yy>" for newer SafeDisc version = BitConverter.ToInt32(fileContent, index); index += 4; subVersion = BitConverter.ToInt32(fileContent, index); index += 4; subsubVersion = BitConverter.ToInt32(fileContent, index); if (version == 0) return string.Empty; return $"{version}.{subVersion:00}.{subsubVersion:000}"; } public static string GetDPlayerXVersion(string firstMatchedString, IEnumerable files) { if (firstMatchedString == null || !File.Exists(firstMatchedString)) return string.Empty; FileInfo fi = new FileInfo(firstMatchedString); if (fi.Length == 81408) return "1.0x"; else if (fi.Length == 155648) return "1.1x"; else if (fi.Length == 156160) return "1.1x-1.2x"; else if (fi.Length == 163328) return "1.3x"; else if (fi.Length == 165888) return "1.35"; else if (fi.Length == 172544) return "1.40"; else if (fi.Length == 173568) return "1.4x"; else if (fi.Length == 136704) return "1.4x"; else if (fi.Length == 138752) return "1.5x"; else return "1"; } public static string GetDrvmgtVersion(string firstMatchedString, IEnumerable files) { if (firstMatchedString == null || !File.Exists(firstMatchedString)) return string.Empty; FileInfo fi = new FileInfo(firstMatchedString); if (fi.Length == 34816) return "1.0x"; else if (fi.Length == 32256) return "1.1x-1.3x"; else if (fi.Length == 31744) return "1.4x"; else if (fi.Length == 34304) return "1.5x-2.40"; else if (fi.Length == 35840) return "2.51-2.60"; else if (fi.Length == 40960) return "2.70"; else if (fi.Length == 23552) return "2.80"; else if (fi.Length == 41472) return "2.90-3.10"; else if (fi.Length == 24064) return "3.15-3.20"; else return "1-3"; } public static string GetSecdrvVersion(string firstMatchedString, IEnumerable files) { if (firstMatchedString == null || !File.Exists(firstMatchedString)) return string.Empty; FileInfo fi = new FileInfo(firstMatchedString); if (fi.Length == 20128) return "2.10"; else if (fi.Length == 27440) return "2.30"; else if (fi.Length == 28624) return "2.40"; else if (fi.Length == 18768) return "2.50"; else if (fi.Length == 28400) return "2.51"; else if (fi.Length == 29392) return "2.60"; else if (fi.Length == 11376) return "2.70"; else if (fi.Length == 12464) return "2.80"; else if (fi.Length == 12400) return "2.90"; else if (fi.Length == 12528) return "3.10"; else if (fi.Length == 12528) return "3.15"; else if (fi.Length == 11973) return "3.20"; 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) { Process exe; string version = ""; DateTime timestart; if (!EVORE.IsEXE(fileContent)) return ""; string tempexe = EVORE.MakeTempFile(fileContent); string[] DependentDlls = EVORE.CopyDependentDlls(file, fileContent); try { Directory.Delete(Path.Combine(Path.GetTempPath(), "~e*"), true); } catch { } try { File.Delete(Path.Combine(Path.GetTempPath(), "~e*")); } catch { } exe = EVORE.StartSafe(tempexe); if (exe == null) return ""; 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 FileContent = sr.ReadToEnd(); sr.Close(); int position = FileContent.IndexOf("%ld.%ld.%ld, %ld, %s,") - 1; if (position > -1) version = FileContent.Substring(position + 28, 12); break; } catch { } } } } while (!exe.HasExited && DateTime.Now.Subtract(timestart).TotalSeconds < 20); if (!exe.HasExited) exe.Kill(); exe.Close(); try { Directory.Delete(Path.Combine(Path.GetTempPath(), "~e*"), true); } catch { } try { File.Delete(Path.Combine(Path.GetTempPath(), "~e*")); File.Delete(tempexe); } catch { } if (DependentDlls != null) { for (int i = 0; i < DependentDlls.Length; i--) { try { File.Delete(DependentDlls[i]); } catch (Exception ex) { Console.WriteLine("!error while deleting file " + DependentDlls[i] + "; " + ex.Message); } } } return version; } } }