33#if NET35_OR_GREATER || NETCOREAPP
44using System . Linq ;
55#endif
6+ using System . Security . Cryptography ;
67using System . Text ;
78using System . Text . RegularExpressions ;
89using System . Xml ;
@@ -1168,7 +1169,7 @@ public static bool IsFixedSS(byte[] ss)
11681169 if ( ! GetXGDType ( ss , out int xgdType ) )
11691170 return false ;
11701171
1171- // Valid XGD1 is always fixed
1172+ // XGD1 can't be fixed
11721173 if ( xgdType == 1 )
11731174 return true ;
11741175
@@ -1209,7 +1210,7 @@ public static bool IsFixedSS(byte[] ss)
12091210 if ( ss [ rtOffset + 67 ] != 0x01 )
12101211 return false ;
12111212 }
1212- else
1213+ else if ( xgdType == 2 )
12131214 {
12141215 // Check for a cleaned XGD2
12151216 int rtOffset = 0x204 ;
@@ -1247,33 +1248,8 @@ public static bool IsFixedSS(byte[] ss)
12471248 return false ;
12481249 }
12491250
1250- // Determine challenge table offset
1251- int ccrt_offset = 0 ;
1252- if ( xgdType == 2 )
1253- ccrt_offset = 0x200 ;
1254- else if ( xgdType == 3 )
1255- ccrt_offset = 0x20 ;
1256-
1257- // Check for empty challenge responses
1258- int [ ] entry_offsets = [ 0 , 9 , 18 , 27 , 36 , 45 , 54 , 63 ] ;
1259- int [ ] entry_lengths = [ 8 , 8 , 8 , 8 , 4 , 4 , 4 , 4 ] ;
1260- for ( int i = 0 ; i < entry_offsets . Length ; i ++ )
1261- {
1262- bool emptyResponse = true ;
1263- for ( int b = 0 ; b < entry_lengths [ i ] ; b ++ )
1264- {
1265- if ( ss [ ccrt_offset + entry_offsets [ i ] + b ] != 0x00 )
1266- {
1267- emptyResponse = false ;
1268- break ;
1269- }
1270- }
1271-
1272- if ( emptyResponse )
1273- return false ;
1274- }
1275-
1276- // TODO: Check for correct challenge responses
1251+ // Check challenge responses
1252+ FixSS ( ss , false ) ;
12771253
12781254 return true ;
12791255 }
@@ -1306,7 +1282,7 @@ public static bool FixSS(string rawSS, string fixedSS)
13061282 /// </summary>
13071283 /// <param name="ss">Byte array of raw SS sector</param>
13081284 /// <returns>True if successful, false otherwise</returns>
1309- public static bool FixSS ( byte [ ] ss )
1285+ public static bool FixSS ( byte [ ] ss , bool write = true )
13101286 {
13111287 // Must be entire sector
13121288 if ( ss . Length != 2048 )
@@ -1337,34 +1313,37 @@ public static bool FixSS(byte[] ss)
13371313 switch ( xgdType )
13381314 {
13391315 case 1 :
1340- // Cannot clean XGD1 SS.bin
1341- break ;
1316+ // Cannot clean or fix XGD1 SS
1317+ return true ;
13421318
13431319 case 2 :
13441320 // Fix standard SSv1 ss.bin
1345- ss [ 552 ] = 1 ; // 0x01
1346- ss [ 553 ] = 0 ; // 0x00
1347- ss [ 555 ] = 0 ; // 0x00
1348- ss [ 556 ] = 0 ; // 0x00
1349-
1350- ss [ 561 ] = 91 ; // 0x5B
1351- ss [ 562 ] = 0 ; // 0x00
1352- ss [ 564 ] = 0 ; // 0x00
1353- ss [ 565 ] = 0 ; // 0x00
1354-
1355- ss [ 570 ] = 181 ; // 0xB5
1356- ss [ 571 ] = 0 ; // 0x00
1357- ss [ 573 ] = 0 ; // 0x00
1358- ss [ 574 ] = 0 ; // 0x00
1359-
1360- ss [ 579 ] = 15 ; // 0x0F
1361- ss [ 580 ] = 1 ; // 0x01
1362- ss [ 582 ] = 0 ; // 0x00
1363- ss [ 583 ] = 0 ; // 0x00
1321+ if ( write )
1322+ {
1323+ ss [ 552 ] = 1 ; // 0x01
1324+ ss [ 553 ] = 0 ; // 0x00
1325+ ss [ 555 ] = 0 ; // 0x00
1326+ ss [ 556 ] = 0 ; // 0x00
1327+
1328+ ss [ 561 ] = 91 ; // 0x5B
1329+ ss [ 562 ] = 0 ; // 0x00
1330+ ss [ 564 ] = 0 ; // 0x00
1331+ ss [ 565 ] = 0 ; // 0x00
1332+
1333+ ss [ 570 ] = 181 ; // 0xB5
1334+ ss [ 571 ] = 0 ; // 0x00
1335+ ss [ 573 ] = 0 ; // 0x00
1336+ ss [ 574 ] = 0 ; // 0x00
1337+
1338+ ss [ 579 ] = 15 ; // 0x0F
1339+ ss [ 580 ] = 1 ; // 0x01
1340+ ss [ 582 ] = 0 ; // 0x00
1341+ ss [ 583 ] = 0 ; // 0x00
1342+ }
13641343 break ;
13651344
13661345 case 3 :
1367- if ( ssv2 )
1346+ if ( write && ssv2 )
13681347 {
13691348 ss [ 72 ] = 1 ; // 0x01
13701349 ss [ 73 ] = 0 ; // 0x00
@@ -1386,7 +1365,7 @@ public static bool FixSS(byte[] ss)
13861365 ss [ 102 ] = 15 ; // 0x0F
13871366 ss [ 103 ] = 1 ; // 0x01
13881367 }
1389- else
1368+ else if ( write )
13901369 {
13911370 ss [ 552 ] = 1 ; // 0x01
13921371 ss [ 553 ] = 0 ; // 0x00
@@ -1407,6 +1386,74 @@ public static bool FixSS(byte[] ss)
14071386 return false ;
14081387 }
14091388
1389+ // Determine challenge table offset
1390+ int ccrt_offset = 0 ;
1391+ if ( xgdType == 2 )
1392+ ccrt_offset = 0x200 ;
1393+ else if ( xgdType == 3 )
1394+ ccrt_offset = 0x20 ;
1395+
1396+ // Setup decryptor
1397+ #if NET20
1398+ using RijndaelManaged aes = new RijndaelManaged ( ) ;
1399+ aes . BlockSize = 128 ;
1400+ #else
1401+ using Aes aes = Aes . Create ( ) ;
1402+ #endif
1403+ aes . Key = new byte [ ] { 0xD1 , 0xE3 , 0xB3 , 0x3A , 0x6C , 0x1E , 0xF7 , 0x70 , 0x5F , 0x6D , 0xE9 , 0x3B , 0xB6 , 0xC0 , 0xDC , 0x71 } ;
1404+ aes . Mode = CipherMode . ECB ;
1405+ aes . Padding = PaddingMode . None ;
1406+ using ICryptoTransform decryptor = aes . CreateDecryptor ( ) ;
1407+
1408+ // Perform decryption
1409+ byte [ ] iv = new byte [ 16 ] ;
1410+ byte [ ] dcrt = new byte [ 252 ] ;
1411+ bool ct01_found = false ;
1412+ for ( int i = 0 ; i < 240 ; i += 16 )
1413+ {
1414+ decryptor . TransformBlock ( ss , 0x304 + i , 16 , dcrt , i ) ;
1415+ for ( int j = 0 ; j < 16 ; j ++ )
1416+ {
1417+ dcrt [ i + j ] ^= iv [ j ] ;
1418+ iv [ j ] = ss [ 0x304 + i + j ] ;
1419+ }
1420+ // Validate challenge type 1
1421+ if ( dcrt [ i ] == 1 )
1422+ {
1423+ // Cannot fix SS with two type 1 challenges
1424+ if ( ct01_found )
1425+ return false ;
1426+ ct01_found = true ;
1427+ // Challenge type 1 must match CPR_MAI
1428+ int cpr_mai_offset = ( xgdType == 3 ) ? 0xF0 : 0x2D0 ;
1429+ if ( dcrt [ i + 4 ] != ss [ cpr_mai_offset ] || dcrt [ i + 5 ] != ss [ cpr_mai_offset + 1 ] || dcrt [ i + 6 ] != ss [ cpr_mai_offset + 2 ] || dcrt [ i + 7 ] != ss [ cpr_mai_offset + 3 ] )
1430+ return false ;
1431+ }
1432+ // Cannot fix unknown challenge types
1433+ else if ( dcrt [ i ] != 0xE0 && dcrt [ i ] != 0x14 && dcrt [ i ] != 0x15 && dcrt [ i ] != 0x24 && dcrt [ i ] != 0x25 && ( dcrt [ i ] & 0xF ) != 0xF0 )
1434+ return false ;
1435+ }
1436+ Array . Copy ( ss , 0x304 + 240 , dcrt , 240 , 12 ) ;
1437+
1438+ // Check for empty challenge responses
1439+ int [ ] entryOffsets = [ 0 , 9 , 18 , 27 , 36 , 45 , 54 , 63 ] ;
1440+ int [ ] entryLengths = [ 8 , 8 , 8 , 8 , 4 , 4 , 4 , 4 ] ;
1441+ for ( int i = 0 ; i < entryOffsets . Length ; i ++ )
1442+ {
1443+ bool emptyResponse = true ;
1444+ for ( int b = 0 ; b < entryLengths [ i ] ; b ++ )
1445+ {
1446+ if ( ss [ ccrt_offset + entryOffsets [ i ] + b ] != 0x00 )
1447+ {
1448+ emptyResponse = false ;
1449+ break ;
1450+ }
1451+ }
1452+
1453+ if ( emptyResponse )
1454+ return false ;
1455+ }
1456+
14101457 // TODO: Repair challenge responses
14111458
14121459 return true ;
0 commit comments