2019-09-27 23:52:24 -07:00
using System ;
2021-07-18 09:44:23 -07:00
using System.Collections.Concurrent ;
2019-09-27 23:52:24 -07:00
using System.Collections.Generic ;
2021-09-02 22:32:06 -07:00
using System.Linq ;
2020-10-26 23:30:35 -07:00
using System.Text ;
2022-03-14 10:40:44 -07:00
using BurnOutSharp.ExecutableType.Microsoft.PE ;
2022-05-01 17:41:50 -07:00
using BurnOutSharp.Interfaces ;
2021-03-21 22:19:38 -07:00
using BurnOutSharp.Matching ;
2021-08-25 15:09:42 -07:00
using BurnOutSharp.Tools ;
2019-09-27 23:52:24 -07:00
namespace BurnOutSharp.ProtectionType
{
2021-09-10 16:10:15 -07:00
// TODO: Investigate SecuROM for Macintosh
2022-05-01 17:23:00 -07:00
public class SecuROM : IPathCheck , IPortableExecutableCheck
2019-09-27 23:52:24 -07:00
{
2021-09-02 22:32:06 -07:00
/// <inheritdoc/>
2022-05-01 17:17:15 -07:00
public string CheckPortableExecutable ( string file , PortableExecutable pex , bool includeDebug )
2021-03-23 09:52:09 -07:00
{
2021-09-02 22:32:06 -07:00
// Get the sections from the executable, if possible
var sections = pex ? . SectionTable ;
if ( sections = = null )
return null ;
2022-04-02 16:12:23 -07:00
string name = pex . FileDescription ;
2022-03-15 22:09:28 -07:00
if ( ! string . IsNullOrWhiteSpace ( name ) & & name . Contains ( "SecuROM PA" ) )
2022-04-01 10:16:31 -07:00
return $"SecuROM PA v{Utilities.GetInternalVersion(pex)}" ;
2022-03-15 22:09:28 -07:00
// Get the matrosch section, if it exists
bool matroschSection = pex . ContainsSection ( "matrosch" , exact : true ) ;
if ( matroschSection )
return $"SecuROM Matroschka Package" ;
2021-09-02 22:32:06 -07:00
// Get the .securom section, if it exists
2021-09-11 21:03:36 -07:00
bool securomSection = pex . ContainsSection ( ".securom" , exact : true ) ;
if ( securomSection )
2022-03-14 23:44:17 -07:00
return $"SecuROM {GetV7Version(pex)}" ;
2021-09-02 22:32:06 -07:00
2022-03-15 22:09:28 -07:00
// TODO: This needs a lot of verification, including version
// Get the .shr section, if it exists
bool shrSection = pex . ContainsSection ( ".shr" , exact : true ) ;
if ( shrSection )
return $"SecuROM 8 (White Label)" ;
2022-03-15 22:11:37 -07:00
// Get the .sll section, if it exists
2022-03-15 22:09:28 -07:00
bool sllSection = pex . ContainsSection ( ".sll" , exact : true ) ;
if ( sllSection )
return $"SecuROM SLL Protected (for SecuROM v8.x)" ;
2021-09-02 22:32:06 -07:00
// Search after the last section
2022-03-14 23:32:19 -07:00
// TODO: Figure out how to do this in a more reasonable way
2021-09-02 22:32:06 -07:00
var lastSection = sections . LastOrDefault ( ) ;
if ( lastSection ! = null )
2021-07-17 23:40:16 -07:00
{
2021-09-02 22:32:06 -07:00
int sectionAddr = ( int ) lastSection . PointerToRawData ;
int sectionEnd = sectionAddr + ( int ) lastSection . VirtualSize ;
2022-03-15 10:39:06 -07:00
var postLastSectionData = pex . ReadArbitraryRange ( rangeStart : sectionEnd ) ;
if ( postLastSectionData ! = null )
2021-07-17 23:40:16 -07:00
{
2022-03-15 10:39:06 -07:00
var matchers = new List < ContentMatchSet >
{
// AddD + (char)0x03 + (char)0x00 + (char)0x00 + (char)0x00)
new ContentMatchSet ( new byte? [ ] { 0x41 , 0x64 , 0x64 , 0x44 , 0x03 , 0x00 , 0x00 , 0x00 } , GetV4Version , "SecuROM" ) ,
} ;
2021-09-02 22:32:06 -07:00
2022-03-15 10:39:06 -07:00
string match = MatchUtil . GetFirstMatch ( file , postLastSectionData , matchers , includeDebug ) ;
if ( ! string . IsNullOrWhiteSpace ( match ) )
return match ;
}
2021-09-02 22:32:06 -07:00
}
2021-03-23 09:52:09 -07:00
2021-09-02 22:32:06 -07:00
// Get the sections 5+, if they exist (example names: .fmqyrx, .vcltz, .iywiak)
for ( int i = 4 ; i < sections . Length ; i + + )
{
var nthSection = sections [ i ] ;
2022-03-14 23:28:31 -07:00
string nthSectionName = nthSection . NameString ;
2021-09-02 22:32:06 -07:00
if ( nthSection ! = null & & nthSectionName ! = ".idata" & & nthSectionName ! = ".rsrc" )
2021-07-17 23:40:16 -07:00
{
2022-03-14 23:28:31 -07:00
var nthSectionData = pex . ReadRawSection ( nthSectionName , first : true ) ;
2022-03-14 23:17:45 -07:00
if ( nthSectionData ! = null )
2021-09-02 22:32:06 -07:00
{
2022-03-14 23:17:45 -07:00
var matchers = new List < ContentMatchSet >
{
// (char)0xCA + (char)0xDD + (char)0xDD + (char)0xAC + (char)0x03
new ContentMatchSet ( new byte? [ ] { 0xCA , 0xDD , 0xDD , 0xAC , 0x03 } , GetV5Version , "SecuROM" ) ,
} ;
2021-09-02 22:32:06 -07:00
2022-03-14 23:17:45 -07:00
string match = MatchUtil . GetFirstMatch ( file , nthSectionData , matchers , includeDebug ) ;
if ( ! string . IsNullOrWhiteSpace ( match ) )
return match ;
}
2021-09-02 22:32:06 -07:00
}
}
// Get the .rdata section, if it exists
2021-09-11 16:47:25 -07:00
if ( pex . ResourceDataSectionRaw ! = null )
2021-09-02 22:32:06 -07:00
{
var matchers = new List < ContentMatchSet >
2021-07-17 23:40:16 -07:00
{
2021-09-02 22:32:06 -07:00
// drm_pagui_doit -- shortened from "_and_play.dll + (char)0x00 + drm_pagui_doit"
2021-09-11 16:47:25 -07:00
new ContentMatchSet ( new byte? [ ]
{
0x64 , 0x72 , 0x6D , 0x5F , 0x70 , 0x61 , 0x67 , 0x75 ,
0x69 , 0x5F , 0x64 , 0x6F , 0x69 , 0x74
2022-04-01 10:16:31 -07:00
} , Utilities . GetInternalVersion , "SecuROM Product Activation" ) ,
2021-09-02 22:32:06 -07:00
// TODO: Re-enable this one if the above undermatches somehow
// // S + (char)0x00 + e + (char)0x00 + c + (char)0x00 + u + (char)0x00 + R + (char)0x00 + O + (char)0x00 + M + (char)0x00 + + (char)0x00 + P + (char)0x00 + A + (char)0x00
2021-09-11 16:47:25 -07:00
// new ContentMatchSet(new byte?[]
// {
// 0x53, 0x00, 0x65, 0x00, 0x63, 0x00, 0x75, 0x00,
// 0x52, 0x00, 0x4F, 0x00, 0x4D, 0x00, 0x20, 0x00,
// 0x50, 0x00, 0x41, 0x00
2022-04-01 10:16:31 -07:00
// }, Utilities.GetInternalVersion, "SecuROM Product Activation"),
2021-09-02 22:32:06 -07:00
} ;
2021-09-11 16:47:25 -07:00
string match = MatchUtil . GetFirstMatch ( file , pex . ResourceDataSectionRaw , matchers , includeDebug ) ;
2021-09-02 22:32:06 -07:00
if ( ! string . IsNullOrWhiteSpace ( match ) )
return match ;
}
2021-07-17 23:06:11 -07:00
2021-09-02 22:32:06 -07:00
// Get the .cms_d and .cms_t sections, if they exist -- TODO: Confirm if both are needed or either/or is fine
2021-09-11 21:03:36 -07:00
bool cmsdSection = pex . ContainsSection ( ".cmd_d" , true ) ;
bool cmstSection = pex . ContainsSection ( ".cms_t" , true ) ;
if ( cmsdSection | | cmstSection )
2021-09-02 22:32:06 -07:00
return $"SecuROM 1-3" ;
2021-03-23 09:52:09 -07:00
2021-09-02 22:32:06 -07:00
return null ;
2021-08-25 19:37:32 -07:00
}
2021-03-23 09:52:09 -07:00
2021-02-26 00:32:09 -08:00
/// <inheritdoc/>
2021-07-18 09:44:23 -07:00
public ConcurrentQueue < string > CheckDirectoryPath ( string path , IEnumerable < string > files )
2019-09-27 23:52:24 -07:00
{
2021-03-23 10:36:14 -07:00
var matchers = new List < PathMatchSet >
2019-09-27 23:52:24 -07:00
{
2021-03-23 10:36:14 -07:00
// TODO: Verify if these are OR or AND
new PathMatchSet ( new PathMatch ( "CMS16.DLL" , useEndsWith : true ) , "SecuROM" ) ,
new PathMatchSet ( new PathMatch ( "CMS_95.DLL" , useEndsWith : true ) , "SecuROM" ) ,
new PathMatchSet ( new PathMatch ( "CMS_NT.DLL" , useEndsWith : true ) , "SecuROM" ) ,
new PathMatchSet ( new PathMatch ( "CMS32_95.DLL" , useEndsWith : true ) , "SecuROM" ) ,
new PathMatchSet ( new PathMatch ( "CMS32_NT.DLL" , useEndsWith : true ) , "SecuROM" ) ,
// TODO: Verify if these are OR or AND
new PathMatchSet ( new PathMatch ( "SINTF32.DLL" , useEndsWith : true ) , "SecuROM New" ) ,
new PathMatchSet ( new PathMatch ( "SINTF16.DLL" , useEndsWith : true ) , "SecuROM New" ) ,
new PathMatchSet ( new PathMatch ( "SINTFNT.DLL" , useEndsWith : true ) , "SecuROM New" ) ,
2022-03-14 09:03:43 -07:00
// TODO: Find more samples of this for different versions
new PathMatchSet ( new List < PathMatch >
{
new PathMatch ( "securom_v7_01.bak" , useEndsWith : true ) ,
new PathMatch ( "securom_v7_01.dat" , useEndsWith : true ) ,
new PathMatch ( "securom_v7_01.tmp" , useEndsWith : true ) ,
} , "SecuROM 7.01" ) ,
2021-03-23 10:36:14 -07:00
} ;
2021-03-23 13:35:12 -07:00
return MatchUtil . GetAllMatches ( files , matchers , any : true ) ;
2021-03-19 15:41:49 -07:00
}
/// <inheritdoc/>
public string CheckFilePath ( string path )
{
2021-03-23 10:36:14 -07:00
var matchers = new List < PathMatchSet >
2021-03-19 15:41:49 -07:00
{
2021-03-23 10:36:14 -07:00
new PathMatchSet ( new PathMatch ( "CMS16.DLL" , useEndsWith : true ) , "SecuROM" ) ,
new PathMatchSet ( new PathMatch ( "CMS_95.DLL" , useEndsWith : true ) , "SecuROM" ) ,
new PathMatchSet ( new PathMatch ( "CMS_NT.DLL" , useEndsWith : true ) , "SecuROM" ) ,
new PathMatchSet ( new PathMatch ( "CMS32_95.DLL" , useEndsWith : true ) , "SecuROM" ) ,
new PathMatchSet ( new PathMatch ( "CMS32_NT.DLL" , useEndsWith : true ) , "SecuROM" ) ,
new PathMatchSet ( new PathMatch ( "SINTF32.DLL" , useEndsWith : true ) , "SecuROM New" ) ,
new PathMatchSet ( new PathMatch ( "SINTF16.DLL" , useEndsWith : true ) , "SecuROM New" ) ,
new PathMatchSet ( new PathMatch ( "SINTFNT.DLL" , useEndsWith : true ) , "SecuROM New" ) ,
2022-03-14 09:03:43 -07:00
new PathMatchSet ( new PathMatch ( "securom_v7_01.bak" , useEndsWith : true ) , "SecuROM 7.01" ) ,
new PathMatchSet ( new PathMatch ( "securom_v7_01.dat" , useEndsWith : true ) , "SecuROM 7.01" ) ,
new PathMatchSet ( new PathMatch ( "securom_v7_01.tmp" , useEndsWith : true ) , "SecuROM 7.01" ) ,
2021-03-23 10:36:14 -07:00
} ;
return MatchUtil . GetFirstMatch ( path , matchers , any : true ) ;
2019-09-27 23:52:24 -07:00
}
2021-03-22 11:43:51 -07:00
public static string GetV4Version ( string file , byte [ ] fileContent , List < int > positions )
2019-09-27 23:52:24 -07:00
{
2021-03-22 11:43:51 -07:00
int index = positions [ 0 ] + 8 ; // Begin reading after "AddD"
2020-09-10 21:10:32 -07:00
char version = ( char ) fileContent [ index ] ;
index + = 2 ;
2019-09-30 11:08:44 -07:00
2020-10-26 23:30:35 -07:00
string subVersion = Encoding . ASCII . GetString ( fileContent , index , 2 ) ;
2020-09-10 21:10:32 -07:00
index + = 3 ;
2020-10-26 23:30:35 -07:00
string subSubVersion = Encoding . ASCII . GetString ( fileContent , index , 2 ) ;
2020-09-10 21:10:32 -07:00
index + = 3 ;
2020-10-26 23:30:35 -07:00
string subSubSubVersion = Encoding . ASCII . GetString ( fileContent , index , 4 ) ;
2020-09-10 21:10:32 -07:00
if ( ! char . IsNumber ( version ) )
return "(very old, v3 or less)" ;
return $"{version}.{subVersion}.{subSubVersion}.{subSubSubVersion}" ;
2019-09-27 23:52:24 -07:00
}
2021-03-22 11:43:51 -07:00
public static string GetV5Version ( string file , byte [ ] fileContent , List < int > positions )
2019-09-27 23:52:24 -07:00
{
2021-03-22 11:43:51 -07:00
int index = positions [ 0 ] + 8 ; // Begin reading after "ÊÝݬ"
2020-09-10 21:10:32 -07:00
byte version = ( byte ) ( fileContent [ index ] & 0x0F ) ;
index + = 2 ;
byte [ ] subVersion = new byte [ 2 ] ;
subVersion [ 0 ] = ( byte ) ( fileContent [ index ] ^ 36 ) ;
index + + ;
subVersion [ 1 ] = ( byte ) ( fileContent [ index ] ^ 28 ) ;
index + = 2 ;
byte [ ] subSubVersion = new byte [ 2 ] ;
subSubVersion [ 0 ] = ( byte ) ( fileContent [ index ] ^ 42 ) ;
index + + ;
subSubVersion [ 0 ] = ( byte ) ( fileContent [ index ] ^ 8 ) ;
index + = 2 ;
byte [ ] subSubSubVersion = new byte [ 4 ] ;
subSubSubVersion [ 0 ] = ( byte ) ( fileContent [ index ] ^ 16 ) ;
index + + ;
subSubSubVersion [ 1 ] = ( byte ) ( fileContent [ index ] ^ 116 ) ;
index + + ;
subSubSubVersion [ 2 ] = ( byte ) ( fileContent [ index ] ^ 34 ) ;
index + + ;
subSubSubVersion [ 3 ] = ( byte ) ( fileContent [ index ] ^ 22 ) ;
if ( version = = 0 | | version > 9 )
2021-03-22 16:25:40 -07:00
return string . Empty ;
2020-09-10 21:10:32 -07:00
return $"{version}.{subVersion[0]}{subVersion[1]}.{subSubVersion[0]}{subSubVersion[1]}.{subSubSubVersion[0]}{subSubSubVersion[1]}{subSubSubVersion[2]}{subSubSubVersion[3]}" ;
2019-09-27 23:52:24 -07:00
}
2022-03-14 23:44:17 -07:00
// These live in the MS-DOS stub, for some reason
private static string GetV7Version ( PortableExecutable pex )
2019-09-27 23:52:24 -07:00
{
2022-03-14 23:44:17 -07:00
int index = 172 ; // 64 bytes for DOS stub, 236 bytes in total
byte [ ] bytes = new ReadOnlySpan < byte > ( pex . DOSStubHeader . ExecutableData , index , 4 ) . ToArray ( ) ;
2020-09-10 21:10:32 -07:00
//SecuROM 7 new and 8
if ( bytes [ 3 ] = = 0x5C ) // if (bytes[0] == 0xED && bytes[3] == 0x5C {
{
return $"{bytes[0] ^ 0xEA}.{bytes[1] ^ 0x2C:00}.{bytes[2] ^ 0x8:0000}" ;
}
2019-09-30 11:08:44 -07:00
2020-09-10 21:10:32 -07:00
// SecuROM 7 old
else
2019-09-27 23:52:24 -07:00
{
2022-03-14 23:44:17 -07:00
index = 58 ; // 64 bytes for DOS stub, 122 bytes in total
bytes = new ReadOnlySpan < byte > ( pex . DOSStubHeader . ExecutableData , index , 2 ) . ToArray ( ) ;
2020-09-10 21:10:32 -07:00
return $"7.{bytes[0] ^ 0x10:00}.{bytes[1] ^ 0x10:0000}" ; //return "7.01-7.10"
2019-09-27 23:52:24 -07:00
}
}
}
}