using System; using System.Collections.Concurrent; using System.Collections.Generic; using BinaryObjectScanner.Interfaces; using BinaryObjectScanner.Matching; using BinaryObjectScanner.Wrappers; namespace BinaryObjectScanner.Protection { /// /// Denuvo (https://irdeto.com/denuvo/) is a family of DRM originally created in 2014 by Denuvo Software Solutions, which was acquired by Irdeto in 2018 (https://www.gamesindustry.biz/irdeto-acquires-denuvo-in-bid-to-beef-up-security-in-the-games-industry). /// Denuvo Anti-Tamper (https://irdeto.com/denuvo/anti-tamper/) is the most common, preventing game files from being modified and requiring online activation of games. /// Denuvo Anti-Tamper datasheet: https://resources.irdeto.com/video-games/datasheet-anti-tamper /// Lists of games with Denuvo Anti-Tamper: /// https://store.steampowered.com/curator/26095454-Denuvo-Games/ /// https://www.pcgamingwiki.com/wiki/Denuvo /// Denuvo Anti-Cheat (https://irdeto.com/denuvo/anti-cheat/) is a form of anti-cheat, though information on what games use it is rather sparse. /// It was used briefly in Doom Eternal Update 1 (https://store.steampowered.com/news/app/782330/view/2187005925152148469), before being completely removed in Update 1.1 (https://store.steampowered.com/news/app/782330/view/2187006557874536446). /// It's somewhat difficult to find other games that may use this, as quite a few sources seem to erroneously refer to Anti-Tamper as Anti-Cheat. /// Support page for Denuvo Anti-Cheat: https://support.codefusion.technology/anti-cheat /// Announcements for Denuvo Anti-Cheat: /// https://irdeto.com/news/leveling-the-playing-field-with-denuvo-anti-cheat/ /// https://irdeto.com/news/denuvo-anti-cheat-now-available-on-steamworks/ /// https://irdeto.com/news/denuvo-joins-exclusive-playstation5-tools-and-middleware-program-to-offer-anti-cheat-technology-to-game-developers/ /// Denuvo Anti-Cheat datasheet: https://web.archive.org/web/20190512082146/https://resources.irdeto.com/video-games/datasheet-anti-cheat /// Denuvo also has a number of products available, such as ones targeting mobile games: /// https://irdeto.com/denuvo/mobile-games-protection/ /// https://resources.irdeto.com/video-games/datasheet-anti-tamper-and-anti-cheat-technology-for-mobile /// Additional information and resources: /// https://en.wikipedia.org/wiki/Denuvo /// https://www.wired.com/story/empress-drm-cracking-denuvo-video-game-piracy/ /// public class Denuvo : IPathCheck, IPortableExecutableCheck { // TODO: Investigate possible filename checks for Denuvo Anti-Tamper. // https://www.pcgamingwiki.com/wiki/Denuvo#Redeem.exe /// 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; // All current checks for Denuvo Anti-Cheat come from Doom Eternal Update 1 (Steam Depot 782332, Manifest 7064393210727378308). // Found in "denuvo-anti-cheat.sys". string name = pex.FileDescription; if (name?.Equals("Denuvo Anti-Cheat Driver", StringComparison.OrdinalIgnoreCase) == true) return $"Denuvo Anti-Cheat"; // Found in "denuvo-anti-cheat-update-service.exe"/"Denuvo Anti-Cheat Installer.exe". if (name?.Equals("Denuvo Anti-Cheat Update Service", StringComparison.OrdinalIgnoreCase) == true) return $"Denuvo Anti-Cheat"; // Found in "denuvo-anti-cheat-runtime.dll". if (name?.Equals("Denuvo Anti-Cheat Runtime", StringComparison.OrdinalIgnoreCase) == true) return $"Denuvo Anti-Cheat"; // Data sourced from: // https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/Denuvo%20protector.2.sg // https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/_denuvoComplete.2.sg // TODO: Re-enable all Entry Point checks after implementing // Denuvo Protector // if (pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus && pex.EntryPointRaw != null) // { // byte?[] denuvoProtector = new byte?[] // { // 0x48, 0x8D, 0x0D, null, null, null, null, null, // null, null, null, 0xE9, null, null, null, null, // 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // }; // if (pex.EntryPointRaw.StartsWith(denuvoProtector)) // return "Denuvo Protector"; // } // Denuvo var timingMatchers = new List { // Denuvo Timing new ContentMatchSet( new byte?[] { 0x44, 0x65, 0x6E, 0x75, 0x76, 0x6F, 0x20, 0x54, 0x69, 0x6D, 0x69, 0x6E, 0x67, }, "Denuvo") }; // TODO: Re-enable all Entry Point checks after implementing // if (pex.ContainsSection(".arch") || pex.ContainsSection(".srdata") || !string.IsNullOrWhiteSpace(MatchUtil.GetFirstMatch(file, pex.EntryPointRaw, timingMatchers, includeDebug))) // { // if (pex.OH_Magic == OptionalHeaderType.PE32Plus) // { // var matchers = new List // { // // Mad Max, Metal Gear Solid: TPP, Rise of the Tomb Raider // new ContentMatchSet( // new ContentMatch( // new byte?[] // { // 0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x4C, 0x8D, // null, null, null, null, null, 0x4C, 0x8D, null, // null, null, null, null, 0x4D, 0x29, 0xC1, // }, // end: 0 // ), // "Denuvo v1.0 (x64)"), // // Lords of the Fallen, Batman: AK, Just Cause 3, Sherlock Holmes: TdD, Tales of Berseria etc // new ContentMatchSet( // new ContentMatch( // new byte?[] // { // 0x48, 0x8D, 0x0D, null, null, null, null, 0xE9, // null, null, null, null, // }, // end: 0 // ), // "Denuvo v2.0a (x64)"), // // Yesterday Origins // new ContentMatchSet( // new ContentMatch( // new byte?[] // { // 0x48, 0x89, null, null, null, null, null, 0x48, // 0x89, null, null, null, null, null, 0x4C, 0x89, // null, null, null, null, null, 0x4C, 0x89, null, // null, null, null, null, 0x48, 0x83, 0xFA, 0x01, // }, // end: 0 // ), // "Denuvo v2.0b (x64)"), // // Sniper Ghost Warrior 3 (beta), Dead Rising 4 (SteamStub-free) // new ContentMatchSet( // new ContentMatch( // new byte?[] // { // null, null, null, null, null, null, null, null, // 0x4C, 0x89, 0x1C, 0x24, 0x49, 0x89, 0xE3, // }, // end: 0 // ), // "Denuvo v3.0a (x64)"), // // Train Sim World CSX Heavy Haul // new ContentMatchSet( // new ContentMatch( // new byte?[] // { // 0x4D, 0x8D, null, null, null, null, null, null, // null, null, null, 0x48, 0x89, null, null, null, // null, null, 0x48, 0x8D, null, null, 0x48, 0x89, // null, 0x48, 0x89, null, 0x48, 0x89, // }, // end: 0 // ), // "Denuvo v3.0b (x64)"), // }; // string match = MatchUtil.GetFirstMatch(file, pex.EntryPointRaw, matchers, includeDebug); // if (!string.IsNullOrWhiteSpace(match)) // return match; // return "Denuvo (Unknown x64 Version)"; // //// Check if steam_api64.dll present // //if (PE.isLibraryPresent("steam_api64.dll")) // //{ // // // Override additional info // // sOptions = "x64 -> Steam"; // // bDetected = 1; // //} // //// Check if uplay_r1_loader64.dll present // //if (PE.isLibraryPresent("uplay_r1_loader64.dll")) // //{ // // // Override additional info // // sOptions = "x64 -> uPlay"; // // bDetected = 1; // //} // //// Check if uplay_r2_loader64.dll present // //if (PE.isLibraryPresent("uplay_r2_loader64.dll")) // //{ // // // Override additional info // // sOptions = "x64 -> uPlay"; // // bDetected = 1; // //} // //// Check if Core/Activation64.dll present // //if (PE.isLibraryPresent("Core/Activation64.dll")) // //{ // // // Override additional info // // sOptions = "x64 -> Origin"; // // bDetected = 1; // //} // } // else // { // var matchers = new List // { // // Pro Evolution Soccer 2017, Champions of Anteria // new ContentMatchSet( // new ContentMatch( // new byte?[] // { // 0x55, 0x89, 0xE5, 0x8D, null, null, null, null, // null, null, 0xE8, null, null, null, null, 0xE8, // null, null, null, null, 0xE8, null, null, null, // null, 0xE8, null, null, null, null, // }, // end: 0 // ), // "Denuvo v1.0 (x86)"), // // Romance of 13 Kingdoms, 2Dark // new ContentMatchSet( // new ContentMatch( // new byte?[] // { // 0x8D, null, null, null, null, null, null, 0x89, // 0x7C, 0x24, 0x04, 0x89, 0xE7, // }, // end: 0 // ), // "Denuvo v2.0 (x86)"), // }; // string match = MatchUtil.GetFirstMatch(file, pex.EntryPointRaw, matchers, includeDebug); // if (!string.IsNullOrWhiteSpace(match)) // return match; // //// Check if steam_api64.dll present // //if (PE.isLibraryPresent("steam_api.dll")) // //{ // // // Override additional info // // sOptions = "x86 -> Steam"; // // bDetected = 1; // //} // //// Check if uplay_r1_loader.dll present // //if (PE.isLibraryPresent("uplay_r1_loader.dll")) // //{ // // // Override additional info // // sOptions = "x86 -> uPlay"; // // bDetected = 1; // //} // //// Check if Core/Activation.dll present // //if (PE.isLibraryPresent("Core/Activation.dll")) // //{ // // // Override additional info // // sOptions = "x86 -> Origin"; // // bDetected = 1; // //} // } // } return null; } /// public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable files) { var matchers = new List { // Found in Doom Eternal Update 1 (Steam Depot 782332, Manifest 7064393210727378308). // These files are automatically installed into an "Denuvo Anti-Cheat" folder when the game is installed. new PathMatchSet(new PathMatch("denuvo-anti-cheat.sys", useEndsWith: true), "Denuvo Anti-Cheat"), new PathMatchSet(new PathMatch("denuvo-anti-cheat-update-service.exe", useEndsWith: true), "Denuvo Anti-Cheat"), new PathMatchSet(new PathMatch("denuvo-anti-cheat-runtime.dll", useEndsWith: true), "Denuvo Anti-Cheat"), // This file is a renamed copy of "denuvo-anti-cheat-update-service.exe" which is only seen in the folder of the main game executable after it has been run, but before Denuvo Anti-Cheat is finished installing. new PathMatchSet(new PathMatch("Denuvo Anti-Cheat Installer.exe", useEndsWith: true), "Denuvo Anti-Cheat"), }; return MatchUtil.GetAllMatches(files, matchers, any: false); } /// public string CheckFilePath(string path) { var matchers = new List { // Found in Doom Eternal Update 1 (Steam Depot 782332, Manifest 7064393210727378308). // These files are automatically installed into an "Denuvo Anti-Cheat" folder when the game is installed. new PathMatchSet(new PathMatch("denuvo-anti-cheat.sys", useEndsWith: true), "Denuvo Anti-Cheat"), new PathMatchSet(new PathMatch("denuvo-anti-cheat-update-service.exe", useEndsWith: true), "Denuvo Anti-Cheat"), new PathMatchSet(new PathMatch("denuvo-anti-cheat-runtime.dll", useEndsWith: true), "Denuvo Anti-Cheat"), // This file is a renamed copy of "denuvo-anti-cheat-update-service.exe" which is only seen in the folder of the main game executable after it has been run, but before Denuvo Anti-Cheat is finished installing. new PathMatchSet(new PathMatch("Denuvo Anti-Cheat Installer.exe", useEndsWith: true), "Denuvo Anti-Cheat"), }; return MatchUtil.GetFirstMatch(path, matchers, any: true); } } }