-
Notifications
You must be signed in to change notification settings - Fork 15
Initial ISO Protection Detection #389
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 29 commits
0ca0a84
ca9f667
ec76f82
f1374a7
4871899
495e220
0bb0285
55ebf89
571e639
33040b8
53f96be
a07f50f
d5dfcae
b3ba774
5c42ed5
c5ef1da
47bd3bf
cf3f874
4af8d71
81f0662
fc81ca1
e7c2628
5b91424
d490a83
6ae8b26
33391fa
696016b
e50ea79
852015c
dfba726
50acaa8
8dc43b9
cbdd32a
c6947bb
c48f373
a4bd666
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.IO; | ||
| using BinaryObjectScanner.Data; | ||
| using BinaryObjectScanner.Interfaces; | ||
| using SabreTools.IO.Extensions; | ||
| using SabreTools.Serialization.Wrappers; | ||
|
|
||
| namespace BinaryObjectScanner.FileType | ||
| { | ||
| /// <summary> | ||
| /// .iso file | ||
| /// </summary> | ||
| public abstract class DiskImage<T> : DetectableBase<T> | ||
| where T : WrapperBase | ||
| { | ||
| /// <inheritdoc/> | ||
| public DiskImage(T wrapper) : base(wrapper) { } | ||
|
|
||
| #region Check Runners | ||
|
|
||
| /// <summary> | ||
| /// Handle a single file based on all ISO check implementations | ||
| /// </summary> | ||
| /// <param name="file">Name of the source file of the ISO, for tracking</param> | ||
| /// <param name="iso">ISO to scan</param> | ||
| /// <param name="checks">Set of checks to use</param> | ||
| /// <param name="includeDebug">True to include debug data, false otherwise</param> | ||
| /// <returns>Set of protections in file, empty on error</returns> | ||
| protected IDictionary<U, string> RunISOChecks<U>(string file, T iso, U[] checks, bool includeDebug) | ||
mnadareski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| where U : IISOCheck<T> | ||
| { | ||
| // Create the output dictionary | ||
| var protections = new CheckDictionary<U>(); | ||
|
|
||
| // Iterate through all checks | ||
| checks.IterateWithAction(checkClass => | ||
| { | ||
| // Get the protection for the class, if possible | ||
| var protection = checkClass.CheckISO(file, iso, includeDebug); | ||
| if (string.IsNullOrEmpty(protection)) | ||
| return; | ||
|
|
||
| protections.Append(checkClass, protection); | ||
| }); | ||
|
|
||
| return protections; | ||
| } | ||
|
|
||
| #endregion | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.IO; | ||
| using System.Text; | ||
| using System.Text.RegularExpressions; | ||
| using BinaryObjectScanner.Data; | ||
| using SabreTools.Data.Models.ISO9660; | ||
| using SabreTools.IO.Extensions; | ||
|
|
||
| namespace BinaryObjectScanner.FileType | ||
| { | ||
| /// <summary> | ||
| /// ISO9660 | ||
| /// </summary> | ||
| public class ISO9660 : DiskImage<SabreTools.Serialization.Wrappers.ISO9660> | ||
| { | ||
| /// <inheritdoc/> | ||
| public ISO9660(SabreTools.Serialization.Wrappers.ISO9660 wrapper) : base(wrapper) { } | ||
|
|
||
| /// <inheritdoc/> | ||
| public override string? Detect(Stream stream, string file, bool includeDebug) | ||
| { | ||
| // Create the output dictionary | ||
| var protections = new ProtectionDictionary(); | ||
|
|
||
| // Standard checks | ||
| var subProtections | ||
| = RunISOChecks(file, _wrapper, StaticChecks.ISO9660CheckClasses, includeDebug); | ||
| protections.Append(file, subProtections.Values); | ||
|
|
||
| // If there are no protections | ||
| if (protections.Count == 0) | ||
| return null; | ||
|
|
||
| // Create the internal list | ||
| var protectionList = new List<string>(); | ||
| foreach (string key in protections.Keys) | ||
| { | ||
| protectionList.AddRange(protections[key]); | ||
| } | ||
|
|
||
| return string.Join(";", [.. protectionList]); | ||
| } | ||
|
|
||
| // Checks whether the sequence of bytes is pure data (as in, not empty, not text, just high-entropy data) | ||
mnadareski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| public static bool IsPureData(byte[] bytes) | ||
| { | ||
| // Check if there are three 0x00s in a row. Two seems like pushing it | ||
| byte[] containedZeroes = {0x00, 0x00, 0x00}; | ||
| int index = 0; | ||
| for (int i = 0; i < bytes.Length; ++i) { | ||
mnadareski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (bytes[i] == containedZeroes[index]) | ||
| { | ||
| if (++index >= containedZeroes.Length) | ||
| return false; | ||
| } | ||
| else | ||
| index = 0; | ||
mnadareski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // Checks if there are strings in the data | ||
| // TODO: is this too dangerous, or too faulty? | ||
| // Currently-found worst cases: | ||
| // "Y:1BY:1BC" in Redump ID 23339 | ||
| var strings = bytes.ReadStringsWithEncoding(charLimit: 7, Encoding.ASCII); | ||
mnadareski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Regex rgx = new Regex("[^a-zA-Z0-9 -'!?,.]"); | ||
mnadareski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| foreach (string str in strings) | ||
| { | ||
| if (rgx.Replace(str, "").Length > 7) | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| // TODO: can these 2 "noteworthy" functions be cached? | ||
| // Checks whether the Application Use data is "noteworthy" enough to be worth checking for protection. | ||
| public static bool NoteworthyApplicationUse(PrimaryVolumeDescriptor pvd) | ||
mnadareski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| int offset = 0; | ||
mnadareski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| var applicationUse = pvd.ApplicationUse; | ||
| var noteworthyApplicationUse = true; | ||
mnadareski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (Array.TrueForAll(applicationUse, b => b == 0x00)) | ||
| noteworthyApplicationUse = false; | ||
| string? potentialAppUseString = applicationUse.ReadNullTerminatedAnsiString(ref offset); | ||
| if (potentialAppUseString != null && potentialAppUseString.Length > 0) // Some image authoring programs add a starting string to AU data | ||
| { | ||
| if (potentialAppUseString.StartsWith("ImgBurn")) | ||
| noteworthyApplicationUse = false; | ||
| else if (potentialAppUseString.StartsWith("ULTRAISO")) | ||
| noteworthyApplicationUse = false; | ||
| else if (potentialAppUseString.StartsWith("Rimage")) | ||
| noteworthyApplicationUse = false; | ||
| else if (Array.TrueForAll(Encoding.ASCII.GetBytes(potentialAppUseString), b => b == 0x20)) | ||
| noteworthyApplicationUse = false; | ||
| // TODO: Unhandled "norb" mastering that puts stuff everywhere, inconsistently. See RID 103641 | ||
| // More things will have to go here as more disc authoring softwares are found that do this. | ||
| // Redump ID 24478 has a bunch of 0x20 with norb in the middle, some discs have 0x20 that ends in a "/" | ||
| // character. If these are found to be causing issues they can be added. | ||
| } | ||
|
|
||
| offset = 141; | ||
| potentialAppUseString = applicationUse.ReadNullTerminatedAnsiString(ref offset); | ||
| if (potentialAppUseString == "CD-XA001") | ||
| noteworthyApplicationUse = false; | ||
|
|
||
| return noteworthyApplicationUse; | ||
| } | ||
|
|
||
| // Checks whether the Reserved 653 Bytes are "noteworthy" enough to be worth checking for protection. | ||
| public static bool NoteworthyReserved653Bytes(PrimaryVolumeDescriptor pvd) | ||
| { | ||
| var reserved653Bytes = pvd.Reserved653Bytes; | ||
| var noteworthyReserved653Bytes = true; | ||
| if (Array.TrueForAll(reserved653Bytes, b => b == 0x00)) | ||
| noteworthyReserved653Bytes = false; | ||
| // Unsure if more will be needed | ||
| return noteworthyReserved653Bytes; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| using SabreTools.Serialization.Wrappers; | ||
|
|
||
| namespace BinaryObjectScanner.Interfaces | ||
| { | ||
| /// <summary> | ||
| /// Check an ISO for protection | ||
| /// </summary> | ||
| public interface IISOCheck<T> where T : WrapperBase | ||
mnadareski marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| /// <summary> | ||
| /// Check a path for protections based on file contents | ||
| /// </summary> | ||
| /// <param name="file">File to check for protection indicators</param> | ||
| /// <param name="iso">ISO representing the read-in file</param> | ||
| /// <param name="includeDebug">True to include debug data, false otherwise</param> | ||
| /// <returns>String containing any protections found in the file</returns> | ||
| string? CheckISO(string file, T iso, bool includeDebug); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.