Skip to content

Improve detection for cd/dvd-cops version string #368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions BinaryObjectScanner.Test/Protection/CDDVDCopsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,6 @@ namespace BinaryObjectScanner.Test.Protection
{
public class CDDVDCopsTests
{
[Fact]
public void CheckContentsTest()
{
string file = "filename";
byte[] fileContent = [0x01, 0x02, 0x03, 0x04];

var checker = new CDDVDCops();
string? actual = checker.CheckContents(file, fileContent, includeDebug: true);
Assert.Null(actual);
}

[Fact]
public void CheckNewExecutableTest()
{
Expand Down
110 changes: 80 additions & 30 deletions BinaryObjectScanner/Protection/CDDVDCops.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
#endif
using System.Text;
using System.Text.RegularExpressions;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
Expand Down Expand Up @@ -64,35 +65,12 @@ namespace BinaryObjectScanner.Protection
///
/// List of applications that have CD/DVD/WEB-Cops relating to a Windows update: https://www.betaarchive.com/wiki/index.php/Microsoft_KB_Archive/924867
/// </summary>

public class CDDVDCops : IContentCheck, IExecutableCheck<NewExecutable>, IExecutableCheck<PortableExecutable>, IPathCheck
// TODO: Investigate reference to "CD32COPS.DLL" in "WETFLIPP.QZ_" in IA item "Triada_Russian_DVD_Complete_Collection_of_Erotic_Games".
// TODO: Investigate cdcode.key for redump ID 108167, may be key-less cd-cops?
// TODO: Document update 12 for redump ID 108167 bumping version, adding key, adding vista(?) support

public class CDDVDCops : IExecutableCheck<NewExecutable>, IExecutableCheck<PortableExecutable>, IPathCheck
{
// TODO: Investigate reference to "CD32COPS.DLL" in "WETFLIPP.QZ_" in IA item "Triada_Russian_DVD_Complete_Collection_of_Erotic_Games".
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// TODO: Obtain a sample to find where this string is in a typical executable
var contentMatchSets = new List<ContentMatchSet>
{
// TODO: Remove from here once it's confirmed that no PE executables contain this string
// CD-Cops, ver.
new(new byte?[]
{
0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C,
0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "CD-Cops (Unconfirmed - Please report to us on Github)"),

// // DVD-Cops, ver.
new(new byte?[]
{
0x44, 0x56, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73,
0x2C, 0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "DVD-Cops (Unconfirmed - Please report to us on Github)"),
};

return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}

/// <inheritdoc/>
public string? CheckExecutable(string file, NewExecutable nex, bool includeDebug)
{
Expand All @@ -104,13 +82,39 @@ public class CDDVDCops : IContentCheck, IExecutableCheck<NewExecutable>, IExecut
// TODO: Figure out what NE section this lives in
var neMatchSets = new List<ContentMatchSet>
{
// CD-Cops, ver.
// Checking for variants with one or two spaces, just in case; the Brockhaus DVDs only had one
new(new byte?[]
{
0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C,
0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "CD-Cops"),
// CD-Cops, ver.

// Found in "h3blade.exe" in Redump entry 85077.
new(new byte?[]
{
0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C,
0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "CD-Cops"),
// CD-Cops, ver.

// Found in IA entries "der-brockhaus-multimedial-2002-premium" and "der-brockhaus-multimedial-2003-premium"
// TODO: 2002 returns DVD-Cops 2.01, 2003 returns DVD-Cops 1,60. CD-Cops version numbers seem to "reset"
// after some point in time in existing redump entries- perhaps the command instead of the period may have
// some significance?
new(new byte?[]
{
0x44, 0x56, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73,
0x2C, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "DVD-Cops"),
// DVD-Cops, ver.

new(new byte?[]
{
0x44, 0x56, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73,
0x2C, 0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "DVD-Cops"),
// DVD-Cops, ver.
};

var match = MatchUtil.GetFirstMatch(file, data, neMatchSets, includeDebug);
Expand Down Expand Up @@ -186,7 +190,22 @@ public class CDDVDCops : IContentCheck, IExecutableCheck<NewExecutable>, IExecut
// Found in "FGP.exe" in IA item "flaklypa-grand-prix-dvd"/Redump entry 108169.
if (pex.ContainsSection("UNICops", exact: true))
return "UNI-Cops";


// Get the DATA section, if it exists
// Found in "bib.dll" in IA item "https://archive.org/details/cover_202501"
// This contains the version section that the Content Check looked for. There are likely other sections
// that may contain it. Update when more are found.
var strs = pex.GetFirstSectionStrings("DATA");
if (strs != null)
{
var match = strs.Find(s => s.Contains(" ver. ") && (s.Contains("CD-Cops, ") || s.Contains("DVD-Cops, ")));
if (match != null)
if (match.Contains("CD-Cops"))
return $"CD-Cops {GetVersionString(match)}";
else if (match.Contains("DVD-Cops"))
return $"DVD-Cops {GetVersionString(match)}";
}

return null;
}

Expand All @@ -206,6 +225,16 @@ public List<string> CheckDirectoryPath(string path, List<string>? files)

new(new PathMatch(".GZ_", matchCase: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
new(new PathMatch(".Qz", matchCase: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),

// Found in Redump entries 84517, 108167, 119435, 119436, and 119437. This is the official
// name from their website https://www.linkdatasecurity.com/index.htm#/protection-products/cd-dvd-usb-copy-protection/cdcops
// I can't find this specific filename documented anywhere, but, all of these
// games do not require a key to be input
new(new FilePathMatch("cdcode.key"), "CD-Cops Codefree"),

// DVD-Cops Codefree does exist https://www.linkdatasecurity.com/index.htm#/protection-products/cd-dvd-usb-copy-protection/dvdvers
// but we currently have no samples. Presumably this is what the file would be called?
new(new FilePathMatch("dvdcode.key"), "DVD-Cops Codefree (Unconfirmed - Please report to us on Github)"),
};

return MatchUtil.GetAllMatches(files, matchers, any: true);
Expand All @@ -226,6 +255,15 @@ public List<string> CheckDirectoryPath(string path, List<string>? files)

new(new PathMatch(".GZ_", matchCase: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
new(new PathMatch(".Qz", matchCase: true, useEndsWith: true), "CD-Cops (Unconfirmed - Please report to us on Github)"),
// Found in Redump entries 84517, 108167, 119435, 119436, and 119437. This is the official
// name from their website https://www.linkdatasecurity.com/index.htm#/protection-products/cd-dvd-usb-copy-protection/cdcops
// I can't find this specific filename documented anywhere, but, all of these
// games do not require a key to be input
new(new FilePathMatch("cdcode.key"), "CD-Cops Codefree"),

// DVD-Cops Codefree does exist https://www.linkdatasecurity.com/index.htm#/protection-products/cd-dvd-usb-copy-protection/dvdvers
// but we currently have no samples. Presumably this is what the file would be called?
new(new FilePathMatch("dvdcode.key"), "DVD-Cops Codefree (Unconfirmed - Please report to us on Github)"),
};

return MatchUtil.GetFirstMatch(path, matchers, any: true);
Expand All @@ -243,5 +281,17 @@ public List<string> CheckDirectoryPath(string path, List<string>? files)

return version;
}

private static string GetVersionString(string match)
{
// Full string ends with # (i.e. "CD-Cops, ver. 1.72, #"), use that to compensate for comma in version
// number cases (don't change the comma, see earlier to-do) like "DVD-Cops, ver. 1,60, #"
// TODO: improve regex via the starting "N" character? Possibly unnecessary?
var versionMatch = Regex.Match(match, @"(?<=D-Cops,\s{1,}ver. )(.*?)(?=,\s{1,}#)");
if (versionMatch.Success)
return versionMatch.Value;

return "(Unknown Version - Please report to us on GitHub)";
}
}
}
Loading