@@ -1294,6 +1294,10 @@ public static bool FixSS(byte[] ss, bool write = true)
12941294 if ( ! GetXGDType ( ss , out int xgdType ) )
12951295 return false ;
12961296
1297+ // Cannot fix XGD1
1298+ if ( xgdType == 1 )
1299+ return true ;
1300+
12971301 // Determine if XGD3 SS.bin is SSv1 (Original Kreon) or SSv2 (0800 / Repaired Kreon)
12981302#if NET20
12991303 var checkArr = new byte [ 72 ] ;
@@ -1307,13 +1311,171 @@ public static bool FixSS(byte[] ss, bool write = true)
13071311 if ( xgdType == 3 && ! ssv2 )
13081312 return false ;
13091313
1314+ // Must be 21 challenge entries
1315+ if ( ss [ 0x660 ] != 21 )
1316+ return false ;
1317+
1318+ // Setup decryptor
1319+ #if NET20
1320+ using RijndaelManaged aes = new RijndaelManaged ( ) ;
1321+ aes . BlockSize = 128 ;
1322+ #else
1323+ using Aes aes = Aes . Create ( ) ;
1324+ #endif
1325+ aes . Key = new byte [ ] { 0xD1 , 0xE3 , 0xB3 , 0x3A , 0x6C , 0x1E , 0xF7 , 0x70 , 0x5F , 0x6D , 0xE9 , 0x3B , 0xB6 , 0xC0 , 0xDC , 0x71 } ;
1326+ aes . Mode = CipherMode . CBC ;
1327+ aes . Padding = PaddingMode . None ;
1328+ using ICryptoTransform decryptor = aes . CreateDecryptor ( ) ;
1329+
1330+ // Perform decryption
1331+ byte [ ] iv = new byte [ 16 ] ;
1332+ byte [ ] dcrt = new byte [ 252 ] ;
1333+ bool ct01_found = false ;
1334+ for ( int i = 0 ; i < 240 ; i += 16 )
1335+ decryptor . TransformBlock ( ss , 0x304 + i , 16 , dcrt , i ) ;
1336+ Array . Copy ( ss , 0x304 + 240 , dcrt , 240 , 12 ) ;
1337+
1338+ // Rebuild challenge response table
1339+ var cids = new Dictionary < byte , byte > ( ) ;
1340+ for ( int i = 0 ; i < dcrt . Length ; i += 12 )
1341+ {
1342+ // Validate challenge type 1
1343+ if ( dcrt [ i ] == 1 )
1344+ {
1345+ // Cannot fix SS with two type 1 challenges
1346+ if ( ct01_found )
1347+ return false ;
1348+ ct01_found = true ;
1349+ // Challenge type 1 must match CPR_MAI
1350+ int cpr_mai_offset = ( xgdType == 3 ) ? 0xF0 : 0x2D0 ;
1351+ 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 ] )
1352+ return false ;
1353+ }
1354+ // Check CIDs of known challenges
1355+ else if ( dcrt [ i ] == 0x14 || dcrt [ i ] == 0x15 || dcrt [ i ] == 0x24 || dcrt [ i ] == 0x25 || dcrt [ i ] != 0xE0 || ( dcrt [ i ] & 0xF ) != 0xF0 )
1356+ {
1357+ // Cannot fix SS with duplicate Challenge IDs
1358+ if ( cids . ContainsKey ( dcrt [ i + 1 ] ) )
1359+ return false ;
1360+ cids . Add ( dcrt [ i + 1 ] , i ) ;
1361+ }
1362+ // Cannot fix SS with unknown challenge types
1363+ else
1364+ return false ;
1365+ }
1366+
1367+ // Determine challenge table offset
1368+ int ccrt_offset = 0 ;
1369+ if ( xgdType == 2 )
1370+ ccrt_offset = 0x200 ;
1371+ else if ( xgdType == 3 )
1372+ ccrt_offset = 0x20 ;
1373+
1374+ // Repair challenge table
1375+ for ( int i = 0 ; i < 23 ; i ++ )
1376+ {
1377+ // Cannot rebuild SS with orphan challenge ID
1378+ if ( ! cids . TryGetValue ( ss [ 0x730 + i * 9 + 1 ] , out byte cOffset ) )
1379+ return ;
1380+
1381+ // Validate challenge type with response type
1382+ byte rOffset = 0x730 + i * 9 ;
1383+ bool angle_challenge = false ;
1384+ bool other_challenge = false ;
1385+ int challenge_count = 0 ;
1386+ switch ( ss [ cOffset ] )
1387+ {
1388+ case 0x14 :
1389+ if ( ss [ rOffset ] != 3 )
1390+ return false ;
1391+ challenge_count += 1 ;
1392+ // Challenge must be in expected order
1393+ if ( challenge_count > 5 )
1394+ return false ;
1395+ break ;
1396+ case 0x15 :
1397+ if ( ss [ rOffset ] != 1 )
1398+ return false ;
1399+ challenge_count += 1 ;
1400+ // Challenge must be in expected order
1401+ if ( challenge_count < 5 )
1402+ return false ;
1403+ break ;
1404+ case 0x24 :
1405+ if ( ss [ rOffset ] != 7 )
1406+ return false ;
1407+ challenge_count += 1 ;
1408+ // Challenge must be in expected order
1409+ if ( challenge_count < 5 || challenge_count > 8 )
1410+ return false ;
1411+ angle_challenge = true ;
1412+ break ;
1413+ case 0x25 :
1414+ if ( ss [ rOffset ] != 9 )
1415+ return false ;
1416+ challenge_count += 1 ;
1417+ // Challenge must be in expected order
1418+ if ( challenge_count < 5 || challenge_count > 8 )
1419+ return false ;
1420+ angle_challenge = true ;
1421+ break ;
1422+ default :
1423+ other_challenge = true ;
1424+ break ;
1425+ }
1426+
1427+ // Skip other challenges
1428+ if ( other_challenge )
1429+ continue ;
1430+
1431+ // Set/check challenge data
1432+ if ( ! write && ss [ ccrt_offset + i * 9 ] != ss [ cOffset + 4 ] )
1433+ return false ;
1434+ else
1435+ ss [ ccrt_offset + i * 9 ] = ss [ cOffset + 4 ] ;
1436+ if ( ! write && ss [ ccrt_offset + i * 9 + 1 ] != ss [ cOffset + 5 ] )
1437+ return false
1438+ else
1439+ ss[ ccrt_offset + i * 9 + 1 ] = ss [ cOffset + 5 ] ;
1440+ if ( ! write && ss [ ccrt_offset + i * 9 + 2 ] != ss [ cOffset + 6 ] )
1441+ return false
1442+ else
1443+ ss[ ccrt_offset + i * 9 + 2 ] = ss [ cOffset + 6 ] ;
1444+ if ( ! write && ss [ ccrt_offset + i * 9 + 3 ] != ss [ cOffset + 7 ] )
1445+ return false
1446+ else
1447+ ss[ ccrt_offset + i * 9 + 2 ] = ss [ cOffset + 7 ] ;
1448+
1449+ // Set challenge response for non-angle challenges
1450+ if ( ! angle_challenge )
1451+ {
1452+ if ( ! write && ss [ ccrt_offset + i * 9 + 4 ] != ss [ cOffset + 8 ] )
1453+ return false ;
1454+ else
1455+ ss [ ccrt_offset + i * 9 + 4 ] = ss [ cOffset + 8 ] ;
1456+ if ( ! write && ss [ ccrt_offset + i * 9 + 5 ] != ss [ cOffset + 9 ] )
1457+ return false ;
1458+ else
1459+ ss [ ccrt_offset + i * 9 + 5 ] = ss [ cOffset + 9 ] ;
1460+ if ( ! write && ss [ ccrt_offset + i * 9 + 6 ] != ss [ cOffset + 10 ] )
1461+ return false ;
1462+ else
1463+ ss [ ccrt_offset + i * 9 + 6 ] = ss [ cOffset + 10 ] ;
1464+ if ( ! write && ss [ ccrt_offset + i * 9 + 7 ] != ss [ cOffset + 11 ] )
1465+ return false ;
1466+ else
1467+ ss [ ccrt_offset + i * 9 + 7 ] = ss [ cOffset + 11 ] ;
1468+ if ( ! write && ss [ ccrt_offset + i * 9 + 8 ] != 0 )
1469+ return false ;
1470+ else
1471+ ss [ ccrt_offset + i * 9 + 8 ] = 0 ;
1472+ }
1473+
1474+ }
1475+
13101476 // Clean SS (set fixed angles)
13111477 switch ( xgdType )
13121478 {
1313- case 1 :
1314- // Cannot clean or fix XGD1 SS
1315- return true ;
1316-
13171479 case 2 :
13181480 // Fix standard SSv1 ss.bin
13191481 if ( write )
@@ -1370,80 +1532,6 @@ public static bool FixSS(byte[] ss, bool write = true)
13701532 return false ;
13711533 }
13721534
1373- // Must be 21 challenge entries
1374- if ( ss [ 0x660 ] != 21 )
1375- return false ;
1376-
1377- // Determine challenge table offset
1378- int ccrt_offset = 0 ;
1379- if ( xgdType == 2 )
1380- ccrt_offset = 0x200 ;
1381- else if ( xgdType == 3 )
1382- ccrt_offset = 0x20 ;
1383-
1384- // Setup decryptor
1385- #if NET20
1386- using RijndaelManaged aes = new RijndaelManaged ( ) ;
1387- aes . BlockSize = 128 ;
1388- #else
1389- using Aes aes = Aes . Create ( ) ;
1390- #endif
1391- aes . Key = new byte [ ] { 0xD1 , 0xE3 , 0xB3 , 0x3A , 0x6C , 0x1E , 0xF7 , 0x70 , 0x5F , 0x6D , 0xE9 , 0x3B , 0xB6 , 0xC0 , 0xDC , 0x71 } ;
1392- aes . Mode = CipherMode . ECB ;
1393- aes . Padding = PaddingMode . None ;
1394- using ICryptoTransform decryptor = aes . CreateDecryptor ( ) ;
1395-
1396- // Perform decryption
1397- byte [ ] iv = new byte [ 16 ] ;
1398- byte [ ] dcrt = new byte [ 252 ] ;
1399- bool ct01_found = false ;
1400- for ( int i = 0 ; i < 240 ; i += 16 )
1401- {
1402- decryptor . TransformBlock ( ss , 0x304 + i , 16 , dcrt , i ) ;
1403- for ( int j = 0 ; j < 16 ; j ++ )
1404- {
1405- dcrt [ i + j ] ^= iv [ j ] ;
1406- iv [ j ] = ss [ 0x304 + i + j ] ;
1407- }
1408-
1409- // Validate challenge type 1
1410- if ( dcrt [ i ] == 1 )
1411- {
1412- // Cannot fix SS with two type 1 challenges
1413- if ( ct01_found )
1414- return false ;
1415- ct01_found = true ;
1416- // Challenge type 1 must match CPR_MAI
1417- int cpr_mai_offset = ( xgdType == 3 ) ? 0xF0 : 0x2D0 ;
1418- 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 ] )
1419- return false ;
1420- }
1421- // Cannot fix unknown challenge types
1422- else if ( dcrt [ i ] != 0xE0 && dcrt [ i ] != 0x14 && dcrt [ i ] != 0x15 && dcrt [ i ] != 0x24 && dcrt [ i ] != 0x25 && ( dcrt [ i ] & 0xF ) != 0xF0 )
1423- return false ;
1424- }
1425- Array . Copy ( ss , 0x304 + 240 , dcrt , 240 , 12 ) ;
1426-
1427- int [ ] entryOffsets = [ 0 , 9 , 18 , 27 , 36 , 45 , 54 , 63 ] ;
1428- int [ ] entryLengths = [ 8 , 8 , 8 , 8 , 4 , 4 , 4 , 4 ] ;
1429- for ( int i = 0 ; i < entryOffsets . Length ; i ++ )
1430- {
1431- bool emptyResponse = true ;
1432- for ( int b = 0 ; b < entryLengths [ i ] ; b ++ )
1433- {
1434- if ( ss [ ccrt_offset + entryOffsets [ i ] + b ] != 0x00 )
1435- {
1436- emptyResponse = false ;
1437- break ;
1438- }
1439- }
1440-
1441- if ( emptyResponse )
1442- return false ;
1443- }
1444-
1445- // TODO: Repair challenge responses
1446-
14471535 return true ;
14481536 }
14491537
0 commit comments