2019-09-27 23:52:24 -07:00
using System ;
2021-03-22 11:13:14 -07:00
using System.Collections.Generic ;
2020-09-10 21:10:32 -07:00
using System.Linq ;
2023-03-09 11:52:28 -05:00
using BinaryObjectScanner.Interfaces ;
2023-09-16 22:08:18 -04:00
using SabreTools.Matching ;
2023-09-16 02:04:47 -04:00
using SabreTools.Serialization.Wrappers ;
2019-09-27 23:52:24 -07:00
2023-03-09 23:19:27 -05:00
namespace BinaryObjectScanner.Protection
2019-09-27 23:52:24 -07:00
{
2021-09-07 23:53:05 -07:00
// This protection was called VOB ProtectCD / ProtectDVD in versions prior to 6
2023-12-01 22:28:21 -07:00
// ProtectDISC 9/10 checks for the presence of CSS on the disc to run, but don't encrypt any sectors or check for keys. Confirmed in Redump entries 78367 and 110095.
2022-05-01 17:17:15 -07:00
public class ProtectDISC : IPortableExecutableCheck
2019-09-27 23:52:24 -07:00
{
2021-08-25 19:37:32 -07:00
/// <inheritdoc/>
2023-09-17 22:37:01 -04:00
public string? CheckPortableExecutable ( string file , PortableExecutable pex , bool includeDebug )
2021-03-22 11:13:14 -07:00
{
2021-09-01 23:09:01 -07:00
// Get the sections from the executable, if possible
2023-09-17 22:37:01 -04:00
var sections = pex . Model . SectionTable ;
2021-09-01 23:09:01 -07:00
if ( sections = = null )
return null ;
2022-12-03 22:17:48 -08:00
// Get the 4th and 5th sections, if they exist (example names: ACE4/ACE5) (Found in Redump entries 94792, 94793)
for ( int i = 3 ; i < sections . Length ; i + + )
2021-03-22 11:13:14 -07:00
{
2022-12-03 22:17:48 -08:00
var nthSectionData = pex . GetSectionData ( i ) ;
2022-12-08 17:19:42 -08:00
if ( nthSectionData = = null )
continue ;
var matchers = new List < ContentMatchSet >
2021-09-01 23:09:01 -07:00
{
2022-12-08 17:19:42 -08:00
// ACE-PCD
2023-11-22 13:28:13 -05:00
new ( new byte? [ ] { 0x41 , 0x43 , 0x45 , 0x2D , 0x50 , 0x43 , 0x44 } , GetVersion6till8 , "ProtectDISC" ) ,
2022-12-08 17:19:42 -08:00
} ;
2021-09-01 23:09:01 -07:00
2023-09-17 22:37:01 -04:00
var match = MatchUtil . GetFirstMatch ( file , nthSectionData , matchers , includeDebug ) ;
2023-11-22 12:22:01 -05:00
if ( ! string . IsNullOrEmpty ( match ) )
2022-12-08 17:19:42 -08:00
return match ;
2019-09-27 23:52:24 -07:00
}
2022-12-03 22:17:48 -08:00
// Get the .data/DATA section, if it exists
var dataSectionRaw = pex . GetFirstSectionData ( ".data" ) ? ? pex . GetFirstSectionData ( "DATA" ) ;
if ( dataSectionRaw ! = null )
2021-09-07 23:53:05 -07:00
{
var matchers = new List < ContentMatchSet >
{
// DCP-BOV + (char)0x00 + (char)0x00
2023-11-22 13:28:13 -05:00
new ( new byte? [ ] { 0x44 , 0x43 , 0x50 , 0x2D , 0x42 , 0x4F , 0x56 , 0x00 , 0x00 } , GetVersion3till6 , "VOB ProtectCD/DVD" ) ,
2021-09-07 23:53:05 -07:00
} ;
2023-09-17 22:37:01 -04:00
var match = MatchUtil . GetFirstMatch ( file , dataSectionRaw , matchers , includeDebug ) ;
2023-11-22 12:22:01 -05:00
if ( ! string . IsNullOrEmpty ( match ) )
2021-09-07 23:53:05 -07:00
return match ;
}
// Get the second to last section
2022-12-09 20:53:25 -08:00
if ( sections . Length > 1 )
2021-09-07 23:53:05 -07:00
{
2022-12-09 20:53:25 -08:00
// Get the n - 1 section strings, if they exist
2023-09-17 22:37:01 -04:00
var strs = pex . GetSectionStrings ( sections . Length - 2 ) ;
2022-12-09 20:53:25 -08:00
if ( strs ! = null )
2021-09-07 23:53:05 -07:00
{
2023-09-17 23:11:32 -04:00
var str = strs . FirstOrDefault ( s = > s . Contains ( "VOB ProtectCD" ) ) ;
2022-12-09 20:53:25 -08:00
if ( str ! = null )
return $"VOB ProtectCD {GetOldVersion(str)}" ;
2022-03-14 23:17:45 -07:00
}
2021-09-07 23:53:05 -07:00
}
2021-09-01 23:09:01 -07:00
// Get the last section (example names: ACE5, akxpxgcv, and piofinqb)
2022-12-09 20:53:25 -08:00
if ( sections . Length > 0 )
2019-09-27 23:52:24 -07:00
{
2023-09-17 22:37:01 -04:00
var lastSectionData = pex . GetSectionData ( sections . Length - 1 ) ;
if ( lastSectionData ! = null )
{
var matchers = new List < ContentMatchSet >
2019-09-27 23:52:24 -07:00
{
2022-12-09 20:53:25 -08:00
// HúMETINF
2023-11-22 13:28:13 -05:00
new ( new byte? [ ] { 0x48 , 0xFA , 0x4D , 0x45 , 0x54 , 0x49 , 0x4E , 0x46 } , GetVersion76till10 , "ProtectDISC" ) ,
2022-12-09 20:53:25 -08:00
// DCP-BOV + (char)0x00 + (char)0x00
2023-11-22 13:28:13 -05:00
new ( new byte? [ ] { 0x44 , 0x43 , 0x50 , 0x2D , 0x42 , 0x4F , 0x56 , 0x00 , 0x00 } , GetVersion3till6 , "VOB ProtectCD/DVD" ) ,
2022-12-09 20:53:25 -08:00
} ;
2023-09-17 22:37:01 -04:00
var match = MatchUtil . GetFirstMatch ( file , lastSectionData , matchers , includeDebug ) ;
2023-11-22 12:22:01 -05:00
if ( ! string . IsNullOrEmpty ( match ) )
2023-09-17 22:37:01 -04:00
return match ;
}
2019-09-27 23:52:24 -07:00
}
2021-09-07 23:53:05 -07:00
// Get the .vob.pcd section, if it exists
2021-09-11 21:03:36 -07:00
bool vobpcdSection = pex . ContainsSection ( ".vob.pcd" , exact : true ) ;
if ( vobpcdSection )
2021-09-07 23:53:05 -07:00
return "VOB ProtectCD" ;
2019-09-27 23:52:24 -07:00
return null ;
}
2022-12-09 20:53:25 -08:00
public static string GetOldVersion ( string matchedString )
2021-09-07 23:53:05 -07:00
{
2022-12-09 20:53:25 -08:00
// Remove unnecessary parts
matchedString = matchedString . Trim ( )
. Replace ( "----====#### " , string . Empty )
. Replace ( " ####====----" , string . Empty ) ;
// Split the string
string [ ] matchedStringArray = matchedString . Split ( ' ' ) ;
// If we have no version
if ( matchedStringArray . Length < = 2 )
return "old" ;
else if ( matchedString . StartsWith ( "VOB ProtectCD with LEGACY SYSIPHOS Support V" ) )
return $"with LEGACY SYSIPHOS Support {matchedStringArray[6].TrimStart('V')}" ;
// Return the version string with leading `V` trimmed
return matchedStringArray [ 2 ] . TrimStart ( 'V' ) ;
2021-09-07 23:53:05 -07:00
}
2023-09-18 15:53:24 -04:00
public static string? GetVersion3till6 ( string file , byte [ ] ? fileContent , List < int > positions )
2021-09-07 23:53:05 -07:00
{
2023-09-18 15:53:24 -04:00
// If we have no content
if ( fileContent = = null )
return null ;
2021-09-07 23:53:05 -07:00
string version = GetVOBVersion ( fileContent , positions [ 0 ] ) ;
if ( version . Length > 0 )
return version ;
return $"5.9-6.0 {GetVOBBuild(fileContent, positions[0])}" ;
}
2023-09-18 15:53:24 -04:00
public static string? GetVersion6till8 ( string file , byte [ ] ? fileContent , List < int > positions )
2019-09-27 23:52:24 -07:00
{
2023-09-18 15:53:24 -04:00
// If we have no content
if ( fileContent = = null )
return null ;
2021-09-01 23:09:01 -07:00
string version , strBuild = string . Empty ;
int index = positions [ 0 ] - 12 ;
2019-09-30 11:08:44 -07:00
2021-09-01 23:09:01 -07:00
// Version 6-7 with Build Number in plain text
2023-11-22 12:22:01 -05:00
#if NET20 | | NET35 | | NET40
2023-11-14 16:10:10 -05:00
byte [ ] temp = new byte [ 4 ] ;
Array . Copy ( fileContent , index , temp , 0 , 4 ) ;
if ( temp . SequenceEqual ( new byte [ ] { 0x0A , 0x0D , 0x0A , 0x0D } ) )
#else
2021-09-01 23:09:01 -07:00
if ( new ArraySegment < byte > ( fileContent , index , 4 ) . SequenceEqual ( new byte [ ] { 0x0A , 0x0D , 0x0A , 0x0D } ) )
2023-11-14 16:10:10 -05:00
#endif
2019-09-27 23:52:24 -07:00
{
2021-09-01 23:09:01 -07:00
index = positions [ 0 ] - 12 - 6 ;
2019-09-27 23:52:24 -07:00
2021-09-01 23:09:01 -07:00
// Version 7
2023-11-22 12:22:01 -05:00
#if NET20 | | NET35 | | NET40
2023-11-14 16:10:10 -05:00
temp = new byte [ 6 ] ;
Array . Copy ( fileContent , index , temp , 0 , 6 ) ;
if ( new string ( temp . Select ( b = > ( char ) b ) . ToArray ( ) ) = = "Henrik" )
#else
2020-09-10 21:10:32 -07:00
if ( new string ( new ArraySegment < byte > ( fileContent , index , 6 ) . Select ( b = > ( char ) b ) . ToArray ( ) ) = = "Henrik" )
2023-11-14 16:10:10 -05:00
#endif
2019-09-27 23:52:24 -07:00
{
2020-09-10 21:10:32 -07:00
version = "7.1-7.5" ;
2021-09-01 23:09:01 -07:00
index = positions [ 0 ] - 12 - 6 - 6 ;
2019-09-27 23:52:24 -07:00
}
2020-09-10 21:10:32 -07:00
2021-09-01 23:09:01 -07:00
// Version 6
2019-09-27 23:52:24 -07:00
else
{
2021-09-01 23:09:01 -07:00
// TODO: Figure out if the version can be more granular
2020-09-10 21:10:32 -07:00
version = "6" ;
2021-09-01 23:09:01 -07:00
index = positions [ 0 ] - 12 - 10 ;
2020-09-10 21:10:32 -07:00
while ( true ) //search for e.g. "Build 050913 - September 2005"
2019-09-27 23:52:24 -07:00
{
2020-09-10 21:10:32 -07:00
if ( Char . IsNumber ( ( char ) fileContent [ index ] ) )
break ;
2021-09-01 23:09:01 -07:00
index - - ; // Search upwards
2019-09-27 23:52:24 -07:00
}
2020-09-10 21:10:32 -07:00
index - = 5 ;
2019-09-27 23:52:24 -07:00
}
2021-09-01 23:09:01 -07:00
2023-11-22 12:22:01 -05:00
#if NET20 | | NET35 | | NET40
2023-11-14 16:10:10 -05:00
temp = new byte [ 6 ] ;
Array . Copy ( fileContent , index , temp , 0 , 6 ) ;
char [ ] arrBuild = temp . Select ( b = > ( char ) b ) . ToArray ( ) ;
#else
2021-09-01 23:09:01 -07:00
char [ ] arrBuild = new ArraySegment < byte > ( fileContent , index , 6 ) . Select ( b = > ( char ) b ) . ToArray ( ) ;
2023-11-14 16:10:10 -05:00
#endif
2021-09-01 23:09:01 -07:00
if ( ! Int32 . TryParse ( new string ( arrBuild ) , out int intBuild ) )
strBuild = $"[Build {new string(arrBuild).Trim()}]" ;
else
strBuild = $"[Build 0x{intBuild:X} / {intBuild}]" ;
return $"{version} {strBuild}" . Trim ( ) ;
2019-09-27 23:52:24 -07:00
}
2020-09-10 21:10:32 -07:00
else
{
2021-09-01 23:09:01 -07:00
index = positions [ 0 ] + 28 ;
2020-09-10 21:10:32 -07:00
if ( fileContent [ index ] = = 0xFB )
return "7.6-7.x" ;
else
return "8.0" ;
}
2019-09-27 23:52:24 -07:00
}
2023-09-18 15:53:24 -04:00
public static string? GetVersion76till10 ( string file , byte [ ] ? fileContent , List < int > positions )
2019-09-27 23:52:24 -07:00
{
2023-09-18 15:53:24 -04:00
// If we have no content
if ( fileContent = = null )
return null ;
2021-09-01 23:09:01 -07:00
int index = positions [ 0 ] + 37 ;
2020-09-10 21:10:32 -07:00
byte subversion = fileContent [ index ] ;
2021-09-01 23:09:01 -07:00
index + = 2 ;
2020-09-10 21:10:32 -07:00
byte version = fileContent [ index ] ;
2021-09-01 23:09:01 -07:00
index = positions [ 0 ] + 49 ;
int irefBuild = BitConverter . ToInt32 ( fileContent , index ) ;
index = positions [ 0 ] + 53 ;
2020-09-10 21:10:32 -07:00
byte versionindicatorPD9 = fileContent [ index ] ;
2021-09-01 23:09:01 -07:00
index = positions [ 0 ] + 0x40 ;
2020-09-10 21:10:32 -07:00
byte subsubversionPD9x = fileContent [ index ] ;
index + + ;
byte subversionPD9x2 = fileContent [ index ] ;
index + + ;
byte subversionPD9x1 = fileContent [ index ] ;
2019-09-30 11:08:44 -07:00
2021-09-01 23:09:01 -07:00
// Version 7
2020-09-10 21:10:32 -07:00
if ( version = = 0xAC )
2021-09-01 23:09:01 -07:00
{
// TODO: Figure out if the version can be more granular
return $"7.{subversion ^ 0x43} [Build 0x{irefBuild:X} / {irefBuild}]" ;
}
2020-09-10 21:10:32 -07:00
2021-09-01 23:09:01 -07:00
// Version 8
2020-09-10 21:10:32 -07:00
else if ( version = = 0xA2 )
2019-09-27 23:52:24 -07:00
{
2020-09-10 21:10:32 -07:00
if ( subversion = = 0x46 )
2019-09-27 23:52:24 -07:00
{
2020-09-10 21:10:32 -07:00
if ( ( irefBuild & 0x3A00 ) = = 0x3A00 )
2021-09-01 23:09:01 -07:00
return $"8.2 [Build 0x{irefBuild:X} / {irefBuild}]" ;
2020-09-10 21:10:32 -07:00
else
2021-09-01 23:09:01 -07:00
return $"8.1 [Build 0x{irefBuild:X} / {irefBuild}]" ;
2019-09-27 23:52:24 -07:00
}
2020-09-10 21:10:32 -07:00
2021-09-01 23:09:01 -07:00
// TODO: Figure out if the version can be more granular
return $"8.{subversion ^ 0x47} [Build 0x{irefBuild:X} / {irefBuild}]" ;
2020-09-10 21:10:32 -07:00
}
2021-09-01 23:09:01 -07:00
// Version 9
2020-09-10 21:10:32 -07:00
else if ( version = = 0xA3 )
{
2021-09-01 23:09:01 -07:00
// Version removed or not given
2020-09-10 21:10:32 -07:00
if ( ( subversionPD9x2 = = 0x5F & & subversionPD9x1 = = 0x61 ) | | ( subversionPD9x1 = = 0 & & subversionPD9x2 = = 0 ) )
2019-09-27 23:52:24 -07:00
{
2020-09-10 21:10:32 -07:00
if ( versionindicatorPD9 = = 0xB )
2019-09-27 23:52:24 -07:00
{
2021-09-01 23:09:01 -07:00
return $"9.0-9.4 [Build 0x{irefBuild:X} / {irefBuild}]" ;
2020-09-10 21:10:32 -07:00
}
else if ( versionindicatorPD9 = = 0xC )
{
2021-09-01 23:09:01 -07:00
// TODO: Figure out if the version can be more granular
2020-09-10 21:10:32 -07:00
if ( subversionPD9x2 = = 0x5F & & subversionPD9x1 = = 0x61 )
2021-09-01 23:09:01 -07:00
return $"9.5-9.11 [Build 0x{irefBuild:X} / {irefBuild}]" ;
2020-09-10 21:10:32 -07:00
else if ( subversionPD9x1 = = 0 & & subversionPD9x2 = = 0 )
2021-09-01 23:09:01 -07:00
return $"9.11-9.20 [Build 0x{irefBuild:X} / {irefBuild}]" ;
2020-09-10 21:10:32 -07:00
}
2019-09-27 23:52:24 -07:00
}
2021-09-01 23:09:01 -07:00
else
{
return $"9.{subversionPD9x1}{subversionPD9x2}.{subsubversionPD9x} [Build 0x{irefBuild:X} / {irefBuild}]" ;
}
2020-09-10 21:10:32 -07:00
}
2021-09-01 23:09:01 -07:00
// Version 10
2020-09-10 21:10:32 -07:00
else if ( version = = 0xA0 )
{
2021-09-01 23:09:01 -07:00
// Version removed -- TODO: Figure out if the version can be more granular
2020-09-10 21:10:32 -07:00
if ( subversionPD9x1 ! = 0 | | subversionPD9x2 ! = 0 )
2021-09-01 23:09:01 -07:00
return $"10.{subversionPD9x1}.{subsubversionPD9x} [Build 0x{irefBuild:X} / {irefBuild}]" ;
2019-09-27 23:52:24 -07:00
else
2021-09-01 23:09:01 -07:00
return $"10.x [Build 0x{irefBuild:X} / {irefBuild}]" ;
2020-09-10 21:10:32 -07:00
}
2019-09-27 23:52:24 -07:00
2021-09-01 23:09:01 -07:00
// Unknown version
2020-09-10 21:10:32 -07:00
else
{
2021-09-01 23:09:01 -07:00
return $"7.6-10.x [Build 0x{irefBuild:X} / {irefBuild}]" ;
2019-09-27 23:52:24 -07:00
}
2020-09-10 21:10:32 -07:00
2021-08-23 22:05:18 -07:00
return string . Empty ;
2019-09-27 23:52:24 -07:00
}
2022-12-08 17:19:42 -08:00
2021-09-07 23:53:05 -07:00
private static string GetVOBBuild ( byte [ ] fileContent , int position )
{
if ( ! char . IsNumber ( ( char ) fileContent [ position - 13 ] ) )
return string . Empty ; //Build info removed
int build = BitConverter . ToInt16 ( fileContent , position - 4 ) ; // Check if this is supposed to be a 4-byte read
return $" (Build {build})" ;
}
// TODO: Ensure that this version finding works for all known versions
private static string GetVOBVersion ( byte [ ] fileContent , int position )
{
byte version = fileContent [ position - 2 ] ;
byte subVersion = ( byte ) ( ( fileContent [ position - 3 ] & 0xF0 ) > > 4 ) ;
byte subSubVersion = ( byte ) ( ( fileContent [ position - 4 ] & 0xF0 ) > > 4 ) ;
return $"{version}.{subVersion}.{subSubVersion}" ;
}
2019-09-27 23:52:24 -07:00
}
}