|
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
| 3 | +using System.Text.RegularExpressions; |
3 | 4 | using BinaryObjectScanner.Interfaces; |
| 5 | +using SabreTools.Data.Models.ISO9660; |
4 | 6 | using SabreTools.IO; |
5 | 7 | using SabreTools.IO.Extensions; |
6 | 8 | using SabreTools.IO.Matching; |
7 | 9 | using SabreTools.Serialization.Wrappers; |
8 | 10 |
|
9 | 11 | namespace BinaryObjectScanner.Protection |
10 | 12 | { |
11 | | - public class StarForce : IExecutableCheck<PortableExecutable>, IPathCheck |
| 13 | + public class StarForce : IExecutableCheck<PortableExecutable>, IPathCheck, IISOCheck<ISO9660> |
12 | 14 | { |
13 | 15 | // TODO: Bring up to par with PiD. |
14 | 16 | // Known issues: |
@@ -160,5 +162,48 @@ public List<string> CheckDirectoryPath(string path, List<string>? files) |
160 | 162 | // TODO: Determine if there are any file name checks that aren't too generic to use on their own. |
161 | 163 | return null; |
162 | 164 | } |
| 165 | + |
| 166 | + public string? CheckISO(string file, ISO9660 iso, bool includeDebug) |
| 167 | + { |
| 168 | + var pvd = (PrimaryVolumeDescriptor)iso.VolumeDescriptorSet[0]; |
| 169 | + |
| 170 | + int offset = 0; |
| 171 | + |
| 172 | + // StarForce Keyless check #1: the key is stored in the Data Preparer identifier. Length varies, minimum |
| 173 | + // length unknown, but it shouldn't be less than 8 at the very least. It's usually 15-24. It's only |
| 174 | + // made up of numbers, capital letters, and dashes. |
| 175 | + var dataPreparerIdentiferString = pvd.DataPreparerIdentifier.ReadNullTerminatedAnsiString(ref offset)?.Trim(); |
| 176 | + if (dataPreparerIdentiferString == null || dataPreparerIdentiferString.Length < 8) |
| 177 | + return null; |
| 178 | + |
| 179 | + if (!Regex.IsMatch(dataPreparerIdentiferString, "^[A-Z0-9-]*$")) |
| 180 | + return null; |
| 181 | + |
| 182 | + // Starforce Keyless check #2: the reserved 653 bytes start with a 32-bit LE number that's slightly less |
| 183 | + // than the length of the volume size space. The difference varies, it's usually around 10. Check 500 to be |
| 184 | + // safe. The rest of the data is all 0x00. |
| 185 | + if (FileType.ISO9660.NoteworthyApplicationUse(pvd)) |
| 186 | + return null; |
| 187 | + |
| 188 | + if (!FileType.ISO9660.NoteworthyReserved653Bytes(pvd)) |
| 189 | + return null; |
| 190 | + |
| 191 | + offset = 0; |
| 192 | + |
| 193 | + var reserved653Bytes = pvd.Reserved653Bytes; |
| 194 | + var initialValue = reserved653Bytes.ReadUInt32LittleEndian(ref offset); |
| 195 | + var zeroBytes = reserved653Bytes.ReadBytes(ref offset, 508); |
| 196 | + |
| 197 | + if (initialValue + 500 < pvd.VolumeSpaceSize || !Array.TrueForAll(zeroBytes, b => b == 0x00)) |
| 198 | + return null; |
| 199 | + |
| 200 | + // It's unfortunately not known to be possible to detect non-keyless StarForce discs. |
| 201 | + |
| 202 | + // It may be worth returning the key, as it tells you what set of DPM your disc corresponds to, and it would |
| 203 | + // also help show why a disc might be an alt of another disc (there are at least a decent amount of StarForce |
| 204 | + // Keyless alts that would amtch otherwise). Unclear if this is desired by the users of BOS or those affected |
| 205 | + // by it. |
| 206 | + return $"StarForce Keyless - {dataPreparerIdentiferString}"; |
| 207 | + } |
163 | 208 | } |
164 | 209 | } |
0 commit comments