Skip to content

Commit 7dcb946

Browse files
authored
Repair CCRT
1 parent 28d63a1 commit 7dcb946

File tree

1 file changed

+166
-78
lines changed

1 file changed

+166
-78
lines changed

MPF.Processors/ProcessingTool.cs

Lines changed: 166 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)