Skip to content

Commit 6cc6f66

Browse files
Add CEG protection detection (#406)
* Initial work * Finish PR * Update test count
1 parent fbee5a1 commit 6cc6f66

File tree

4 files changed

+129
-1
lines changed

4 files changed

+129
-1
lines changed

BinaryObjectScanner.Test/Data/StaticChecksTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public void PathCheckClasses_Populated()
4444
public void PortableExecutableCheckClasses_Populated()
4545
{
4646
var actual = StaticChecks.PortableExecutableCheckClasses;
47-
Assert.Equal(105, actual.Length);
47+
Assert.Equal(106, actual.Length);
4848
}
4949
}
5050
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.IO;
2+
using BinaryObjectScanner.Protection;
3+
using Xunit;
4+
5+
namespace BinaryObjectScanner.Test.Protection
6+
{
7+
public class CEGTests
8+
{
9+
[Fact]
10+
public void CheckPortableExecutableTest()
11+
{
12+
string file = "filename";
13+
SabreTools.Data.Models.PortableExecutable.Executable model = new();
14+
Stream source = new MemoryStream(new byte[1024]);
15+
SabreTools.Serialization.Wrappers.PortableExecutable exe = new(model, source);
16+
17+
var checker = new CenegaProtectDVD();
18+
string? actual = checker.CheckExecutable(file, exe, includeDebug: false);
19+
Assert.Null(actual);
20+
}
21+
}
22+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System.Collections.Generic;
2+
3+
namespace BinaryObjectScanner.Protection
4+
{
5+
public partial class CEG
6+
{
7+
/// <summary>
8+
/// Dictionary of known CEG executables with compilation time as the key, and the string value as a combination
9+
/// of depot ID, manifest version, and filename.
10+
/// </summary>
11+
/// <remarks>Contained in a separate file since dictionary size will be very large.</remarks>
12+
private static readonly Dictionary<uint, string> CEGDictionary = new()
13+
{
14+
//{ 1298033762, "Shogun total war 2 demo test" },
15+
{ 1264170802, "10681 (v0-1) - AvP_DX11.exe" },
16+
{ 1264171199, "10681 (v0-1) - AvP.exe" },
17+
{ 1264759825, "10681 (v2) - AvP.exe" },
18+
{ 1264760178, "10681 (v2) - AvP_DX11.exe" },
19+
{ 1265104029, "10681 (v3) - AvP.exe" },
20+
{ 1265104767, "10681 (v3) - AvP_DX11.exe" },
21+
{ 1265196934, "10681 (v4) - AvP.exe" },
22+
{ 1265197111, "10681 (v4) - AvP_DX11.exe" },
23+
{ 1265200884, "10681 (v5) - AvP_DX11.exe" },
24+
{ 1265201120, "10681 (v5) - AvP.exe" },
25+
{ 1265218568, "10681 (v6) - AvP.exe" },
26+
{ 1265218748, "10681 (v6) - AvP_DX11.exe" },
27+
{ 1265626467, "10681 (v7) - AvP_DX11.exe" },
28+
{ 1265626733, "10681 (v7) - AvP.exe" },
29+
{ 1265639234, "10681 (v8) - AvP.exe" },
30+
{ 1265639459, "10681 (v8) - AvP_DX11.exe" },
31+
{ 1265711093, "10681 (v9) - AvP_DX11.exe" },
32+
{ 1265711343, "10681 (v9) - AvP.exe" },
33+
{ 1265729320, "10681 (v10-11) - AvP.exe" },
34+
{ 1265729583, "10681 (v10-11) - AvP_DX11.exe" },
35+
{ 1265898579, "10681 (v12) - AvP.exe" },
36+
{ 1265898814, "10681 (v12) - AvP_DX11.exe" },
37+
{ 1265910002, "10681 (v13) - AvP_DX11.exe" },
38+
{ 1265910166, "10681 (v13) - AvP.exe" },
39+
{ 1265973550, "10681 (v14) - AvP.exe" },
40+
{ 1265973915, "10681 (v14) - AvP_DX11.exe" },
41+
{ 1265992000, "10681 (v15) - AvP_DX11.exe" },
42+
{ 1265992237, "10681 (v15) - AvP.exe" },
43+
{ 1266001507, "10681 (v16) - AvP_DX11.exe" },
44+
{ 1266001711, "10681 (v16) - AvP.exe" },
45+
{ 1266254226, "10681 (v17) - AvP_DX11.exe" },
46+
{ 1266254418, "10681 (v17) - AvP.exe" },
47+
{ 1266280922, "10681 (v18-19) - AvP.exe" },
48+
{ 1266283570, "10681 (v18-19) - AvP_DX11.exe" },
49+
{ 1266338581, "10681 (v20) - AvP_DX11.exe" },
50+
{ 1266339302, "10681 (v20) - AvP.exe" },
51+
{ 1266493077, "10681 (v21) - AvP.exe" },
52+
{ 1266493275, "10681 (v21) - AvP_DX11.exe" },
53+
{ 1266593945, "10681 (v22) - AvP.exe" },
54+
{ 1266594188, "10681 (v22) - AvP_DX11.exe" },
55+
{ 1266799462, "10681 (v23) - AvP.exe" },
56+
{ 1266802085, "10681 (v23) - AvP_DX11.exe" },
57+
{ 1266863479, "10681 (v24) - AvP.exe" },
58+
{ 1266863657, "10681 (v24) - AvP_DX11.exe" },
59+
{ 1266927862, "10681 (v25) - AvP_DX11.exe" },
60+
{ 1266928166, "10681 (v25) - AvP.exe" },
61+
};
62+
}
63+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using BinaryObjectScanner.Interfaces;
2+
using SabreTools.Serialization.Wrappers;
3+
4+
namespace BinaryObjectScanner.Protection
5+
{
6+
/// <summary>
7+
/// Protection that used to be offered by Valve for games on Steam. By default, protected executables are "stripped"
8+
/// of varying 4KiB "strips", and these "strips" would only be downloaded when the user attempted to run the game on
9+
/// Steam.
10+
/// </summary>
11+
public partial class CEG : IExecutableCheck<PortableExecutable>
12+
{
13+
/// <inheritdoc/>
14+
public string? CheckExecutable(string file, PortableExecutable exe, bool includeDebug)
15+
{
16+
var strs = exe.GetFirstSectionStrings(".rdata");
17+
if (strs is not null)
18+
{
19+
if (strs.Exists(s => s.Contains("STEAMSTART") && s.Contains("STEAM_DRM_IPC")))
20+
{
21+
if (strs.Exists(s => s.Contains("This file has been stripped")))
22+
{
23+
return "CEG - Stripped";
24+
}
25+
else if (strs.Exists(s => s.Contains("This file contains strips")))
26+
{
27+
// TODO: Will be uncommented in the future when the rest of the CEG samples can be obtained.
28+
/*var value = CEGDictionary.TryGetValue(exe.COFFFileHeader.TimeDateStamp, out var gameName);
29+
if (value)
30+
{
31+
return $"CEG - Contains Strips - {gameName}";
32+
}*/
33+
return "CEG - Contains Strips";
34+
}
35+
36+
return "CEG - Could not determine whether executable contains strips, please report to us on GitHub!";
37+
}
38+
}
39+
40+
return null;
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)