diff --git a/BinaryObjectScanner/Protection/StarForce.cs b/BinaryObjectScanner/Protection/StarForce.cs index 1ec17df9..7ca2a7e6 100644 --- a/BinaryObjectScanner/Protection/StarForce.cs +++ b/BinaryObjectScanner/Protection/StarForce.cs @@ -29,16 +29,51 @@ namespace BinaryObjectScanner.Protection if (diskImage.VolumeDescriptorSet[0] is not PrimaryVolumeDescriptor pvd) return null; - // Starforce Keyless check #1: the reserved 653 bytes start with a 32-bit LE number that's slightly less + int offset = 0; + + // StarForce Keyless check: the key is stored in the Data Preparer identifier. + string? dataPreparerIdentiferString = pvd.DataPreparerIdentifier.ReadNullTerminatedAnsiString(ref offset)?.Trim(); + + if (dataPreparerIdentiferString != null + && dataPreparerIdentiferString.Length != 0 + && Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9-]*$")) + { + // It is returning the key, as it tells you what set of DPM your disc corresponds to, and it would also + // help show why a disc might be an alt of another disc (there are at least a decent amount of StarForce + // Keyless alts that would amtch otherwise). Unclear if this is desired by the users of BOS or those + // affected by it. + + // Thus far, the StarForce Keyless key is always made up of a number of characters, all either capital letters or + // numbers, sometimes with dashes in between. Thus far, 4 formats have been observed: + // XXXXXXXXXXXXXXXXXXXXXXXXX (25 characters) + // XXXXX-XXXXX-XXXXX-XXXXX-XXXXX (25 characters, plus 4 dashes seperating 5 groups of 5) + // XXXXXXXXXXXXXXXXXXXXXXXXXXXX (28 characters) + // XXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX (28 characters, with 4 dashes) + if (Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{25}$") + || Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}$") + || Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{28}$") + || Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{4}-[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{6}$")) + { + return $"StarForce Keyless - {dataPreparerIdentiferString}"; + } + + // Redump ID 60270 is a unique case, there could possibly be more. + if (UnusualStarforceKeylessKeys.ContainsKey(dataPreparerIdentiferString)) + return $"StarForce Keyless - {dataPreparerIdentiferString}"; + } + + // Starforce general check: the reserved 653 bytes start with a 32-bit LE number that's slightly less // than the length of the volume size space. The difference varies, it's usually around 10. Check 500 to be - // safe. The rest of the data is all 0x00. + // safe. The rest of the data is all 0x00. Not many starforce discs have this, but some do, and it's + // currently the only known non-keyless check. Redump ID 60266, 72531, 87181, 91734, 106732, 105356, 74578, + // 78200 are some examples. if (FileType.ISO9660.NoteworthyApplicationUse(pvd)) return null; if (!FileType.ISO9660.NoteworthyReserved653Bytes(pvd)) return null; - int offset = 0; + offset = 0; var reserved653Bytes = pvd.Reserved653Bytes; uint initialValue = reserved653Bytes.ReadUInt32LittleEndian(ref offset); @@ -48,48 +83,7 @@ namespace BinaryObjectScanner.Protection // through here. if (initialValue > pvd.VolumeSpaceSize || initialValue + 500 < pvd.VolumeSpaceSize || !Array.TrueForAll(zeroBytes, b => b == 0x00)) return null; - - offset = 0; - - // StarForce Keyless check #2: the key is stored in the Data Preparer identifier. - - // It turns out that some (i.e. Redump ID 60266, 72531, 87181, 91734, 106732, 105356, 74578, 78200) - // non-keyless StarForce discs still have this value here? This check may need to be disabled, but it - // seems to avoid any false positives in practice so far. - var dataPreparerIdentiferString = pvd.DataPreparerIdentifier.ReadNullTerminatedAnsiString(ref offset)?.Trim(); - if (dataPreparerIdentiferString == null || dataPreparerIdentiferString.Length == 0) - return "StarForce"; - - // It is returning the key, as it tells you what set of DPM your disc corresponds to, and it would also - // help show why a disc might be an alt of another disc (there are at least a decent amount of StarForce - // Keyless alts that would amtch otherwise). Unclear if this is desired by the users of BOS or those - // affected by it. - - // Thus far, the StarForce Keyless key is always made up of a number of characters, all either capital letters or - // numbers, sometimes with dashes in between. Thus far, 4 formats have been observed: - // XXXXXXXXXXXXXXXXXXXXXXXXX (25 characters) - // XXXXX-XXXXX-XXXXX-XXXXX-XXXXX (25 characters, plus 4 dashes seperating 5 groups of 5) - // XXXXXXXXXXXXXXXXXXXXXXXXXXXX (28 characters) - // XXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX (28 characters, with 4 dashes) - if (Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{25}$") - || Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}$") - || Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{28}$") - || Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{4}-[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{6}$")) - { - return $"StarForce Keyless - {dataPreparerIdentiferString}"; - } - - // Redump ID 60270 is a unique case, there could possibly be more. - if (UnusualStarforceKeylessKeys.ContainsKey(dataPreparerIdentiferString)) - return $"StarForce Keyless - {dataPreparerIdentiferString}"; - - // In case any variants were missed. - if (Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9-]*$")) - return $"StarForce Keyless - {dataPreparerIdentiferString} - Unknown variant, please report to us on GitHub!"; - - // 34206 reaches this because it's not keyless, and has "WinISO software" as the DPI string. However, since - // it has lowercase letters and spaces, it's caught here. It is genuinely StarForce, so it's not a false - // positive. + return "StarForce"; }