diff --git a/BinaryObjectScanner/Protection/CopyX.cs b/BinaryObjectScanner/Protection/CopyX.cs index 968a1f62..16066d3d 100644 --- a/BinaryObjectScanner/Protection/CopyX.cs +++ b/BinaryObjectScanner/Protection/CopyX.cs @@ -21,7 +21,7 @@ public class CopyX : IPathCheck, IPortableExecutableCheck { // Previous check 'Tivola Ring Protect' removed because it was found to actually be copy-x. // The checks were for ZDAT/webmast.dxx and ZDAT/webmast.dxx, for Redump IDs 81628 and 116418. - + // https://web.archive.org/web/20011016234742/http://www.optimal-online.de:80/product/copy_x.htm // There are four kinds of copy-X; Light, Profesisonal, audio, and Trial Maker. // Audio is for Audio CDs. Might be scannable, might not. Samples needed to confirm. @@ -37,14 +37,15 @@ public class CopyX : IPathCheck, IPortableExecutableCheck // Both Light and Professional have a directory at the end of the image. The files within this directory are // intersected by the physical ring. // This file is usually called ZDAT, but not always. At least one instance of Light calls it ZDATA. At least one - // instance of Professional calls it System. + // instance of Light calls it System. // Seemingly it can be anything. It doesn't help that most known samples are specifically from one company's // games, Tivola. Still, most use ZDAT. // Professional: // All instances of professional contain a disc check, performed via optgraph.dll. - // All instances of professional contain in the directory at the end of the image 3 files. gov_[something].x64, - // iofile.x64, and sound.x64. + // All instances of professional contain in a directory usually (but not always, German Emergency 2 Deluxe has a + // Videos folder as well, which isn't involved in rings/protection) at the end of the image, 3 files: + // gov_[something].x64, iofile.x64, and sound.x64. So far, they have always been in a directory called "System". // Due to gov's minor name variance, sound.x64 sometimes being intersected by a ring at the start, and // iofile.x64 being referenced directly in optgraph.x64, only iofile.x64 is being checked for now. // TODO: optgraph.dll also contains DRM to prevent kernel debugger SoftICE from being used, via a process called @@ -53,10 +54,11 @@ public class CopyX : IPathCheck, IPortableExecutableCheck // It has none here since it wouldn't be necessary. // Light: - // All instances of light contain 1 or more files in the directory at the end of the image. They all consist of - // either 0x00, or some data that matches between entries (and also is present in the 3 Professional files), - // except for the parts with the rings running through them. - // TODO: Check the last directory alphabetically and not just ZDAT* + // All instances of light contain 1 or more files in the directory usually (but not always; Kenny's Adventure has + // uses a System folder, and then has a non-protection Xtras folder on the disc as well) at the end of the image. + // They all consist of either 0x00, or some data that matches between entries (and also is present in the 3 + // Professional files), except for the parts with the rings running through them. + // Find a viable way to check the last directory alphabetically and not just ZDAT* /// public string? CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug) @@ -114,22 +116,32 @@ public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable !f.EndsWith(".x64", StringComparison.OrdinalIgnoreCase)) - .Where(f => - { - // TODO: Compensate for the check being run a directory or more higher - f = f.Remove(0, path.Length); - f = f.TrimStart('/', '\\'); - return f.StartsWith("ZDAT", StringComparison.OrdinalIgnoreCase); - }) - .OrderBy(f => f) - .ToList(); - - if (fileList.Count > 0) + + // Kenny's Adventure uses System instead of ZDAT. + string[] dirs = ["ZDAT", "ZDATA", "System"]; + List? lightFiles = null; + + // TODO: Compensate for the check being run a directory or more higher + var fileList = files.Where(f => !f.EndsWith(".x64", StringComparison.OrdinalIgnoreCase)); + foreach (var dir in dirs) + { + lightFiles = fileList.Where(f => + { + f = f.Remove(0, path.Length); + f = f.TrimStart('/', '\\'); + return f.StartsWith(dir + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase); + }) + .OrderBy(f => f) + .ToList(); + if (lightFiles.Count() > 0) + break; + } + + if ((lightFiles != null) && (lightFiles.Count > 0)) { try { - using var stream = File.OpenRead(fileList[0]); + using var stream = File.OpenRead(lightFiles[0]); byte[] block = stream.ReadBytes(1024); var matchers = new List @@ -153,7 +165,7 @@ public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable CheckDirectoryPath(string path, IEnumerable