Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 39 additions & 45 deletions BinaryObjectScanner/Protection/StarForce.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,51 @@ public class StarForce : IDiskImageCheck<ISO9660>, IExecutableCheck<PortableExec
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);
Expand All @@ -48,48 +83,7 @@ public class StarForce : IDiskImageCheck<ISO9660>, IExecutableCheck<PortableExec
// 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";
}

Expand Down