@@ -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