Skip to content

Commit 9eb74a4

Browse files
committed
SecuROM cleanup
1 parent f263781 commit 9eb74a4

File tree

1 file changed

+58
-51
lines changed

1 file changed

+58
-51
lines changed

BinaryObjectScanner/Protection/SecuROM.cs

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ public class SecuROM : IExecutableCheck<PortableExecutable>, IPathCheck
1616
/// <summary>
1717
/// Matches hash of the Release Control-encrypted executable to known hashes
1818
/// </summary>
19-
// Allegedly, some version of Runaway: A Twist of Fate has RC
20-
private static readonly Dictionary<string, string> MatroschkaHashDictionary = new Dictionary<string, string>()
19+
/// <remarks>Allegedly, some version of Runaway: A Twist of Fate has RC</remarks>
20+
private static readonly Dictionary<string, string> MatroschkaHashDictionary = new()
2121
{
2222
{"C6DFF6B08EE126893840E107FD4EC9F6", "Alice - Madness Returns (USA)+(Europe)"},
2323
{"D7703D32B72185358D58448B235BD55E", "Arcania - Gothic 4 - Not in redump yet"},
@@ -62,9 +62,10 @@ public class SecuROM : IExecutableCheck<PortableExecutable>, IPathCheck
6262
};
6363

6464
/// <summary>
65-
/// If hash isn't currently known, check size and pathname of the encrypted executable to determine if alt or entirely missing
65+
/// If hash isn't currently known, check size and pathname of the encrypted executable
66+
/// to determine if alt or entirely missing
6667
/// </summary>
67-
private static readonly Dictionary<uint, string> MatroschkaSizeFilenameDictionary = new Dictionary<uint, string>()
68+
private static readonly Dictionary<uint, string> MatroschkaSizeFilenameDictionary = new()
6869
{
6970
{4646091, "hp8.aec"},
7071
{5124592, "output\\LaunchGTAIV.aec"},
@@ -105,7 +106,6 @@ public class SecuROM : IExecutableCheck<PortableExecutable>, IPathCheck
105106
return paModule;
106107

107108
// Check if executable contains a SecuROM Matroschka Package
108-
109109
var package = exe.MatroschkaPackage;
110110
if (package != null)
111111
{
@@ -230,7 +230,6 @@ public List<string> CheckDirectoryPath(string path, List<string>? files)
230230
/// <summary>
231231
/// Try to get the SecuROM v4 version from the overlay, if possible
232232
/// </summary>
233-
/// <param name="exe">Executable to retrieve the overlay from</param>
234233
/// <returns>The version on success, null otherwise</returns>
235234
private static string? GetV4Version(PortableExecutable exe)
236235
{
@@ -276,6 +275,10 @@ public List<string> CheckDirectoryPath(string path, List<string>? files)
276275
return $"{major}.{minor}.{patch}.{revision}";
277276
}
278277

278+
/// <summary>
279+
/// Try to get the SecuROM v5 version from section data, if possible
280+
/// </summary>
281+
/// <returns>The version on success, null otherwise</returns>
279282
private static string? GetV5Version(string file, byte[]? fileContent, List<int> positions)
280283
{
281284
// If we have no content
@@ -313,7 +316,10 @@ public List<string> CheckDirectoryPath(string path, List<string>? files)
313316
return $"{major}.{minor[0]}{minor[1]}.{patch[0]}{patch[1]}.{revision[0]}{revision[1]}{revision[2]}{revision[3]}";
314317
}
315318

316-
// These live in the MS-DOS stub, for some reason
319+
/// <summary>
320+
/// Try to get the SecuROM v7 version from MS-DOS stub data, if possible
321+
/// </summary>
322+
/// <returns>The version on success, null otherwise</returns>
317323
private static string GetV7Version(PortableExecutable exe)
318324
{
319325
// If SecuROM is stripped, the MS-DOS stub might be shorter.
@@ -348,6 +354,10 @@ private static string GetV7Version(PortableExecutable exe)
348354
return "7 remnants";
349355
}
350356

357+
/// <summary>
358+
/// Try to get the SecuROM v8 (White Label) version from the .data section, if possible
359+
/// </summary>
360+
/// <returns>The version on success, null otherwise</returns>
351361
private static string GetV8WhiteLabelVersion(PortableExecutable exe)
352362
{
353363
// Get the .data/DATA section, if it exists
@@ -379,6 +389,47 @@ private static string GetV8WhiteLabelVersion(PortableExecutable exe)
379389
return $"{major}.{minor:00}.{patch:0000}";
380390
}
381391

392+
/// <summary>
393+
/// Helper method to run checks on a SecuROM Matroschka Package
394+
/// </summary>
395+
private static string? CheckMatroschkaPackage(SecuROMMatroschkaPackage package, bool includeDebug)
396+
{
397+
// Check for all 0x00 required, as at least one known non-RC matroschka has the field, just empty.
398+
if (package.KeyHexString == null || package.KeyHexString.Trim('\0').Length == 0)
399+
return "SecuROM Matroschka Package";
400+
401+
if (package.Entries == null || package.Entries.Length == 0)
402+
return "SecuROM Matroschka Package - No Entries? - Please report to us on GitHub";
403+
404+
// The second entry in a Release Control matroschka package is always the encrypted executable
405+
var entry = package.Entries[1];
406+
407+
if (entry.MD5 == null || entry.MD5.Length == 0)
408+
return "SecuROM Matroschka Package - No MD5? - Please report to us on GitHub";
409+
410+
string md5String = BitConverter.ToString(entry.MD5!);
411+
md5String = md5String.ToUpperInvariant().Replace("-", string.Empty);
412+
413+
// TODO: Not used yet, but will be in the future
414+
var fileData = package.ReadFileData(entry, includeDebug);
415+
416+
// Check if encrypted executable is known via hash
417+
if (MatroschkaHashDictionary.TryGetValue(md5String, out var gameName))
418+
return $"SecuROM Release Control - {gameName}";
419+
420+
// If not known, check if encrypted executable is likely an alt signing of a known executable
421+
// Filetime could be checked here, but if it was signed at a different time, the time will vary anyways
422+
var readPathBytes = entry.Path;
423+
if (readPathBytes == null || readPathBytes.Length == 0)
424+
return $"SecuROM Release Control - Unknown executable {md5String},{entry.Size} - Please report to us on GitHub!";
425+
426+
var readPathName = Encoding.ASCII.GetString(readPathBytes).TrimEnd('\0');
427+
if (MatroschkaSizeFilenameDictionary.TryGetValue(entry.Size, out var pathName) && pathName == readPathName)
428+
return $"SecuROM Release Control - Unknown possible alt executable of size {entry.Size} - Please report to us on GitHub";
429+
430+
return $"SecuROM Release Control - Unknown executable {readPathName},{md5String},{entry.Size} - Please report to us on GitHub";
431+
}
432+
382433
/// <summary>
383434
/// Helper method to check if a given PortableExecutable is a SecuROM PA module.
384435
/// </summary>
@@ -426,49 +477,5 @@ private static string GetV8WhiteLabelVersion(PortableExecutable exe)
426477

427478
return null;
428479
}
429-
430-
/// <summary>
431-
/// Helper method to run checks on a SecuROM Matroschka Package
432-
/// </summary>
433-
private static string? CheckMatroschkaPackage(SecuROMMatroschkaPackage package, bool includeDebug)
434-
{
435-
// Check for all 0x00 required, as at least one known non-RC matroschka has the field, just empty.
436-
if (package.KeyHexString == null || package.KeyHexString.Trim('\0').Length == 0)
437-
return "SecuROM Matroschka Package";
438-
439-
if (package.Entries == null || package.Entries.Length == 0)
440-
return "SecuROM Matroschka Package - No Entries? Please report";
441-
442-
// The second entry in a Release Control matroschka package is always the encrypted executable
443-
var entry = package.Entries[1];
444-
445-
if (entry.MD5 == null || entry.MD5.Length == 0)
446-
return "SecuROM Matroschka Package - No MD5? Please report";
447-
448-
string md5String = BitConverter.ToString(entry.MD5!);
449-
md5String = md5String.ToUpperInvariant().Replace("-", string.Empty);
450-
451-
// Not used yet, but will be in the future
452-
var fileData = package.ReadFileData(entry, includeDebug);
453-
454-
// Check if encrypted executable is known via hash
455-
if (MatroschkaHashDictionary.TryGetValue(md5String, out var gameName))
456-
{
457-
// Returning "SecuROM Matroschka Package" technically redundant since implied.
458-
return $"SecuROM Release Control - {gameName}";
459-
}
460-
461-
// If not known, check if encrypted executable is likely an alt signing of a known executable
462-
// Filetime could be checked here, but if it was signed at a different time, the time will vary anyways
463-
var readPathBytes = entry.Path;
464-
if (readPathBytes == null || readPathBytes.Length == 0)
465-
return $"SecuROM Release Control - Unknown executable {md5String},{entry.Size}, please report to us on Github!";
466-
467-
var readPathName = Encoding.ASCII.GetString(readPathBytes).TrimEnd('\0');
468-
if (MatroschkaSizeFilenameDictionary.TryGetValue(entry.Size, out var pathName) && pathName == readPathName)
469-
return $"SecuROM Release Control - Unknown possible alt executable of size {entry.Size}, please report to us on Github!";
470-
471-
return $"SecuROM Release Control - Unknown executable {readPathName},{md5String},{entry.Size}, please report to us on Github!";
472-
}
473480
}
474481
}

0 commit comments

Comments
 (0)