From af882fa588fe829c7945bede7152a504336c98af Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 2 Dec 2022 14:56:08 -0800 Subject: [PATCH] Properly differentiate between Code-Lock and CopyLok (TheRogueArchivist) --- BurnOutSharp/ProtectionType/CDDVDCops.cs | 1 + .../ProtectionType/ChosenBytesCode-Lock.cs | 113 ++++++++++++++++++ BurnOutSharp/ProtectionType/CodeLock.cs | 51 -------- BurnOutSharp/ProtectionType/CopyLok.cs | 43 +++++++ README.md | 3 +- 5 files changed, 159 insertions(+), 52 deletions(-) create mode 100644 BurnOutSharp/ProtectionType/ChosenBytesCode-Lock.cs delete mode 100644 BurnOutSharp/ProtectionType/CodeLock.cs create mode 100644 BurnOutSharp/ProtectionType/CopyLok.cs diff --git a/BurnOutSharp/ProtectionType/CDDVDCops.cs b/BurnOutSharp/ProtectionType/CDDVDCops.cs index 4e770ab8..9b390d6e 100644 --- a/BurnOutSharp/ProtectionType/CDDVDCops.cs +++ b/BurnOutSharp/ProtectionType/CDDVDCops.cs @@ -9,6 +9,7 @@ using BurnOutSharp.Matching; namespace BurnOutSharp.ProtectionType { + // TODO: Investigate "Cops Copylock II" (https://www.cbmstuff.com/forum/showthread.php?tid=488). public class CDDVDCops : IContentCheck, INewExecutableCheck, IPathCheck, IPortableExecutableCheck { /// diff --git a/BurnOutSharp/ProtectionType/ChosenBytesCode-Lock.cs b/BurnOutSharp/ProtectionType/ChosenBytesCode-Lock.cs new file mode 100644 index 00000000..aae4bccd --- /dev/null +++ b/BurnOutSharp/ProtectionType/ChosenBytesCode-Lock.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using BurnOutSharp.ExecutableType.Microsoft.PE; +using BurnOutSharp.Interfaces; +using BurnOutSharp.Matching; + +namespace BurnOutSharp.ProtectionType +{ + /// + /// Code-Lock by ChosenBytes (https://web.archive.org/web/20040225072021/http://chosenbytes.com/) is a form of DRM that protects Visual Basic and .NET programs. + /// It requires the use of a registration code that is unique to each individual user (https://web.archive.org/web/20031210093259/http://www.chosenbytes.com/codemain.php). + /// As an advertising point, ChosenBytes apparently held a contest with a cash prize to see if a protected file could be cracked (https://web.archive.org/web/20031106163334/http://www.chosenbytes.com/challenge.php). + /// + /// Previous versions of BurnOutSharp incorrectly reported this DRM as "CodeLock / CodeLok / CopyLok". It was later discovered that due to the similar names, two entirely different DRM were erroneously lumped together. + /// Not only is "CodeLok / CopyLok" an entirely separate form of DRM, but "CodeLock" (as opposed to "Code-Lock") appears to refer specifically to another unrelated DRM (https://web.archive.org/web/20031106033758/http://www.codelock.co.nz/). + /// Also not to be confused with https://www.youtube.com/watch?v=AHqdgk0uJyc. + /// + /// Code-Lock FAQ: https://web.archive.org/web/20041205165232/http://www.chosenbytes.com/codefaq.php + /// Download (Version 2.35 trial): https://web.archive.org/web/20060220121200/http://www.chosenbytes.com:80/Code-Lock_cnet.zip + /// + public class ChosenBytesCodeLock : IContentCheck, IPathCheck, IPortableExecutableCheck + { + /// + public string CheckContents(string file, byte[] fileContent, bool includeDebug) + { + // TODO: Obtain a sample to find where this string is in a typical executable. + if (includeDebug) + { + var contentMatchSets = new List + { + // CODE-LOCK.OCX + new ContentMatchSet(new byte?[] + { + 0x43, 0x4F, 0x44, 0x45, 0x2D, 0x4C, 0x4F, 0x43, + 0x4B, 0x2E, 0x4F, 0x43, 0x58 + }, "ChosenBytes Code-Lock (Unconfirmed - Please report to us on Github)"), + }; + + return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug); + } + + return null; + } + + /// + public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug) + { + // Get the sections from the executable, if possible + var sections = pex?.SectionTable; + if (sections == null) + return null; + + // Found in "Code-Lock.ocx" in Code-Lock version 2.35. + // Also worth noting is the File Description for this file, which is "A future for you, a challenge for the rest.". + // This check is currently broken until executable checks are overhauled. + string name = pex.ProductName; + if (name?.StartsWith("Code-Lock", StringComparison.OrdinalIgnoreCase) == true) + return $"ChosenBytes Code-Lock {pex.ProductVersion}"; + + // Get the .text section, if it exists + if (pex.TextSectionRaw != null) + { + var matchers = new List + { + // Found in compiled code examples created with Code-Lock 2.35. + // Code-Lock.ocx + new ContentMatchSet(new byte?[] + { + 0x43, 0x6F, 0x64, 0x65, 0x2D, 0x4C, 0x6F, 0x63, + 0x6B, 0x2E, 0x6F, 0x63, 0x78 + }, "ChosenBytes Code-Lock"), + }; + + string match = MatchUtil.GetFirstMatch(file, pex.TextSectionRaw, matchers, includeDebug); + if (!string.IsNullOrWhiteSpace(match)) + return match; + } + + return null; + } + + /// + public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable files) + { + var matchers = new List + { + // Found in the installation directory of Code-Lock version 2.35. + new PathMatchSet(new PathMatch("Code-Lock.chm", useEndsWith: true), "ChosenBytes Code-Lock"), + new PathMatchSet(new PathMatch("Code-Lock.DEP", useEndsWith: true), "ChosenBytes Code-Lock"), + new PathMatchSet(new PathMatch("Code-Lock.ocx", useEndsWith: true), "ChosenBytes Code-Lock"), + new PathMatchSet(new PathMatch("Code-Lock Wizard.exe", useEndsWith: true), "ChosenBytes Code-Lock"), + }; + + return MatchUtil.GetAllMatches(files, matchers, any: true); + } + + /// + public string CheckFilePath(string path) + { + var matchers = new List + { + // Found in the installation directory of Code-Lock version 2.35. + new PathMatchSet(new PathMatch("Code-Lock.chm", useEndsWith: true), "ChosenBytes Code-Lock"), + new PathMatchSet(new PathMatch("Code-Lock.DEP", useEndsWith: true), "ChosenBytes Code-Lock"), + new PathMatchSet(new PathMatch("Code-Lock.ocx", useEndsWith: true), "ChosenBytes Code-Lock"), + new PathMatchSet(new PathMatch("Code-Lock Wizard.exe", useEndsWith: true), "ChosenBytes Code-Lock"), + }; + + return MatchUtil.GetFirstMatch(path, matchers, any: true); + } + } +} \ No newline at end of file diff --git a/BurnOutSharp/ProtectionType/CodeLock.cs b/BurnOutSharp/ProtectionType/CodeLock.cs deleted file mode 100644 index adf255a4..00000000 --- a/BurnOutSharp/ProtectionType/CodeLock.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using BurnOutSharp.ExecutableType.Microsoft.PE; -using BurnOutSharp.Interfaces; -using BurnOutSharp.Matching; - -namespace BurnOutSharp.ProtectionType -{ - // CodeLock / CodeLok / CopyLok - public class CodeLock : IContentCheck, IPortableExecutableCheck - { - /// - public string CheckContents(string file, byte[] fileContent, bool includeDebug) - { - // TODO: Obtain a sample to find where this string is in a typical executable - if (includeDebug) - { - var contentMatchSets = new List - { - // CODE-LOCK.OCX - new ContentMatchSet(new byte?[] - { - 0x43, 0x4F, 0x44, 0x45, 0x2D, 0x4C, 0x4F, 0x43, - 0x4B, 0x2E, 0x4F, 0x43, 0x58 - }, "CodeLock / CodeLok / CopyLok (Unconfirmed - Please report to us on Github)"), - }; - - return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug); - } - - return null; - } - - /// - public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug) - { - // Get the sections from the executable, if possible - var sections = pex?.SectionTable; - if (sections == null) - return null; - - // If there are more than 2 icd-prefixed sections, then we have a match - // Found in Redump entry 31557. - int icdSectionCount = pex.GetSectionNames().Count(s => s.StartsWith("icd")); - if (icdSectionCount >= 2) - return "CodeLock / CodeLok / CopyLok"; - - return null; - } - } -} diff --git a/BurnOutSharp/ProtectionType/CopyLok.cs b/BurnOutSharp/ProtectionType/CopyLok.cs new file mode 100644 index 00000000..3a370a09 --- /dev/null +++ b/BurnOutSharp/ProtectionType/CopyLok.cs @@ -0,0 +1,43 @@ +using System.Linq; +using BurnOutSharp.ExecutableType.Microsoft.PE; +using BurnOutSharp.Interfaces; + +namespace BurnOutSharp.ProtectionType +{ + /// + /// CopyLok (AKA CodeLok) is a DRM created by PAN Technology (https://web.archive.org/web/19991117100625/http://www.pantechnology.com/). + /// More specifically, it may have been created a spin-off division known as "Panlok" (https://cdmediaworld.com/hardware/cdrom/cd_protections_copylok.shtml). + /// Though it may also be that "PanLok" was an alternate name for the program itself (https://gamecopyworld.com/games/pc_generic_copylok.shtml). + /// There was a PanLok website, but it's unknown what content it had hosted (https://web.archive.org/web/20041215075727/http://www.panlok.com/). + /// + /// CopyLok made use of bad sectors, using an average of 720-750 per disc, and appears to have been a form of ring protection (http://forum.redump.org/topic/29842/issues-dumping-pc-disc-with-code-lock-copy-protection/). + /// At least one disc with CopyLok appears to contain an excerpt of the poem "Jabberwocky" by Lewis Carroll in the raw sector data (http://forum.redump.org/post/54050/#p54050). + /// According to the Readme for poxylok (https://gf.wiretarget.com/copylok.htm), some version of Gangsters 2 may have this protection. + /// + /// Previous versions of BurnOutSharp incorrectly reported this DRM as "CodeLock / CodeLok / CopyLok". It was later discovered that due to the similar names, two entirely different DRM were erroneously lumped together. + /// "CodeLock" (in this case actually referring to "Code-Lock") is an entirely separate form of DRM, with the existing check now getting used separately. + /// Also not to be confused with https://en.wikipedia.org/wiki/Rob_Northen_copylock. + /// + /// COPYLOK trademark: https://www.trademarkelite.com/europe/trademark/trademark-detail/000618512/COPYLOK. + /// + public class CopyLok : IPortableExecutableCheck + { + /// + public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug) + { + // Get the sections from the executable, if possible + var sections = pex?.SectionTable; + if (sections == null) + return null; + + // If there are more than 2 icd-prefixed sections, then we have a match + // Though this is the same name that SafeDisc uses for protected executables, this seems to be a coincidence. + // Found in Redump entries 31557, 31674, 31675, 31708, 38239, 44210, and 53929. + int icdSectionCount = pex.GetSectionNames().Count(s => s.StartsWith("icd")); + if (icdSectionCount >= 2) + return "CopyLok / CodeLok"; + + return null; + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index c0d22c98..effd48b2 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,9 @@ Below is a list of protections detected by BurnOutSharp. The two columns explain | CD-X | False | True | Unconfirmed¹ | | CDSHiELD SE | True | False | | | Cenga ProtectDVD | True | True | | -| CodeLock / CodeLok / CopyLok | True | False | Partially unconfirmed² | +| ChosenBytes CodeLock | True | True | Partially unconfirmed² | | CopyKiller | True | True | Unconfirmed¹ | +| CopyLok/CodeLok | True | False | | | Cucko (EA Custom) | True | False | Does not detect all known cases | | Denuvo Anti-Cheat/Anti-Tamper| True | True | | | Dinamic Multimedia Protection/LockBlocks | False | True | LockBlocks needs manual confirmation of the presence of 2 rings |