mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-02-10 21:30:24 +00:00
188 lines
12 KiB
C#
188 lines
12 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using BurnOutSharp.ExecutableType.Microsoft.PE;
|
|
using BurnOutSharp.Interfaces;
|
|
using BurnOutSharp.Matching;
|
|
|
|
namespace BurnOutSharp.ProtectionType
|
|
{
|
|
/// <summary>
|
|
/// DiscGuard was a copy protection created by TTR (https://web.archive.org/web/19981212021829/http://ttrtech.com/) for protecting software.
|
|
/// They also created a similar copy protection for audio CDs called DiscAudit (https://web.archive.org/web/19981206095259/http://www.ttrtech.com/discaudi.htm).
|
|
/// It seems to work by encrypting the main game executable, and by having a "signature" that is supposedly only present on a genuine disc (https://www.cdmediaworld.com/hardware/cdrom/cd_protections_discguard.shtml).
|
|
/// Due to the fact that these games can seemingly be burned to CD-R under the right conditions using CloneCD, it likely isn't using twin sectors or DPM (https://www.gameburnworld.com/protections_discguard.shtml).
|
|
/// It seems likely to be using subchannels as the basis for this signature, as no errored sectors are used.
|
|
/// DiscGuard is seemingly able to be detect so-called "active debuggers", based on text found in "Alternate.exe" (Redump entry 31914) and "Alt.exe" (Redump entries 46743, 46961, 79284, and 79374).
|
|
/// There's a reference to a file "Dg.vbn" being present in "Alternate.exe" (Redump entry 31914) and "Alt.exe" (Redump entries 46743, 46961, 79284, and 79374), but no copy has been found in any sample so far.
|
|
/// There seem to be two distinct versions of DiscGuard, with one only being present on one known game (Redump entry 31914).
|
|
/// "Alternate.exe" in the outlying version is "Alt.exe" in the rest.
|
|
/// "TTR1.DLL" and "TTR2.DLL" in the outlying version appear to be "T111.DLL" and "T222.DLL" in the rest, respectively.
|
|
/// "IOSLink.sys" and "IOSLink.vxd" seem to be the same throughout all versions, even down to the reported File Version in "IOSLink.sys".
|
|
/// There are other various DLLs, but their names seem to be different on every disc. Their filenames all seem to start with the letter "T", and it seems to be one of these specifically that the protected executable imports.
|
|
/// These outlying DLLs are:
|
|
/// "T29.dll" (Redump entry 31914).
|
|
/// "T5375.dll" (Redump entry 79284).
|
|
/// "TD352.dll" and "TE091.dll" (Redump entry 46743).
|
|
/// "T71E1.dll" and "T7181.dll" (Redump entry 46961).
|
|
/// "TA0E4.DLL" (Redump entry 79374).
|
|
/// </summary>
|
|
public class DiscGuard : IPathCheck, IPortableExecutableCheck
|
|
{
|
|
// TODO: Add checks for the game executables, which seem likely to contain some kind of indicators that can be checked for. The game executables all seem to import "Ord(1)" from one of the varying DLLs present.
|
|
/// <inheritdoc/>
|
|
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 "IOSLinksys.dll" (Redump entries 31914, 46743, 46961, 79284, and 79374).
|
|
string name = pex.FileDescription;
|
|
if (name?.StartsWith("IOSLinkNT", StringComparison.OrdinalIgnoreCase) == true)
|
|
return $"DiscGuard";
|
|
|
|
// Found in "T29.dll" (Redump entry 31914).
|
|
name = pex.ProductName;
|
|
if (name?.StartsWith("DiscGuard (tm)", StringComparison.OrdinalIgnoreCase) == true)
|
|
return $"DiscGuard";
|
|
|
|
// Found in "IOSLinksys.dll" (Redump entries 31914, 46743, 46961, 79284, and 79374).
|
|
name = pex.ProductName;
|
|
if (name?.StartsWith("TTR Technologies Ltd. DiscGuard (tm)", StringComparison.OrdinalIgnoreCase) == true)
|
|
return $"DiscGuard";
|
|
|
|
// Get the .vbn section, if it exists
|
|
var DiscGuardSection = pex.ReadRawSection(".vbn");
|
|
if (DiscGuardSection != null)
|
|
{
|
|
var matchers = new List<ContentMatchSet>
|
|
{
|
|
// Found in "T29.dll" (Redump entry 31914).
|
|
// This check should be as long as the following check, as this data is nearly identical (including length) in the original files, but for some reason the section ends early, causing part of the remaining data to not be part of a section.
|
|
new ContentMatchSet(new byte?[]
|
|
{
|
|
0x7B, 0x39, 0x8F, 0x07, 0x47, 0xE9, 0x96, 0x8C, 0xCA, 0xB2, 0x5C, 0x50,
|
|
0xC7, 0x5A, 0x18, 0xBD, 0x75, 0xB5, 0x68, 0x6A, 0x78, 0xB5, 0xCF, 0xF2,
|
|
0xBE, 0xB3, 0xDB, 0xE9, 0x4E, 0x87, 0x8D, 0x46, 0x63, 0x0A, 0x54, 0xB8,
|
|
0x4F, 0x85, 0x60, 0x2C, 0x06, 0xEC, 0xBD, 0x75, 0xF5, 0x6A, 0x6E, 0x35,
|
|
0x4D, 0x5A, 0x8B, 0xF4, 0x12, 0x15, 0x23, 0xC8, 0xE9, 0x80, 0x01, 0x10,
|
|
0xFE, 0xDB, 0xC6, 0x70, 0x1D, 0xC1, 0x4D, 0xAE, 0x9E, 0xE1, 0x01, 0xAA,
|
|
0x9E, 0x50, 0x50, 0xC5, 0x66, 0x80, 0xC0, 0xA2, 0x2F, 0xA9, 0x7A, 0x3B,
|
|
0x48, 0x74, 0x9D, 0x17, 0x33, 0x5D, 0x4C, 0x84, 0xD9, 0x54, 0xC4, 0x08,
|
|
0xCC, 0x10, 0x2A, 0xF6, 0x91, 0x40, 0x51, 0xD3, 0xF5, 0x9A, 0x07, 0xE7,
|
|
0xAB, 0xE9, 0x0B, 0xAD, 0xD4, 0x3A, 0xEC, 0xBA, 0x4B, 0x6C, 0xD2, 0x82,
|
|
0x0D, 0xF5, 0x49, 0x83, 0x8E, 0xAB, 0x85, 0x92, 0x78, 0x1D, 0x69, 0x1E,
|
|
0x44, 0xC6, 0xF6, 0xB4, 0x5F, 0x5F, 0xC2, 0x48, 0x5A, 0xED, 0x43, 0xD3,
|
|
0xA4, 0x41, 0x81
|
|
}, "DiscGuard"),
|
|
|
|
// Found in "T5375.dll" (Redump entry 79284), "TD352.dll" and "TE091.dll" (Redump entry 46743), "T71E1.dll" and "T7181.dll" (Redump entry 46961), and "TA0E4.DLL" (Redump entry 79374).
|
|
new ContentMatchSet(new byte?[]
|
|
{
|
|
0x7B, 0x39, 0x8F, 0x07, 0x45, 0xE9, 0x96, 0x8C, 0xCA, 0xB2, 0x5C, 0x50,
|
|
0xC7, 0x5A, 0x18, 0xBD, 0x75, 0xB5, 0x68, 0x6A, 0x78, 0xB5, 0xCF, 0xF2,
|
|
0xBE, 0xB3, 0xDB, 0xE9, 0x4E, 0x87, 0x8D, 0x46, 0x63, 0x0A, 0x54, 0xB8,
|
|
0x4F, 0x85, 0x60, 0x2C, 0x06, 0xEC, 0xBD, 0x75, 0xC6, 0xEB, 0x6E, 0x35,
|
|
0xED, 0xD0, 0x8B, 0xF4, 0x15, 0x12, 0x3D, 0xF3, 0x65, 0xF7, 0x01, 0x10,
|
|
0xF8, 0xFA, 0xC6, 0x70, 0x1D, 0xC1, 0x4D, 0xAE, 0x9E, 0xE1, 0x01, 0xAA,
|
|
0x9E, 0x50, 0x50, 0xC5, 0x66, 0x80, 0xC0, 0xA2, 0x2F, 0xA9, 0x7A, 0x3B,
|
|
0x48, 0x74, 0x9D, 0x17, 0x33, 0x5D, 0x4C, 0x84, 0xD9, 0x54, 0xC4, 0x08,
|
|
0xCC, 0x10, 0x2A, 0xF6, 0x91, 0x40, 0x51, 0xD3, 0x41, 0x9A, 0x07, 0xE7,
|
|
0xAB, 0xE9, 0x0B, 0xAD, 0xD4, 0x3A, 0xEC, 0xBA, 0xAF, 0x69, 0xD2, 0x82,
|
|
0x67, 0xF5, 0x49, 0x83, 0x8E, 0xAB, 0x85, 0x92, 0x04, 0x19, 0x69, 0x1E,
|
|
0x44, 0xC6, 0xF6, 0xB4, 0x5F, 0x5F, 0xC2, 0x48, 0x5A, 0xED, 0x43, 0xD3,
|
|
0xA4, 0x41, 0x81, 0xAF, 0xB8, 0xCB, 0x46, 0xE3, 0xDA, 0x05, 0x36, 0xEA,
|
|
0x05, 0xF5, 0xB9, 0xCE, 0x5F, 0x9A, 0xF5, 0x7D, 0x9E, 0x64, 0x66, 0xF9,
|
|
0xA5, 0x7C, 0x4D, 0x1D, 0x1D, 0x95, 0x02, 0x52, 0x66, 0x23, 0xEF, 0xFF,
|
|
0xEC, 0x63, 0x11, 0xEB, 0xF6, 0x66, 0x8F, 0x2B, 0xCF, 0x07, 0x50, 0x18,
|
|
0xBE, 0x58, 0xCA, 0x08, 0x24, 0xAD, 0x81, 0x1A, 0xAB, 0x0E, 0x2D, 0x16,
|
|
0x38, 0xAB, 0x22, 0xB5, 0xA8, 0xF0, 0x7D, 0x2E, 0xAF, 0x5E, 0xEA, 0x02,
|
|
0x72, 0x20, 0x14, 0x19, 0x0E, 0x31, 0xF3, 0xD0, 0x40, 0xAE, 0xA2, 0xD5,
|
|
0x0A, 0xA7, 0xB7, 0xAE, 0x02, 0xCF, 0xAC, 0x5F, 0xB8, 0x03, 0x15, 0x80,
|
|
0x9A, 0x58, 0x5C, 0x03, 0x28, 0x31, 0x9E, 0xB8, 0x21, 0x5D, 0x07, 0xB3,
|
|
0xB9, 0xEC, 0x75, 0xBA, 0xC2, 0xC8, 0x9D, 0x6F, 0x7A, 0xA1, 0x00, 0x8A
|
|
}, "DiscGuard"),
|
|
};
|
|
|
|
string match = MatchUtil.GetFirstMatch(file, DiscGuardSection, matchers, includeDebug);
|
|
if (!string.IsNullOrWhiteSpace(match))
|
|
return match;
|
|
}
|
|
|
|
// Get the .rsrc section, if it exists
|
|
var rsrcSection = pex.ReadRawSection(".rsrc");
|
|
if (rsrcSection != null)
|
|
{
|
|
var matchers = new List<ContentMatchSet>
|
|
{
|
|
// Found in "Alternate.exe" (Redump entry 31914) and "Alt.exe" (Redump entries 46743, 46961, 79284, and 79374).
|
|
// T.h.e. .f.i.l.e. .I.o.s.L.i.n.k...V.x.D. .w.a.s. .n.o.t. .f.o.u.n.d.
|
|
new ContentMatchSet(new byte?[]
|
|
{
|
|
0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x66, 0x00, 0x69, 0x00,
|
|
0x6C, 0x00, 0x65, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6F, 0x00, 0x73, 0x00,
|
|
0x4C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x6B, 0x00, 0x2E, 0x00, 0x56, 0x00,
|
|
0x78, 0x00, 0x44, 0x00, 0x20, 0x00, 0x77, 0x00, 0x61, 0x00, 0x73, 0x00,
|
|
0x20, 0x00, 0x6E, 0x00, 0x6F, 0x00, 0x74, 0x00, 0x20, 0x00, 0x66, 0x00,
|
|
0x6F, 0x00, 0x75, 0x00, 0x6E, 0x00, 0x64, 0x00
|
|
}, "DiscGuard"),
|
|
};
|
|
|
|
string match = MatchUtil.GetFirstMatch(file, rsrcSection, matchers, includeDebug);
|
|
if (!string.IsNullOrWhiteSpace(match))
|
|
return match;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
|
|
{
|
|
var matchers = new List<PathMatchSet>
|
|
{
|
|
// Found together in seemingly every DiscGuard game (Redump entries 31914, 46743, 46961, 79284, and 79374).
|
|
new PathMatchSet(new List<PathMatch>
|
|
{
|
|
new PathMatch("IOSLINK.VXD", useEndsWith: true),
|
|
new PathMatch("IOSLINK.SYS", useEndsWith: true),
|
|
}, "DiscGuard"),
|
|
|
|
// Found together in one DiscGuard game (Redump entry 31914).
|
|
new PathMatchSet(new List<PathMatch>
|
|
{
|
|
new PathMatch("TTR1.DLL", useEndsWith: true),
|
|
new PathMatch("TTR2.DLL", useEndsWith: true),
|
|
}, "DiscGuard"),
|
|
|
|
// Found together in most DiscGuard games (Redump entries 46743, 46961, 79284, and 79374).
|
|
new PathMatchSet(new List<PathMatch>
|
|
{
|
|
new PathMatch("T111.DLL", useEndsWith: true),
|
|
new PathMatch("T222.DLL", useEndsWith: true),
|
|
}, "DiscGuard"),
|
|
};
|
|
|
|
return MatchUtil.GetAllMatches(files, matchers, any: false);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public string CheckFilePath(string path)
|
|
{
|
|
var matchers = new List<PathMatchSet>
|
|
{
|
|
// Found together in seemingly every DiscGuard game (Redump entries 31914, 46743, 46961, 79284, and 79374).
|
|
new PathMatchSet(new PathMatch("IOSLINK.VXD", useEndsWith: true), "DiscGuard"),
|
|
new PathMatchSet(new PathMatch("IOSLINK.SYS", useEndsWith: true), "DiscGuard"),
|
|
|
|
// IOSLINK.DLL doesn't seem to be present in any known samples, but a check for it was in the original BurnOut.
|
|
new PathMatchSet(new PathMatch("IOSLINK.DLL", useEndsWith: true), "DiscGuard (Unconfirmed check, report this to us on GitHub))"),
|
|
};
|
|
|
|
return MatchUtil.GetFirstMatch(path, matchers, any: true);
|
|
}
|
|
}
|
|
}
|