Skip to content

Commit 805beb3

Browse files
Improve starforce keyless detection (#396)
1 parent cc7592e commit 805beb3

File tree

1 file changed

+39
-45
lines changed

1 file changed

+39
-45
lines changed

BinaryObjectScanner/Protection/StarForce.cs

Lines changed: 39 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,51 @@ public class StarForce : IDiskImageCheck<ISO9660>, IExecutableCheck<PortableExec
2929
if (diskImage.VolumeDescriptorSet[0] is not PrimaryVolumeDescriptor pvd)
3030
return null;
3131

32-
// Starforce Keyless check #1: the reserved 653 bytes start with a 32-bit LE number that's slightly less
32+
int offset = 0;
33+
34+
// StarForce Keyless check: the key is stored in the Data Preparer identifier.
35+
string? dataPreparerIdentiferString = pvd.DataPreparerIdentifier.ReadNullTerminatedAnsiString(ref offset)?.Trim();
36+
37+
if (dataPreparerIdentiferString != null
38+
&& dataPreparerIdentiferString.Length != 0
39+
&& Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9-]*$"))
40+
{
41+
// It is returning the key, as it tells you what set of DPM your disc corresponds to, and it would also
42+
// help show why a disc might be an alt of another disc (there are at least a decent amount of StarForce
43+
// Keyless alts that would amtch otherwise). Unclear if this is desired by the users of BOS or those
44+
// affected by it.
45+
46+
// Thus far, the StarForce Keyless key is always made up of a number of characters, all either capital letters or
47+
// numbers, sometimes with dashes in between. Thus far, 4 formats have been observed:
48+
// XXXXXXXXXXXXXXXXXXXXXXXXX (25 characters)
49+
// XXXXX-XXXXX-XXXXX-XXXXX-XXXXX (25 characters, plus 4 dashes seperating 5 groups of 5)
50+
// XXXXXXXXXXXXXXXXXXXXXXXXXXXX (28 characters)
51+
// XXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX (28 characters, with 4 dashes)
52+
if (Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{25}$")
53+
|| Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}$")
54+
|| Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{28}$")
55+
|| Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{4}-[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{6}$"))
56+
{
57+
return $"StarForce Keyless - {dataPreparerIdentiferString}";
58+
}
59+
60+
// Redump ID 60270 is a unique case, there could possibly be more.
61+
if (UnusualStarforceKeylessKeys.ContainsKey(dataPreparerIdentiferString))
62+
return $"StarForce Keyless - {dataPreparerIdentiferString}";
63+
}
64+
65+
// Starforce general check: the reserved 653 bytes start with a 32-bit LE number that's slightly less
3366
// than the length of the volume size space. The difference varies, it's usually around 10. Check 500 to be
34-
// safe. The rest of the data is all 0x00.
67+
// safe. The rest of the data is all 0x00. Not many starforce discs have this, but some do, and it's
68+
// currently the only known non-keyless check. Redump ID 60266, 72531, 87181, 91734, 106732, 105356, 74578,
69+
// 78200 are some examples.
3570
if (FileType.ISO9660.NoteworthyApplicationUse(pvd))
3671
return null;
3772

3873
if (!FileType.ISO9660.NoteworthyReserved653Bytes(pvd))
3974
return null;
4075

41-
int offset = 0;
76+
offset = 0;
4277

4378
var reserved653Bytes = pvd.Reserved653Bytes;
4479
uint initialValue = reserved653Bytes.ReadUInt32LittleEndian(ref offset);
@@ -48,48 +83,7 @@ public class StarForce : IDiskImageCheck<ISO9660>, IExecutableCheck<PortableExec
4883
// through here.
4984
if (initialValue > pvd.VolumeSpaceSize || initialValue + 500 < pvd.VolumeSpaceSize || !Array.TrueForAll(zeroBytes, b => b == 0x00))
5085
return null;
51-
52-
offset = 0;
53-
54-
// StarForce Keyless check #2: the key is stored in the Data Preparer identifier.
55-
56-
// It turns out that some (i.e. Redump ID 60266, 72531, 87181, 91734, 106732, 105356, 74578, 78200)
57-
// non-keyless StarForce discs still have this value here? This check may need to be disabled, but it
58-
// seems to avoid any false positives in practice so far.
59-
var dataPreparerIdentiferString = pvd.DataPreparerIdentifier.ReadNullTerminatedAnsiString(ref offset)?.Trim();
60-
if (dataPreparerIdentiferString == null || dataPreparerIdentiferString.Length == 0)
61-
return "StarForce";
62-
63-
// It is returning the key, as it tells you what set of DPM your disc corresponds to, and it would also
64-
// help show why a disc might be an alt of another disc (there are at least a decent amount of StarForce
65-
// Keyless alts that would amtch otherwise). Unclear if this is desired by the users of BOS or those
66-
// affected by it.
67-
68-
// Thus far, the StarForce Keyless key is always made up of a number of characters, all either capital letters or
69-
// numbers, sometimes with dashes in between. Thus far, 4 formats have been observed:
70-
// XXXXXXXXXXXXXXXXXXXXXXXXX (25 characters)
71-
// XXXXX-XXXXX-XXXXX-XXXXX-XXXXX (25 characters, plus 4 dashes seperating 5 groups of 5)
72-
// XXXXXXXXXXXXXXXXXXXXXXXXXXXX (28 characters)
73-
// XXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX (28 characters, with 4 dashes)
74-
if (Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{25}$")
75-
|| Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}$")
76-
|| Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{28}$")
77-
|| Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9]{4}-[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{6}$"))
78-
{
79-
return $"StarForce Keyless - {dataPreparerIdentiferString}";
80-
}
81-
82-
// Redump ID 60270 is a unique case, there could possibly be more.
83-
if (UnusualStarforceKeylessKeys.ContainsKey(dataPreparerIdentiferString))
84-
return $"StarForce Keyless - {dataPreparerIdentiferString}";
85-
86-
// In case any variants were missed.
87-
if (Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9-]*$"))
88-
return $"StarForce Keyless - {dataPreparerIdentiferString} - Unknown variant, please report to us on GitHub!";
89-
90-
// 34206 reaches this because it's not keyless, and has "WinISO software" as the DPI string. However, since
91-
// it has lowercase letters and spaces, it's caught here. It is genuinely StarForce, so it's not a false
92-
// positive.
86+
9387
return "StarForce";
9488
}
9589

0 commit comments

Comments
 (0)