diff --git a/BurnOutSharp/ProtectionType/LaserLock.cs b/BurnOutSharp/ProtectionType/LaserLock.cs
deleted file mode 100644
index 42fd0d2e..00000000
--- a/BurnOutSharp/ProtectionType/LaserLock.cs
+++ /dev/null
@@ -1,159 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using BurnOutSharp.Matching;
-using BurnOutSharp.Tools;
-
-namespace BurnOutSharp.ProtectionType
-{
- // TODO: Figure out how to use GetContentMatches here
- public class LaserLock : IContentCheck, IPathCheck
- {
- ///
- public List GetContentMatchSets()
- {
- return new List
- {
- // :\\LASERLOK\\LASERLOK.IN + (char)0x00 + C:\\NOMOUSE.SP
- new ContentMatchSet(new byte?[]
- {
- 0x3A, 0x5C, 0x5C, 0x4C, 0x41, 0x53, 0x45, 0x52,
- 0x4C, 0x4F, 0x4B, 0x5C, 0x5C, 0x4C, 0x41, 0x53,
- 0x45, 0x52, 0x4C, 0x4F, 0x4B, 0x2E, 0x49, 0x4E,
- 0x00, 0x43, 0x3A, 0x5C, 0x5C, 0x4E, 0x4F, 0x4D,
- 0x4F, 0x55, 0x53, 0x45, 0x2E, 0x53, 0x50
- }, "LaserLock 3"),
-
- // LASERLOK_INIT + (char)0xC + LASERLOK_RUN + (char)0xE + LASERLOK_CHECK + (char)0xF + LASERLOK_CHECK2 + (char)0xF + LASERLOK_CHECK3
- new ContentMatchSet(new byte?[]
- {
- 0x4C, 0x41, 0x53, 0x45, 0x52, 0x4C, 0x4F, 0x4B,
- 0x5F, 0x49, 0x4E, 0x49, 0x54, 0x0C, 0x4C, 0x41,
- 0x53, 0x45, 0x52, 0x4C, 0x4F, 0x4B, 0x5F, 0x52,
- 0x55, 0x4E, 0x0E, 0x4C, 0x41, 0x53, 0x45, 0x52,
- 0x4C, 0x4F, 0x4B, 0x5F, 0x43, 0x48, 0x45, 0x43,
- 0x4B, 0x0F, 0x4C, 0x41, 0x53, 0x45, 0x52, 0x4C,
- 0x4F, 0x4B, 0x5F, 0x43, 0x48, 0x45, 0x43, 0x4B,
- 0x32, 0x0F, 0x4C, 0x41, 0x53, 0x45, 0x52, 0x4C,
- 0x4F, 0x4B, 0x5F, 0x43, 0x48, 0x45, 0x43, 0x4B,
- 0x33
- }, "LaserLock 5"),
- };
- }
-
- ///
- public string CheckContents(string file, byte[] fileContent, bool includeDebug = false)
- {
- // "Packed by SPEEnc V2 Asterios Parlamentas.PE"
- byte?[] check = new byte?[] { 0x50, 0x61, 0x63, 0x6B, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x53, 0x50, 0x45, 0x45, 0x6E, 0x63, 0x20, 0x56, 0x32, 0x20, 0x41, 0x73, 0x74, 0x65, 0x72, 0x69, 0x6F, 0x73, 0x20, 0x50, 0x61, 0x72, 0x6C, 0x61, 0x6D, 0x65, 0x6E, 0x74, 0x61, 0x73, 0x2E, 0x50, 0x45 };
- bool containsCheck = fileContent.FirstPosition(check, out int position);
-
- // "GetModuleHandleA" + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + "GetProcAddress" + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + "LoadLibraryA" + (char)0x00 + (char)0x00 + "KERNEL32.dll" + (char)0x00 + "ëy" + (char)0x01 + "SNIF"
- byte?[] check2 = { 0x47, 0x65, 0x74, 0x4D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x41, 0x00, 0x00, 0x00, 0x00, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6F, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x6F, 0x61, 0x64, 0x4C, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x41, 0x00, 0x00, 0x4B, 0x45, 0x52, 0x4E, 0x45, 0x4C, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C, 0x00, 0xEB, 0x79, 0x01, 0x53, 0x4E, 0x49, 0x46 };
- bool containsCheck2 = fileContent.FirstPosition(check2, out int position2);
-
- if (containsCheck && containsCheck2)
- return $"LaserLock {GetVersion(fileContent, position2)} {GetBuild(fileContent, true)}" + (includeDebug ? $" (Index {position}, {position2})" : string.Empty);
- else if (containsCheck && !containsCheck2)
- return $"LaserLock Marathon {GetBuild(fileContent, false)}" + (includeDebug ? $" (Index {position})" : string.Empty);
- else if (!containsCheck && containsCheck2)
- return $"LaserLock {GetVersion(fileContent, --position2)} {GetBuild(fileContent, false)}" + (includeDebug ? $" (Index {position2})" : string.Empty);
-
- if (file != null && string.Equals(Path.GetFileName(file), "NOMOUSE.SP", StringComparison.OrdinalIgnoreCase))
- return $"LaserLock {GetVersion16Bit(fileContent)}" + (includeDebug ? $" (Index 71)" : string.Empty);
-
- return null;
- }
-
- ///
- public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable files)
- {
- var matchers = new List
- {
- new PathMatchSet($"LASERLOK{Path.DirectorySeparatorChar}", "LaserLock"),
-
- // TODO: Verify if these are OR or AND
- new PathMatchSet(new PathMatch("NOMOUSE.SP", useEndsWith: true), "LaserLock"),
- new PathMatchSet(new PathMatch("NOMOUSE.COM", useEndsWith: true), "LaserLock"),
- new PathMatchSet(new PathMatch("l16dll.dll", useEndsWith: true), "LaserLock"),
- new PathMatchSet(new PathMatch("laserlok.in", useEndsWith: true), "LaserLock"),
- new PathMatchSet(new PathMatch("laserlok.o10", useEndsWith: true), "LaserLock"),
- new PathMatchSet(new PathMatch("laserlok.011", useEndsWith: true), "LaserLock"),
- };
-
- return MatchUtil.GetAllMatches(files, matchers, any: true);
- }
-
- ///
- public string CheckFilePath(string path)
- {
- var matchers = new List
- {
- new PathMatchSet(new PathMatch("NOMOUSE.SP", useEndsWith: true), GetVersion16Bit, "LaserLock"),
- new PathMatchSet(new PathMatch("NOMOUSE.COM", useEndsWith: true), "LaserLock"),
- new PathMatchSet(new PathMatch("l16dll.dll", useEndsWith: true), "LaserLock"),
- new PathMatchSet(new PathMatch("laserlok.in", useEndsWith: true), "LaserLock"),
- new PathMatchSet(new PathMatch("laserlok.o10", useEndsWith: true), "LaserLock"),
- new PathMatchSet(new PathMatch("laserlok.011", useEndsWith: true), "LaserLock"),
- };
-
- return MatchUtil.GetFirstMatch(path, matchers, any: true);
- }
-
- private static string GetBuild(byte[] fileContent, bool versionTwo)
- {
- // "Unkown" + (char)0x00 + "Unkown" // TODO: Is this supposed to be "Unknown"?
- byte?[] check = new byte?[] { 0x55, 0x6E, 0x6B, 0x6F, 0x77, 0x6E, 0x00, 0x55, 0x6E, 0x6B, 0x6F, 0x77, 0x6E };
- fileContent.FirstPosition(check, out int position);
- string year, month, day;
- if (versionTwo)
- {
- int index = position + 14;
- day = new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
- index += 3;
- month = new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
- index += 3;
- year = "20" + new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
- }
- else
- {
- int index = position + 13;
- day = new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
- index += 3;
- month = new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
- index += 3;
- year = "20" + new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
- }
-
- return $"(Build {year}-{month}-{day})";
- }
-
- private static string GetVersion(byte[] fileContent, int position)
- {
- return new string(new ArraySegment(fileContent, position + 76, 4).Select(b => (char)b).ToArray());
- }
-
- public static string GetVersion16Bit(string firstMatchedString, IEnumerable files)
- {
- if (!File.Exists(firstMatchedString))
- return string.Empty;
-
- using (var fs = File.Open(firstMatchedString, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
- using (var br = new BinaryReader(fs))
- {
- return GetVersion16Bit(br.ReadBytes((int)fs.Length));
- }
- }
-
- private static string GetVersion16Bit(byte[] fileContent)
- {
- char[] version = new ArraySegment(fileContent, 71, 4).Select(b => (char)b).ToArray();
- if (char.IsNumber(version[0]) && char.IsNumber(version[2]) && char.IsNumber(version[3]))
- return $"{version[0]}.{version[2]}{version[3]}";
-
- return string.Empty;
- }
- }
-}
diff --git a/BurnOutSharp/ProtectionType/LaserLok.cs b/BurnOutSharp/ProtectionType/LaserLok.cs
new file mode 100644
index 00000000..031005cc
--- /dev/null
+++ b/BurnOutSharp/ProtectionType/LaserLok.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using BurnOutSharp.ExecutableType.Microsoft;
+using BurnOutSharp.ExecutableType.Microsoft.Headers;
+using BurnOutSharp.Matching;
+using BurnOutSharp.Tools;
+
+namespace BurnOutSharp.ProtectionType
+{
+ public class LaserLok : IContentCheck, IPathCheck
+ {
+ ///
+ public List GetContentMatchSets() => null;
+
+ ///
+ public string CheckContents(string file, byte[] fileContent, bool includeDebug = false)
+ {
+ // TODO: Additional checks that may or may not be useful with the below
+ //
+ // These two can appear separately
+ // \LASERLOK\LASERLOK.IN
+ // C:\NOMOUSE.SP
+ //
+ // // :\LASERLOK\LASERLOK.IN + (char)0x00 + C:\NOMOUSE.SP
+ // new ContentMatchSet(new byte?[]
+ // {
+ // 0x3A, 0x5C, 0x5C, 0x4C, 0x41, 0x53, 0x45, 0x52,
+ // 0x4C, 0x4F, 0x4B, 0x5C, 0x5C, 0x4C, 0x41, 0x53,
+ // 0x45, 0x52, 0x4C, 0x4F, 0x4B, 0x2E, 0x49, 0x4E,
+ // 0x00, 0x43, 0x3A, 0x5C, 0x5C, 0x4E, 0x4F, 0x4D,
+ // 0x4F, 0x55, 0x53, 0x45, 0x2E, 0x53, 0x50
+ // }, "LaserLok 3"),
+
+ // // LASERLOK_INIT + (char)0xC + LASERLOK_RUN + (char)0xE + LASERLOK_CHECK + (char)0xF + LASERLOK_CHECK2 + (char)0xF + LASERLOK_CHECK3
+ // new ContentMatchSet(new byte?[]
+ // {
+ // 0x4C, 0x41, 0x53, 0x45, 0x52, 0x4C, 0x4F, 0x4B,
+ // 0x5F, 0x49, 0x4E, 0x49, 0x54, 0x0C, 0x4C, 0x41,
+ // 0x53, 0x45, 0x52, 0x4C, 0x4F, 0x4B, 0x5F, 0x52,
+ // 0x55, 0x4E, 0x0E, 0x4C, 0x41, 0x53, 0x45, 0x52,
+ // 0x4C, 0x4F, 0x4B, 0x5F, 0x43, 0x48, 0x45, 0x43,
+ // 0x4B, 0x0F, 0x4C, 0x41, 0x53, 0x45, 0x52, 0x4C,
+ // 0x4F, 0x4B, 0x5F, 0x43, 0x48, 0x45, 0x43, 0x4B,
+ // 0x32, 0x0F, 0x4C, 0x41, 0x53, 0x45, 0x52, 0x4C,
+ // 0x4F, 0x4B, 0x5F, 0x43, 0x48, 0x45, 0x43, 0x4B,
+ // 0x33
+ // }, "LaserLok 5"),
+
+ // Get the sections from the executable, if possible
+ PortableExecutable pex = PortableExecutable.Deserialize(fileContent, 0);
+ var sections = pex?.SectionTable;
+ if (sections == null)
+ return null;
+
+ // Packed by SPEEnc V2 Asterios Parlamentas.PE
+ byte?[] check = new byte?[]
+ {
+ 0x50, 0x61, 0x63, 0x6B, 0x65, 0x64, 0x20, 0x62,
+ 0x79, 0x20, 0x53, 0x50, 0x45, 0x45, 0x6E, 0x63,
+ 0x20, 0x56, 0x32, 0x20, 0x41, 0x73, 0x74, 0x65,
+ 0x72, 0x69, 0x6F, 0x73, 0x20, 0x50, 0x61, 0x72,
+ 0x6C, 0x61, 0x6D, 0x65, 0x6E, 0x74, 0x61, 0x73,
+ 0x2E, 0x50, 0x45
+ };
+ int endDosStub = pex.DOSStubHeader.NewExeHeaderAddr;
+ bool containsCheck = fileContent.FirstPosition(check, out int position, start: 0, end: endDosStub);
+
+ // If the .text section doesn't exist, then the second check can't be found
+ bool containsCheck2 = false;
+ int position2 = -1;
+
+ // Get the .text section, if it exists
+ var textSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".text"));
+ if (textSection != null)
+ {
+ int sectionAddr = (int)textSection.PointerToRawData;
+ int sectionEnd = sectionAddr + (int)textSection.VirtualSize;
+
+ // GetModuleHandleA + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + GetProcAddress + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + LoadLibraryA + (char)0x00 + (char)0x00 + KERNEL32.dll + (char)0x00 + ëy + (char)0x01 + SNIF/MPVI
+ byte?[] check2 = new byte?[]
+ {
+ 0x47, 0x65, 0x74, 0x4D, 0x6F, 0x64, 0x75, 0x6C,
+ 0x65, 0x48, 0x61, 0x6E, 0x64, 0x6C, 0x65, 0x41,
+ 0x00, 0x00, 0x00, 0x00, 0x47, 0x65, 0x74, 0x50,
+ 0x72, 0x6F, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65,
+ 0x73, 0x73, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x6F,
+ 0x61, 0x64, 0x4C, 0x69, 0x62, 0x72, 0x61, 0x72,
+ 0x79, 0x41, 0x00, 0x00, 0x4B, 0x45, 0x52, 0x4E,
+ 0x45, 0x4C, 0x33, 0x32, 0x2E, 0x64, 0x6C, 0x6C,
+ 0x00, 0xEB, 0x79, 0x01, null, null, null, null,
+ };
+ containsCheck2 = fileContent.FirstPosition(check2, out position2, start: sectionAddr, end: sectionEnd);
+ }
+
+ if (containsCheck && containsCheck2)
+ return $"LaserLok {GetVersion(fileContent, position2)} {GetBuild(sections, fileContent, true)}" + (includeDebug ? $" (Index {position}, {position2})" : string.Empty);
+ else if (containsCheck && !containsCheck2)
+ return $"LaserLok Marathon {GetBuild(sections, fileContent, false)}" + (includeDebug ? $" (Index {position})" : string.Empty);
+ else if (!containsCheck && containsCheck2)
+ return $"LaserLok {GetVersion(fileContent, --position2)} {GetBuild(sections, fileContent, false)}" + (includeDebug ? $" (Index {position2})" : string.Empty);
+
+ return null;
+ }
+
+ ///
+ public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable files)
+ {
+ var matchers = new List
+ {
+ new PathMatchSet($"LASERLOK{Path.DirectorySeparatorChar}", "LaserLok"),
+
+ // TODO: Verify if these are OR or AND
+ new PathMatchSet(new PathMatch("NOMOUSE.SP", useEndsWith: true), GetVersion16Bit, "LaserLok"),
+ new PathMatchSet(new PathMatch("NOMOUSE.COM", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("l16dll.dll", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("laserlok.in", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("laserlok.o10", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("laserlok.o11", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("laserlok.o12", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("laserlok.out", useEndsWith: true), "LaserLok"),
+ };
+
+ return MatchUtil.GetAllMatches(files, matchers, any: true);
+ }
+
+ ///
+ public string CheckFilePath(string path)
+ {
+ var matchers = new List
+ {
+ new PathMatchSet(new PathMatch("NOMOUSE.SP", useEndsWith: true), GetVersion16Bit, "LaserLok"),
+
+ // TODO: Verify if these are OR or AND
+ new PathMatchSet(new PathMatch("NOMOUSE.COM", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("l16dll.dll", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("laserlok.in", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("laserlok.o10", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("laserlok.o11", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("laserlok.o12", useEndsWith: true), "LaserLok"),
+ new PathMatchSet(new PathMatch("laserlok.out", useEndsWith: true), "LaserLok"),
+ };
+
+ return MatchUtil.GetFirstMatch(path, matchers, any: true);
+ }
+
+ private static string GetBuild(SectionHeader[] sections, byte[] fileContent, bool versionTwo)
+ {
+ var textSection = sections.FirstOrDefault(s => Encoding.ASCII.GetString(s.Name).StartsWith(".text"));
+ if (textSection == null)
+ return "(Build unknown)";
+
+ int sectionAddr = (int)textSection.PointerToRawData;
+ int sectionEnd = sectionAddr + (int)textSection.VirtualSize;
+
+ // Unkown + (char)0x00 + Unkown
+ byte?[] check = new byte?[]
+ {
+ 0x55, 0x6E, 0x6B, 0x6F, 0x77, 0x6E, 0x00, 0x55,
+ 0x6E, 0x6B, 0x6F, 0x77, 0x6E
+ };
+ if (!fileContent.FirstPosition(check, out int position, start: sectionAddr, end: sectionEnd))
+ return "(Build unknown)";
+
+ string year, month, day;
+ if (versionTwo)
+ {
+ int index = position + 14;
+ day = new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
+ index += 3;
+ month = new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
+ index += 3;
+ year = "20" + new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
+ }
+ else
+ {
+ int index = position + 13;
+ day = new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
+ index += 3;
+ month = new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
+ index += 3;
+ year = "20" + new string(new ArraySegment(fileContent, index, 2).Select(b => (char)b).ToArray());
+ }
+
+ return $"(Build {year}-{month}-{day})";
+ }
+
+ private static string GetVersion(byte[] fileContent, int position)
+ {
+ return new string(new ArraySegment(fileContent, position + 76, 4).Select(b => (char)b).ToArray());
+ }
+
+ public static string GetVersion16Bit(string firstMatchedString, IEnumerable files)
+ {
+ if (!File.Exists(firstMatchedString))
+ return string.Empty;
+
+ using (var fs = File.Open(firstMatchedString, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ using (var br = new BinaryReader(fs))
+ {
+ return GetVersion16Bit(br.ReadBytes((int)fs.Length));
+ }
+ }
+
+ private static string GetVersion16Bit(byte[] fileContent)
+ {
+ char[] version = new ArraySegment(fileContent, 71, 7).Select(b => (char)b).ToArray();
+ if (char.IsNumber(version[0]) && char.IsNumber(version[2]) && char.IsNumber(version[3]))
+ {
+ if (char.IsNumber(version[5]) && char.IsNumber(version[6]))
+ return $"{version[0]}.{version[2]}{version[3]}.{version[5]}{version[6]}";
+ else if (char.IsNumber(version[5]))
+ return $"{version[0]}.{version[2]}{version[3]}.{version[5]}";
+
+ return $"{version[0]}.{version[2]}{version[3]}";
+ }
+
+ return string.Empty;
+ }
+ }
+}